istereo2

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