1 #include <Elementary.h>
5 #define NON_EXISTING (void *)-1
6 static const char *icon_theme = NULL;
12 * A standard icon that may be provided by the theme (delete, edit,
13 * arrows etc.) or a custom file (PNG, JPG, EDJE etc.) used for an
14 * icon. The Icon may scale or not and of course... support alpha
17 * Signals that you can add callbacks for are:
19 * clicked - This is called when a user has clicked the icon
22 typedef struct _Widget_Data Widget_Data;
28 Elm_Icon_Lookup_Order lookup_order;
35 Eina_Bool scale_up : 1;
36 Eina_Bool scale_down : 1;
38 Eina_Bool fill_outside : 1;
39 Eina_Bool no_scale : 1;
42 static const char *widtype = NULL;
43 static void _del_hook(Evas_Object *obj);
44 static void _theme_hook(Evas_Object *obj);
45 static void _sizing_eval(Evas_Object *obj);
46 static void _mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
48 static Eina_Bool _icon_standard_set(Widget_Data *wd, Evas_Object *obj, const char *name);
49 static Eina_Bool _icon_freedesktop_set(Widget_Data *wd, Evas_Object *obj, const char *name, int size);
51 //FIXME: move this code to ecore
54 _path_is_absolute(const char *path)
56 //TODO: Check if this works with all absolute paths in windows
57 return ((isalpha (*path)) && (*(path + 1) == ':') && ((*(path + 2) == '\\') || (*(path + 2) == '/')));
61 _path_is_absolute(const char *path)
63 return (*path == '/');
68 _del_hook(Evas_Object *obj)
70 Widget_Data *wd = elm_widget_data_get(obj);
73 if (wd->stdicon) eina_stringshare_del(wd->stdicon);
78 _theme_hook(Evas_Object *obj)
80 Widget_Data *wd = elm_widget_data_get(obj);
83 _elm_theme_object_icon_set(obj, wd->img, wd->stdicon, elm_widget_style_get(obj));
88 _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source)
90 Widget_Data *wd = elm_widget_data_get(obj);
92 Evas_Object *icon_edje;
93 icon_edje = _els_smart_icon_edje_get(wd->img);
94 if (!icon_edje) return;
95 edje_object_signal_emit(icon_edje, emission, source);
99 _signal_callback_add_hook(Evas_Object *obj, const char *emission, const char *source, void (*func_cb) (void *data, Evas_Object *o, const char *emission, const char *source), void *data)
101 Widget_Data *wd = elm_widget_data_get(obj);
103 Evas_Object *icon_edje;
104 icon_edje = _els_smart_icon_edje_get(wd->img);
105 if (!icon_edje) return;
106 edje_object_signal_callback_add(icon_edje, emission, source, func_cb, data);
110 _signal_callback_del_hook(Evas_Object *obj, const char *emission, const char *source, void (*func_cb) (void *data, Evas_Object *o, const char *emission, const char *source), void *data)
112 Widget_Data *wd = elm_widget_data_get(obj);
114 Evas_Object *icon_edje;
115 icon_edje = _els_smart_icon_edje_get(wd->img);
116 if (!icon_edje) return;
117 edje_object_signal_callback_del_full(icon_edje, emission, source, func_cb,
122 _sizing_eval(Evas_Object *obj)
124 Widget_Data *wd = elm_widget_data_get(obj);
126 Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
129 _els_smart_icon_size_get(wd->img, &w, &h);
131 if ((wd->freedesktop.use) && (!((w - wd->freedesktop.requested_size) % 16)))
133 /* This icon has been set to a freedesktop icon, and the requested
134 appears to have a different size than the requested size, so try to
135 request another, higher resolution, icon.
136 FIXME: Find a better heuristic to determine if there should be
137 an icon with a different resolution. */
138 _icon_freedesktop_set(wd, obj, wd->stdicon, w);
141 _els_smart_icon_scale_up_set(wd->img, wd->scale_up);
142 _els_smart_icon_scale_down_set(wd->img, wd->scale_down);
143 _els_smart_icon_smooth_scale_set(wd->img, wd->smooth);
144 _els_smart_icon_fill_inside_set(wd->img, !(wd->fill_outside));
145 if (wd->no_scale) _els_smart_icon_scale_set(wd->img, 1.0);
148 _els_smart_icon_scale_set(wd->img, elm_widget_scale_get(obj) *
150 _els_smart_icon_size_get(wd->img, &w, &h);
162 evas_object_size_hint_min_set(obj, minw, minh);
163 evas_object_size_hint_max_set(obj, maxw, maxh);
167 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
169 Evas_Event_Mouse_Up *ev = event_info;
170 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
171 evas_object_smart_callback_call(data, "clicked", event_info);
175 * Add a new icon to the parent
177 * @param parent The parent object
178 * @return The new object or NULL if it cannot be created
183 elm_icon_add(Evas_Object *parent)
189 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
191 wd = ELM_NEW(Widget_Data);
192 e = evas_object_evas_get(parent);
194 obj = elm_widget_add(e);
195 ELM_SET_WIDTYPE(widtype, "icon");
196 elm_widget_type_set(obj, "icon");
197 elm_widget_can_focus_set(obj, EINA_FALSE);
198 elm_widget_sub_object_add(parent, obj);
199 elm_widget_data_set(obj, wd);
200 elm_widget_del_hook_set(obj, _del_hook);
201 elm_widget_theme_hook_set(obj, _theme_hook);
202 elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
203 elm_widget_signal_callback_add_hook_set(obj, _signal_callback_add_hook);
204 elm_widget_signal_callback_del_hook_set(obj, _signal_callback_del_hook);
206 wd->lookup_order = ELM_ICON_LOOKUP_THEME_FDO;
207 wd->img = _els_smart_icon_add(e);
208 evas_object_event_callback_add(wd->img, EVAS_CALLBACK_MOUSE_UP,
210 evas_object_repeat_events_set(wd->img, EINA_TRUE);
211 elm_widget_resize_object_set(obj, wd->img);
213 wd->smooth = EINA_TRUE;
214 wd->scale_up = EINA_TRUE;
215 wd->scale_down = EINA_TRUE;
222 * Set the file that will be used as icon
224 * @param obj The icon object
225 * @param file The path to file that will be used as icon
226 * @param group The group that the icon belongs in edje file
228 * @return (1 = success, 0 = error)
233 elm_icon_file_set(Evas_Object *obj, const char *file, const char *group)
235 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
236 Widget_Data *wd = elm_widget_data_get(obj);
240 if (!wd) return EINA_FALSE;
241 EINA_SAFETY_ON_NULL_RETURN_VAL(file, EINA_FALSE);
242 if (wd->stdicon) eina_stringshare_del(wd->stdicon);
244 if (((p = strrchr(file, '.'))) && (!strcasecmp(p, ".edj")))
245 ret = _els_smart_icon_file_edje_set(wd->img, file, group);
247 ret = _els_smart_icon_file_key_set(wd->img, file, group);
253 * Get the file that will be used as icon
255 * @param obj The icon object
256 * @param file The path to file that will be used as icon
257 * @param group The group that the icon belongs in edje file
262 elm_icon_file_get(const Evas_Object *obj, const char **file, const char **group)
264 ELM_CHECK_WIDTYPE(obj, widtype);
265 Widget_Data *wd = elm_widget_data_get(obj);
267 _els_smart_icon_file_get(wd->img, file, group);
271 _icon_standard_set(Widget_Data *wd, Evas_Object *obj, const char *name)
273 if (_elm_theme_object_icon_set(obj, wd->img, name, "default"))
276 /* TODO: elm_unneed_efreet() */
277 wd->freedesktop.use = EINA_FALSE;
285 _icon_file_set(Widget_Data *wd, Evas_Object *obj, const char *path)
287 if (elm_icon_file_set(obj, path, NULL))
290 /* TODO: elm_unneed_efreet() */
291 wd->freedesktop.use = EINA_FALSE;
299 _icon_freedesktop_set(Widget_Data *wd, Evas_Object *obj, const char *name, int size)
305 if (icon_theme == NON_EXISTING) return EINA_FALSE;
308 Efreet_Icon_Theme *theme;
309 /* TODO: Listen for EFREET_EVENT_ICON_CACHE_UPDATE */
310 theme = efreet_icon_theme_find(getenv("E_ICON_THEME"));
314 static const char *themes[] = {
315 "gnome", "Human", "oxygen", "hicolor", NULL
317 for (itr = themes; *itr; itr++)
319 theme = efreet_icon_theme_find(*itr);
326 icon_theme = NON_EXISTING;
330 icon_theme = eina_stringshare_add(theme->name.internal);
332 path = efreet_icon_path_find(icon_theme, name, size);
333 wd->freedesktop.use = !!path;
334 if (wd->freedesktop.use)
336 wd->freedesktop.requested_size = size;
337 elm_icon_file_set(obj, path, NULL);
345 _icon_size_min_get(Evas_Object *icon)
348 _els_smart_icon_size_get(icon, &size, NULL);
349 return (size < 32) ? 32 : size;
353 * Set the theme, as standard, for a icon.
354 * If theme was not found and it is the absolute path of an image file, this
355 * image will be used.
357 * @param obj The icon object
358 * @param name The theme name
360 * @return (1 = success, 0 = error)
365 elm_icon_standard_set(Evas_Object *obj, const char *name)
367 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
368 Widget_Data *wd = elm_widget_data_get(obj);
372 if ((!wd) || (!name)) return EINA_FALSE;
374 /* try locating the icon using the specified lookup order */
375 switch (wd->lookup_order)
377 case ELM_ICON_LOOKUP_FDO:
378 ret = _icon_freedesktop_set(wd, obj, name, _icon_size_min_get(wd->img));
380 case ELM_ICON_LOOKUP_THEME:
381 ret = _icon_standard_set(wd, obj, name);
383 case ELM_ICON_LOOKUP_THEME_FDO:
384 ret = _icon_standard_set(wd, obj, name) ||
385 _icon_freedesktop_set(wd, obj, name, _icon_size_min_get(wd->img));
387 case ELM_ICON_LOOKUP_FDO_THEME:
389 ret = _icon_freedesktop_set(wd, obj, name, _icon_size_min_get(wd->img)) ||
390 _icon_standard_set(wd, obj, name);
396 eina_stringshare_replace(&wd->stdicon, name);
401 if (_path_is_absolute(name))
402 return _icon_file_set(wd, obj, name);
404 /* if that fails, see if icon name is in the format size/name. if so,
405 try locating a fallback without the size specification */
406 if (!(tmp = strchr(name, '/'))) return EINA_FALSE;
408 if (*tmp) return elm_icon_standard_set(obj, tmp);
415 * Get the theme, as standard, for a icon
417 * @param obj The icon object
418 * @return The theme name
423 elm_icon_standard_get(const Evas_Object *obj)
425 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
426 Widget_Data *wd = elm_widget_data_get(obj);
427 if (!wd) return NULL;
432 * Sets icon lookup order, used by elm_icon_standard_set().
434 * @param obj The icon object
435 * @param order The icon lookup order
440 elm_icon_order_lookup_set(Evas_Object *obj, Elm_Icon_Lookup_Order order)
442 ELM_CHECK_WIDTYPE(obj, widtype);
443 Widget_Data *wd = elm_widget_data_get(obj);
444 if (wd) wd->lookup_order = order;
448 * Gets the icon lookup order.
450 * @param obj The icon object
451 * @return The icon lookup order
455 EAPI Elm_Icon_Lookup_Order
456 elm_icon_order_lookup_get(const Evas_Object *obj)
458 ELM_CHECK_WIDTYPE(obj, widtype) ELM_ICON_LOOKUP_THEME_FDO;
459 Widget_Data *wd = elm_widget_data_get(obj);
460 if (!wd) return ELM_ICON_LOOKUP_THEME_FDO;
461 return wd->lookup_order;
465 * Set the smooth effect for a icon
467 * @param obj The icon object
468 * @param smooth A bool to set (or no) smooth effect
469 * (1 = smooth, 0 = not smooth)
474 elm_icon_smooth_set(Evas_Object *obj, Eina_Bool smooth)
476 ELM_CHECK_WIDTYPE(obj, widtype);
477 Widget_Data *wd = elm_widget_data_get(obj);
485 * Get the smooth effect for a icon
487 * @param obj The icon object
488 * @return If setted smooth effect
493 elm_icon_smooth_get(const Evas_Object *obj)
495 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
496 Widget_Data *wd = elm_widget_data_get(obj);
498 if (!wd) return EINA_FALSE;
503 * Set if the object is scalable
505 * @param obj The icon object
506 * @param no_scale A bool to set scale (or no)
507 * (1 = no_scale, 0 = scale)
512 elm_icon_no_scale_set(Evas_Object *obj, Eina_Bool no_scale)
514 ELM_CHECK_WIDTYPE(obj, widtype);
515 Widget_Data *wd = elm_widget_data_get(obj);
518 wd->no_scale = no_scale;
523 * Get if the object isn't scalable
525 * @param obj The icon object
526 * @return If isn't scalable
531 elm_icon_no_scale_get(const Evas_Object *obj)
533 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
534 Widget_Data *wd = elm_widget_data_get(obj);
535 if (!wd) return EINA_FALSE;
540 * Set if the object is (up/down) scalable
542 * @param obj The icon object
543 * @param scale_up A bool to set if the object is scalable up
544 * @param scale_down A bool to set if the object is scalable down
549 elm_icon_scale_set(Evas_Object *obj, Eina_Bool scale_up, Eina_Bool scale_down)
551 ELM_CHECK_WIDTYPE(obj, widtype);
552 Widget_Data *wd = elm_widget_data_get(obj);
555 wd->scale_up = scale_up;
556 wd->scale_down = scale_down;
561 * Get if the object is (up/down) scalable
563 * @param obj The icon object
564 * @param scale_up A bool to set if the object is scalable up
565 * @param scale_down A bool to set if the object is scalable down
570 elm_icon_scale_get(const Evas_Object *obj, Eina_Bool *scale_up, Eina_Bool *scale_down)
572 ELM_CHECK_WIDTYPE(obj, widtype);
573 Widget_Data *wd = elm_widget_data_get(obj);
575 if (scale_up) *scale_up = wd->scale_up;
576 if (scale_down) *scale_down = wd->scale_down;
580 * Set if the object is filled outside
582 * @param obj The icon object
583 * @param fill_outside A bool to set if the object is filled outside
584 * (1 = filled, 0 = no filled)
589 elm_icon_fill_outside_set(Evas_Object *obj, Eina_Bool fill_outside)
591 ELM_CHECK_WIDTYPE(obj, widtype);
592 Widget_Data *wd = elm_widget_data_get(obj);
595 wd->fill_outside = fill_outside;
600 * Get if the object is filled outside
602 * @param obj The icon object
603 * @return If the object is filled outside
608 elm_icon_fill_outside_get(const Evas_Object *obj)
610 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
611 Widget_Data *wd = elm_widget_data_get(obj);
613 if (!wd) return EINA_FALSE;
614 return wd->fill_outside;
618 * Set the prescale size for the icon
620 * @param obj The icon object
621 * @param size The prescale size
626 elm_icon_prescale_set(Evas_Object *obj, int size)
628 ELM_CHECK_WIDTYPE(obj, widtype);
629 Widget_Data *wd = elm_widget_data_get(obj);
632 _els_smart_icon_scale_size_set(wd->img, size);
636 * Get the prescale size for the icon
638 * @param obj The icon object
639 * @return The prescale size
644 elm_icon_prescale_get(const Evas_Object *obj)
646 ELM_CHECK_WIDTYPE(obj, widtype) 0;
647 Widget_Data *wd = elm_widget_data_get(obj);
650 return _els_smart_icon_scale_size_get(wd->img);