2. make elementary be able to determine theme from PREFIX/share/elementary/themes or ~/.elementary/themes (~/ takes preference) currently using a delimited list of theme names in order to check like: mytheme/fallback/morestuff/default (if the last theme entry is on default it is added explicitly). this allows multiple theme files bascially to work a bit like a fontset - try the first one - if not there, try the next and so on. set $ELM_THEME to your theme setting 3. determine prefix and thus data dir - where system themes go. if it can't rely on dladdr, or the compiled-in prefix/data dir, you can set $ELM_PREFIX and/or $ELM_DATA_DIR accordingly. SVN revision: 38568devs/felipealmeida/promises
parent
478ebffb67
commit
90f79c27db
9 changed files with 492 additions and 26 deletions
@ -0,0 +1,259 @@ |
||||
#include <Elementary.h> |
||||
#include "elm_priv.h" |
||||
|
||||
// FIXME: this is NOT the carousel - yet!
|
||||
|
||||
typedef struct _Widget_Data Widget_Data; |
||||
typedef struct _Item Item; |
||||
|
||||
struct _Widget_Data |
||||
{ |
||||
Evas_Object *scr, *bx; |
||||
Eina_List *items; |
||||
int icon_size; |
||||
Evas_Bool scrollable : 1; |
||||
}; |
||||
|
||||
struct _Item |
||||
{ |
||||
Evas_Object *obj; |
||||
Evas_Object *base; |
||||
const char *label; |
||||
Evas_Object *icon; |
||||
void (*func) (void *data, Evas_Object *obj, void *event_info); |
||||
const void *data; |
||||
Evas_Bool selected : 1; |
||||
}; |
||||
|
||||
static void _del_hook(Evas_Object *obj); |
||||
static void _theme_hook(Evas_Object *obj); |
||||
static void _sizing_eval(Evas_Object *obj); |
||||
|
||||
static void |
||||
_item_show(Item *it) |
||||
{ |
||||
Widget_Data *wd = elm_widget_data_get(it->obj); |
||||
Evas_Coord x, y, w, h, bx, by; |
||||
|
||||
evas_object_geometry_get(wd->bx, &bx, &by, NULL, NULL); |
||||
evas_object_geometry_get(it->base, &x, &y, &w, &h); |
||||
elm_smart_scroller_child_region_show(wd->scr, x - bx, y - by, w, h); |
||||
} |
||||
|
||||
static void |
||||
_item_select(Item *it) |
||||
{ |
||||
Item *it2; |
||||
Widget_Data *wd = elm_widget_data_get(it->obj); |
||||
Evas_Object *obj2; |
||||
Eina_List *l; |
||||
if (it->selected) return; |
||||
for (l = wd->items; l; l = l->next) |
||||
{ |
||||
it2 = l->data; |
||||
if (it2->selected) |
||||
{ |
||||
it2->selected = 0; |
||||
edje_object_signal_emit(it2->base, "elm,state,unselected", "elm"); |
||||
break; |
||||
} |
||||
} |
||||
it->selected = 1; |
||||
edje_object_signal_emit(it->base, "elm,state,selected", "elm"); |
||||
_item_show(it); |
||||
obj2 = it->obj; |
||||
if (it->func) it->func((void *)(it->data), it->obj, it); |
||||
evas_object_smart_callback_call(obj2, "clicked", it); |
||||
} |
||||
|
||||
static void |
||||
_del_hook(Evas_Object *obj) |
||||
{ |
||||
Widget_Data *wd = elm_widget_data_get(obj); |
||||
free(wd); |
||||
} |
||||
|
||||
static void |
||||
_theme_hook(Evas_Object *obj) |
||||
{ |
||||
Widget_Data *wd = elm_widget_data_get(obj); |
||||
Eina_List *l; |
||||
Item *it; |
||||
Evas_Coord mw, mh; |
||||
for (l = wd->items; l; l = l->next) |
||||
{ |
||||
it = l->data; |
||||
if (it->selected) |
||||
edje_object_signal_emit(it->base, "elm,state,selected", "elm"); |
||||
_elm_theme_set(it->base, "carousel", "item", "default"); |
||||
if (it->icon) |
||||
{ |
||||
edje_extern_object_min_size_set(it->icon,
|
||||
(double)wd->icon_size * _elm_config->scale,
|
||||
(double)wd->icon_size * _elm_config->scale); |
||||
edje_object_part_swallow(it->base, "elm.swallow.icon", it->icon); |
||||
} |
||||
edje_object_part_text_set(it->base, "elm.text", it->label); |
||||
edje_object_size_min_calc(it->base, &mw, &mh); |
||||
evas_object_size_hint_min_set(it->base, mw, mh); |
||||
evas_object_size_hint_max_set(it->base, 9999, mh); |
||||
} |
||||
_sizing_eval(obj); |
||||
} |
||||
|
||||
static void |
||||
_sizing_eval(Evas_Object *obj) |
||||
{ |
||||
Widget_Data *wd = elm_widget_data_get(obj); |
||||
Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1; |
||||
Evas_Coord vw = 0, vh = 0; |
||||
|
||||
edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr), &minw, &minh); |
||||
evas_object_resize(wd->scr, 500, 500); |
||||
evas_object_size_hint_min_get(wd->bx, &minw, &minh); |
||||
evas_object_resize(wd->bx, minw, minh); |
||||
elm_smart_scroller_child_viewport_size_get(wd->scr, &vw, &vh); |
||||
if (wd->scrollable) |
||||
{ |
||||
minw = 500 - vw; |
||||
minh = minh + (500 - vh); |
||||
} |
||||
else |
||||
{ |
||||
minw = minw + (500 - vw); |
||||
minh = minh + (500 - vh); |
||||
} |
||||
evas_object_size_hint_min_set(obj, minw, minh); |
||||
evas_object_size_hint_max_set(obj, maxw, maxh); |
||||
} |
||||
|
||||
static void |
||||
_resize(void *data, Evas *e, Evas_Object *obj, void *event_info) |
||||
{ |
||||
Widget_Data *wd = elm_widget_data_get(data); |
||||
Evas_Coord mw, mh, vw, vh, w, h; |
||||
Eina_List *l; |
||||
Item *it; |
||||
|
||||
elm_smart_scroller_child_viewport_size_get(wd->scr, &vw, &vh); |
||||
evas_object_size_hint_min_get(wd->bx, &mw, &mh); |
||||
evas_object_geometry_get(wd->bx, NULL, NULL, &w, &h); |
||||
if (vw >= mw) |
||||
{ |
||||
if (w != vw) evas_object_resize(wd->bx, vw, h); |
||||
} |
||||
for (l = wd->items; l; l = l->next) |
||||
{ |
||||
it = l->data; |
||||
if (it->selected) |
||||
{ |
||||
_item_show(it); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
static void |
||||
_select(void *data, Evas_Object *obj, const char *emission, const char *source) |
||||
{ |
||||
_item_select(data); |
||||
} |
||||
|
||||
EAPI Evas_Object * |
||||
elm_carousel_add(Evas_Object *parent) |
||||
{ |
||||
Evas_Object *obj; |
||||
Evas *e; |
||||
Widget_Data *wd; |
||||
|
||||
wd = ELM_NEW(Widget_Data); |
||||
e = evas_object_evas_get(parent); |
||||
obj = elm_widget_add(e); |
||||
elm_widget_data_set(obj, wd); |
||||
elm_widget_del_hook_set(obj, _del_hook); |
||||
elm_widget_theme_hook_set(obj, _theme_hook); |
||||
elm_widget_can_focus_set(obj, 0); |
||||
|
||||
wd->scr = elm_smart_scroller_add(e); |
||||
elm_smart_scroller_theme_set(wd->scr, "carousel", "base", "default"); |
||||
elm_widget_resize_object_set(obj, wd->scr); |
||||
elm_smart_scroller_policy_set(wd->scr,
|
||||
ELM_SMART_SCROLLER_POLICY_AUTO, |
||||
ELM_SMART_SCROLLER_POLICY_OFF); |
||||
|
||||
wd->icon_size = 32; |
||||
wd->scrollable = 1; |
||||
|
||||
wd->bx = _els_smart_box_add(e); |
||||
_els_smart_box_orientation_set(wd->bx, 1); |
||||
_els_smart_box_homogenous_set(wd->bx, 1); |
||||
elm_widget_sub_object_add(obj, wd->bx); |
||||
elm_smart_scroller_child_set(wd->scr, wd->bx); |
||||
evas_object_show(wd->bx); |
||||
|
||||
evas_object_event_callback_add(wd->scr, EVAS_CALLBACK_RESIZE, |
||||
_resize, obj); |
||||
|
||||
_sizing_eval(obj); |
||||
return obj; |
||||
} |
||||
|
||||
EAPI Elm_Carousel_Item * |
||||
elm_carousel_item_add(Evas_Object *obj, Evas_Object *icon, const char *label, void (*func) (void *data, Evas_Object *obj, void *event_info), const void *data) |
||||
{ |
||||
Widget_Data *wd = elm_widget_data_get(obj); |
||||
Evas_Coord mw, mh; |
||||
Item *it = calloc(1, sizeof(Item)); |
||||
if (!it) return NULL; |
||||
wd->items = eina_list_append(wd->items, it); |
||||
it->obj = obj; |
||||
it->label = eina_stringshare_add(label); |
||||
it->icon = icon; |
||||
it->func = func; |
||||
it->data = data; |
||||
it->base = edje_object_add(evas_object_evas_get(obj)); |
||||
_elm_theme_set(it->base, "carousel", "item", "default"); |
||||
edje_object_signal_callback_add(it->base, "elm,action,click", "elm", |
||||
_select, it); |
||||
elm_widget_sub_object_add(obj, it->base); |
||||
if (it->icon) |
||||
{ |
||||
edje_extern_object_min_size_set(it->icon,
|
||||
(double)wd->icon_size * _elm_config->scale,
|
||||
(double)wd->icon_size * _elm_config->scale); |
||||
edje_object_part_swallow(it->base, "elm.swallow.icon", it->icon); |
||||
evas_object_show(it->icon); |
||||
elm_widget_sub_object_add(obj, it->icon); |
||||
} |
||||
edje_object_part_text_set(it->base, "elm.text", it->label); |
||||
edje_object_size_min_calc(it->base, &mw, &mh); |
||||
evas_object_size_hint_weight_set(it->base, 0.0, 0.0); |
||||
evas_object_size_hint_align_set(it->base, -1.0, -1.0); |
||||
evas_object_size_hint_min_set(it->base, mw, mh); |
||||
evas_object_size_hint_max_set(it->base, 9999, mh); |
||||
_els_smart_box_pack_end(wd->bx, it->base); |
||||
evas_object_show(it->base); |
||||
_sizing_eval(obj); |
||||
return (Elm_Carousel_Item *)it; |
||||
} |
||||
|
||||
EAPI void |
||||
elm_carousel_item_del(Elm_Carousel_Item *item) |
||||
{ |
||||
Item *it = (Item *)item; |
||||
Widget_Data *wd = elm_widget_data_get(it->obj); |
||||
Evas_Object *obj2 = it->obj; |
||||
wd->items = eina_list_remove(wd->items, it); |
||||
eina_stringshare_del(it->label); |
||||
if (it->icon) evas_object_del(it->icon); |
||||
evas_object_del(it->base); |
||||
free(it); |
||||
_theme_hook(obj2); |
||||
} |
||||
|
||||
EAPI void |
||||
elm_carousel_item_select(Elm_Carousel_Item *item) |
||||
{ |
||||
_item_select(item); |
||||
} |
@ -1,39 +1,154 @@ |
||||
#include <Elementary.h> |
||||
#include "elm_priv.h" |
||||
|
||||
static Eina_List *themes = NULL; |
||||
static Eina_Hash *cache = NULL; |
||||
|
||||
static const char * |
||||
_elm_theme_group_file_find(const char *group) |
||||
{ |
||||
Eina_List *l; |
||||
char buf[PATH_MAX]; |
||||
char *p; |
||||
static const char *home = NULL; |
||||
const char *file = eina_hash_find(cache, group); |
||||
if (file) return file; |
||||
if (!home) |
||||
{ |
||||
home = getenv("HOME"); |
||||
if (!home) home = ""; |
||||
} |
||||
for (l = themes; l; l = l->next) |
||||
{ |
||||
snprintf(buf, sizeof(buf), "%s/.elementary/themes/%s.edj", home, l->data); |
||||
if (edje_file_group_exists(buf, group)) |
||||
{ |
||||
file = eina_stringshare_add(buf); |
||||
if (file) |
||||
{ |
||||
eina_hash_add(cache, group, file); |
||||
return file; |
||||
} |
||||
} |
||||
snprintf(buf, sizeof(buf), "%s/themes/%s.edj", PACKAGE_DATA_DIR, l->data); |
||||
if (edje_file_group_exists(buf, group)) |
||||
{ |
||||
file = eina_stringshare_add(buf); |
||||
if (file) |
||||
{ |
||||
eina_hash_add(cache, group, file); |
||||
return file; |
||||
} |
||||
} |
||||
} |
||||
return NULL; |
||||
} |
||||
|
||||
int |
||||
_elm_theme_set(Evas_Object *o, const char *clas, const char *group, const char *style) |
||||
{ |
||||
char buf[PATH_MAX]; |
||||
const char *file; |
||||
char buf2[1024]; |
||||
int ok; |
||||
|
||||
// FIXME: actually handle themes for real
|
||||
snprintf(buf, sizeof(buf), "%s/themes/%s.edj", PACKAGE_DATA_DIR, "default"); |
||||
snprintf(buf2, sizeof(buf2), "elm/%s/%s/%s", clas, group, style); |
||||
ok = edje_object_file_set(o, buf, buf2); |
||||
if (ok) return 1; |
||||
file = _elm_theme_group_file_find(buf2); |
||||
if (file) |
||||
{ |
||||
ok = edje_object_file_set(o, file, buf2); |
||||
if (ok) return 1; |
||||
} |
||||
snprintf(buf2, sizeof(buf2), "elm/%s/%s/default", clas, group); |
||||
ok = edje_object_file_set(o, buf, buf2); |
||||
file = _elm_theme_group_file_find(buf2); |
||||
if (!file) return 0; |
||||
ok = edje_object_file_set(o, file, buf2); |
||||
return ok; |
||||
} |
||||
|
||||
int |
||||
_elm_theme_icon_set(Evas_Object *o, const char *group, const char *style) |
||||
{ |
||||
char buf[PATH_MAX]; |
||||
const char *file; |
||||
char buf2[1024]; |
||||
int w, h; |
||||
int ok; |
||||
|
||||
// FIXME: actually handle themes for real
|
||||
snprintf(buf, sizeof(buf), "%s/themes/%s.edj", PACKAGE_DATA_DIR, "default"); |
||||
snprintf(buf2, sizeof(buf2), "elm/icon/%s/%s", group, style); |
||||
_els_smart_icon_file_edje_set(o, buf, buf2); |
||||
_els_smart_icon_size_get(o, &w, &h); |
||||
if (w > 0) return 1; |
||||
file = _elm_theme_group_file_find(buf2); |
||||
if (file) |
||||
{ |
||||
_els_smart_icon_file_edje_set(o, file, buf2); |
||||
_els_smart_icon_size_get(o, &w, &h); |
||||
if (w > 0) return 1; |
||||
} |
||||
snprintf(buf2, sizeof(buf2), "elm/icon/%s/default", group); |
||||
_els_smart_icon_file_edje_set(o, buf, buf2); |
||||
file = _elm_theme_group_file_find(buf2); |
||||
if (!file) return 0; |
||||
_els_smart_icon_file_edje_set(o, file, buf2); |
||||
_els_smart_icon_size_get(o, &w, &h); |
||||
return (w > 0); |
||||
} |
||||
|
||||
static Eina_Bool |
||||
_cache_free_cb(const Eina_Hash *hash, const void *key, void *data, void *fdata) |
||||
{ |
||||
eina_stringshare_del(data); |
||||
} |
||||
|
||||
int |
||||
_elm_theme_parse(const char *theme) |
||||
{ |
||||
Eina_List *names = NULL; |
||||
const char *p, *pe; |
||||
|
||||
p = theme; |
||||
pe = p; |
||||
for (;;) |
||||
{ |
||||
if ((*pe == '/') || (*pe == 0)) |
||||
{ // p -> pe == 'name/'
|
||||
if (pe > p) |
||||
{ |
||||
char *n = malloc(pe - p + 1); |
||||
if (n) |
||||
{ |
||||
const char *nn; |
||||
strncpy(n, p, pe - p); |
||||
n[pe - p] = 0; |
||||
nn = eina_stringshare_add(n); |
||||
if (nn) |
||||
names = eina_list_append(names, nn); |
||||
free(n); |
||||
} |
||||
} |
||||
if (*pe == 0) break; |
||||
p = pe + 1; |
||||
pe = p; |
||||
} |
||||
else |
||||
pe++; |
||||
} |
||||
p = eina_list_data_get(eina_list_last(names)); |
||||
if ((!p) || ((p) && (strcmp(p, "default")))) |
||||
{ |
||||
p = eina_stringshare_add("default"); |
||||
if (p) |
||||
names = eina_list_append(names, p); |
||||
} |
||||
if (cache) |
||||
{ |
||||
eina_hash_foreach(cache, _cache_free_cb, NULL); |
||||
eina_hash_free(cache); |
||||
cache = NULL; |
||||
} |
||||
cache = eina_hash_string_superfast_new(NULL); |
||||
|
||||
while (themes) |
||||
{ |
||||
eina_stringshare_del(themes->data); |
||||
themes = eina_list_remove_list(themes, themes); |
||||
} |
||||
|
||||
themes = names; |
||||
return 1; |
||||
} |
||||
|
Loading…
Reference in new issue