2 GoatKit - a themable/animated widget toolkit for games
3 Copyright (C) 2014-2018 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/>.
30 static void *dlopen(const char *name, int flags);
31 static void dlclose(void *so);
32 static void *dlsym(void *so, const char *symbol);
44 #include <OpenGL/gl.h>
49 #endif /* HAVE_OPENGL_H_ */
52 #define PREFIX "/usr/local"
59 WidgetDrawFunc (*lookup_theme_draw_func)(const char*);
60 mutable std::map<std::string, WidgetDrawFunc> func_cache;
64 static std::vector<std::string> search_paths;
65 static const char *fallback_paths[] = {
66 PREFIX "/share/goatkit",
70 typedef std::map<std::string, Theme*> ThemeMap;
71 static ThemeMap *themes;
74 void add_theme_path(const char *path)
76 if(!path || !*path) return;
79 int last = s.length() - 1;
80 if(s[last] == '/' || s[last] == '\\') {
84 if(std::find(search_paths.begin(), search_paths.end(), s) != search_paths.end()) {
88 search_paths.push_back(s);
91 void register_theme(const char *name, Theme *theme)
94 themes = new ThemeMap;
97 Theme *prev = (*themes)[name];
101 (*themes)[name] = theme;
104 Theme *get_theme(const char *name)
106 // first search in the already registered themes
107 ThemeMap::const_iterator it = themes->find(name);
108 if(it != themes->end()) {
112 // then try loading it from a theme plugin
113 Theme *theme = new Theme;
114 if(theme->load(name)) {
118 fprintf(stderr, "[goatkit] theme \"%s\" not found!\n", name);
125 impl = new ThemeImpl;
127 impl->lookup_theme_draw_func = 0;
130 Theme::Theme(const char *name, WidgetLookupFunc func)
132 impl = new ThemeImpl;
134 impl->lookup_theme_draw_func = func;
136 register_theme(name, this);
145 typedef WidgetDrawFunc (*LookupFunc)(const char*);
147 bool Theme::load(const char *name)
151 std::string fname = std::string(name) + ".gtheme";
152 if(!(impl->so = dlopen(fname.c_str(), RTLD_LAZY))) {
153 for(size_t i=0; i<search_paths.size(); i++) {
154 std::string path = search_paths[i] + "/" + fname;
156 if((impl->so = dlopen(path.c_str(), RTLD_LAZY))) {
161 // try the fallback paths
163 for(int i=0; fallback_paths[i]; i++) {
164 std::string path = std::string(fallback_paths[i]) + "/" + fname;
166 if((impl->so = dlopen(path.c_str(), RTLD_LAZY))) {
173 fprintf(stderr, "%s: failed to load theme plugin: %s\n", __func__, name);
178 // loaded the shared object, now get the lookup function
179 impl->lookup_theme_draw_func = (LookupFunc)dlsym(impl->so, "get_widget_func");
180 if(!impl->lookup_theme_draw_func) {
181 fprintf(stderr, "%s: invalid theme plugin %s\n", __func__, name);
186 register_theme(name, this);
196 impl->func_cache.clear();
199 WidgetDrawFunc Theme::get_draw_func(const char *type) const
201 std::map<std::string, WidgetDrawFunc>::const_iterator it = impl->func_cache.find(type);
202 if(it == impl->func_cache.end()) {
203 // don't have it cached, try to look it up
205 if(impl->lookup_theme_draw_func && (func = impl->lookup_theme_draw_func(type))) {
206 impl->func_cache[type] = func;
210 // can't look it up, return the default
211 return default_draw_func;
216 #define LERP(a, b, t) ((a) + ((b) - (a)) * t)
217 #define DEF_TEX_SZ 32
218 void default_draw_func(const Widget *w)
220 static unsigned int tex;
223 unsigned char *pixels = new unsigned char[DEF_TEX_SZ * DEF_TEX_SZ * 3];
224 unsigned char *ptr = pixels;
225 for(int i=0; i<DEF_TEX_SZ; i++) {
226 for(int j=0; j<DEF_TEX_SZ; j++) {
227 bool stripe = (((j + i) / 8) & 1) == 1;
228 ptr[0] = ptr[1] = ptr[2] = stripe ? 255 : 0;
233 glGenTextures(1, &tex);
234 glBindTexture(GL_TEXTURE_2D, tex);
235 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
236 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
237 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, DEF_TEX_SZ, DEF_TEX_SZ, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
241 Vec2 pos = w->get_position();
242 Vec2 sz = w->get_size();
243 float aspect = sz.x / sz.y;
245 #if !defined(GL_ES_VERSION_2_0)
246 glPushAttrib(GL_ENABLE_BIT);
247 glEnable(GL_TEXTURE_2D);
249 glBindTexture(GL_TEXTURE_2D, tex);
251 float offs = w->get_pressed() * 0.1 * sz.y;
252 glMatrixMode(GL_MODELVIEW);
254 glTranslatef(offs, -offs, 0);
256 float active = w->get_active();
257 float hover = w->get_under_mouse();
259 float rg = LERP(0.4, 1.0, hover);
260 float b = LERP(rg, 0, active);
261 glColor3f(rg, rg, b);
265 glVertex2f(pos.x, pos.y);
266 glTexCoord2f(aspect, 1);
267 glVertex2f(pos.x + sz.x, pos.y);
268 glTexCoord2f(aspect, 0);
269 glVertex2f(pos.x + sz.x, pos.y + sz.y);
271 glVertex2f(pos.x, pos.y + sz.y);
276 #ifndef GL_ES_VERSION_2_0
281 } // namespace goatkit
285 static void *dlopen(const char *name, int flags)
287 return LoadLibrary(name);
290 static void dlclose(void *so)
295 static void *dlsym(void *so, const char *symbol)
298 so = GetModuleHandle(0);
300 return (void*)GetProcAddress(so, symbol);