istereo2

view libs/goatkit/theme.cc @ 11:03cc3b1884d1

implemented builtin themes registration and lookup in goatkit
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 28 Sep 2015 06:53:06 +0300
parents 64e15874f3bd
children
line source
1 /*
2 GoatKit - a themable/animated widget toolkit for games
3 Copyright (C) 2014-2015 John Tsiombikas <nuclear@member.fsf.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "config.h"
19 #include <stdio.h>
20 #include <vector>
21 #include <string>
22 #include <map>
23 #include <algorithm>
24 #include <string.h>
25 #include "theme.h"
26 #include "widget.h"
28 #ifdef WIN32
29 #include <windows.h>
31 #define RTLD_DEFAULT ((void*)0)
33 static void *dlopen(const char *name, int flags);
34 static void dlclose(void *so);
35 static void *dlsym(void *so, const char *symbol);
36 #else
37 #include <unistd.h>
38 #include <dlfcn.h>
39 #endif
41 #ifdef HAVE_OPENGL_H
42 #include "opengl.h"
44 #else
46 #ifdef __APPLE__
47 #include <OpenGL/gl.h>
48 #else
49 #include <GL/gl.h>
50 #endif
52 #endif /* HAVE_OPENGL_H_ */
54 #ifndef PREFIX
55 #define PREFIX "/usr/local"
56 #endif
58 namespace goatkit {
60 struct ThemeImpl {
61 void *so;
62 WidgetDrawFunc (*lookup_theme_draw_func)(const char*);
63 mutable std::map<std::string, WidgetDrawFunc> func_cache;
64 };
66 Theme *theme;
67 static std::vector<std::string> search_paths;
68 static const char *fallback_paths[] = {
69 PREFIX "/share/goatkit",
70 0
71 };
73 typedef std::map<std::string, Theme*> ThemeMap;
74 static ThemeMap *themes;
77 void add_theme_path(const char *path)
78 {
79 if(!path || !*path) return;
81 std::string s = path;
82 int last = s.length() - 1;
83 if(s[last] == '/' || s[last] == '\\') {
84 s.erase(last);
85 }
87 if(std::find(search_paths.begin(), search_paths.end(), s) != search_paths.end()) {
88 return;
89 }
91 search_paths.push_back(s);
92 }
94 void register_theme(const char *name, Theme *theme)
95 {
96 if(!themes) {
97 themes = new ThemeMap;
98 }
100 Theme *prev = (*themes)[name];
101 if(prev) {
102 delete prev;
103 }
104 (*themes)[name] = theme;
105 }
107 Theme *get_theme(const char *name)
108 {
109 // first search in the already registered themes
110 ThemeMap::const_iterator it = themes->find(name);
111 if(it != themes->end()) {
112 return it->second;
113 }
115 // then try loading it from a theme plugin
116 Theme *theme = new Theme;
117 if(theme->load(name)) {
118 return theme;
119 }
121 fprintf(stderr, "[goatkit] theme \"%s\" not found!\n", name);
122 return 0;
123 }
125 Theme::Theme()
126 {
127 impl = new ThemeImpl;
128 impl->so = 0;
129 impl->lookup_theme_draw_func = 0;
130 }
132 Theme::Theme(const char *name, WidgetLookupFunc func)
133 {
134 impl = new ThemeImpl;
135 impl->so = 0;
136 impl->lookup_theme_draw_func = func;
138 register_theme(name, this);
139 }
141 Theme::~Theme()
142 {
143 unload();
144 delete impl;
145 }
147 typedef WidgetDrawFunc (*LookupFunc)(const char*);
149 bool Theme::load(const char *name)
150 {
151 unload();
153 std::string fname = std::string(name) + ".gtheme";
154 if(!(impl->so = dlopen(fname.c_str(), RTLD_LAZY))) {
155 for(size_t i=0; i<search_paths.size(); i++) {
156 std::string path = search_paths[i] + "/" + fname;
158 if((impl->so = dlopen(path.c_str(), RTLD_LAZY))) {
159 break;
160 }
161 }
163 // try the fallback paths
164 if(!impl->so) {
165 for(int i=0; fallback_paths[i]; i++) {
166 std::string path = std::string(fallback_paths[i]) + "/" + fname;
168 if((impl->so = dlopen(path.c_str(), RTLD_LAZY))) {
169 break;
170 }
171 }
172 }
174 if(!impl->so) {
175 fprintf(stderr, "%s: failed to load theme plugin: %s\n", __func__, name);
176 return false;
177 }
178 }
180 // loaded the shared object, now get the lookup function
181 impl->lookup_theme_draw_func = (LookupFunc)dlsym(impl->so, "get_widget_func");
182 if(!impl->lookup_theme_draw_func) {
183 fprintf(stderr, "%s: invalid theme plugin %s\n", __func__, name);
184 unload();
185 return false;
186 }
188 register_theme(name, this);
189 return true;
190 }
192 void Theme::unload()
193 {
194 if(impl->so) {
195 if(impl->so != RTLD_DEFAULT) {
196 dlclose(impl->so);
197 }
198 impl->so = 0;
199 }
200 impl->func_cache.clear();
201 }
203 WidgetDrawFunc Theme::get_draw_func(const char *type) const
204 {
205 std::map<std::string, WidgetDrawFunc>::const_iterator it = impl->func_cache.find(type);
206 if(it == impl->func_cache.end()) {
207 // don't have it cached, try to look it up
208 WidgetDrawFunc func;
209 if(impl->lookup_theme_draw_func && (func = impl->lookup_theme_draw_func(type))) {
210 impl->func_cache[type] = func;
211 return func;
212 }
214 // can't look it up, return the default
215 return default_draw_func;
216 }
217 return it->second;
218 }
220 #define LERP(a, b, t) ((a) + ((b) - (a)) * t)
221 #define DEF_TEX_SZ 32
222 void default_draw_func(const Widget *w)
223 {
224 static unsigned int tex;
226 if(!tex) {
227 unsigned char *pixels = new unsigned char[DEF_TEX_SZ * DEF_TEX_SZ * 3];
228 unsigned char *ptr = pixels;
229 for(int i=0; i<DEF_TEX_SZ; i++) {
230 for(int j=0; j<DEF_TEX_SZ; j++) {
231 bool stripe = (((j + i) / 8) & 1) == 1;
232 ptr[0] = ptr[1] = ptr[2] = stripe ? 255 : 0;
233 ptr += 3;
234 }
235 }
237 glGenTextures(1, &tex);
238 glBindTexture(GL_TEXTURE_2D, tex);
239 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
240 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
241 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, DEF_TEX_SZ, DEF_TEX_SZ, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
242 delete [] pixels;
243 }
245 Vec2 pos = w->get_position();
246 Vec2 sz = w->get_size();
247 float aspect = sz.x / sz.y;
249 #if !defined(GL_ES_VERSION_2_0)
250 glPushAttrib(GL_ENABLE_BIT);
251 glEnable(GL_TEXTURE_2D);
252 #endif
253 glBindTexture(GL_TEXTURE_2D, tex);
255 float offs = w->get_pressed() * 0.1 * sz.y;
256 glMatrixMode(GL_MODELVIEW);
257 glPushMatrix();
258 glTranslatef(offs, -offs, 0);
260 float active = w->get_active();
261 float hover = w->get_under_mouse();
263 float rg = LERP(0.4, 1.0, hover);
264 float b = LERP(rg, 0, active);
265 glColor3f(rg, rg, b);
267 glBegin(GL_QUADS);
268 glTexCoord2f(0, 1);
269 glVertex2f(pos.x, pos.y);
270 glTexCoord2f(aspect, 1);
271 glVertex2f(pos.x + sz.x, pos.y);
272 glTexCoord2f(aspect, 0);
273 glVertex2f(pos.x + sz.x, pos.y + sz.y);
274 glTexCoord2f(0, 0);
275 glVertex2f(pos.x, pos.y + sz.y);
276 glEnd();
278 glPopMatrix();
280 #ifndef GL_ES_VERSION_2_0
281 glPopAttrib();
282 #endif
283 }
285 } // namespace goatkit
287 #ifdef WIN32
288 // XXX untested
289 static void *dlopen(const char *name, int flags)
290 {
291 return LoadLibrary(name);
292 }
294 static void dlclose(void *so)
295 {
296 FreeLibrary(so);
297 }
299 static void *dlsym(void *so, const char *symbol)
300 {
301 if(so == RTLD_DEFAULT) {
302 so = GetModuleHandle(0);
303 }
304 return (void*)GetProcAddress(so, symbol);
305 }
306 #endif