PageRenderTime 38ms CodeModel.GetById 9ms app.highlight 24ms RepoModel.GetById 1ms app.codeStats 0ms

/src/ftk_theme.c

http://ftk.googlecode.com/
C | 608 lines | 481 code | 85 blank | 42 comment | 100 complexity | 8e19a613ab8cc200380360915ca08d44 MD5 | raw file
  1/*
  2 * File: ftk_theme.c   
  3 * Author:  Li XianJing <xianjimli@hotmail.com>
  4 * Brief:   theme
  5 *
  6 * Copyright (c) 2009 - 2010  Li XianJing <xianjimli@hotmail.com>
  7 *
  8 * Licensed under the Academic Free License version 2.1
  9 *
 10 * This program is free software; you can redistribute it and/or modify
 11 * it under the terms of the GNU General Public License as published by
 12 * the Free Software Foundation; either version 2 of the License, or
 13 * (at your option) any later version.
 14 *
 15 * This program is distributed in the hope that it will be useful,
 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 18 * GNU General Public License for more details.
 19 *
 20 * You should have received a copy of the GNU General Public License
 21 * along with this program; if not, write to the Free Software
 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 23 */
 24
 25/*
 26 * History:
 27 * ================================================================
 28 * 2009-12-05 Li XianJing <xianjimli@hotmail.com> created
 29 *
 30 */
 31
 32#include "ftk_log.h"
 33#include "ftk_util.h"
 34#include "ftk_mmap.h"
 35#include "ftk_theme.h"
 36#include "ftk_globals.h"
 37#include "ftk_icon_cache.h"
 38#include "ftk_xml_parser.h"
 39#include "ftk_animation_trigger_default.h"
 40#include "ftk_animation_trigger_silence.h"
 41
 42static void ftk_init_default_path();
 43
 44typedef struct _FtkWidgetTheme
 45{
 46	FtkColor   bg[FTK_WIDGET_STATE_NR];
 47	FtkColor   fg[FTK_WIDGET_STATE_NR];
 48	FtkColor   border[FTK_WIDGET_STATE_NR];
 49	FtkBitmap* bg_image[FTK_WIDGET_STATE_NR];
 50	char bg_image_name[FTK_WIDGET_STATE_NR][32];
 51	FtkFontDesc* font_desc;
 52}FtkWidgetTheme;
 53
 54struct _FtkTheme
 55{
 56	char name[32];
 57	FtkIconCache* icon_cache;
 58	FtkFontDesc* default_font_desc;
 59	FtkAnimationTrigger* animation_trigger;
 60	FtkWidgetTheme widget_themes[FTK_WIDGET_TYPE_NR];
 61};
 62
 63static const char* const s_default_theme = "\
 64	<theme name=\"default\">\
 65	<button bg_image[normal]=\"btn_default_normal"FTK_STOCK_IMG_SUFFIX"\" \
 66	bg_image[focused]=\"btn_default_selected"FTK_STOCK_IMG_SUFFIX"\" \
 67	bg_image[active]=\"btn_default_pressed"FTK_STOCK_IMG_SUFFIX"\" \
 68	bg_image[disable]=\"btn_default_normal_disable"FTK_STOCK_IMG_SUFFIX"\" \
 69	/> \
 70	<progress_bar \
 71	bg[normal]=\"ff9d9e9d\" fg[normal]=\"ffffd300\"\
 72	bg[focused]=\"ff9d9e9d\" fg[focused]=\"ffffd300\"\
 73	bg[active]=\"ff9d9e9d\" fg[active]=\"ffffd300\"\
 74	bg[disable]=\"ff9d9e9d\" fg[disable]=\"ffffd300\"\
 75	/>\
 76	<entry \
 77	bg[normal]=\"ffffffff\" fg[normal]=\"ff000000\" bd[normal]=\"ffe2ceee\"\
 78	bg[focused]=\"ffffffff\" fg[focused]=\"ff000000\" bd[focused]=\"ffffbb00\"\
 79	bg[active]=\"ffffffff\" fg[active]=\"ff000000\" bd[active]=\"ffe2ceee\"\
 80	bg[disable]=\"ffffffff\" fg[disable]=\"ffaca899\" bd[disable]=\"ffe2ceee\"\
 81	/>\
 82	<text_view \
 83	bg[normal]=\"ffffffff\" fg[normal]=\"ff000000\" bd[normal]=\"ffe2ceee\"\
 84	bg[focused]=\"ffffffff\" fg[focused]=\"ff000000\" bd[focused]=\"ffffbb00\"\
 85	bg[active]=\"ffffffff\" fg[active]=\"ff000000\" bd[active]=\"ffe2ceee\"\
 86	bg[disable]=\"ffffffff\" fg[disable]=\"ffaca899\" bd[disable]=\"ffe2ceee\"\
 87	/>\
 88	<check_button \
 89		fg[normal]=\"ff000000\"\
 90		fg[focused]=\"ffffbb00\"\
 91		fg[active]=\"ffffbb00\"\
 92		fg[disable]=\"ffaca899\"\
 93	/>\
 94	<radio_button \
 95		fg[normal]=\"ff000000\"\
 96		fg[focused]=\"ffffbb00\"\
 97		fg[active]=\"ffffbb00\"\
 98		fg[disable]=\"ffaca899\"\
 99	/>\
100	<menu_panel \
101	bg[normal]=\"ffffffff\" fg[normal]=\"ffccc9b8\" bd[normal]=\"ffb0a080\"\
102	/>\
103	</theme>";
104
105static Ret ftk_theme_init_default(FtkTheme* thiz)
106{
107#if defined(LINUX) || defined(WIN32)
108	char filename[FTK_MAX_PATH + 1] = {0};
109	ftk_strs_cat(filename, FTK_MAX_PATH, ftk_config_get_data_dir(ftk_default_config()),
110		"/theme/default/theme.xml", NULL);
111	ftk_normalize_path(filename);	
112	return ftk_theme_parse_file(thiz, filename);
113#else
114	return ftk_theme_parse_data(thiz, s_default_theme, strlen(s_default_theme));
115#endif
116}
117
118FtkTheme*  ftk_theme_create(int init_default)
119{
120	FtkTheme* thiz = FTK_NEW(FtkTheme);
121
122	ftk_init_default_path();
123	if(thiz != NULL)
124	{
125		size_t i = 0;
126		size_t j = 0;
127
128		for(i = 0; i < FTK_WIDGET_TYPE_NR; i++)
129		{
130			for(j = 0; j < FTK_WIDGET_STATE_NR; j++)
131			{
132				/*init background color to white*/
133				thiz->widget_themes[i].bg[j].a = 0xff;
134				thiz->widget_themes[i].bg[j].r = 0xff;
135				thiz->widget_themes[i].bg[j].g = 0xff;
136				thiz->widget_themes[i].bg[j].b = 0xff;
137				/*init foreground color to black*/
138				thiz->widget_themes[i].fg[j].a = 0xff;
139				thiz->widget_themes[i].fg[j].r = 0x00;
140				thiz->widget_themes[i].fg[j].g = 0x00;
141				thiz->widget_themes[i].fg[j].b = 0x00;
142			}
143		}
144
145		if(init_default)
146		{
147			ftk_theme_init_default(thiz);
148		}
149		thiz->default_font_desc = ftk_font_desc_create(FTK_DEFAULT_FONT); 
150	}
151
152	return thiz;
153}
154
155typedef struct _WidgetNameType
156{
157	const char* name;
158	FtkWidgetType type;
159}WidgetNameType;
160
161static const WidgetNameType s_widget_name_types[] = 
162{
163	{"label",        FTK_LABEL},
164	{"entry",        FTK_ENTRY},
165	{"text_view",    FTK_TEXT_VIEW},
166	{"image",        FTK_IMAGE},
167	{"button",       FTK_BUTTON},
168	{"wait_box",     FTK_WAIT_BOX},
169	{"group_box",  FTK_GROUP_BOX},
170	{"radio_button", FTK_RADIO_BUTTON},
171	{"check_button", FTK_CHECK_BUTTON},
172	{"progress_bar", FTK_PROGRESS_BAR},
173	{"scroll_vbar",  FTK_SCROLL_VBAR},
174	{"scroll_hbar",  FTK_SCROLL_HBAR},
175	{"window",       FTK_WINDOW},
176	{"dialog",       FTK_DIALOG},
177	{"menu_item",    FTK_MENU_ITEM},
178	{"list_view",    FTK_LIST_VIEW},
179	{"status_item",  FTK_STATUS_ITEM},
180	{"status_panel", FTK_STATUS_PANEL},
181	{"menu_panel",   FTK_MENU_PANEL},
182	{"icon_view",    FTK_ICON_VIEW},
183	{"combo_box",    FTK_COMBO_BOX},
184	{"tab_page",     FTK_TAB_PAGE},
185	{NULL, FTK_WIDGET_NONE},
186};
187
188static FtkWidgetType ftk_theme_get_widget_type(FtkTheme* thiz, const char* name)
189{
190	size_t i = 0;
191	return_val_if_fail(thiz != NULL && name != NULL, FTK_WIDGET_NONE);
192
193	for(i = 0; s_widget_name_types[i].name != NULL; i++)
194	{
195		if(strcmp(name, s_widget_name_types[i].name) == 0)
196		{
197			return s_widget_name_types[i].type;
198		}
199	}
200
201	return FTK_WIDGET_NONE;
202}
203
204typedef struct _ThemePrivInfo
205{
206	FtkTheme* theme;
207}PrivInfo;
208
209#define TO_STATE(v)\
210	switch(v)\
211	{\
212		case 'n':\
213		{\
214			state = FTK_WIDGET_NORMAL;\
215			break;\
216		}\
217		case 'f':\
218		{\
219			state = FTK_WIDGET_FOCUSED;\
220			break;\
221		}\
222		case 'a':\
223		{\
224			state = FTK_WIDGET_ACTIVE;\
225			break;\
226		}\
227		case 'd':\
228		{\
229			state = FTK_WIDGET_INSENSITIVE;\
230			break;\
231		}\
232		default:\
233		{\
234			return RET_FAIL;\
235		}\
236	}
237	
238static Ret  ftk_theme_parse_fg_color(FtkTheme* thiz, FtkWidgetType type, const char* name, const char* value)
239{
240	FtkWidgetState state = FTK_WIDGET_NORMAL;
241	FtkWidgetTheme* theme = thiz->widget_themes+type;
242
243	TO_STATE(name[3]);
244	theme->fg[state] = ftk_parse_color(value);
245
246//	ftk_logd("fg type=%d state=%d (%02x %02x %2x %02x) \n", type, state, 
247//		theme->fg[state].a, theme->fg[state].r, theme->fg[state].g, theme->fg[state].b);
248
249	return RET_OK;
250}
251
252static Ret  ftk_theme_parse_bg_color(FtkTheme* thiz, FtkWidgetType type, const char* name, const char* value)
253{
254	FtkWidgetState state = FTK_WIDGET_NORMAL;
255	FtkWidgetTheme* theme = thiz->widget_themes+type;
256
257	TO_STATE(name[3]);
258	theme->bg[state] = ftk_parse_color(value);
259	
260//	ftk_logd("bg type=%d state=%d (%02x %02x %2x %02x) \n", type, state, 
261//		theme->bg[state].a, theme->bg[state].r, theme->bg[state].g, theme->bg[state].b);
262
263	return RET_OK;
264}
265
266static Ret  ftk_theme_parse_bd_color(FtkTheme* thiz, FtkWidgetType type, const char* name, const char* value)
267{
268	FtkWidgetState state = FTK_WIDGET_NORMAL;
269	FtkWidgetTheme* theme = thiz->widget_themes+type;
270
271	TO_STATE(name[3]);
272	theme->border[state] = ftk_parse_color(value);
273	
274//	ftk_logd("bd type=%d state=%d (%02x %02x %2x %02x) \n", type, state, 
275//		theme->border[state].a, theme->border[state].r, theme->border[state].g, theme->border[state].b);
276
277	return RET_OK;
278}
279
280static Ret  ftk_theme_parse_bg_image(FtkTheme* thiz, FtkWidgetType type, const char* name, const char* value)
281{
282	FtkWidgetState state = FTK_WIDGET_NORMAL;
283	FtkWidgetTheme* theme = thiz->widget_themes+type;
284
285	TO_STATE(name[9]);
286	ftk_strncpy(theme->bg_image_name[state], value, sizeof(theme->bg_image_name[state]));
287
288//	ftk_logd("bg_image type=%d state=%d name=%s \n", type, state, theme->bg_image_name[state]);
289
290	return RET_OK;
291}
292
293static void ftk_theme_builder_on_start(FtkXmlBuilder* thiz, const char* tag, const char** attrs)
294{
295	size_t i = 0;
296	DECL_PRIV(thiz, priv);
297	const char* name = NULL;
298	const char* value = NULL;
299	FtkTheme* theme = priv->theme;
300	FtkWidgetType type = FTK_WIDGET_NONE;
301	return_if_fail(tag != NULL && attrs != NULL);
302
303	if(strcmp(tag, "theme") == 0)
304	{
305		for(i = 0; attrs[i] != NULL; i += 2)
306		{
307			name = attrs[i];
308			value = attrs[i+1];
309			if(name[0] == 'n')
310			{
311				ftk_strncpy(theme->name, value, sizeof(theme->name));
312				break;
313			}
314		}
315		
316		return;
317	}
318	else if(strcmp(tag, "animation_trigger") == 0)
319	{
320		const char* name = attrs[1];
321		if(name != NULL && theme->animation_trigger == NULL)
322		{
323			if(strcmp(name, "silence") == 0)
324			{
325				theme->animation_trigger = ftk_animation_trigger_silence_create();
326			}
327			else
328			{
329				theme->animation_trigger = ftk_animation_trigger_default_create(theme->name, name);
330				if(theme->animation_trigger == NULL)
331				{
332					ftk_logd("load animation %s failed.\n", name);
333					theme->animation_trigger = ftk_animation_trigger_silence_create();
334				}
335			}
336		}
337		
338		return;
339	}
340
341	type = ftk_theme_get_widget_type(theme, tag);
342	return_if_fail(type != FTK_WIDGET_NONE);
343
344	for(i = 0; attrs[i] != NULL; i += 2)
345	{
346		name = attrs[i];
347		value = attrs[i+1];
348
349		if(strlen(name) < 4)
350		{
351			ftk_logd("%s: unknow %s=%s\n", __func__, name, value);
352			continue;		
353		}
354
355		switch(name[0])
356		{
357			case 'f':
358			{
359				/*fg:forground color*/
360				if(strstr(name, "fg[") != NULL)
361				{
362					ftk_theme_parse_fg_color(theme, type, name, value);
363				}
364				else if(strcmp(name, "font") == 0)
365				{
366					theme->widget_themes[type].font_desc = ftk_font_desc_create(value);
367				}
368				break;
369			}
370			case 'b':
371			{
372				/*bd:border color*/
373				if(name[1] == 'd')
374				{
375					ftk_theme_parse_bd_color(theme, type, name, value);
376				}
377				else if(name[1] == 'g' && name[2] == '[')
378				{
379					/*bg:background color*/
380					ftk_theme_parse_bg_color(theme, type, name, value);
381				}
382				else if(name[1] == 'g' && name[2] == '_')
383				{
384					/*bg_image:background image*/
385					ftk_theme_parse_bg_image(theme, type, name, value);
386				}
387				else
388				{
389					ftk_logd("%s: unknow %s=%s\n", __func__, name, value);
390				}
391				break;
392			}
393			default:
394			{
395				ftk_logd("%s: unknow %s=%s\n", __func__, name, value);
396				break;
397			}
398		}
399	}
400
401	return;
402}
403
404static void ftk_theme_builder_destroy(FtkXmlBuilder* thiz)
405{
406	if(thiz != NULL)
407	{
408		FTK_ZFREE(thiz, sizeof(FtkXmlBuilder) + sizeof(PrivInfo));
409	}
410
411	return;
412}
413static FtkXmlBuilder* ftk_theme_builder_create(void)
414{
415	FtkXmlBuilder* thiz = FTK_NEW_PRIV(FtkXmlBuilder);
416
417	if(thiz != NULL)
418	{
419		thiz->on_start_element = ftk_theme_builder_on_start;
420		thiz->destroy          = ftk_theme_builder_destroy;
421	}
422
423	return thiz;
424}
425
426static const char* s_default_path[FTK_ICON_PATH_NR];
427static void ftk_init_default_path()
428{
429	s_default_path[0] = ftk_config_get_data_dir(ftk_default_config());
430	s_default_path[1] = ftk_config_get_data_root_dir(ftk_default_config());;
431	s_default_path[2] = ftk_config_get_test_data_dir(ftk_default_config());
432
433	return;
434}
435
436Ret        ftk_theme_parse_data(FtkTheme* thiz, const char* xml, size_t length)
437{
438	FtkXmlParser*  parser = NULL;
439	FtkXmlBuilder* builder = NULL;
440	char icon_path[FTK_MAX_PATH] = {0};
441	return_val_if_fail(xml != NULL, RET_FAIL);
442
443	parser  = ftk_xml_parser_create();
444	return_val_if_fail(parser != NULL, RET_FAIL);
445
446	builder = ftk_theme_builder_create();
447	if(builder != NULL)
448	{
449		PrivInfo* priv = (PrivInfo*)builder->priv;
450		priv->theme = thiz;
451		ftk_xml_parser_set_builder(parser, builder);
452		ftk_xml_parser_parse(parser, xml, length);
453	}
454	ftk_xml_builder_destroy(builder);
455	ftk_xml_parser_destroy(parser);
456
457	if(thiz->icon_cache != NULL)
458	{
459		ftk_icon_cache_destroy(thiz->icon_cache);
460		thiz->icon_cache = NULL;
461	}
462
463	ftk_strs_cat(icon_path, FTK_MAX_PATH, "theme/", thiz->name, NULL);
464	thiz->icon_cache = ftk_icon_cache_create(s_default_path, icon_path);
465
466	if(thiz->animation_trigger == NULL)
467	{
468		thiz->animation_trigger = ftk_animation_trigger_silence_create();
469	}
470
471	return RET_OK;
472}
473
474Ret        ftk_theme_parse_file(FtkTheme* thiz, const char* filename)
475{
476	FtkMmap* m = NULL;
477	Ret ret = RET_FAIL;
478	return_val_if_fail(thiz != NULL && filename != NULL, RET_FAIL);
479	
480	m = ftk_mmap_create(filename, 0, -1);
481	if(m == NULL)
482	{
483		ftk_logd("%s: mmap %s failed.\n", __func__, filename);
484	}
485	return_val_if_fail(m != NULL, RET_FAIL);
486	ret = ftk_theme_parse_data(thiz, (const char*)ftk_mmap_data(m), ftk_mmap_length(m));
487	ftk_mmap_destroy(m);
488
489	return ret;
490}
491
492FtkBitmap* ftk_theme_get_bg(FtkTheme* thiz, FtkWidgetType type, FtkWidgetState state)
493{
494	assert(type < FTK_WIDGET_TYPE_NR && state < FTK_WIDGET_STATE_NR);
495	return_val_if_fail(thiz != NULL, NULL);
496
497	if(thiz->widget_themes[type].bg_image[state] == NULL)
498	{
499		if(thiz->widget_themes[type].bg_image_name[state][0])
500		{
501			thiz->widget_themes[type].bg_image[state] = ftk_icon_cache_load(thiz->icon_cache, 
502				thiz->widget_themes[type].bg_image_name[state]);
503		}
504	}
505	
506	if(thiz->widget_themes[type].bg_image[state] != NULL)
507	{
508		ftk_bitmap_ref(thiz->widget_themes[type].bg_image[state]);
509	}
510	
511	return thiz->widget_themes[type].bg_image[state];
512}
513
514FtkBitmap* ftk_theme_load_image(FtkTheme* thiz, const char* filename)
515{
516	return_val_if_fail(thiz != NULL && filename != NULL, NULL);
517
518	return ftk_icon_cache_load(thiz->icon_cache, filename);
519}
520
521FtkColor   ftk_theme_get_bg_color(FtkTheme* thiz, FtkWidgetType type, FtkWidgetState state)
522{
523	FtkColor c = {0};
524	assert(type < FTK_WIDGET_TYPE_NR && state < FTK_WIDGET_STATE_NR);
525	return_val_if_fail(thiz != NULL, c);
526
527	return thiz->widget_themes[type].bg[state];
528}
529
530FtkColor   ftk_theme_get_border_color(FtkTheme* thiz, FtkWidgetType type, FtkWidgetState state)
531{
532	FtkColor c = {0};
533	assert(type < FTK_WIDGET_TYPE_NR && state < FTK_WIDGET_STATE_NR);
534	return_val_if_fail(thiz != NULL, c);
535
536	return thiz->widget_themes[type].border[state];
537}
538
539FtkFontDesc*   ftk_theme_get_font(FtkTheme* thiz, FtkWidgetType type)
540{
541	FtkFontDesc* font_desc = NULL;
542	assert(type < FTK_WIDGET_TYPE_NR);
543	return_val_if_fail(thiz != NULL, NULL);
544	
545	if(thiz->widget_themes[type].font_desc != NULL)
546	{
547		font_desc = thiz->widget_themes[type].font_desc;
548	}
549	else
550	{
551		font_desc = thiz->default_font_desc;
552	}
553
554	ftk_font_desc_ref(font_desc);
555
556	return font_desc;
557}
558
559FtkColor   ftk_theme_get_fg_color(FtkTheme* thiz, FtkWidgetType type, FtkWidgetState state)
560{
561	FtkColor c = {0};
562	assert(type < FTK_WIDGET_TYPE_NR && state < FTK_WIDGET_STATE_NR);
563	return_val_if_fail(thiz != NULL, c);
564
565	return thiz->widget_themes[type].fg[state];
566}
567
568FtkAnimationTrigger* ftk_theme_get_animation_trigger(FtkTheme* thiz)
569{
570	return_val_if_fail(thiz != NULL, NULL);
571
572	return thiz->animation_trigger;
573}
574
575void       ftk_theme_destroy(FtkTheme* thiz)
576{
577	if(thiz != NULL)
578	{
579		size_t i = 0;
580		size_t j = 0;
581
582		ftk_font_desc_unref(thiz->default_font_desc);
583		for(i = 0; i < FTK_WIDGET_TYPE_NR; i++)
584		{
585			for(j = 0; j < FTK_WIDGET_STATE_NR; j++)
586			{
587				if(thiz->widget_themes[i].bg_image[j] != NULL)
588				{
589					ftk_bitmap_unref(thiz->widget_themes[i].bg_image[j]);
590					thiz->widget_themes[i].bg_image[j] = NULL;
591				}
592			}
593
594			if(thiz->widget_themes[i].font_desc != NULL)
595			{
596				ftk_font_desc_unref(thiz->widget_themes[i].font_desc);
597			}
598		}
599		ftk_icon_cache_destroy(thiz->icon_cache);
600		ftk_animation_trigger_destroy(thiz->animation_trigger);
601
602		FTK_ZFREE(thiz, sizeof(FtkTheme));
603	}
604
605	return;
606}
607
608