Merge "gengrid TC modified"
[framework/uifw/elementary.git] / tests / src / lib / elc_anchorblock.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 typedef struct _Widget_Data Widget_Data;
5 typedef struct _Elm_Anchorblock_Item_Provider Elm_Anchorblock_Item_Provider;
6
7 struct _Widget_Data
8 {
9    Evas_Object *entry;
10    Evas_Object *hover_parent;
11    Evas_Object *pop, *hover;
12    Eina_List *item_providers;
13    const char *hover_style;
14 };
15
16 struct _Elm_Anchorblock_Item_Provider
17 {
18    Evas_Object *(*func) (void *data, Evas_Object *anchorblock, const char *item);
19    void *data;
20 };
21
22 static const char *widtype = NULL;
23
24 static const char SIG_ANCHOR_CLICKED[] = "anchor,clicked";
25 static const Evas_Smart_Cb_Description _signals[] = {
26        {SIG_ANCHOR_CLICKED, ""}, /* TODO: declare the type properly, as data is
27                                   * being passed
28                                   */
29        {NULL, NULL}
30 };
31
32 static void _del_pre_hook(Evas_Object *obj);
33 static void _del_hook(Evas_Object *obj);
34 static void _sizing_eval(Evas_Object *obj);
35 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
36 static void _parent_del(void *data, Evas *e, Evas_Object *obj, void *event_info);
37 static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl);
38
39 static void
40 _del_pre_hook(Evas_Object *obj)
41 {
42    Widget_Data *wd = elm_widget_data_get(obj);
43    if (!wd) return;
44    evas_object_event_callback_del_full(wd->entry, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
45                                        _changed_size_hints, obj);
46    elm_anchorblock_hover_end(obj);
47    elm_anchorblock_hover_parent_set(obj, NULL);
48 }
49
50 static void
51 _del_hook(Evas_Object *obj)
52 {
53    Widget_Data *wd = elm_widget_data_get(obj);
54    Elm_Anchorblock_Item_Provider *ip;
55    if (!wd) return;
56    if (wd->hover_style) eina_stringshare_del(wd->hover_style);
57    EINA_LIST_FREE(wd->item_providers, ip)
58      {
59         free(ip);
60      }
61    free(wd);
62 }
63
64 static void
65 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
66 {
67    Widget_Data *wd = elm_widget_data_get(obj);
68    if (!wd) return;
69    elm_widget_mirrored_set(wd->hover, rtl);
70 }
71
72 static void
73 _theme_hook(Evas_Object *obj)
74 {
75    Widget_Data *wd = elm_widget_data_get(obj);
76    if (!wd) return;
77    _elm_widget_mirrored_reload(obj);
78    _mirrored_set(obj, elm_widget_mirrored_get(obj));
79 }
80
81 static void
82 _sizing_eval(Evas_Object *obj)
83 {
84    Widget_Data *wd = elm_widget_data_get(obj);
85    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
86    if (!wd) return;
87    evas_object_size_hint_min_get(wd->entry, &minw, &minh);
88    evas_object_size_hint_min_set(obj, minw, minh);
89    evas_object_size_hint_max_set(obj, maxw, maxh);
90 }
91
92 static void
93 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
94 {
95    _sizing_eval(data);
96 }
97
98 static void
99 _hover_clicked(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
100 {
101    elm_anchorblock_hover_end(data);
102 }
103
104 static void
105 _anchor_clicked(void *data, Evas_Object *obj, void *event_info)
106 {
107    Widget_Data *wd = elm_widget_data_get(data);
108    Elm_Entry_Anchor_Info *info = event_info;
109    Evas_Object *hover_parent;
110    Elm_Entry_Anchorblock_Info ei;
111    Evas_Coord x, w, y, h, px, py;
112    if (!wd) return;
113    wd->pop = elm_icon_add(obj);
114    evas_object_move(wd->pop, info->x, info->y);
115    evas_object_resize(wd->pop, info->w, info->h);
116    wd->hover = elm_hover_add(obj);
117    elm_widget_mirrored_set(wd->hover, elm_widget_mirrored_get((Evas_Object *) data));
118    if (wd->hover_style)
119      elm_object_style_set(wd->hover, wd->hover_style);
120    hover_parent = wd->hover_parent;
121    if (!hover_parent) hover_parent = obj;
122    elm_hover_parent_set(wd->hover, hover_parent);
123    elm_hover_target_set(wd->hover, wd->pop);
124    ei.name = info->name;
125    ei.button = info->button;
126    ei.hover = wd->hover;
127    ei.anchor.x = info->x;
128    ei.anchor.y = info->y;
129    ei.anchor.w = info->w;
130    ei.anchor.h = info->h;
131    evas_object_geometry_get(hover_parent, &x, &y, &w, &h);
132    ei.hover_parent.x = x;
133    ei.hover_parent.y = y;
134    ei.hover_parent.w = w;
135    ei.hover_parent.h = h;
136    px = info->x + (info->w / 2);
137    py = info->y + (info->h / 2);
138    ei.hover_left = 1;
139    if (px < (x + (w / 3))) ei.hover_left = 0;
140    ei.hover_right = 1;
141    if (px > (x + ((w * 2) / 3))) ei.hover_right = 0;
142    ei.hover_top = 1;
143    if (py < (y + (h / 3))) ei.hover_top = 0;
144    ei.hover_bottom = 1;
145    if (py > (y + ((h * 2) / 3))) ei.hover_bottom = 0;
146
147    if (elm_widget_mirrored_get(wd->hover))
148      {  /* Swap right and left because they switch sides in RTL */
149         Eina_Bool tmp = ei.hover_left;
150         ei.hover_left = ei.hover_right;
151         ei.hover_right = tmp;
152      }
153
154    evas_object_smart_callback_call(data, SIG_ANCHOR_CLICKED, &ei);
155    evas_object_smart_callback_add(wd->hover, "clicked", _hover_clicked, data);
156    evas_object_show(wd->hover);
157 }
158
159 static void
160 _parent_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
161 {
162    Widget_Data *wd = elm_widget_data_get(data);
163    if (!wd) return;
164    wd->hover_parent = NULL;
165 }
166
167 static Evas_Object *
168 _item_provider(void *data, Evas_Object *entry __UNUSED__, const char *item)
169 {
170    Widget_Data *wd = elm_widget_data_get(data);
171    Eina_List *l;
172    Elm_Anchorblock_Item_Provider *ip;
173
174    EINA_LIST_FOREACH(wd->item_providers, l, ip)
175      {
176         Evas_Object *o;
177
178         o = ip->func(ip->data, data, item);
179         if (o) return o;
180      }
181    return NULL;
182 }
183
184 static void
185 _elm_anchorblock_text_set(Evas_Object *obj, const char *item, const char *text)
186 {
187    ELM_CHECK_WIDTYPE(obj, widtype);
188    Widget_Data *wd = elm_widget_data_get(obj);
189    if (item && strcmp(item, "default")) return;
190    if (!wd) return;
191    elm_object_text_set(wd->entry, text);
192    if (wd->hover) evas_object_del(wd->hover);
193    if (wd->pop) evas_object_del(wd->pop);
194    wd->hover = NULL;
195    wd->pop = NULL;
196    _sizing_eval(obj);
197 }
198
199 static const char*
200 _elm_anchorblock_text_get(const Evas_Object *obj, const char *item)
201 {
202    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
203    Widget_Data *wd = elm_widget_data_get(obj);
204    if (item && strcmp(item, "default")) return NULL;
205    if (!wd) return NULL;
206    return elm_object_text_get(wd->entry);
207 }
208
209 EAPI Evas_Object *
210 elm_anchorblock_add(Evas_Object *parent)
211 {
212    Evas_Object *obj;
213    Evas *e;
214    Widget_Data *wd;
215
216    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
217
218    ELM_SET_WIDTYPE(widtype, "anchorblock");
219    elm_widget_type_set(obj, "anchorblock");
220    elm_widget_sub_object_add(parent, obj);
221    elm_widget_data_set(obj, wd);
222    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
223    elm_widget_del_hook_set(obj, _del_hook);
224    elm_widget_theme_hook_set(obj, _theme_hook);
225    elm_widget_can_focus_set(obj, EINA_TRUE);
226    elm_widget_text_set_hook_set(obj, _elm_anchorblock_text_set);
227    elm_widget_text_get_hook_set(obj, _elm_anchorblock_text_get);
228
229    wd->entry = elm_entry_add(parent);
230    elm_entry_item_provider_prepend(wd->entry, _item_provider, obj);
231    elm_widget_resize_object_set(obj, wd->entry);
232    elm_entry_editable_set(wd->entry, 0);
233    evas_object_size_hint_weight_set(wd->entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
234    evas_object_size_hint_align_set(wd->entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
235
236    evas_object_event_callback_add(wd->entry, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
237                                   _changed_size_hints, obj);
238
239    elm_object_text_set(wd->entry, "");
240
241    evas_object_smart_callback_add(wd->entry, "anchor,clicked",
242                                   _anchor_clicked, obj);
243
244    _mirrored_set(obj, elm_widget_mirrored_get(obj));
245    _sizing_eval(obj);
246
247    // TODO: convert Elementary to subclassing of Evas_Smart_Class
248    // TODO: and save some bytes, making descriptions per-class and not instance!
249    evas_object_smart_callbacks_descriptions_set(obj, _signals);
250    return obj;
251 }
252
253 EAPI void
254 elm_anchorblock_text_set(Evas_Object *obj, const char *text)
255 {
256    _elm_anchorblock_text_set(obj, NULL, text);
257 }
258
259 EAPI const char*
260 elm_anchorblock_text_get(const Evas_Object *obj)
261 {
262    return _elm_anchorblock_text_get(obj, NULL);
263 }
264
265 EAPI void
266 elm_anchorblock_hover_parent_set(Evas_Object *obj, Evas_Object *parent)
267 {
268    ELM_CHECK_WIDTYPE(obj, widtype);
269    Widget_Data *wd = elm_widget_data_get(obj);
270    if (!wd) return;
271    if (wd->hover_parent)
272      evas_object_event_callback_del_full(wd->hover_parent, EVAS_CALLBACK_DEL, _parent_del, obj);
273    wd->hover_parent = parent;
274    if (wd->hover_parent)
275      evas_object_event_callback_add(wd->hover_parent, EVAS_CALLBACK_DEL, _parent_del, obj);
276 }
277
278 EAPI Evas_Object *
279 elm_anchorblock_hover_parent_get(const Evas_Object *obj)
280 {
281    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
282    Widget_Data *wd = elm_widget_data_get(obj);
283    if (!wd) return NULL;
284    return wd->hover_parent;
285 }
286
287 EAPI void
288 elm_anchorblock_hover_style_set(Evas_Object *obj, const char *style)
289 {
290    ELM_CHECK_WIDTYPE(obj, widtype);
291    Widget_Data *wd = elm_widget_data_get(obj);
292    if (!wd) return;
293    eina_stringshare_replace(&wd->hover_style, style);
294 }
295
296 EAPI const char *
297 elm_anchorblock_hover_style_get(const Evas_Object *obj)
298 {
299    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
300    Widget_Data *wd = elm_widget_data_get(obj);
301    if (!wd) return NULL;
302    return wd->hover_style;
303 }
304
305 EAPI void
306 elm_anchorblock_hover_end(Evas_Object *obj)
307 {
308    ELM_CHECK_WIDTYPE(obj, widtype);
309    Widget_Data *wd = elm_widget_data_get(obj);
310    if (!wd) return;
311    if (wd->hover) evas_object_del(wd->hover);
312    if (wd->pop) evas_object_del(wd->pop);
313    wd->hover = NULL;
314    wd->pop = NULL;
315 }
316
317 EAPI void
318 elm_anchorblock_item_provider_append(Evas_Object *obj, Evas_Object *(*func) (void *data, Evas_Object *anchorblock, const char *item), void *data)
319 {
320    ELM_CHECK_WIDTYPE(obj, widtype);
321    Widget_Data *wd = elm_widget_data_get(obj);
322    if (!wd) return;
323    EINA_SAFETY_ON_NULL_RETURN(func);
324    Elm_Anchorblock_Item_Provider *ip = calloc(1, sizeof(Elm_Anchorblock_Item_Provider));
325    if (!ip) return;
326    ip->func = func;
327    ip->data = data;
328    wd->item_providers = eina_list_append(wd->item_providers, ip);
329 }
330
331 EAPI void
332 elm_anchorblock_item_provider_prepend(Evas_Object *obj, Evas_Object *(*func) (void *data, Evas_Object *anchorblock, const char *item), void *data)
333 {
334    ELM_CHECK_WIDTYPE(obj, widtype);
335    Widget_Data *wd = elm_widget_data_get(obj);
336    if (!wd) return;
337    EINA_SAFETY_ON_NULL_RETURN(func);
338    Elm_Anchorblock_Item_Provider *ip = calloc(1, sizeof(Elm_Anchorblock_Item_Provider));
339    if (!ip) return;
340    ip->func = func;
341    ip->data = data;
342    wd->item_providers = eina_list_prepend(wd->item_providers, ip);
343 }
344
345 EAPI void
346 elm_anchorblock_item_provider_remove(Evas_Object *obj, Evas_Object *(*func) (void *data, Evas_Object *anchorblock, const char *item), void *data)
347 {
348    ELM_CHECK_WIDTYPE(obj, widtype);
349    Widget_Data *wd = elm_widget_data_get(obj);
350    Eina_List *l;
351    Elm_Anchorblock_Item_Provider *ip;
352    if (!wd) return;
353    EINA_SAFETY_ON_NULL_RETURN(func);
354    EINA_LIST_FOREACH(wd->item_providers, l, ip)
355      {
356         if ((ip->func == func) && (ip->data == data))
357           {
358              wd->item_providers = eina_list_remove_list(wd->item_providers, l);
359              free(ip);
360              return;
361           }
362      }
363 }