1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4 
5 #define EFL_ACCESS_OBJECT_PROTECTED
6 #define EFL_ACCESS_WIDGET_ACTION_PROTECTED
7 #define EFL_UI_FOCUS_COMPOSITION_PROTECTED
8 #define EFL_UI_FOCUS_OBJECT_PROTECTED
9 
10 #include <Elementary.h>
11 #include "elm_priv.h"
12 #include "elm_widget_calendar.h"
13 #include "elm_calendar_eo.h"
14 #include "elm_calendar_item_eo.h"
15 
16 #define MY_CLASS ELM_CALENDAR_CLASS
17 
18 #define MY_CLASS_NAME "Elm_Calendar"
19 #define MY_CLASS_NAME_LEGACY "elm_calendar"
20 
21 #define ELM_CALENDAR_BUTTON_LEFT "elm,calendar,button,left"
22 #define ELM_CALENDAR_BUTTON_RIGHT "elm,calendar,button,right"
23 #define ELM_CALENDAR_BUTTON_YEAR_LEFT "elm,calendar,button_year,left"
24 #define ELM_CALENDAR_BUTTON_YEAR_RIGHT "elm,calendar,button_year,right"
25 #define ELM_CALENDAR_CH_WEEKEND "elm,calendar,ch_%d,weekend"
26 #define ELM_CALENDAR_CH_WEEKDAY "elm,calendar,ch_%d,weekday"
27 
28 #define ELM_CALENDAR_CH_TEXT_PART_STR "elm.ch_%d.text"
29 #define ELM_CALENDAR_CIT_TEXT_PART_STR "elm.cit_%d.text"
30 #define ELM_CALENDAR_CIT_ACCESS_PART_STR "elm.cit_%d.access"
31 
_part_name_snprintf(char * buffer,int buffer_size,const Evas_Object * obj,const char * template,int n)32 static void _part_name_snprintf(char *buffer, int buffer_size,
33    const Evas_Object *obj, const char *template, int n)
34 {
35    snprintf(buffer, buffer_size, template, n);
36    if (!edje_object_part_exists (obj, buffer))
37      {
38         // Skip the namespace prefix "elm." which was not present
39         // in previous versions
40         snprintf(buffer, buffer_size, template + 4, n);
41      }
42 }
43 
44 static const char SIG_CHANGED[] = "changed";
45 static const char SIG_DISPLAY_CHANGED[] = "display,changed";
46 
47 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
48    {SIG_CHANGED, ""},
49    {SIG_DISPLAY_CHANGED, ""},
50    {SIG_WIDGET_LANG_CHANGED, ""}, /**< handled by elm_widget */
51    {SIG_WIDGET_ACCESS_CHANGED, ""}, /**< handled by elm_widget */
52    {SIG_LAYOUT_FOCUSED, ""}, /**< handled by elm_layout */
53    {SIG_LAYOUT_UNFOCUSED, ""}, /**< handled by elm_layout */
54    {NULL, NULL}
55 };
56 
57 /* Originally, the button functionalities of month, year spinners were
58  * implemented by its own edc. There was a bunch of callback functions
59  * for handle the signals. The following functions are the old callback
60  * functions for handle the signals.
61  *    _button_month_dec_start
62  *    _button_year_inc_start
63  *    _button_year_dec_start
64  *    _button_month_stop
65  *    _button_year_stop
66  *
67  * But, it is replaced by elm_button widget objects. The following
68  * callback functions are also newly added for button objects.
69  * We still keep the old signal callback functions for backward compatibility. */
70 
71 static void
72 _inc_dec_button_clicked_cb(void *data, const Efl_Event *event EINA_UNUSED);
73 static void
74 _inc_dec_button_pressed_cb(void *data, const Efl_Event *event);
75 static void
76 _inc_dec_button_unpressed_cb(void *data, const Efl_Event *event EINA_UNUSED);
77 
78 EFL_CALLBACKS_ARRAY_DEFINE( _inc_dec_button_cb,
79    { EFL_INPUT_EVENT_CLICKED, _inc_dec_button_clicked_cb},
80    { EFL_INPUT_EVENT_PRESSED, _inc_dec_button_pressed_cb},
81    { EFL_INPUT_EVENT_UNPRESSED, _inc_dec_button_unpressed_cb}
82 );
83 
84 static Eina_Bool _key_action_activate(Evas_Object *obj, const char *params);
85 
86 static const Elm_Action key_actions[] = {
87    {"activate", _key_action_activate},
88    {NULL, NULL}
89 };
90 
91 /* Should not be translated, it's used if we failed
92  * getting from locale. */
93 static const char *_days_abbrev[] =
94 {
95    "Sun", "Mon", "Tue", "Wed",
96    "Thu", "Fri", "Sat"
97 };
98 
99 static int _days_in_month[2][12] =
100 {
101    {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
102    {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
103 };
104 
105 static Elm_Calendar_Mark *
_mark_new(Evas_Object * obj,const char * mark_type,struct tm * mark_time,Elm_Calendar_Mark_Repeat_Type repeat)106 _mark_new(Evas_Object *obj,
107           const char *mark_type,
108           struct tm *mark_time,
109           Elm_Calendar_Mark_Repeat_Type repeat)
110 {
111    Elm_Calendar_Mark *mark;
112 
113    mark = calloc(1, sizeof(Elm_Calendar_Mark));
114    if (!mark) return NULL;
115    mark->obj = obj;
116    mark->mark_type = eina_stringshare_add(mark_type);
117    mark->mark_time = *mark_time;
118    mark->repeat = repeat;
119 
120    return mark;
121 }
122 
123 static inline void
_mark_free(Elm_Calendar_Mark * mark)124 _mark_free(Elm_Calendar_Mark *mark)
125 {
126    eina_stringshare_del(mark->mark_type);
127    free(mark);
128 }
129 
130 static inline int
_maxdays_get(struct tm * selected_time,int month_offset)131 _maxdays_get(struct tm *selected_time, int month_offset)
132 {
133    int month, year;
134 
135    month = (selected_time->tm_mon + month_offset) % 12;
136    year = selected_time->tm_year + 1900;
137 
138    if (month < 0) month += 12;
139 
140    return _days_in_month
141           [((!(year % 4)) && ((!(year % 400)) || (year % 100)))][month];
142 }
143 
144 static inline void
_unselect(Evas_Object * obj,int selected)145 _unselect(Evas_Object *obj,
146           int selected)
147 {
148    char emission[32];
149 
150    snprintf(emission, sizeof(emission), "cit_%i,unselected", selected);
151    elm_layout_signal_emit(obj, emission, "elm");
152 }
153 
154 static inline void
_select(Evas_Object * obj,int selected)155 _select(Evas_Object *obj,
156         int selected)
157 {
158    char emission[32];
159 
160    ELM_CALENDAR_DATA_GET(obj, sd);
161 
162    sd->focused_it = sd->selected_it = selected;
163    snprintf(emission, sizeof(emission), "cit_%i,selected", selected);
164    elm_layout_signal_emit(obj, emission, "elm");
165 }
166 
167 static inline void
_not_today(Elm_Calendar_Data * sd)168 _not_today(Elm_Calendar_Data *sd)
169 {
170    char emission[32];
171 
172    snprintf(emission, sizeof(emission), "cit_%i,not_today", sd->today_it);
173    elm_layout_signal_emit(sd->obj, emission, "elm");
174    sd->today_it = -1;
175 }
176 
177 static inline void
_today(Elm_Calendar_Data * sd,int it)178 _today(Elm_Calendar_Data *sd,
179        int it)
180 {
181    char emission[32];
182 
183    snprintf(emission, sizeof(emission), "cit_%i,today", it);
184    elm_layout_signal_emit(sd->obj, emission, "elm");
185    sd->today_it = it;
186 }
187 
188 static inline void
_enable(Elm_Calendar_Data * sd,int it)189 _enable(Elm_Calendar_Data *sd,
190         int it)
191 {
192    char emission[32];
193 
194    snprintf(emission, sizeof(emission), "cit_%i,enable", it);
195    elm_layout_signal_emit(sd->obj, emission, "elm");
196 }
197 
198 static inline void
_disable(Elm_Calendar_Data * sd,int it)199 _disable(Elm_Calendar_Data *sd,
200          int it)
201 {
202    char emission[32];
203 
204    snprintf(emission, sizeof(emission), "cit_%i,disable", it);
205    elm_layout_signal_emit(sd->obj, emission, "elm");
206 }
207 
208 static char *
_format_month_year(struct tm * selected_time)209 _format_month_year(struct tm *selected_time)
210 {
211    return eina_strftime(E_("%B %Y"), selected_time);
212 }
213 
214 static char *
_format_month(struct tm * selected_time)215 _format_month(struct tm *selected_time)
216 {
217    return eina_strftime(E_("%B"), selected_time);
218 }
219 
220 static char *
_format_year(struct tm * selected_time)221 _format_year(struct tm *selected_time)
222 {
223    return eina_strftime(E_("%Y"), selected_time);
224 }
225 
226 static inline void
_cit_mark(Evas_Object * cal,int cit,const char * mtype)227 _cit_mark(Evas_Object *cal,
228           int cit,
229           const char *mtype)
230 {
231    ELM_CALENDAR_DATA_GET(cal, sd);
232 
233    int day = cit - sd->first_day_it + 1;
234    int mon = sd->shown_time.tm_mon;
235    int yr = sd->shown_time.tm_year;
236 
237    if (strcmp(mtype, "clear")
238        && (((yr == sd->date_min.tm_year) && (mon == sd->date_min.tm_mon) && (day < sd->date_min.tm_mday))
239            || ((yr == sd->date_max.tm_year) && (mon == sd->date_max.tm_mon) && (day > sd->date_max.tm_mday))))
240      return;
241 
242    char sign[64];
243 
244    snprintf(sign, sizeof(sign), "cit_%i,%s", cit, mtype);
245    elm_layout_signal_emit(cal, sign, "elm");
246 }
247 
248 static inline int
_weekday_get(int first_week_day,int day)249 _weekday_get(int first_week_day,
250              int day)
251 {
252    return (day + first_week_day - 1) % ELM_DAY_LAST;
253 }
254 
255 // EINA_DEPRECATED
256 static void
_text_day_color_update(Elm_Calendar_Data * sd,int pos)257 _text_day_color_update(Elm_Calendar_Data *sd,
258                        int pos)
259 {
260    char emission[32];
261 
262    switch (sd->day_color[pos])
263      {
264       case DAY_WEEKDAY:
265         snprintf(emission, sizeof(emission), "cit_%i,weekday", pos);
266         break;
267 
268       case DAY_SATURDAY:
269         snprintf(emission, sizeof(emission), "cit_%i,saturday", pos);
270         break;
271 
272       case DAY_SUNDAY:
273         snprintf(emission, sizeof(emission), "cit_%i,sunday", pos);
274         break;
275 
276       default:
277         return;
278      }
279 
280    elm_layout_signal_emit(sd->obj, emission, "elm");
281 }
282 
283 static void
_set_month_year(Elm_Calendar_Data * sd)284 _set_month_year(Elm_Calendar_Data *sd)
285 {
286    char *buf;
287 
288    sd->filling = EINA_TRUE;
289    if (sd->double_spinners) /* theme has spinner for year */
290      {
291         buf = _format_year(&sd->shown_time);
292         if (buf)
293           {
294              elm_layout_text_set(sd->obj, "year_text", buf);
295              free(buf);
296           }
297         else elm_layout_text_set(sd->obj, "year_text", "");
298 
299         buf = _format_month(&sd->shown_time);
300      }
301    else
302       buf = sd->format_func(&sd->shown_time);
303 
304    if (buf)
305      {
306         elm_layout_text_set(sd->obj, "month_text", buf);
307         free(buf);
308      }
309    else elm_layout_text_set(sd->obj, "month_text", "");
310    sd->filling = EINA_FALSE;
311 }
312 
313 static char *
_access_info_cb(void * data EINA_UNUSED,Evas_Object * obj)314 _access_info_cb(void *data EINA_UNUSED, Evas_Object *obj)
315 {
316    char *ret;
317    Eina_Strbuf *buf;
318    buf = eina_strbuf_new();
319 
320    eina_strbuf_append_printf(buf, "day %s", elm_widget_access_info_get(obj));
321 
322    ret = eina_strbuf_string_steal(buf);
323    eina_strbuf_free(buf);
324    return ret;
325 }
326 
327 static void
_access_calendar_item_register(Evas_Object * obj)328 _access_calendar_item_register(Evas_Object *obj)
329 {
330    unsigned int maxdays, i;
331    char day_s[13], pname[18];
332    unsigned day = 0;
333    Evas_Object *ao;
334 
335    ELM_CALENDAR_DATA_GET(obj, sd);
336 
337    maxdays = _maxdays_get(&sd->shown_time, 0);
338    for (i = 0; i < 42; i++)
339      {
340         if ((!day) && (i == sd->first_day_it)) day = 1;
341         if ((day) && (day <= maxdays))
342           {
343              _part_name_snprintf(pname, sizeof(pname),
344                 elm_layout_edje_get(obj), ELM_CALENDAR_CIT_ACCESS_PART_STR, i);
345 
346              ao = _elm_access_edje_object_part_object_register
347                         (obj, elm_layout_edje_get(obj), pname);
348              _elm_access_text_set(_elm_access_info_get(ao),
349                          ELM_ACCESS_TYPE, E_("calendar item"));
350              _elm_access_callback_set(_elm_access_info_get(ao),
351                            ELM_ACCESS_INFO, _access_info_cb, NULL);
352 
353              snprintf(day_s, sizeof(day_s), "%i", (int) (day++));
354              elm_widget_access_info_set(ao, (const char*)day_s);
355           }
356         else
357           {
358              _part_name_snprintf(pname, sizeof(pname),
359                 elm_layout_edje_get(obj), ELM_CALENDAR_CIT_ACCESS_PART_STR, i);
360              _elm_access_edje_object_part_object_unregister
361                      (obj, elm_layout_edje_get(obj), pname);
362           }
363      }
364 }
365 
366 static void
_access_calendar_spinner_register(Evas_Object * obj)367 _access_calendar_spinner_register(Evas_Object *obj)
368 {
369    Evas_Object *po, *o;
370    Elm_Access_Info *ai;
371    ELM_CALENDAR_DATA_GET(obj, sd);
372 
373    if (!sd->dec_btn_month)
374      sd->dec_btn_month = _elm_access_edje_object_part_object_register
375         (obj, elm_layout_edje_get(obj), "left_bt");
376    ai = _elm_access_info_get(sd->dec_btn_month);
377    _elm_access_text_set(ai, ELM_ACCESS_TYPE, E_("calendar decrement month button"));
378 
379    if (!sd->dec_btn_year)
380      sd->dec_btn_year = _elm_access_edje_object_part_object_register
381         (obj, elm_layout_edje_get(obj), "left_bt_year");
382    ai = _elm_access_info_get(sd->dec_btn_year);
383    _elm_access_text_set(ai, ELM_ACCESS_TYPE, E_("calendar decrement year button"));
384 
385    if (!sd->inc_btn_month)
386      sd->inc_btn_month = _elm_access_edje_object_part_object_register
387         (obj, elm_layout_edje_get(obj), "right_bt");
388    ai = _elm_access_info_get(sd->inc_btn_month);
389    _elm_access_text_set(ai, ELM_ACCESS_TYPE, E_("calendar increment month button"));
390 
391    if (!sd->inc_btn_year)
392      sd->inc_btn_year = _elm_access_edje_object_part_object_register
393         (obj, elm_layout_edje_get(obj), "right_bt_year");
394    ai = _elm_access_info_get(sd->inc_btn_year);
395    _elm_access_text_set(ai, ELM_ACCESS_TYPE, E_("calendar increment year button"));
396 
397    sd->month_access = _elm_access_edje_object_part_object_register
398                           (obj, elm_layout_edje_get(obj), "text_month");
399    ai = _elm_access_info_get(sd->month_access);
400    _elm_access_text_set(ai, ELM_ACCESS_TYPE, E_("calendar month"));
401 
402    sd->year_access = _elm_access_edje_object_part_object_register
403                           (obj, elm_layout_edje_get(obj), "year_text");
404    ai = _elm_access_info_get(sd->year_access);
405    _elm_access_text_set(ai, ELM_ACCESS_TYPE, E_("calendar year"));
406 
407    o = elm_layout_edje_get(obj);
408    edje_object_freeze(o);
409    po = (Evas_Object *)edje_object_part_object_get(o, "month_text");
410    evas_object_pass_events_set(po, EINA_FALSE);
411 
412    po = (Evas_Object *)edje_object_part_object_get(o, "year_text");
413    evas_object_pass_events_set(po, EINA_FALSE);
414    edje_object_thaw(o);
415 }
416 
417 static void
_access_calendar_register(Evas_Object * obj)418 _access_calendar_register(Evas_Object *obj)
419 {
420    _access_calendar_spinner_register(obj);
421    _access_calendar_item_register(obj);
422 }
423 
424 static void
_flush_calendar_composite_elements(Evas_Object * obj,Elm_Calendar_Data * sd)425 _flush_calendar_composite_elements(Evas_Object *obj, Elm_Calendar_Data *sd)
426 {
427    Eina_List *items = NULL;
428    int max_day = _maxdays_get(&sd->shown_time, 0);
429 
430 #define EXTEND(v) \
431     if (v) items = eina_list_append(items, v); \
432 
433     EXTEND(sd->month_access);
434     EXTEND(sd->dec_btn_month);
435     EXTEND(sd->inc_btn_month);
436     EXTEND(sd->year_access);
437     EXTEND(sd->dec_btn_year);
438     EXTEND(sd->inc_btn_year);
439 
440 #undef EXTEND
441 
442    for (int i = sd->first_day_it; i <= max_day; ++i)
443      items = eina_list_append(items, sd->items[i]);
444 
445    efl_ui_focus_composition_elements_set(obj, items);
446 }
447 
448 static void
_populate(Evas_Object * obj)449 _populate(Evas_Object *obj)
450 {
451    int maxdays, adjusted_wday, prev_month_maxdays, day, mon, yr, i;
452    Elm_Calendar_Mark *mark;
453    char part[16], day_s[16];
454    struct tm first_day;
455    Eina_List *l;
456    Eina_Bool last_row = EINA_TRUE;
457 
458    ELM_CALENDAR_DATA_GET(obj, sd);
459 
460    elm_layout_freeze(obj);
461 
462    sd->filling = EINA_FALSE;
463    if (sd->today_it > 0) _not_today(sd);
464 
465    maxdays = _maxdays_get(&sd->shown_time, 0);
466    prev_month_maxdays = _maxdays_get(&sd->shown_time, -1);
467    mon = sd->shown_time.tm_mon;
468    yr = sd->shown_time.tm_year;
469 
470    _set_month_year(sd);
471    sd->filling = EINA_TRUE;
472 
473    /* Set days */
474    day = 0;
475    first_day = sd->shown_time;
476    first_day.tm_mday = 1;
477    mktime(&first_day);
478 
479    // Layout of the calendar is changed for removing the unfilled last row.
480    if (first_day.tm_wday < (int)sd->first_week_day)
481      sd->first_day_it = first_day.tm_wday + ELM_DAY_LAST - sd->first_week_day;
482    else
483      sd->first_day_it = first_day.tm_wday - sd->first_week_day;
484 
485    if ((35 - sd->first_day_it) > (maxdays - 1)) last_row = EINA_FALSE;
486 
487    if (!last_row)
488      {
489         char emission[32];
490 
491         for (i = 0; i < 5; i++)
492           {
493              snprintf(emission, sizeof(emission), "cseph_%i,row_hide", i);
494              elm_layout_signal_emit(obj, emission, "elm");
495           }
496         snprintf(emission, sizeof(emission), "cseph_%i,row_invisible", 5);
497         elm_layout_signal_emit(obj, emission, "elm");
498         for (i = 0; i < 35; i++)
499           {
500              snprintf(emission, sizeof(emission), "cit_%i,cell_expanded", i);
501              elm_layout_signal_emit(obj, emission, "elm");
502           }
503         for (i = 35; i < 42; i++)
504           {
505              snprintf(emission, sizeof(emission), "cit_%i,cell_invisible", i);
506              elm_layout_signal_emit(obj, emission, "elm");
507           }
508      }
509    else
510      {
511         char emission[32];
512 
513         for (i = 0; i < 6; i++)
514           {
515              snprintf(emission, sizeof(emission), "cseph_%i,row_show", i);
516              elm_layout_signal_emit(obj, emission, "elm");
517           }
518         for (i = 0; i < 42; i++)
519           {
520              snprintf(emission, sizeof(emission), "cit_%i,cell_default", i);
521              elm_layout_signal_emit(obj, emission, "elm");
522           }
523      }
524 
525    for (i = 0; i < 42; i++)
526      {
527         _text_day_color_update(sd, i); // EINA_DEPRECATED
528         if ((!day) && (i == sd->first_day_it)) day = 1;
529 
530         if ((day == sd->current_time.tm_mday)
531             && (mon == sd->current_time.tm_mon)
532             && (yr == sd->current_time.tm_year))
533           _today(sd, i);
534 
535         if (day == sd->selected_time.tm_mday)
536           {
537              if ((sd->selected_it > -1) && (sd->selected_it != i))
538                _unselect(obj, sd->selected_it);
539 
540              if (sd->select_mode == ELM_CALENDAR_SELECT_MODE_ONDEMAND)
541                {
542                   if ((mon == sd->selected_time.tm_mon)
543                       && (yr == sd->selected_time.tm_year)
544                       && (sd->selected))
545                     {
546                        _select(obj, i);
547                     }
548                }
549              else if (sd->select_mode != ELM_CALENDAR_SELECT_MODE_NONE)
550                {
551                   _select(obj, i);
552                }
553           }
554 
555         if ((day) && (day <= maxdays))
556           {
557              if (((yr == sd->date_min.tm_year) && (mon == sd->date_min.tm_mon) && (day < sd->date_min.tm_mday))
558                  || ((yr == sd->date_max.tm_year) && (mon == sd->date_max.tm_mon) && (day > sd->date_max.tm_mday)))
559                _disable(sd, i);
560              else
561                _enable(sd, i);
562 
563              snprintf(day_s, sizeof(day_s), "%i", day++);
564           }
565         else
566           {
567              _disable(sd, i);
568 
569              if (day <= maxdays)
570                snprintf(day_s, sizeof(day_s), "%i", prev_month_maxdays - sd->first_day_it + i + 1);
571              else
572                snprintf(day_s, sizeof(day_s), "%i", i - sd->first_day_it - maxdays + 1);
573           }
574 
575         _part_name_snprintf(part, sizeof(part), obj, ELM_CALENDAR_CIT_TEXT_PART_STR, i);
576         elm_layout_text_set(obj, part, day_s);
577 
578         /* Clear previous marks */
579         _cit_mark(obj, i, "clear");
580      }
581 
582    // ACCESS
583    if ((_elm_config->access_mode != ELM_ACCESS_MODE_OFF))
584      _access_calendar_item_register(obj);
585 
586    /* Set marks */
587    EINA_LIST_FOREACH(sd->marks, l, mark)
588      {
589         struct tm *mtime = &mark->mark_time;
590         int month = sd->shown_time.tm_mon;
591         int year = sd->shown_time.tm_year;
592         int mday_it = mtime->tm_mday + sd->first_day_it - 1;
593 
594         switch (mark->repeat)
595           {
596            case ELM_CALENDAR_UNIQUE:
597              if ((mtime->tm_mon == month) && (mtime->tm_year == year))
598                _cit_mark(obj, mday_it, mark->mark_type);
599              break;
600 
601            case ELM_CALENDAR_DAILY:
602              if (((mtime->tm_year == year) && (mtime->tm_mon < month)) ||
603                  (mtime->tm_year < year))
604                day = 1;
605              else if ((mtime->tm_year == year) && (mtime->tm_mon == month))
606                day = mtime->tm_mday;
607              else
608                break;
609              for (; day <= maxdays; day++)
610                _cit_mark(obj, day + sd->first_day_it - 1,
611                          mark->mark_type);
612              break;
613 
614            case ELM_CALENDAR_WEEKLY:
615              if (((mtime->tm_year == year) && (mtime->tm_mon < month)) ||
616                  (mtime->tm_year < year))
617                day = 1;
618              else if ((mtime->tm_year == year) && (mtime->tm_mon == month))
619                day = mtime->tm_mday;
620              else
621                break;
622 
623              adjusted_wday = (mtime->tm_wday - sd->first_week_day);
624              if (adjusted_wday < 0)
625                adjusted_wday = ELM_DAY_LAST + adjusted_wday;
626 
627              for (; day <= maxdays; day++)
628                if (adjusted_wday == _weekday_get(sd->first_day_it, day))
629                  _cit_mark(obj, day + sd->first_day_it - 1,
630                            mark->mark_type);
631              break;
632 
633            case ELM_CALENDAR_MONTHLY:
634              if (((mtime->tm_year < year) ||
635                   ((mtime->tm_year == year) && (mtime->tm_mon <= month))) &&
636                  (mtime->tm_mday <= maxdays))
637                _cit_mark(obj, mday_it, mark->mark_type);
638              break;
639 
640            case ELM_CALENDAR_ANNUALLY:
641              if ((mtime->tm_year <= year) && (mtime->tm_mon == month) &&
642                  (mtime->tm_mday <= maxdays))
643                _cit_mark(obj, mday_it, mark->mark_type);
644              break;
645 
646            case ELM_CALENDAR_LAST_DAY_OF_MONTH:
647              if (((mtime->tm_year < year) ||
648                   ((mtime->tm_year == year) && (mtime->tm_mon <= month))))
649                _cit_mark(obj, maxdays + sd->first_day_it - 1, mark->mark_type);
650              break;
651 
652            case ELM_CALENDAR_REVERSE_DAILY:
653              if (((mtime->tm_year == year) && (mtime->tm_mon > month)) ||
654                  (mtime->tm_year > year))
655                day = maxdays;
656              else if ((mtime->tm_year == year) && (mtime->tm_mon == month))
657                day = mtime->tm_mday - 1;
658              else
659                break;
660              for (; day >= 1; day--)
661                _cit_mark(obj, day + sd->first_day_it - 1,
662                          mark->mark_type);
663              break;
664 
665           }
666      }
667    sd->filling = EINA_FALSE;
668 
669    elm_layout_thaw(obj);
670    edje_object_message_signal_process(elm_layout_edje_get(obj));
671 
672    _flush_calendar_composite_elements(obj, sd);
673 }
674 
675 static void
_set_headers(Evas_Object * obj)676 _set_headers(Evas_Object *obj)
677 {
678    static char part[64];
679    static char emission[64];
680    int i;
681    struct tm *t;
682    time_t temp = 259200; // the first sunday since epoch
683    ELM_CALENDAR_DATA_GET(obj, sd);
684 
685    elm_layout_freeze(obj);
686 
687    sd->filling = EINA_TRUE;
688 
689    t = gmtime(&temp);
690    if (t && !sd->weekdays_set)
691      {
692         t->tm_wday = 0;
693         for (i = 0; i < ELM_DAY_LAST; i++)
694           {
695              char *buf;
696              buf = eina_strftime("%a", t);
697              if (buf)
698                {
699                   sd->weekdays[i] = eina_stringshare_add(buf);
700                   free(buf);
701                }
702              else
703                {
704                   /* If we failed getting day, get a default value */
705                   sd->weekdays[i] = _days_abbrev[i];
706                   WRN("Failed getting weekday name for '%s' from locale.",
707                       _days_abbrev[i]);
708                }
709              t->tm_wday++;
710           }
711      }
712 
713    for (i = 0; i < ELM_DAY_LAST; i++)
714      {
715         _part_name_snprintf(part, sizeof(part), obj, ELM_CALENDAR_CH_TEXT_PART_STR, i);
716         int weekday_index = (i + sd->first_week_day) % ELM_DAY_LAST;
717         elm_layout_text_set(obj, part, sd->weekdays[weekday_index]);
718         // Signaling the theme about which days are weekdays and which weekend
719         if (weekday_index == ELM_DAY_SATURDAY || weekday_index == ELM_DAY_SUNDAY)
720            _part_name_snprintf(emission, sizeof(emission), obj, ELM_CALENDAR_CH_WEEKEND, i);
721         else
722            _part_name_snprintf(emission, sizeof(emission), obj, ELM_CALENDAR_CH_WEEKDAY, i);
723 
724         elm_layout_signal_emit(obj, emission, "elm");
725      }
726 
727    sd->filling = EINA_FALSE;
728 
729    elm_layout_thaw(obj);
730 }
731 
732 static void
_spinner_buttons_add(Evas_Object * obj,Elm_Calendar_Data * sd)733 _spinner_buttons_add(Evas_Object *obj, Elm_Calendar_Data *sd)
734 {
735    char left_buf[255] = { 0 };
736    char right_buf[255] = { 0 };
737 
738    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
739 
740    snprintf(left_buf, sizeof(left_buf), "calendar/decrease/%s", elm_object_style_get(obj));
741    snprintf(right_buf, sizeof(right_buf), "calendar/increase/%s", elm_object_style_get(obj));
742 
743    if (edje_object_part_exists(wd->resize_obj, ELM_CALENDAR_BUTTON_LEFT))
744      {
745         if (sd->dec_btn_month && efl_isa(sd->dec_btn_month, ELM_ACCESS_CLASS))
746           {
747              _elm_access_edje_object_part_object_unregister
748                (obj, elm_layout_edje_get(obj), "left_bt");
749              sd->dec_btn_month = NULL;
750           }
751 
752         if (!sd->dec_btn_month)
753           {
754              sd->dec_btn_month = elm_button_add(obj);
755              efl_event_callback_array_add(sd->dec_btn_month, _inc_dec_button_cb(), obj);
756           }
757 
758         elm_object_style_set(sd->dec_btn_month, left_buf);
759         elm_layout_content_set(obj, ELM_CALENDAR_BUTTON_LEFT, sd->dec_btn_month);
760      }
761    else if (sd->dec_btn_month && !efl_isa(sd->dec_btn_month, ELM_ACCESS_CLASS))
762      {
763         evas_object_del(sd->dec_btn_month);
764         sd->dec_btn_month = NULL;
765      }
766 
767    if (edje_object_part_exists(wd->resize_obj, ELM_CALENDAR_BUTTON_RIGHT))
768      {
769         if (sd->inc_btn_month && efl_isa(sd->inc_btn_month, ELM_ACCESS_CLASS))
770           {
771              _elm_access_edje_object_part_object_unregister
772                (obj, elm_layout_edje_get(obj), "right_bt");
773              sd->inc_btn_month = NULL;
774           }
775 
776         if (!sd->inc_btn_month)
777           {
778              sd->inc_btn_month = elm_button_add(obj);
779              efl_event_callback_array_add(sd->inc_btn_month, _inc_dec_button_cb(), obj);
780           }
781 
782         elm_object_style_set(sd->inc_btn_month, right_buf);
783         elm_layout_content_set(obj, ELM_CALENDAR_BUTTON_RIGHT, sd->inc_btn_month);
784      }
785    else if (sd->inc_btn_month && !efl_isa(sd->inc_btn_month, ELM_ACCESS_CLASS))
786      {
787         evas_object_del(sd->inc_btn_month);
788         sd->inc_btn_month = NULL;
789      }
790 
791    if (edje_object_part_exists(wd->resize_obj, ELM_CALENDAR_BUTTON_YEAR_LEFT))
792      {
793         if (sd->dec_btn_year && efl_isa(sd->dec_btn_year, ELM_ACCESS_CLASS))
794           {
795              _elm_access_edje_object_part_object_unregister
796                (obj, elm_layout_edje_get(obj), "left_bt_year");
797              sd->dec_btn_year = NULL;
798           }
799 
800         if (!sd->dec_btn_year)
801           {
802              sd->dec_btn_year = elm_button_add(obj);
803              efl_event_callback_array_add(sd->dec_btn_year, _inc_dec_button_cb(), obj);
804           }
805 
806         elm_object_style_set(sd->dec_btn_year, left_buf);
807         elm_layout_content_set(obj, ELM_CALENDAR_BUTTON_YEAR_LEFT, sd->dec_btn_year);
808      }
809    else if (sd->dec_btn_year && !efl_isa(sd->dec_btn_year, ELM_ACCESS_CLASS))
810      {
811         evas_object_del(sd->dec_btn_year);
812         sd->dec_btn_year = NULL;
813      }
814 
815    if (edje_object_part_exists(wd->resize_obj, ELM_CALENDAR_BUTTON_YEAR_RIGHT))
816      {
817         if (sd->inc_btn_year && efl_isa(sd->inc_btn_year, ELM_ACCESS_CLASS))
818           {
819              _elm_access_edje_object_part_object_unregister
820                (obj, elm_layout_edje_get(obj), "right_bt_year");
821              sd->inc_btn_year = NULL;
822           }
823 
824         if (!sd->inc_btn_year)
825           {
826              sd->inc_btn_year = elm_button_add(obj);
827              efl_event_callback_array_add(sd->inc_btn_year, _inc_dec_button_cb(), obj);
828           }
829 
830         elm_object_style_set(sd->inc_btn_year, right_buf);
831         elm_layout_content_set(obj, ELM_CALENDAR_BUTTON_YEAR_RIGHT, sd->inc_btn_year);
832      }
833    else if (sd->inc_btn_year && !efl_isa(sd->inc_btn_year, ELM_ACCESS_CLASS))
834      {
835         evas_object_del(sd->inc_btn_year);
836         sd->inc_btn_year = NULL;
837      }
838 }
839 
840 EOLIAN static Eina_Error
_elm_calendar_efl_ui_widget_theme_apply(Eo * obj,Elm_Calendar_Data * sd)841 _elm_calendar_efl_ui_widget_theme_apply(Eo *obj, Elm_Calendar_Data *sd)
842 {
843    Eina_Error int_ret = EFL_UI_THEME_APPLY_ERROR_GENERIC;
844 
845    int_ret = efl_ui_widget_theme_apply(efl_super(obj, MY_CLASS));
846    if (int_ret == EFL_UI_THEME_APPLY_ERROR_GENERIC) return int_ret;
847 
848    _spinner_buttons_add(obj, sd);
849 
850    evas_object_smart_changed(obj);
851    return int_ret;
852 }
853 
854 /* Set correct tm_wday and tm_yday after other fields changes*/
855 static inline void
_fix_selected_time(Elm_Calendar_Data * sd)856 _fix_selected_time(Elm_Calendar_Data *sd)
857 {
858    if (sd->selected_time.tm_mon != sd->shown_time.tm_mon)
859      sd->selected_time.tm_mon = sd->shown_time.tm_mon;
860    if (sd->selected_time.tm_year != sd->shown_time.tm_year)
861      sd->selected_time.tm_year = sd->shown_time.tm_year;
862 
863    if ((sd->selected_time.tm_year == sd->date_min.tm_year)
864        && (sd->selected_time.tm_mon == sd->date_min.tm_mon)
865        && (sd->selected_time.tm_mday < sd->date_min.tm_mday))
866      {
867         sd->selected_time.tm_mday = sd->date_min.tm_mday;
868      }
869    else if ((sd->selected_time.tm_year == sd->date_max.tm_year)
870             && (sd->selected_time.tm_mon == sd->date_max.tm_mon)
871             && (sd->selected_time.tm_mday > sd->date_max.tm_mday))
872      {
873         sd->selected_time.tm_mday = sd->date_max.tm_mday;
874      }
875 
876    mktime(&sd->selected_time);
877 }
878 
879 static Eina_Bool
_update_data(Evas_Object * obj,Eina_Bool month,int delta)880 _update_data(Evas_Object *obj, Eina_Bool month,
881               int delta)
882 {
883    struct tm time_check;
884    int maxdays, years;
885 
886    ELM_CALENDAR_DATA_GET(obj, sd);
887 
888    /* check if it's a valid time. for 32 bits, year greater than 2037 is not */
889    time_check = sd->shown_time;
890    if (month)
891        time_check.tm_mon += delta;
892    else
893        time_check.tm_year += delta;
894    if (mktime(&time_check) == -1)
895      return EINA_FALSE;
896 
897    if (month)
898      {
899         sd->shown_time.tm_mon += delta;
900         if (delta < 0)
901           {
902              if (sd->shown_time.tm_year == sd->date_min.tm_year)
903                {
904                   if (sd->shown_time.tm_mon < sd->date_min.tm_mon)
905                     {
906                        sd->shown_time.tm_mon = sd->date_min.tm_mon;
907                        return EINA_FALSE;
908                     }
909                }
910              else if (sd->shown_time.tm_mon < 0)
911                {
912                   sd->shown_time.tm_mon = 11;
913                   sd->shown_time.tm_year--;
914                }
915           }
916         else
917           {
918              if (sd->shown_time.tm_year == sd->date_max.tm_year)
919                {
920                   if (sd->shown_time.tm_mon > sd->date_max.tm_mon)
921                     {
922                        sd->shown_time.tm_mon = sd->date_max.tm_mon;
923                        return EINA_FALSE;
924                     }
925                }
926              else if (sd->shown_time.tm_mon > 11)
927                {
928                   sd->shown_time.tm_mon = 0;
929                   sd->shown_time.tm_year++;
930                }
931           }
932      }
933    else
934      {
935         years = sd->shown_time.tm_year + delta;
936         if (((years > sd->date_max.tm_year) && (sd->date_max.tm_year != -1)) ||
937             years < sd->date_min.tm_year)
938           return EINA_FALSE;
939 
940         sd->shown_time.tm_year = years;
941         if ((years == sd->date_min.tm_year) && (sd->shown_time.tm_mon < sd->date_min.tm_mon))
942           {
943              sd->shown_time.tm_mon = sd->date_min.tm_mon;
944           }
945         else if ((years == sd->date_max.tm_year) && (sd->shown_time.tm_mon > sd->date_max.tm_mon))
946           {
947              sd->shown_time.tm_mon = sd->date_max.tm_mon;
948           }
949      }
950 
951    if ((sd->select_mode != ELM_CALENDAR_SELECT_MODE_ONDEMAND)
952        && (sd->select_mode != ELM_CALENDAR_SELECT_MODE_NONE))
953      {
954         maxdays = _maxdays_get(&sd->shown_time, 0);
955         if (sd->selected_time.tm_mday > maxdays)
956           sd->selected_time.tm_mday = maxdays;
957 
958         _fix_selected_time(sd);
959         efl_event_callback_legacy_call(obj, ELM_CALENDAR_EVENT_CHANGED, NULL);
960      }
961    efl_event_callback_legacy_call(obj, ELM_CALENDAR_EVENT_DISPLAY_CHANGED, NULL);
962 
963    return EINA_TRUE;
964 }
965 
966 static Eina_Bool
_spin_value(void * data)967 _spin_value(void *data)
968 {
969    ELM_CALENDAR_DATA_GET(data, sd);
970 
971    if (_update_data(data, sd->month_btn_clicked, sd->spin_speed))
972      evas_object_smart_changed(data);
973 
974    if (sd->spin_timer)
975      {
976         sd->interval = sd->interval / 1.05;
977         ecore_timer_interval_set(sd->spin_timer, sd->interval);
978      }
979 
980    return ECORE_CALLBACK_RENEW;
981 }
982 
983 /* Legacy callbacks for signals from edje */
984 static void
_button_month_inc_start(void * data,Evas_Object * obj EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)985 _button_month_inc_start(void *data,
986                   Evas_Object *obj EINA_UNUSED,
987                   const char *emission EINA_UNUSED,
988                   const char *source EINA_UNUSED)
989 {
990    ELM_CALENDAR_DATA_GET(data, sd);
991 
992    sd->interval = sd->first_interval;
993    sd->spin_speed = 1;
994    sd->month_btn_clicked = EINA_TRUE;
995    ecore_timer_del(sd->spin_timer);
996    sd->spin_timer = ecore_timer_add(sd->interval, _spin_value, data);
997 
998    elm_widget_scroll_freeze_push(data);
999 
1000    _spin_value(data);
1001 }
1002 
1003 /* Legacy callbacks for signals from edje */
1004 static void
_button_month_dec_start(void * data,Evas_Object * obj EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)1005 _button_month_dec_start(void *data,
1006                   Evas_Object *obj EINA_UNUSED,
1007                   const char *emission EINA_UNUSED,
1008                   const char *source EINA_UNUSED)
1009 {
1010    ELM_CALENDAR_DATA_GET(data, sd);
1011 
1012    sd->interval = sd->first_interval;
1013    sd->spin_speed = -1;
1014    sd->month_btn_clicked = EINA_TRUE;
1015    ecore_timer_del(sd->spin_timer);
1016    sd->spin_timer = ecore_timer_add(sd->interval, _spin_value, data);
1017 
1018    elm_widget_scroll_freeze_push(data);
1019 
1020    _spin_value(data);
1021 }
1022 
1023 /* Legacy callbacks for signals from edje */
1024 static void
_button_month_stop(void * data,Evas_Object * obj EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)1025 _button_month_stop(void *data,
1026                    Evas_Object *obj EINA_UNUSED,
1027                    const char *emission EINA_UNUSED,
1028                    const char *source EINA_UNUSED)
1029 {
1030    ELM_CALENDAR_DATA_GET(data, sd);
1031 
1032    sd->interval = sd->first_interval;
1033    ELM_SAFE_FREE(sd->spin_timer, ecore_timer_del);
1034 
1035    elm_widget_scroll_freeze_pop(obj);
1036 }
1037 
1038 /* Legacy callbacks for signals from edje */
1039 static void
_button_year_inc_start(void * data,Evas_Object * obj EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)1040 _button_year_inc_start(void *data,
1041                        Evas_Object *obj EINA_UNUSED,
1042                        const char *emission EINA_UNUSED,
1043                        const char *source EINA_UNUSED)
1044 {
1045    ELM_CALENDAR_DATA_GET(data, sd);
1046 
1047    sd->interval = sd->first_interval;
1048    sd->spin_speed = 1;
1049    sd->month_btn_clicked = EINA_FALSE;
1050    ecore_timer_del(sd->spin_timer);
1051    sd->spin_timer = ecore_timer_add(sd->interval, _spin_value, data);
1052 
1053    elm_widget_scroll_freeze_push(data);
1054 
1055    _spin_value(data);
1056 }
1057 
1058 /* Legacy callbacks for signals from edje */
1059 static void
_button_year_dec_start(void * data,Evas_Object * obj EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)1060 _button_year_dec_start(void *data,
1061                   Evas_Object *obj EINA_UNUSED,
1062                   const char *emission EINA_UNUSED,
1063                   const char *source EINA_UNUSED)
1064 {
1065    ELM_CALENDAR_DATA_GET(data, sd);
1066 
1067    sd->interval = sd->first_interval;
1068    sd->spin_speed = -1;
1069    sd->month_btn_clicked = EINA_FALSE;
1070    ecore_timer_del(sd->spin_timer);
1071    sd->spin_timer = ecore_timer_add(sd->interval, _spin_value, data);
1072 
1073    elm_widget_scroll_freeze_push(data);
1074 
1075    _spin_value(data);
1076 }
1077 
1078 /* Legacy callbacks for signals from edje */
1079 static void
_button_year_stop(void * data,Evas_Object * obj EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)1080 _button_year_stop(void *data,
1081                   Evas_Object *obj EINA_UNUSED,
1082                   const char *emission EINA_UNUSED,
1083                   const char *source EINA_UNUSED)
1084 {
1085    ELM_CALENDAR_DATA_GET(data, sd);
1086 
1087    sd->interval = sd->first_interval;
1088    ELM_SAFE_FREE(sd->spin_timer, ecore_timer_del);
1089 
1090    elm_widget_scroll_freeze_pop(obj);
1091 }
1092 
1093 static void
_inc_dec_button_clicked_cb(void * data,const Efl_Event * event EINA_UNUSED)1094 _inc_dec_button_clicked_cb(void *data, const Efl_Event *event EINA_UNUSED)
1095 {
1096    ELM_CALENDAR_DATA_GET(data, sd);
1097 
1098    sd->interval = sd->first_interval;
1099    ELM_SAFE_FREE(sd->spin_timer, ecore_timer_del);
1100 
1101    _spin_value(data);
1102 }
1103 static void
_inc_dec_button_pressed_cb(void * data,const Efl_Event * event)1104 _inc_dec_button_pressed_cb(void *data, const Efl_Event *event)
1105 {
1106    ELM_CALENDAR_DATA_GET(data, sd);
1107 
1108    sd->interval = sd->first_interval;
1109    sd->spin_speed = ((sd->inc_btn_month == event->object) ||
1110                      (sd->inc_btn_year == event->object)) ? 1 : -1;
1111 
1112    sd->month_btn_clicked = ((sd->inc_btn_month == event->object) ||
1113                             (sd->dec_btn_month == event->object)) ? EINA_TRUE : EINA_FALSE;
1114 
1115    ELM_SAFE_FREE(sd->spin_timer, ecore_timer_del);
1116    sd->spin_timer = ecore_timer_add(sd->interval, _spin_value, data);
1117 
1118    elm_widget_scroll_freeze_push(data);
1119 }
1120 
1121 static void
_inc_dec_button_unpressed_cb(void * data,const Efl_Event * event EINA_UNUSED)1122 _inc_dec_button_unpressed_cb(void *data, const Efl_Event *event EINA_UNUSED)
1123 {
1124    ELM_CALENDAR_DATA_GET(data, sd);
1125 
1126    sd->interval = sd->first_interval;
1127    ELM_SAFE_FREE(sd->spin_timer, ecore_timer_del);
1128 
1129    elm_widget_scroll_freeze_pop(data);
1130 }
1131 
1132 static int
_get_item_day(Evas_Object * obj,int selected_it)1133 _get_item_day(Evas_Object *obj,
1134               int selected_it)
1135 {
1136    int day;
1137 
1138    ELM_CALENDAR_DATA_GET(obj, sd);
1139 
1140    day = selected_it - sd->first_day_it + 1;
1141    if ((day < 0) || (day > _maxdays_get(&sd->shown_time, 0)))
1142      return 0;
1143 
1144    if ((sd->shown_time.tm_year == sd->date_min.tm_year)
1145        && (sd->shown_time.tm_mon == sd->date_min.tm_mon)
1146        && (day < sd->date_min.tm_mday))
1147      {
1148         return 0;
1149      }
1150    else if ((sd->shown_time.tm_year == sd->date_max.tm_year)
1151             && (sd->shown_time.tm_mon == sd->date_max.tm_mon)
1152             && (day > sd->date_max.tm_mday))
1153      {
1154         return 0;
1155      }
1156 
1157    return day;
1158 }
1159 
1160 static void
_update_unfocused_it(Evas_Object * obj,int unfocused_it)1161 _update_unfocused_it(Evas_Object *obj, int unfocused_it)
1162 {
1163    int day;
1164    char emission[32];
1165 
1166    ELM_CALENDAR_DATA_GET(obj, sd);
1167 
1168    day = _get_item_day(obj, unfocused_it);
1169    if (!day)
1170      return;
1171 
1172    sd->focused_it = -1;
1173 
1174    snprintf(emission, sizeof(emission), "cit_%i,unfocused", unfocused_it);
1175    elm_layout_signal_emit(obj, emission, "elm");
1176 }
1177 
1178 static Eina_Bool
_update_focused_it(Evas_Object * obj,int focused_it)1179 _update_focused_it(Evas_Object *obj, int focused_it)
1180 {
1181    int day;
1182    char emission[32];
1183 
1184    ELM_CALENDAR_DATA_GET(obj, sd);
1185 
1186    day = _get_item_day(obj, focused_it);
1187    if (!day)
1188      return EINA_FALSE;
1189 
1190    snprintf(emission, sizeof(emission), "cit_%i,unfocused", sd->focused_it);
1191    elm_layout_signal_emit(obj, emission, "elm");
1192 
1193    sd->focused_it = focused_it;
1194 
1195    snprintf(emission, sizeof(emission), "cit_%i,focused", sd->focused_it);
1196    elm_layout_signal_emit(obj, emission, "elm");
1197 
1198    return EINA_TRUE;
1199 }
1200 
1201 static void
_update_sel_it(Evas_Object * obj,int sel_it)1202 _update_sel_it(Evas_Object *obj,
1203                int sel_it)
1204 {
1205    int day;
1206 
1207    ELM_CALENDAR_DATA_GET(obj, sd);
1208 
1209    if (sd->select_mode == ELM_CALENDAR_SELECT_MODE_NONE)
1210      return;
1211 
1212    day = _get_item_day(obj, sel_it);
1213    if (!day)
1214      return;
1215 
1216    _unselect(obj, sd->selected_it);
1217    if (!sd->selected)
1218      sd->selected = EINA_TRUE;
1219    if (sd->focused_it)
1220      _update_unfocused_it(obj, sd->focused_it);
1221 
1222    sd->selected_time.tm_mday = day;
1223    _fix_selected_time(sd);
1224    _select(obj, sel_it);
1225    efl_event_callback_legacy_call(obj, ELM_CALENDAR_EVENT_CHANGED, NULL);
1226 }
1227 
1228 static void
_day_selected(void * data,Evas_Object * obj EINA_UNUSED,const char * emission EINA_UNUSED,const char * source)1229 _day_selected(void *data,
1230               Evas_Object *obj EINA_UNUSED,
1231               const char *emission EINA_UNUSED,
1232               const char *source)
1233 {
1234    int sel_it;
1235 
1236    ELM_CALENDAR_DATA_GET(data, sd);
1237 
1238    if (sd->select_mode == ELM_CALENDAR_SELECT_MODE_NONE)
1239      return;
1240 
1241    sel_it = atoi(source);
1242 
1243    _update_sel_it(data, sel_it);
1244 }
1245 
1246 static inline int
_time_to_next_day(struct tm * t)1247 _time_to_next_day(struct tm *t)
1248 {
1249    return ((((24 - t->tm_hour) * 60) - t->tm_min) * 60) - t->tm_sec;
1250 }
1251 
1252 static Eina_Bool
_update_cur_date(void * data)1253 _update_cur_date(void *data)
1254 {
1255    time_t current_time;
1256    int t, day;
1257    ELM_CALENDAR_DATA_GET(data, sd);
1258 
1259    if (sd->today_it > 0) _not_today(sd);
1260 
1261    current_time = time(NULL);
1262    localtime_r(&current_time, &sd->current_time);
1263    t = _time_to_next_day(&sd->current_time);
1264    ecore_timer_interval_set(sd->update_timer, t);
1265 
1266    if ((sd->current_time.tm_mon != sd->shown_time.tm_mon) ||
1267        (sd->current_time.tm_year != sd->shown_time.tm_year))
1268      return ECORE_CALLBACK_RENEW;
1269 
1270    day = sd->current_time.tm_mday + sd->first_day_it - 1;
1271    _today(sd, day);
1272 
1273    return ECORE_CALLBACK_RENEW;
1274 }
1275 
1276 static Eina_Bool
_key_action_activate(Evas_Object * obj,const char * params EINA_UNUSED)1277 _key_action_activate(Evas_Object *obj, const char *params EINA_UNUSED)
1278 {
1279    ELM_CALENDAR_DATA_GET(obj, sd);
1280 
1281    _update_sel_it(obj, sd->focused_it);
1282 
1283    return EINA_TRUE;
1284 }
1285 
1286 EOLIAN static Eina_Bool
_elm_calendar_efl_ui_focus_object_on_focus_update(Eo * obj,Elm_Calendar_Data * sd)1287 _elm_calendar_efl_ui_focus_object_on_focus_update(Eo *obj, Elm_Calendar_Data *sd)
1288 {
1289    Eina_Bool int_ret = EINA_FALSE;
1290 
1291    int_ret = efl_ui_focus_object_on_focus_update(efl_super(obj, MY_CLASS));
1292    if (!int_ret) return EINA_FALSE;
1293 
1294    if (efl_ui_focus_object_focus_get(obj))
1295      _update_focused_it(obj, sd->selected_it);
1296    else
1297      _update_unfocused_it(obj, sd->focused_it);
1298 
1299    return EINA_TRUE;
1300 }
1301 
1302 EOLIAN static void
_elm_calendar_efl_canvas_group_group_calculate(Eo * obj,Elm_Calendar_Data * _pd EINA_UNUSED)1303 _elm_calendar_efl_canvas_group_group_calculate(Eo *obj, Elm_Calendar_Data *_pd EINA_UNUSED)
1304 {
1305    efl_canvas_group_need_recalculate_set(obj, EINA_FALSE);
1306    _set_headers(obj);
1307    _populate(obj);
1308    efl_canvas_group_calculate(efl_super(obj, MY_CLASS));
1309 }
1310 
1311 static void
_style_changed(void * data,Evas_Object * obj EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)1312 _style_changed(void *data,
1313                Evas_Object *obj EINA_UNUSED,
1314                const char *emission EINA_UNUSED,
1315                const char *source EINA_UNUSED)
1316 {
1317    ELM_CALENDAR_DATA_GET(data, sd);
1318 
1319    if (!strcmp("double_spinners", elm_object_style_get(sd->obj)))
1320       sd->double_spinners = EINA_TRUE;
1321    else
1322       sd->double_spinners = EINA_FALSE;
1323 
1324    _set_month_year(sd);
1325 }
1326 
1327 EOLIAN static void
_elm_calendar_efl_canvas_group_group_add(Eo * obj,Elm_Calendar_Data * priv)1328 _elm_calendar_efl_canvas_group_group_add(Eo *obj, Elm_Calendar_Data *priv)
1329 {
1330    time_t current_time;
1331    int t;
1332 
1333    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
1334 
1335    efl_canvas_group_add(efl_super(obj, MY_CLASS));
1336 
1337    priv->first_interval = 0.85;
1338    priv->date_min.tm_year = 2;
1339    priv->date_min.tm_mon = 0;
1340    priv->date_min.tm_mday = 1;
1341    priv->date_max.tm_year = -1;
1342    priv->date_max.tm_mon = 11;
1343    priv->date_max.tm_mday = 31;
1344    priv->today_it = -1;
1345    priv->selected_it = -1;
1346    priv->first_day_it = -1;
1347    priv->format_func = _format_month_year;
1348    priv->selectable = (~(ELM_CALENDAR_SELECTABLE_NONE));
1349 
1350    edje_object_signal_callback_add
1351      (wd->resize_obj, "elm,action,increment,start", "*",
1352      _button_month_inc_start, obj);
1353    edje_object_signal_callback_add
1354      (wd->resize_obj, "elm,action,decrement,start", "*",
1355       _button_month_dec_start, obj);
1356    edje_object_signal_callback_add
1357      (wd->resize_obj, "elm,action,increment,startyear", "*",
1358      _button_year_inc_start, obj);
1359    edje_object_signal_callback_add
1360      (wd->resize_obj, "elm,action,decrement,startyear", "*",
1361      _button_year_dec_start, obj);
1362    edje_object_signal_callback_add
1363      (wd->resize_obj, "elm,action,stop", "*",
1364      _button_month_stop, obj);
1365    edje_object_signal_callback_add
1366      (wd->resize_obj, "elm,action,stopyear", "*",
1367      _button_year_stop, obj);
1368    edje_object_signal_callback_add
1369      (wd->resize_obj, "elm,action,selected", "*",
1370      _day_selected, obj);
1371    edje_object_signal_callback_add
1372       (wd->resize_obj, "load", "*",
1373        _style_changed, obj);
1374 
1375    current_time = time(NULL);
1376    localtime_r(&current_time, &priv->shown_time);
1377    priv->current_time = priv->shown_time;
1378    priv->selected_time = priv->shown_time;
1379    t = _time_to_next_day(&priv->current_time);
1380    priv->update_timer = ecore_timer_add(t, _update_cur_date, obj);
1381 
1382    elm_widget_can_focus_set(obj, EINA_TRUE);
1383 
1384    if (!elm_layout_theme_set(obj, "calendar", "base",
1385                              elm_object_style_get(obj)))
1386      CRI("Failed to set layout!");
1387 
1388    _spinner_buttons_add(obj, priv);
1389 
1390    // 7x8 (1 month+year, days, 6 dates.)
1391    efl_ui_layout_finger_size_multiplier_set(obj, 7, 8);
1392 
1393    evas_object_smart_changed(obj);
1394 
1395    // ACCESS
1396    if ((_elm_config->access_mode != ELM_ACCESS_MODE_OFF))
1397       _access_calendar_spinner_register(obj);
1398 
1399    // Items for composition
1400    for (int i = 0; i < 42; ++i)
1401      {
1402         priv->items[i] = efl_add(ELM_CALENDAR_ITEM_CLASS, obj, elm_calendar_item_day_number_set(efl_added, i));
1403      }
1404 }
1405 
1406 EOLIAN static void
_elm_calendar_efl_canvas_group_group_del(Eo * obj,Elm_Calendar_Data * sd)1407 _elm_calendar_efl_canvas_group_group_del(Eo *obj, Elm_Calendar_Data *sd)
1408 {
1409    int i;
1410    Elm_Calendar_Mark *mark;
1411 
1412    ecore_timer_del(sd->spin_timer);
1413    ecore_timer_del(sd->update_timer);
1414 
1415    if (sd->marks)
1416      {
1417         EINA_LIST_FREE(sd->marks, mark)
1418           {
1419              _mark_free(mark);
1420           }
1421      }
1422 
1423    for (i = 0; i < ELM_DAY_LAST; i++)
1424      eina_stringshare_del(sd->weekdays[i]);
1425 
1426    efl_canvas_group_del(efl_super(obj, MY_CLASS));
1427 }
1428 
1429 static Eina_Bool _elm_calendar_smart_focus_next_enable = EINA_FALSE;
1430 
1431 static void
_access_obj_process(Evas_Object * obj,Eina_Bool is_access)1432 _access_obj_process(Evas_Object *obj, Eina_Bool is_access)
1433 {
1434    int maxdays, day, i;
1435 
1436    ELM_CALENDAR_DATA_GET(obj, sd);
1437    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
1438 
1439    if (is_access)
1440      _access_calendar_register(obj);
1441    else
1442      {
1443         day = 0;
1444         maxdays = _maxdays_get(&sd->shown_time, 0);
1445         for (i = 0; i < 42; i++)
1446           {
1447              if ((!day) && (i == sd->first_day_it)) day = 1;
1448              if ((day) && (day <= maxdays))
1449                {
1450                   char pname[18];
1451                   _part_name_snprintf(pname, sizeof(pname),
1452                      obj, ELM_CALENDAR_CIT_ACCESS_PART_STR, i);
1453 
1454                   _elm_access_edje_object_part_object_unregister
1455                           (obj, elm_layout_edje_get(obj), pname);
1456                }
1457           }
1458 
1459         if (sd->dec_btn_month && efl_isa(sd->dec_btn_month, ELM_ACCESS_CLASS))
1460           {
1461              _elm_access_edje_object_part_object_unregister
1462                (obj, elm_layout_edje_get(obj), "left_bt");
1463              sd->dec_btn_month = NULL;
1464           }
1465         if (sd->inc_btn_month && efl_isa(sd->inc_btn_month, ELM_ACCESS_CLASS))
1466           {
1467              _elm_access_edje_object_part_object_unregister
1468                (obj, elm_layout_edje_get(obj), "right_bt");
1469              sd->inc_btn_month = NULL;
1470           }
1471         if (sd->month_access)
1472           _elm_access_edje_object_part_object_unregister
1473             (obj, elm_layout_edje_get(obj), "month_text");
1474 
1475         if (sd->dec_btn_year && efl_isa(sd->dec_btn_year, ELM_ACCESS_CLASS))
1476           {
1477              _elm_access_edje_object_part_object_unregister
1478                (obj, elm_layout_edje_get(obj), "left_bt_year");
1479              sd->dec_btn_year = NULL;
1480           }
1481         if (sd->inc_btn_year && efl_isa(sd->inc_btn_year, ELM_ACCESS_CLASS))
1482           {
1483              _elm_access_edje_object_part_object_unregister
1484                (obj, elm_layout_edje_get(obj), "right_bt_year");
1485              sd->inc_btn_year = NULL;
1486           }
1487         if (sd->year_access)
1488           _elm_access_edje_object_part_object_unregister
1489             (obj, elm_layout_edje_get(obj), "year_text");
1490      }
1491 }
1492 
1493 EOLIAN static void
_elm_calendar_efl_ui_widget_on_access_update(Eo * obj EINA_UNUSED,Elm_Calendar_Data * _pd EINA_UNUSED,Eina_Bool acs)1494 _elm_calendar_efl_ui_widget_on_access_update(Eo *obj EINA_UNUSED, Elm_Calendar_Data *_pd EINA_UNUSED, Eina_Bool acs)
1495 {
1496    _elm_calendar_smart_focus_next_enable = acs;
1497    _access_obj_process(obj, _elm_calendar_smart_focus_next_enable);
1498 }
1499 
1500 EAPI Evas_Object *
elm_calendar_add(Evas_Object * parent)1501 elm_calendar_add(Evas_Object *parent)
1502 {
1503    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
1504    return elm_legacy_add(MY_CLASS, parent);
1505 }
1506 
1507 EOLIAN static Eo *
_elm_calendar_efl_object_constructor(Eo * obj,Elm_Calendar_Data * sd)1508 _elm_calendar_efl_object_constructor(Eo *obj, Elm_Calendar_Data *sd)
1509 {
1510    obj = efl_constructor(efl_super(obj, MY_CLASS));
1511    sd->obj = obj;
1512 
1513    efl_canvas_object_type_set(obj, MY_CLASS_NAME_LEGACY);
1514    evas_object_smart_callbacks_descriptions_set(obj, _smart_callbacks);
1515    efl_access_object_role_set(obj, EFL_ACCESS_ROLE_CALENDAR);
1516 
1517    return obj;
1518 }
1519 
1520 EOLIAN static void
_elm_calendar_weekdays_names_set(Eo * obj,Elm_Calendar_Data * sd,const char ** weekdays)1521 _elm_calendar_weekdays_names_set(Eo *obj, Elm_Calendar_Data *sd, const char **weekdays)
1522 {
1523    int i;
1524 
1525    EINA_SAFETY_ON_NULL_RETURN(weekdays);
1526 
1527    for (i = 0; i < ELM_DAY_LAST; i++)
1528      {
1529         eina_stringshare_replace(&sd->weekdays[i], weekdays[i]);
1530      }
1531    sd->weekdays_set = EINA_TRUE;
1532 
1533    evas_object_smart_changed(obj);
1534 }
1535 
1536 EOLIAN static const char**
_elm_calendar_weekdays_names_get(const Eo * obj EINA_UNUSED,Elm_Calendar_Data * sd)1537 _elm_calendar_weekdays_names_get(const Eo *obj EINA_UNUSED, Elm_Calendar_Data *sd)
1538 {
1539    return sd->weekdays;
1540 }
1541 
1542 EOLIAN static void
_elm_calendar_interval_set(Eo * obj EINA_UNUSED,Elm_Calendar_Data * sd,double interval)1543 _elm_calendar_interval_set(Eo *obj EINA_UNUSED, Elm_Calendar_Data *sd, double interval)
1544 {
1545    sd->first_interval = interval;
1546 }
1547 
1548 EOLIAN static double
_elm_calendar_interval_get(const Eo * obj EINA_UNUSED,Elm_Calendar_Data * sd)1549 _elm_calendar_interval_get(const Eo *obj EINA_UNUSED, Elm_Calendar_Data *sd)
1550 {
1551    return sd->first_interval;
1552 }
1553 
1554 EAPI void
elm_calendar_min_max_year_set(Elm_Calendar * obj,int min,int max)1555 elm_calendar_min_max_year_set(Elm_Calendar *obj, int min, int max)
1556 {
1557    Elm_Calendar_Data *sd;
1558 
1559    if (!efl_isa(obj, ELM_CALENDAR_CLASS)) return ;
1560    sd = efl_data_scope_get(obj, ELM_CALENDAR_CLASS);
1561 
1562    min -= 1900;
1563    max -= 1900;
1564    if ((sd->date_min.tm_year == min) && (sd->date_max.tm_year == max)) return;
1565    sd->date_min.tm_year = min > 2 ? min : 2;
1566    if (max > sd->date_min.tm_year)
1567      sd->date_max.tm_year = max;
1568    else
1569      sd->date_max.tm_year = sd->date_min.tm_year;
1570    sd->date_min.tm_mon = 0;
1571    sd->date_min.tm_mday = 1;
1572    sd->date_max.tm_mon = 11;
1573    sd->date_max.tm_mday = 31;
1574 
1575    if (sd->shown_time.tm_year > sd->date_max.tm_year)
1576      sd->shown_time.tm_year = sd->date_max.tm_year;
1577    if (sd->shown_time.tm_year < sd->date_min.tm_year)
1578      sd->shown_time.tm_year = sd->date_min.tm_year;
1579 
1580    evas_object_smart_changed(obj);
1581 }
1582 
1583 EAPI void
elm_calendar_min_max_year_get(const Elm_Calendar * obj,int * min,int * max)1584 elm_calendar_min_max_year_get(const Elm_Calendar *obj, int *min, int *max)
1585 {
1586    Elm_Calendar_Data *sd;
1587 
1588    if (!efl_isa(obj, ELM_CALENDAR_CLASS)) return ;
1589    sd = efl_data_scope_get(obj, ELM_CALENDAR_CLASS);
1590 
1591    if (min) *min = sd->date_min.tm_year + 1900;
1592    if (max) *max = sd->date_max.tm_year + 1900;
1593 }
1594 
1595 EOLIAN static void
_elm_calendar_date_min_set(Eo * obj,Elm_Calendar_Data * sd,const struct tm * min)1596 _elm_calendar_date_min_set(Eo *obj, Elm_Calendar_Data *sd, const struct tm *min)
1597 {
1598    Eina_Bool upper = EINA_FALSE;
1599 
1600    if ((sd->date_min.tm_year == min->tm_year)
1601        && (sd->date_min.tm_mon == min->tm_mon)
1602        && (sd->date_min.tm_mday == min->tm_mday))
1603      return;
1604 
1605    if (min->tm_year < 2)
1606      {
1607         sd->date_min.tm_year = 2;
1608         sd->date_min.tm_mon = 0;
1609         sd->date_min.tm_mday = 1;
1610      }
1611    else
1612      {
1613         if (sd->date_max.tm_year != -1)
1614           {
1615              if (min->tm_year > sd->date_max.tm_year)
1616                {
1617                   upper = EINA_TRUE;
1618                }
1619              else if (min->tm_year == sd->date_max.tm_year)
1620                {
1621                   if (min->tm_mon > sd->date_max.tm_mon)
1622                     upper = EINA_TRUE;
1623                   else if ((min->tm_mon == sd->date_max.tm_mon) && (min->tm_mday > sd->date_max.tm_mday))
1624                     upper = EINA_TRUE;
1625                }
1626           }
1627 
1628         if (upper)
1629           {
1630              sd->date_min.tm_year = sd->date_max.tm_year;
1631              sd->date_min.tm_mon = sd->date_max.tm_mon;
1632              sd->date_min.tm_mday = sd->date_max.tm_mday;
1633           }
1634         else
1635           {
1636              sd->date_min.tm_year = min->tm_year;
1637              sd->date_min.tm_mon = min->tm_mon;
1638              sd->date_min.tm_mday = min->tm_mday;
1639           }
1640      }
1641 
1642    if (sd->shown_time.tm_year <= sd->date_min.tm_year)
1643      {
1644         sd->shown_time.tm_year = sd->date_min.tm_year;
1645         if (sd->shown_time.tm_mon < sd->date_min.tm_mon)
1646           sd->shown_time.tm_mon = sd->date_min.tm_mon;
1647      }
1648 
1649    _fix_selected_time(sd);
1650 
1651    evas_object_smart_changed(obj);
1652 }
1653 
1654 EOLIAN static const struct tm *
_elm_calendar_date_min_get(const Eo * obj EINA_UNUSED,Elm_Calendar_Data * sd)1655 _elm_calendar_date_min_get(const Eo *obj EINA_UNUSED, Elm_Calendar_Data *sd)
1656 {
1657    return &(sd->date_min);
1658 }
1659 
1660 EOLIAN static void
_elm_calendar_date_max_set(Eo * obj,Elm_Calendar_Data * sd,const struct tm * max)1661 _elm_calendar_date_max_set(Eo *obj, Elm_Calendar_Data *sd, const struct tm *max)
1662 {
1663    Eina_Bool lower = EINA_FALSE;
1664 
1665    if ((sd->date_max.tm_year == max->tm_year)
1666        && (sd->date_max.tm_mon == max->tm_mon)
1667        && (sd->date_max.tm_mday == max->tm_mday))
1668      return;
1669 
1670    if (max->tm_year < sd->date_min.tm_year)
1671      {
1672         lower = EINA_TRUE;
1673      }
1674    else if (max->tm_year == sd->date_min.tm_year)
1675      {
1676         if (max->tm_mon < sd->date_min.tm_mon)
1677           lower = EINA_TRUE;
1678         else if ((max->tm_mon == sd->date_min.tm_mon) && (max->tm_mday < sd->date_min.tm_mday))
1679           lower = EINA_TRUE;
1680      }
1681 
1682    if (lower)
1683      {
1684         sd->date_max.tm_year = sd->date_min.tm_year;
1685         sd->date_max.tm_mon = sd->date_min.tm_mon;
1686         sd->date_max.tm_mday = sd->date_min.tm_mday;
1687      }
1688    else
1689      {
1690         sd->date_max.tm_year = max->tm_year;
1691         sd->date_max.tm_mon = max->tm_mon;
1692         sd->date_max.tm_mday = max->tm_mday;
1693      }
1694 
1695    if (sd->shown_time.tm_year >= sd->date_max.tm_year)
1696      {
1697         sd->shown_time.tm_year = sd->date_max.tm_year;
1698         if (sd->shown_time.tm_mon > sd->date_max.tm_mon)
1699           sd->shown_time.tm_mon = sd->date_max.tm_mon;
1700      }
1701 
1702    _fix_selected_time(sd);
1703 
1704    evas_object_smart_changed(obj);
1705 }
1706 
1707 EOLIAN static const struct tm *
_elm_calendar_date_max_get(const Eo * obj EINA_UNUSED,Elm_Calendar_Data * sd)1708 _elm_calendar_date_max_get(const Eo *obj EINA_UNUSED, Elm_Calendar_Data *sd)
1709 {
1710    return &(sd->date_max);
1711 }
1712 
1713 EINA_DEPRECATED EAPI void
elm_calendar_day_selection_disabled_set(Evas_Object * obj,Eina_Bool disabled)1714 elm_calendar_day_selection_disabled_set(Evas_Object *obj,
1715                                         Eina_Bool disabled)
1716 {
1717    ELM_CALENDAR_CHECK(obj);
1718 
1719    if (disabled)
1720      elm_calendar_select_mode_set(obj, ELM_CALENDAR_SELECT_MODE_NONE);
1721    else
1722      elm_calendar_select_mode_set(obj, ELM_CALENDAR_SELECT_MODE_DEFAULT);
1723 }
1724 
1725 EINA_DEPRECATED EAPI Eina_Bool
elm_calendar_day_selection_disabled_get(const Evas_Object * obj)1726 elm_calendar_day_selection_disabled_get(const Evas_Object *obj)
1727 {
1728    ELM_CALENDAR_CHECK(obj) EINA_FALSE;
1729    ELM_CALENDAR_DATA_GET(obj, sd);
1730 
1731    return !!(sd->select_mode == ELM_CALENDAR_SELECT_MODE_NONE);
1732 }
1733 
1734 EOLIAN static void
_elm_calendar_selected_time_set(Eo * obj,Elm_Calendar_Data * sd,struct tm * selected_time)1735 _elm_calendar_selected_time_set(Eo *obj, Elm_Calendar_Data *sd, struct tm *selected_time)
1736 {
1737    EINA_SAFETY_ON_NULL_RETURN(selected_time);
1738 
1739    if (sd->selectable & ELM_CALENDAR_SELECTABLE_YEAR)
1740      sd->selected_time.tm_year = selected_time->tm_year;
1741    if (sd->selectable & ELM_CALENDAR_SELECTABLE_MONTH)
1742      sd->selected_time.tm_mon = selected_time->tm_mon;
1743    if (sd->selectable & ELM_CALENDAR_SELECTABLE_DAY)
1744        {
1745           sd->selected_time.tm_mday = selected_time->tm_mday;
1746           if (!sd->selected)
1747             sd->selected = EINA_TRUE;
1748        }
1749    else if (sd->select_mode != ELM_CALENDAR_SELECT_MODE_ONDEMAND)
1750      {
1751         if (!sd->selected)
1752           sd->selected = EINA_TRUE;
1753      }
1754    if (sd->selected_time.tm_year != sd->shown_time.tm_year)
1755      sd->shown_time.tm_year = sd->selected_time.tm_year;
1756    if (sd->selected_time.tm_mon != sd->shown_time.tm_mon)
1757      sd->shown_time.tm_mon = sd->selected_time.tm_mon;
1758 
1759    _fix_selected_time(sd);
1760 
1761    evas_object_smart_changed(obj);
1762 }
1763 
1764 EOLIAN static Eina_Bool
_elm_calendar_selected_time_get(const Eo * obj EINA_UNUSED,Elm_Calendar_Data * sd,struct tm * selected_time)1765 _elm_calendar_selected_time_get(const Eo *obj EINA_UNUSED, Elm_Calendar_Data *sd, struct tm *selected_time)
1766 {
1767    EINA_SAFETY_ON_NULL_RETURN_VAL(selected_time, EINA_FALSE);
1768 
1769    if ((sd->select_mode == ELM_CALENDAR_SELECT_MODE_ONDEMAND)
1770        && (!sd->selected))
1771      return EINA_FALSE;
1772    *selected_time = sd->selected_time;
1773 
1774    return EINA_TRUE;
1775 }
1776 
1777 EOLIAN static void
_elm_calendar_format_function_set(Eo * obj EINA_UNUSED,Elm_Calendar_Data * sd,Elm_Calendar_Format_Cb format_function)1778 _elm_calendar_format_function_set(Eo *obj EINA_UNUSED, Elm_Calendar_Data *sd, Elm_Calendar_Format_Cb format_function)
1779 {
1780    sd->format_func = format_function;
1781    if (sd->double_spinners) /* theme has spinner for year */
1782       _set_month_year(sd);
1783 }
1784 
1785 EOLIAN static Elm_Calendar_Mark*
_elm_calendar_mark_add(Eo * obj,Elm_Calendar_Data * sd,const char * mark_type,struct tm * mark_time,Elm_Calendar_Mark_Repeat_Type repeat)1786 _elm_calendar_mark_add(Eo *obj, Elm_Calendar_Data *sd, const char *mark_type, struct tm *mark_time, Elm_Calendar_Mark_Repeat_Type repeat)
1787 {
1788    Elm_Calendar_Mark *mark;
1789 
1790    mark = _mark_new(obj, mark_type, mark_time, repeat);
1791    if (!mark) return NULL;
1792    sd->marks = eina_list_append(sd->marks, mark);
1793    mark->node = eina_list_last(sd->marks);
1794 
1795    return mark;
1796 }
1797 
1798 EOLIAN static void
_elm_calendar_mark_del(Eo * obj,Elm_Calendar_Data * sd,Elm_Calendar_Mark * mark)1799 _elm_calendar_mark_del(Eo *obj, Elm_Calendar_Data *sd, Elm_Calendar_Mark *mark)
1800 {
1801    EINA_SAFETY_ON_NULL_RETURN(mark);
1802    EINA_SAFETY_ON_TRUE_RETURN(mark->obj != obj);
1803 
1804    sd->marks = eina_list_remove_list(sd->marks, mark->node);
1805    _mark_free(mark);
1806 }
1807 
1808 EAPI void
elm_calendar_mark_del(Elm_Calendar_Mark * mark)1809 elm_calendar_mark_del(Elm_Calendar_Mark *mark)
1810 {
1811    EINA_SAFETY_ON_NULL_RETURN(mark);
1812    ELM_CALENDAR_CHECK(mark->obj);
1813    ELM_CALENDAR_DATA_GET(mark->obj, sd);
1814 
1815    sd->marks = eina_list_remove_list(sd->marks, mark->node);
1816    _mark_free(mark);
1817 }
1818 
1819 EOLIAN static void
_elm_calendar_marks_clear(Eo * obj EINA_UNUSED,Elm_Calendar_Data * sd)1820 _elm_calendar_marks_clear(Eo *obj EINA_UNUSED, Elm_Calendar_Data *sd)
1821 {
1822    Elm_Calendar_Mark *mark;
1823 
1824    EINA_LIST_FREE(sd->marks, mark)
1825      _mark_free(mark);
1826 }
1827 
1828 EOLIAN static const Eina_List*
_elm_calendar_marks_get(const Eo * obj EINA_UNUSED,Elm_Calendar_Data * sd)1829 _elm_calendar_marks_get(const Eo *obj EINA_UNUSED, Elm_Calendar_Data *sd)
1830 {
1831    return sd->marks;
1832 }
1833 
1834 EOLIAN static void
_elm_calendar_marks_draw(Eo * obj,Elm_Calendar_Data * _pd EINA_UNUSED)1835 _elm_calendar_marks_draw(Eo *obj, Elm_Calendar_Data *_pd EINA_UNUSED)
1836 {
1837    evas_object_smart_changed(obj);
1838 }
1839 
1840 EOLIAN static void
_elm_calendar_first_day_of_week_set(Eo * obj,Elm_Calendar_Data * sd,Elm_Calendar_Weekday day)1841 _elm_calendar_first_day_of_week_set(Eo *obj, Elm_Calendar_Data *sd, Elm_Calendar_Weekday day)
1842 {
1843    if (day >= ELM_DAY_LAST) return;
1844    if (sd->first_week_day != day)
1845      {
1846         sd->first_week_day = day;
1847         evas_object_smart_changed(obj);
1848      }
1849 }
1850 
1851 EOLIAN static Elm_Calendar_Weekday
_elm_calendar_first_day_of_week_get(const Eo * obj EINA_UNUSED,Elm_Calendar_Data * sd)1852 _elm_calendar_first_day_of_week_get(const Eo *obj EINA_UNUSED, Elm_Calendar_Data *sd)
1853 {
1854    return sd->first_week_day;
1855 }
1856 
1857 EOLIAN static void
_elm_calendar_select_mode_set(Eo * obj,Elm_Calendar_Data * sd,Elm_Calendar_Select_Mode mode)1858 _elm_calendar_select_mode_set(Eo *obj, Elm_Calendar_Data *sd, Elm_Calendar_Select_Mode mode)
1859 {
1860 
1861    if ((mode <= ELM_CALENDAR_SELECT_MODE_ONDEMAND)
1862        && (sd->select_mode != mode))
1863      {
1864         sd->select_mode = mode;
1865         if (sd->select_mode == ELM_CALENDAR_SELECT_MODE_ONDEMAND)
1866           sd->selected = EINA_FALSE;
1867         if ((sd->select_mode == ELM_CALENDAR_SELECT_MODE_ALWAYS)
1868             || (sd->select_mode == ELM_CALENDAR_SELECT_MODE_DEFAULT))
1869           _select(obj, sd->selected_it);
1870         else
1871           _unselect(obj, sd->selected_it);
1872      }
1873 }
1874 
1875 EOLIAN static Elm_Calendar_Select_Mode
_elm_calendar_select_mode_get(const Eo * obj EINA_UNUSED,Elm_Calendar_Data * sd)1876 _elm_calendar_select_mode_get(const Eo *obj EINA_UNUSED, Elm_Calendar_Data *sd)
1877 {
1878    return sd->select_mode;
1879 }
1880 
1881 EOLIAN static void
_elm_calendar_selectable_set(Eo * obj EINA_UNUSED,Elm_Calendar_Data * sd,Elm_Calendar_Selectable selectable)1882 _elm_calendar_selectable_set(Eo *obj EINA_UNUSED, Elm_Calendar_Data *sd, Elm_Calendar_Selectable selectable)
1883 {
1884    sd->selectable = selectable;
1885 }
1886 
1887 EOLIAN static Elm_Calendar_Selectable
_elm_calendar_selectable_get(const Eo * obj EINA_UNUSED,Elm_Calendar_Data * sd)1888 _elm_calendar_selectable_get(const Eo *obj EINA_UNUSED, Elm_Calendar_Data *sd)
1889 {
1890    return sd->selectable;
1891 }
1892 
1893 EOLIAN static Eina_Bool
_elm_calendar_displayed_time_get(const Eo * obj EINA_UNUSED,Elm_Calendar_Data * sd,struct tm * displayed_time)1894 _elm_calendar_displayed_time_get(const Eo *obj EINA_UNUSED, Elm_Calendar_Data *sd, struct tm *displayed_time)
1895 {
1896    EINA_SAFETY_ON_NULL_RETURN_VAL(displayed_time, EINA_FALSE);
1897    *displayed_time = sd->shown_time;
1898    return EINA_TRUE;
1899 }
1900 
1901 static void
_elm_calendar_class_constructor(Efl_Class * klass)1902 _elm_calendar_class_constructor(Efl_Class *klass)
1903 {
1904    evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
1905 
1906    if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
1907       _elm_calendar_smart_focus_next_enable = EINA_TRUE;
1908 }
1909 
1910 EOLIAN static const Efl_Access_Action_Data*
_elm_calendar_efl_access_widget_action_elm_actions_get(const Eo * obj EINA_UNUSED,Elm_Calendar_Data * sd EINA_UNUSED)1911 _elm_calendar_efl_access_widget_action_elm_actions_get(const Eo *obj EINA_UNUSED, Elm_Calendar_Data *sd EINA_UNUSED)
1912 {
1913    static Efl_Access_Action_Data atspi_actions[] = {
1914           { "activate", "activate", NULL, _key_action_activate},
1915           { NULL, NULL, NULL, NULL }
1916    };
1917    return &atspi_actions[0];
1918 }
1919 
1920 /* Standard widget overrides */
1921 
1922 ELM_WIDGET_KEY_DOWN_DEFAULT_IMPLEMENT(elm_calendar, Elm_Calendar_Data)
1923 
1924 /* Internal EO APIs and hidden overrides */
1925 
1926 #define ELM_CALENDAR_EXTRA_OPS \
1927    EFL_CANVAS_GROUP_ADD_DEL_OPS(elm_calendar)
1928 
1929 #include "elm_calendar_eo.c"
1930 
1931 typedef struct {
1932    int v;
1933    Evas_Object *part;
1934 }  Elm_Calendar_Item_Data;
1935 
1936 EOLIAN static void
_elm_calendar_item_day_number_set(Eo * obj,Elm_Calendar_Item_Data * pd,int i)1937 _elm_calendar_item_day_number_set(Eo *obj, Elm_Calendar_Item_Data *pd, int i)
1938 {
1939    char pname[18];
1940    Evas_Object *po, *o;
1941 
1942    pd->v = i;
1943 
1944    o = elm_layout_edje_get(efl_parent_get(obj));
1945    _part_name_snprintf(pname, sizeof(pname), o, ELM_CALENDAR_CIT_ACCESS_PART_STR, i);
1946    edje_object_freeze(o);
1947    po = (Evas_Object *)edje_object_part_object_get(o, pname);
1948    edje_object_thaw(o);
1949 
1950    if (_elm_config->access_mode != ELM_ACCESS_MODE_ON)
1951      pd->part = po;
1952    else
1953      pd->part = evas_object_data_get(po, "_part_access_obj");
1954 
1955    _efl_ui_focus_event_redirector(pd->part, obj);
1956 
1957    EINA_SAFETY_ON_NULL_RETURN(pd->part);
1958 }
1959 
1960 EOLIAN static int
_elm_calendar_item_day_number_get(const Eo * obj EINA_UNUSED,Elm_Calendar_Item_Data * pd)1961 _elm_calendar_item_day_number_get(const Eo *obj EINA_UNUSED, Elm_Calendar_Item_Data *pd)
1962 {
1963    return pd->v;
1964 }
1965 
1966 EOLIAN static void
_elm_calendar_item_efl_ui_focus_object_focus_set(Eo * obj,Elm_Calendar_Item_Data * pd,Eina_Bool focus)1967 _elm_calendar_item_efl_ui_focus_object_focus_set(Eo *obj, Elm_Calendar_Item_Data *pd, Eina_Bool focus)
1968 {
1969    efl_ui_focus_object_focus_set(efl_super(obj, ELM_CALENDAR_ITEM_CLASS), focus);
1970 
1971    _update_focused_it(efl_parent_get(obj), pd->v);
1972    evas_object_focus_set(pd->part, efl_ui_focus_object_focus_get(obj));
1973 }
1974 
1975 EOLIAN static Eina_Rect
_elm_calendar_item_efl_ui_focus_object_focus_geometry_get(const Eo * obj EINA_UNUSED,Elm_Calendar_Item_Data * pd)1976 _elm_calendar_item_efl_ui_focus_object_focus_geometry_get(const Eo *obj EINA_UNUSED, Elm_Calendar_Item_Data *pd)
1977 {
1978    return efl_gfx_entity_geometry_get(pd->part);
1979 }
1980 
1981 EOLIAN static Efl_Ui_Focus_Object*
_elm_calendar_item_efl_ui_focus_object_focus_parent_get(const Eo * obj,Elm_Calendar_Item_Data * pd EINA_UNUSED)1982 _elm_calendar_item_efl_ui_focus_object_focus_parent_get(const Eo *obj, Elm_Calendar_Item_Data *pd EINA_UNUSED)
1983 {
1984    return efl_parent_get(obj);
1985 }
1986 
1987 
1988 #include "elm_calendar_item_eo.c"
1989