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 static const char SIG_CLICKED[] = "clicked";
53 static const Evas_Smart_Cb_Description _signals[] = {
59 //FIXME: move this code to ecore
62 _path_is_absolute(const char *path)
64 //TODO: Check if this works with all absolute paths in windows
65 return ((isalpha (*path)) && (*(path + 1) == ':') && ((*(path + 2) == '\\') || (*(path + 2) == '/')));
69 _path_is_absolute(const char *path)
71 return (*path == '/');
76 _del_hook(Evas_Object *obj)
78 Widget_Data *wd = elm_widget_data_get(obj);
81 if (wd->stdicon) eina_stringshare_del(wd->stdicon);
86 _theme_hook(Evas_Object *obj)
88 Widget_Data *wd = elm_widget_data_get(obj);
91 _elm_theme_object_icon_set(obj, wd->img, wd->stdicon, elm_widget_style_get(obj));
96 _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source)
98 Widget_Data *wd = elm_widget_data_get(obj);
100 Evas_Object *icon_edje;
101 icon_edje = _els_smart_icon_edje_get(wd->img);
102 if (!icon_edje) return;
103 edje_object_signal_emit(icon_edje, emission, source);
107 _signal_callback_add_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
109 Widget_Data *wd = elm_widget_data_get(obj);
111 Evas_Object *icon_edje;
112 icon_edje = _els_smart_icon_edje_get(wd->img);
113 if (!icon_edje) return;
114 edje_object_signal_callback_add(icon_edje, emission, source, func_cb, data);
118 _signal_callback_del_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
120 Widget_Data *wd = elm_widget_data_get(obj);
122 Evas_Object *icon_edje;
123 icon_edje = _els_smart_icon_edje_get(wd->img);
124 if (!icon_edje) return;
125 edje_object_signal_callback_del_full(icon_edje, emission, source, func_cb,
130 _sizing_eval(Evas_Object *obj)
132 Widget_Data *wd = elm_widget_data_get(obj);
134 Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
137 _els_smart_icon_size_get(wd->img, &w, &h);
139 if ((wd->freedesktop.use) && (!((w - wd->freedesktop.requested_size) % 16)))
141 /* This icon has been set to a freedesktop icon, and the requested
142 appears to have a different size than the requested size, so try to
143 request another, higher resolution, icon.
144 FIXME: Find a better heuristic to determine if there should be
145 an icon with a different resolution. */
146 _icon_freedesktop_set(wd, obj, wd->stdicon, w);
149 _els_smart_icon_scale_up_set(wd->img, wd->scale_up);
150 _els_smart_icon_scale_down_set(wd->img, wd->scale_down);
151 _els_smart_icon_smooth_scale_set(wd->img, wd->smooth);
152 _els_smart_icon_fill_inside_set(wd->img, !(wd->fill_outside));
153 if (wd->no_scale) _els_smart_icon_scale_set(wd->img, 1.0);
156 _els_smart_icon_scale_set(wd->img, elm_widget_scale_get(obj) *
158 _els_smart_icon_size_get(wd->img, &w, &h);
170 evas_object_size_hint_min_set(obj, minw, minh);
171 evas_object_size_hint_max_set(obj, maxw, maxh);
175 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
177 Evas_Event_Mouse_Up *ev = event_info;
178 if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
179 evas_object_smart_callback_call(data, SIG_CLICKED, event_info);
183 * Add a new icon to the parent
185 * @param parent The parent object
186 * @return The new object or NULL if it cannot be created
191 elm_icon_add(Evas_Object *parent)
197 ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
199 ELM_SET_WIDTYPE(widtype, "icon");
200 elm_widget_type_set(obj, "icon");
201 elm_widget_can_focus_set(obj, EINA_FALSE);
202 elm_widget_sub_object_add(parent, obj);
203 elm_widget_data_set(obj, wd);
204 elm_widget_del_hook_set(obj, _del_hook);
205 elm_widget_theme_hook_set(obj, _theme_hook);
206 elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
207 elm_widget_signal_callback_add_hook_set(obj, _signal_callback_add_hook);
208 elm_widget_signal_callback_del_hook_set(obj, _signal_callback_del_hook);
210 wd->lookup_order = ELM_ICON_LOOKUP_THEME_FDO;
211 wd->img = _els_smart_icon_add(e);
212 evas_object_event_callback_add(wd->img, EVAS_CALLBACK_MOUSE_UP,
214 evas_object_repeat_events_set(wd->img, EINA_TRUE);
215 elm_widget_resize_object_set(obj, wd->img);
217 evas_object_smart_callbacks_descriptions_set(obj, _signals);
219 wd->smooth = EINA_TRUE;
220 wd->scale_up = EINA_TRUE;
221 wd->scale_down = EINA_TRUE;
228 * Set the file that will be used as icon
230 * @param obj The icon object
231 * @param file The path to file that will be used as icon
232 * @param group The group that the icon belongs in edje file
234 * @return (1 = success, 0 = error)
239 elm_icon_file_set(Evas_Object *obj, const char *file, const char *group)
241 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
242 Widget_Data *wd = elm_widget_data_get(obj);
246 if (!wd) return EINA_FALSE;
247 EINA_SAFETY_ON_NULL_RETURN_VAL(file, EINA_FALSE);
248 if (wd->stdicon) eina_stringshare_del(wd->stdicon);
250 if (((p = strrchr(file, '.'))) && (!strcasecmp(p, ".edj")))
251 ret = _els_smart_icon_file_edje_set(wd->img, file, group);
253 ret = _els_smart_icon_file_key_set(wd->img, file, group);
259 * Get the file that will be used as icon
261 * @param obj The icon object
262 * @param file The path to file that will be used as icon
263 * @param group The group that the icon belongs in edje file
268 elm_icon_file_get(const Evas_Object *obj, const char **file, const char **group)
270 ELM_CHECK_WIDTYPE(obj, widtype);
271 Widget_Data *wd = elm_widget_data_get(obj);
273 _els_smart_icon_file_get(wd->img, file, group);
277 _icon_standard_set(Widget_Data *wd, Evas_Object *obj, const char *name)
279 if (_elm_theme_object_icon_set(obj, wd->img, name, "default"))
282 /* TODO: elm_unneed_efreet() */
283 wd->freedesktop.use = EINA_FALSE;
291 _icon_file_set(Widget_Data *wd, Evas_Object *obj, const char *path)
293 if (elm_icon_file_set(obj, path, NULL))
296 /* TODO: elm_unneed_efreet() */
297 wd->freedesktop.use = EINA_FALSE;
305 _icon_freedesktop_set(Widget_Data *wd, Evas_Object *obj, const char *name, int size)
311 if (icon_theme == NON_EXISTING) return EINA_FALSE;
314 Efreet_Icon_Theme *theme;
315 /* TODO: Listen for EFREET_EVENT_ICON_CACHE_UPDATE */
316 theme = efreet_icon_theme_find(getenv("E_ICON_THEME"));
320 static const char *themes[] = {
321 "gnome", "Human", "oxygen", "hicolor", NULL
323 for (itr = themes; *itr; itr++)
325 theme = efreet_icon_theme_find(*itr);
332 icon_theme = NON_EXISTING;
336 icon_theme = eina_stringshare_add(theme->name.internal);
338 path = efreet_icon_path_find(icon_theme, name, size);
339 wd->freedesktop.use = !!path;
340 if (wd->freedesktop.use)
342 wd->freedesktop.requested_size = size;
343 elm_icon_file_set(obj, path, NULL);
351 _icon_size_min_get(Evas_Object *icon)
354 _els_smart_icon_size_get(icon, &size, NULL);
355 return (size < 32) ? 32 : size;
359 * Set the theme, as standard, for an icon.
360 * If theme was not found and it is the absolute path of an image file, this
361 * image will be used.
363 * @param obj The icon object
364 * @param name The theme name
366 * @return (1 = success, 0 = error)
371 elm_icon_standard_set(Evas_Object *obj, const char *name)
373 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
374 Widget_Data *wd = elm_widget_data_get(obj);
378 if ((!wd) || (!name)) return EINA_FALSE;
380 /* try locating the icon using the specified lookup order */
381 switch (wd->lookup_order)
383 case ELM_ICON_LOOKUP_FDO:
384 ret = _icon_freedesktop_set(wd, obj, name, _icon_size_min_get(wd->img));
386 case ELM_ICON_LOOKUP_THEME:
387 ret = _icon_standard_set(wd, obj, name);
389 case ELM_ICON_LOOKUP_THEME_FDO:
390 ret = _icon_standard_set(wd, obj, name) ||
391 _icon_freedesktop_set(wd, obj, name, _icon_size_min_get(wd->img));
393 case ELM_ICON_LOOKUP_FDO_THEME:
395 ret = _icon_freedesktop_set(wd, obj, name, _icon_size_min_get(wd->img)) ||
396 _icon_standard_set(wd, obj, name);
402 eina_stringshare_replace(&wd->stdicon, name);
407 if (_path_is_absolute(name))
408 return _icon_file_set(wd, obj, name);
410 /* if that fails, see if icon name is in the format size/name. if so,
411 try locating a fallback without the size specification */
412 if (!(tmp = strchr(name, '/'))) return EINA_FALSE;
414 if (*tmp) return elm_icon_standard_set(obj, tmp);
421 * Get the theme, as standard, for an icon
423 * @param obj The icon object
424 * @return The theme name
429 elm_icon_standard_get(const Evas_Object *obj)
431 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
432 Widget_Data *wd = elm_widget_data_get(obj);
433 if (!wd) return NULL;
438 * Sets icon lookup order, used by elm_icon_standard_set().
440 * @param obj The icon object
441 * @param order The icon lookup order
446 elm_icon_order_lookup_set(Evas_Object *obj, Elm_Icon_Lookup_Order order)
448 ELM_CHECK_WIDTYPE(obj, widtype);
449 Widget_Data *wd = elm_widget_data_get(obj);
450 if (wd) wd->lookup_order = order;
454 * Gets the icon lookup order.
456 * @param obj The icon object
457 * @return The icon lookup order
461 EAPI Elm_Icon_Lookup_Order
462 elm_icon_order_lookup_get(const Evas_Object *obj)
464 ELM_CHECK_WIDTYPE(obj, widtype) ELM_ICON_LOOKUP_THEME_FDO;
465 Widget_Data *wd = elm_widget_data_get(obj);
466 if (!wd) return ELM_ICON_LOOKUP_THEME_FDO;
467 return wd->lookup_order;
471 * Set the smooth effect for an icon
473 * @param obj The icon object
474 * @param smooth A bool to set (or no) smooth effect
475 * (1 = smooth, 0 = not smooth)
480 elm_icon_smooth_set(Evas_Object *obj, Eina_Bool smooth)
482 ELM_CHECK_WIDTYPE(obj, widtype);
483 Widget_Data *wd = elm_widget_data_get(obj);
491 * Get the smooth effect for an icon
493 * @param obj The icon object
494 * @return If setted smooth effect
499 elm_icon_smooth_get(const Evas_Object *obj)
501 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
502 Widget_Data *wd = elm_widget_data_get(obj);
504 if (!wd) return EINA_FALSE;
509 * Set if the object is scalable
511 * @param obj The icon object
512 * @param no_scale A bool to set scale (or no)
513 * (1 = no_scale, 0 = scale)
518 elm_icon_no_scale_set(Evas_Object *obj, Eina_Bool no_scale)
520 ELM_CHECK_WIDTYPE(obj, widtype);
521 Widget_Data *wd = elm_widget_data_get(obj);
524 wd->no_scale = no_scale;
529 * Get if the object isn't scalable
531 * @param obj The icon object
532 * @return If isn't scalable
537 elm_icon_no_scale_get(const Evas_Object *obj)
539 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
540 Widget_Data *wd = elm_widget_data_get(obj);
541 if (!wd) return EINA_FALSE;
546 * Set if the object is (up/down) scalable
548 * @param obj The icon object
549 * @param scale_up A bool to set if the object is scalable up
550 * @param scale_down A bool to set if the object is scalable down
555 elm_icon_scale_set(Evas_Object *obj, Eina_Bool scale_up, Eina_Bool scale_down)
557 ELM_CHECK_WIDTYPE(obj, widtype);
558 Widget_Data *wd = elm_widget_data_get(obj);
561 wd->scale_up = scale_up;
562 wd->scale_down = scale_down;
567 * Get if the object is (up/down) scalable
569 * @param obj The icon object
570 * @param scale_up A bool to set if the object is scalable up
571 * @param scale_down A bool to set if the object is scalable down
576 elm_icon_scale_get(const Evas_Object *obj, Eina_Bool *scale_up, Eina_Bool *scale_down)
578 ELM_CHECK_WIDTYPE(obj, widtype);
579 Widget_Data *wd = elm_widget_data_get(obj);
581 if (scale_up) *scale_up = wd->scale_up;
582 if (scale_down) *scale_down = wd->scale_down;
586 * Set if the object is filled outside
588 * @param obj The icon object
589 * @param fill_outside A bool to set if the object is filled outside
590 * (1 = filled, 0 = no filled)
595 elm_icon_fill_outside_set(Evas_Object *obj, Eina_Bool fill_outside)
597 ELM_CHECK_WIDTYPE(obj, widtype);
598 Widget_Data *wd = elm_widget_data_get(obj);
601 wd->fill_outside = fill_outside;
606 * Get if the object is filled outside
608 * @param obj The icon object
609 * @return If the object is filled outside
614 elm_icon_fill_outside_get(const Evas_Object *obj)
616 ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
617 Widget_Data *wd = elm_widget_data_get(obj);
619 if (!wd) return EINA_FALSE;
620 return wd->fill_outside;
624 * Set the prescale size for the icon
626 * @param obj The icon object
627 * @param size The prescale size
632 elm_icon_prescale_set(Evas_Object *obj, int size)
634 ELM_CHECK_WIDTYPE(obj, widtype);
635 Widget_Data *wd = elm_widget_data_get(obj);
638 _els_smart_icon_scale_size_set(wd->img, size);
642 * Get the prescale size for the icon
644 * @param obj The icon object
645 * @return The prescale size
650 elm_icon_prescale_get(const Evas_Object *obj)
652 ELM_CHECK_WIDTYPE(obj, widtype) 0;
653 Widget_Data *wd = elm_widget_data_get(obj);
656 return _els_smart_icon_scale_size_get(wd->img);