[access] call a callback function with information
[framework/uifw/elementary.git] / src / lib / elm_dayselector.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "elm_widget_dayselector.h"
4
5 EAPI const char ELM_DAYSELECTOR_SMART_NAME[] = "elm_dayselector";
6
7 /* signals to edc */
8 #define ITEM_TYPE_WEEKDAY_DEFAULT "elm,type,weekday,default"
9 #define ITEM_TYPE_WEEKDAY_STYLE1  "elm,type,weekday,style1"
10 #define ITEM_TYPE_WEEKEND_DEFAULT "elm,type,weekend,default"
11 #define ITEM_TYPE_WEEKEND_STYLE1  "elm,type,weekend,style1"
12 #define ITEM_POS_LEFT             "elm,pos,check,left"
13 #define ITEM_POS_RIGHT            "elm,pos,check,right"
14 #define ITEM_POS_MIDDLE           "elm,pos,check,middle"
15
16 static const char SIG_CHANGED[] = "dayselector,changed";
17 static const char SIG_LANG_CHANGED[] = "language,changed";
18 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
19    {SIG_CHANGED, ""},
20    {SIG_LANG_CHANGED, ""},
21    {NULL, NULL}
22 };
23
24 EVAS_SMART_SUBCLASS_NEW
25   (ELM_DAYSELECTOR_SMART_NAME, _elm_dayselector, Elm_Dayselector_Smart_Class,
26   Elm_Layout_Smart_Class, elm_layout_smart_class_get, _smart_callbacks);
27
28 static void
29 _elm_dayselector_smart_sizing_eval(Evas_Object *obj)
30 {
31    Evas_Coord min_w = -1, min_h = -1;
32
33    ELM_DAYSELECTOR_DATA_GET(obj, sd);
34
35    elm_coords_finger_size_adjust(ELM_DAYSELECTOR_MAX, &min_w, 1, &min_h);
36    edje_object_size_min_restricted_calc
37      (ELM_WIDGET_DATA(sd)->resize_obj, &min_w, &min_h, min_w, min_h);
38    elm_coords_finger_size_adjust(ELM_DAYSELECTOR_MAX, &min_w, 1, &min_h);
39    evas_object_size_hint_min_set(obj, min_w, min_h);
40 }
41
42 static void
43 _dayselector_resize(void *data,
44                     Evas *e __UNUSED__,
45                     Evas_Object *obj __UNUSED__,
46                     void *event_info __UNUSED__)
47 {
48    elm_layout_sizing_eval(data);
49 }
50
51 static Eina_Bool
52 _elm_dayselector_smart_translate(Evas_Object *obj)
53 {
54    time_t t;
55    Eina_List *l;
56    char buf[1024];
57    struct tm time_daysel;
58    Elm_Dayselector_Item *it;
59
60    ELM_DAYSELECTOR_DATA_GET(obj, sd);
61
62    t = time(NULL);
63    localtime_r(&t, &time_daysel);
64    EINA_LIST_FOREACH(sd->items, l, it)
65      {
66         time_daysel.tm_wday = it->day;
67         strftime(buf, sizeof(buf), "%a", &time_daysel);
68         elm_object_text_set(VIEW(it), buf);
69      }
70
71    evas_object_smart_callback_call(obj, SIG_LANG_CHANGED, NULL);
72
73    return EINA_TRUE;
74 }
75
76 static void
77 _update_items(Evas_Object *obj)
78 {
79    Eina_List *l;
80    Eina_Bool rtl;
81    unsigned int last_day;
82    Elm_Dayselector_Item *it;
83
84    ELM_DAYSELECTOR_DATA_GET(obj, sd);
85
86    last_day = sd->week_start + ELM_DAYSELECTOR_MAX - 1;
87    if (last_day >= ELM_DAYSELECTOR_MAX)
88      last_day = last_day % ELM_DAYSELECTOR_MAX;
89
90    rtl = elm_widget_mirrored_get(obj);
91    EINA_LIST_FOREACH(sd->items, l, it)
92      {
93         elm_object_signal_emit(VIEW(it), it->day_style, "");
94         if (it->day == sd->week_start)
95           {
96              if (rtl) elm_object_signal_emit(VIEW(it), ITEM_POS_RIGHT, "elm");
97              else elm_object_signal_emit(VIEW(it), ITEM_POS_LEFT, "elm");
98           }
99         else if (it->day == last_day)
100           {
101              if (rtl) elm_object_signal_emit(VIEW(it), ITEM_POS_LEFT, "elm");
102              else elm_object_signal_emit(VIEW(it), ITEM_POS_RIGHT, "elm");
103           }
104         else
105           elm_object_signal_emit(VIEW(it), ITEM_POS_MIDDLE, "elm");
106      }
107 }
108
109 static inline unsigned int
110 _item_location_get(Elm_Dayselector_Smart_Data *sd,
111                    Elm_Dayselector_Item *it)
112 {
113    return (ELM_DAYSELECTOR_MAX - sd->week_start + it->day) %
114           ELM_DAYSELECTOR_MAX;
115 }
116
117 static Eina_Bool
118 _elm_dayselector_smart_theme(Evas_Object *obj)
119 {
120    Eina_List *l;
121    char buf[1024];
122    Elm_Dayselector_Item *it;
123
124    ELM_DAYSELECTOR_DATA_GET(obj, sd);
125
126    if (!ELM_WIDGET_CLASS(_elm_dayselector_parent_sc)->theme(obj))
127      return EINA_FALSE;
128
129    EINA_LIST_FOREACH(sd->items, l, it)
130      {
131         snprintf
132           (buf, sizeof(buf), "dayselector/%s", elm_object_style_get(obj));
133         elm_object_style_set(VIEW(it), buf);
134
135         snprintf
136           (buf, sizeof(buf), "day%d,visible", _item_location_get(sd, it));
137         elm_layout_signal_emit(obj, buf, "elm");
138      }
139
140    _update_items(obj);
141    elm_layout_sizing_eval(obj);
142
143    return EINA_TRUE;
144 }
145
146 static void
147 _item_del_cb(void *data,
148              Evas *e __UNUSED__,
149              Evas_Object *obj,
150              void *event_info __UNUSED__)
151 {
152    Eina_List *l;
153    char buf[1024];
154    Elm_Dayselector_Item *it;
155
156    ELM_DAYSELECTOR_DATA_GET(data, sd);
157
158    EINA_LIST_FOREACH(sd->items, l, it)
159      {
160         if (obj == VIEW(it))
161           {
162              sd->items = eina_list_remove(sd->items, it);
163              eina_stringshare_del(it->day_style);
164              snprintf(buf, sizeof(buf), "day%d,default",
165                       _item_location_get(sd, it));
166              elm_layout_signal_emit(obj, buf, "elm");
167
168              VIEW(it) = NULL;
169              elm_widget_item_free(it);
170
171              elm_layout_sizing_eval(obj);
172              break;
173           }
174      }
175 }
176
177 static void
178 _item_signal_emit_cb(void *data,
179                      Evas_Object *obj __UNUSED__,
180                      const char *emission,
181                      const char *source __UNUSED__)
182 {
183    Elm_Dayselector_Item *it = data;
184
185    eina_stringshare_replace(&it->day_style, emission);
186 }
187
188 static void
189 _item_clicked_cb(void *data,
190                  Evas_Object *obj __UNUSED__,
191                  void *event_info __UNUSED__)
192 {
193    Elm_Dayselector_Item *it = data;
194
195    evas_object_smart_callback_call(WIDGET(it), SIG_CHANGED, (void *)it->day);
196 }
197
198 static Elm_Dayselector_Item *
199 _item_find(const Evas_Object *obj,
200            Elm_Dayselector_Day day)
201 {
202    Eina_List *l;
203    Elm_Dayselector_Item *it;
204
205    ELM_DAYSELECTOR_DATA_GET(obj, sd);
206
207    EINA_LIST_FOREACH(sd->items, l, it)
208      if (day == it->day) return it;
209
210    return NULL;
211 }
212
213 static Eina_Bool
214 _elm_dayselector_smart_content_set(Evas_Object *obj,
215                                    const char *item,
216                                    Evas_Object *content)
217 {
218    int day;
219    char buf[1024];
220    Elm_Dayselector_Item *it = NULL;
221
222    ELM_DAYSELECTOR_DATA_GET(obj, sd);
223
224    if (strcmp(elm_object_widget_type_get(content), "elm_check"))
225      return EINA_FALSE;
226
227    if (!item) return EINA_FALSE;
228
229    day = atoi(item + (strlen(item) - 1));
230    if (day < 0 || day > ELM_DAYSELECTOR_MAX) return EINA_FALSE;
231
232    it = _item_find(obj, day);
233    if (it)
234      {
235         snprintf(buf, sizeof(buf), "day%d", _item_location_get(sd, it));
236
237         if (!ELM_CONTAINER_CLASS(_elm_dayselector_parent_sc)->content_set
238               (obj, buf, content))
239           return EINA_FALSE;
240
241         if (!content) return EINA_TRUE;  /* item deletion already
242                                           * handled */
243
244         evas_object_del(VIEW(it));
245         VIEW(it) = content;
246      }
247    else
248      {
249         it = elm_widget_item_new(obj, Elm_Dayselector_Item);
250         if (!it) return EINA_FALSE;
251
252         it->day = day;
253
254         snprintf(buf, sizeof(buf), "day%d", _item_location_get(sd, it));
255
256         if (!ELM_CONTAINER_CLASS(_elm_dayselector_parent_sc)->content_set
257               (obj, buf, content))
258           {
259              elm_widget_item_free(it);
260              return EINA_FALSE;
261           }
262
263         sd->items = eina_list_append(sd->items, it);
264         VIEW(it) = content;
265      }
266
267    snprintf(buf, sizeof(buf), "day%d,visible", _item_location_get(sd, it));
268    elm_layout_signal_emit(obj, buf, "elm");
269
270    evas_object_smart_callback_add(VIEW(it), "changed", _item_clicked_cb, it);
271    evas_object_event_callback_add
272      (VIEW(it), EVAS_CALLBACK_DEL, _item_del_cb, obj);
273
274    elm_object_signal_callback_add
275      (VIEW(it), ITEM_TYPE_WEEKDAY_DEFAULT, "", _item_signal_emit_cb, it);
276    elm_object_signal_callback_add
277      (VIEW(it), ITEM_TYPE_WEEKDAY_STYLE1, "", _item_signal_emit_cb, it);
278    elm_object_signal_callback_add
279      (VIEW(it), ITEM_TYPE_WEEKEND_DEFAULT, "", _item_signal_emit_cb, it);
280    elm_object_signal_callback_add
281      (VIEW(it), ITEM_TYPE_WEEKEND_STYLE1, "", _item_signal_emit_cb, it);
282
283    elm_layout_sizing_eval(obj);
284    _update_items(obj);
285
286    return EINA_TRUE;
287 }
288
289 static Evas_Object *
290 _elm_dayselector_smart_content_unset(Evas_Object *obj,
291                                      const char *item)
292 {
293    int day;
294    char buf[1024];
295    Evas_Object *content;
296    Elm_Dayselector_Item *it = NULL;
297
298    ELM_DAYSELECTOR_DATA_GET(obj, sd);
299
300    day = atoi(item + (strlen(item) - 1));
301    if (day < 0 || day > ELM_DAYSELECTOR_MAX) return EINA_FALSE;
302
303    it = _item_find(obj, day);
304    if (!it) return NULL;
305
306    content = VIEW(it);
307
308    if (!ELM_CONTAINER_CLASS(_elm_dayselector_parent_sc)->content_unset
309          (obj, buf))
310      return EINA_FALSE;
311
312    sd->items = eina_list_remove(sd->items, it);
313    evas_object_smart_callback_del(content, "changed", _item_clicked_cb);
314    evas_object_event_callback_del(content, EVAS_CALLBACK_DEL, _item_del_cb);
315
316    elm_object_signal_callback_del
317      (content, ITEM_TYPE_WEEKDAY_DEFAULT, "", _item_signal_emit_cb);
318    elm_object_signal_callback_del
319      (content, ITEM_TYPE_WEEKDAY_STYLE1, "", _item_signal_emit_cb);
320    elm_object_signal_callback_del
321      (content, ITEM_TYPE_WEEKEND_DEFAULT, "", _item_signal_emit_cb);
322    elm_object_signal_callback_del
323      (content, ITEM_TYPE_WEEKEND_STYLE1, "", _item_signal_emit_cb);
324
325    snprintf(buf, sizeof(buf), "day%d,default", _item_location_get(sd, it));
326    elm_layout_signal_emit(obj, buf, "elm");
327
328    VIEW(it) = NULL;
329    elm_widget_item_free(it);
330
331    elm_layout_sizing_eval(obj);
332
333    return content;
334 }
335
336 static void
337 _items_style_set(Evas_Object *obj)
338 {
339    Eina_List *l;
340    Elm_Dayselector_Item *it;
341    unsigned int weekend_last;
342
343    ELM_DAYSELECTOR_DATA_GET(obj, sd);
344
345    weekend_last = sd->weekend_start + sd->weekend_len - 1;
346    if (weekend_last >= ELM_DAYSELECTOR_MAX)
347      weekend_last = weekend_last % ELM_DAYSELECTOR_MAX;
348
349    EINA_LIST_FOREACH(sd->items, l, it)
350      {
351         if (weekend_last >= sd->weekend_start)
352           {
353              if ((it->day >= sd->weekend_start) && (it->day <= weekend_last))
354                eina_stringshare_replace(&it->day_style,
355                                         ITEM_TYPE_WEEKEND_DEFAULT);
356              else
357                eina_stringshare_replace(&it->day_style,
358                                         ITEM_TYPE_WEEKDAY_DEFAULT);
359           }
360         else
361           {
362              if ((it->day >= sd->weekend_start) || (it->day <= weekend_last))
363                eina_stringshare_replace(&it->day_style,
364                                         ITEM_TYPE_WEEKEND_DEFAULT);
365              else
366                eina_stringshare_replace(&it->day_style,
367                                         ITEM_TYPE_WEEKDAY_DEFAULT);
368           }
369      }
370 }
371
372 static void
373 _items_create(Evas_Object *obj)
374 {
375    time_t t;
376    char buf[1024];
377    unsigned int idx;
378    struct tm time_daysel;
379
380    t = time(NULL);
381    localtime_r(&t, &time_daysel);
382
383    for (idx = 0; idx < ELM_DAYSELECTOR_MAX; idx++)
384      {
385         Evas_Object *chk;
386
387         chk = elm_check_add(obj);
388         elm_object_style_set(chk, "dayselector/default");
389
390         time_daysel.tm_wday = idx;
391         strftime(buf, sizeof(buf), "%a", &time_daysel);
392         elm_object_text_set(chk, buf);
393
394         snprintf(buf, sizeof(buf), "day%d", idx);
395         elm_layout_content_set(obj, buf, chk);
396
397         // XXX: ACCESS
398         _elm_access_text_set(_elm_access_object_get(chk),
399                  ELM_ACCESS_TYPE, E_("day selector item"));
400      }
401
402    _items_style_set(obj);
403    _update_items(obj);
404 }
405
406 static void
407 _elm_dayselector_smart_add(Evas_Object *obj)
408 {
409    EVAS_SMART_DATA_ALLOC(obj, Elm_Dayselector_Smart_Data);
410
411    ELM_WIDGET_CLASS(_elm_dayselector_parent_sc)->base.add(obj);
412
413    elm_layout_theme_set(obj, "dayselector", "base", "dayselector");
414
415    priv->week_start = _elm_config->week_start;
416    priv->weekend_start = _elm_config->weekend_start;
417    priv->weekend_len = _elm_config->weekend_len;
418    _items_create(obj);
419
420    evas_object_event_callback_add
421      (obj, EVAS_CALLBACK_RESIZE, _dayselector_resize, obj);
422
423    elm_layout_sizing_eval(obj);
424 }
425
426 static void
427 _elm_dayselector_smart_del(Evas_Object *obj)
428 {
429    ELM_DAYSELECTOR_DATA_GET(obj, sd);
430
431    Elm_Dayselector_Item *it;
432
433    EINA_LIST_FREE (sd->items, it)
434      {
435         sd->items = eina_list_remove(sd->items, it);
436         eina_stringshare_del(it->day_style);
437         elm_widget_item_free(it);
438      }
439
440    /* handles freeing sd */
441    ELM_WIDGET_CLASS(_elm_dayselector_parent_sc)->base.del(obj);
442 }
443
444 static void
445 _elm_dayselector_smart_set_user(Elm_Dayselector_Smart_Class *sc)
446 {
447    ELM_WIDGET_CLASS(sc)->base.add = _elm_dayselector_smart_add;
448    ELM_WIDGET_CLASS(sc)->base.del = _elm_dayselector_smart_del;
449
450    ELM_WIDGET_CLASS(sc)->theme = _elm_dayselector_smart_theme;
451    ELM_WIDGET_CLASS(sc)->translate = _elm_dayselector_smart_translate;
452
453    ELM_WIDGET_CLASS(sc)->focus_direction = NULL;
454
455    ELM_CONTAINER_CLASS(sc)->content_set = _elm_dayselector_smart_content_set;
456    ELM_CONTAINER_CLASS(sc)->content_unset =
457      _elm_dayselector_smart_content_unset;
458
459    ELM_LAYOUT_CLASS(sc)->sizing_eval = _elm_dayselector_smart_sizing_eval;
460 }
461
462 EAPI const Elm_Dayselector_Smart_Class *
463 elm_dayselector_smart_class_get(void)
464 {
465    static Elm_Dayselector_Smart_Class _sc =
466      ELM_DAYSELECTOR_SMART_CLASS_INIT_NAME_VERSION(ELM_DAYSELECTOR_SMART_NAME);
467    static const Elm_Dayselector_Smart_Class *class = NULL;
468    Evas_Smart_Class *esc = (Evas_Smart_Class *)&_sc;
469
470    if (class)
471      return class;
472
473    _elm_dayselector_smart_set(&_sc);
474    esc->callbacks = _smart_callbacks;
475    class = &_sc;
476
477    return class;
478 }
479
480 EAPI Evas_Object *
481 elm_dayselector_add(Evas_Object *parent)
482 {
483    Evas_Object *obj;
484
485    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
486
487    obj = elm_widget_add(_elm_dayselector_smart_class_new(), parent);
488    if (!obj) return NULL;
489
490    if (!elm_widget_sub_object_add(parent, obj))
491      ERR("could not add %p as sub object of %p", obj, parent);
492
493    return obj;
494 }
495
496 EAPI void
497 elm_dayselector_day_selected_set(Evas_Object *obj,
498                                  Elm_Dayselector_Day day,
499                                  Eina_Bool selected)
500 {
501    ELM_DAYSELECTOR_CHECK(obj);
502
503    elm_check_state_set(VIEW(_item_find(obj, day)), selected);
504 }
505
506 EAPI Eina_Bool
507 elm_dayselector_day_selected_get(const Evas_Object *obj,
508                                  Elm_Dayselector_Day day)
509 {
510    ELM_DAYSELECTOR_CHECK(obj) EINA_FALSE;
511
512    return elm_check_state_get(VIEW(_item_find(obj, day)));
513 }
514
515 EAPI void
516 elm_dayselector_week_start_set(Evas_Object *obj,
517                                Elm_Dayselector_Day day)
518 {
519    Eina_List *l;
520    char buf[1024];
521    Elm_Dayselector_Item *it;
522
523    ELM_DAYSELECTOR_CHECK(obj);
524    ELM_DAYSELECTOR_DATA_GET(obj, sd);
525
526    /* just shuffling items, so swalling them directly */
527    sd->week_start = day;
528    EINA_LIST_FOREACH(sd->items, l, it)
529      {
530         snprintf(buf, sizeof(buf), "day%d", _item_location_get(sd, it));
531         edje_object_part_swallow
532           (ELM_WIDGET_DATA(sd)->resize_obj, buf, VIEW(it));
533      }
534
535    _update_items(obj);
536 }
537
538 EAPI Elm_Dayselector_Day
539 elm_dayselector_week_start_get(const Evas_Object *obj)
540 {
541    ELM_DAYSELECTOR_CHECK(obj) ELM_DAYSELECTOR_MAX;
542    ELM_DAYSELECTOR_DATA_GET(obj, sd);
543
544    return sd->week_start;
545 }
546
547 EAPI void
548 elm_dayselector_weekend_start_set(Evas_Object *obj,
549                                   Elm_Dayselector_Day day)
550 {
551    ELM_DAYSELECTOR_CHECK(obj);
552    ELM_DAYSELECTOR_DATA_GET(obj, sd);
553
554    sd->weekend_start = day;
555
556    _items_style_set(obj);
557    _update_items(obj);
558 }
559
560 EAPI Elm_Dayselector_Day
561 elm_dayselector_weekend_start_get(const Evas_Object *obj)
562 {
563    ELM_DAYSELECTOR_CHECK(obj) ELM_DAYSELECTOR_MAX;
564    ELM_DAYSELECTOR_DATA_GET(obj, sd);
565
566    return sd->weekend_start;
567 }
568
569 EAPI void
570 elm_dayselector_weekend_length_set(Evas_Object *obj,
571                                    unsigned int length)
572 {
573    ELM_DAYSELECTOR_CHECK(obj);
574    ELM_DAYSELECTOR_DATA_GET(obj, sd);
575
576    sd->weekend_len = length;
577
578    _items_style_set(obj);
579    _update_items(obj);
580 }
581
582 EAPI unsigned int
583 elm_dayselector_weekend_length_get(const Evas_Object *obj)
584 {
585    ELM_DAYSELECTOR_CHECK(obj) 0;
586    ELM_DAYSELECTOR_DATA_GET(obj, sd);
587
588    return sd->weekend_len;
589 }