2 # include "elementary_config.h"
5 #define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED
7 #include <Elementary.h>
9 #include "elm_widget_datetime.h"
11 #define MY_CLASS ELM_DATETIME_CLASS
13 #define MY_CLASS_NAME "Elm_Datetime"
14 #define MY_CLASS_NAME_LEGACY "elm_datetime"
20 #ifdef HAVE_LANGINFO_H
21 # include <langinfo.h>
24 #define MAX_SEPARATOR_LEN 6
25 #define MIN_DAYS_IN_MONTH 28
26 #define BUFFER_SIZE 1024
28 /* interface between EDC & C code (field & signal names). values 0 to
29 * ELM_DATETIME_TYPE_COUNT are in the valid range, and must get in the
32 #define EDC_DATETIME_FOCUSIN_SIG_STR "elm,action,focus"
33 #define EDC_DATETIME_FOCUSOUT_SIG_STR "elm,action,unfocus"
34 #define EDC_PART_FIELD_STR "field%d"
35 #define EDC_PART_SEPARATOR_STR "separator%d"
36 #define EDC_PART_FIELD_ENABLE_SIG_STR "field%d,enable"
37 #define EDC_PART_FIELD_DISABLE_SIG_STR "field%d,disable"
39 /* struct tm does not define the fields in the order year, month,
40 * date, hour, minute. values are reassigned to an array for easy
43 #define DATETIME_TM_ARRAY(intptr, tmptr) \
52 // default limits for individual fields
53 static Format_Map mapping[ELM_DATETIME_TYPE_COUNT] = {
54 [ELM_DATETIME_YEAR] = { "Yy", -1, -1, "" },
55 [ELM_DATETIME_MONTH] = { "mbBh", 0, 11, "" },
56 [ELM_DATETIME_DATE] = { "de", 1, 31, "" },
57 [ELM_DATETIME_HOUR] = { "IHkl", 0, 23, "" },
58 [ELM_DATETIME_MINUTE] = { "M", 0, 59, ":" },
59 [ELM_DATETIME_AMPM] = { "pP", 0, 1, "" }
62 static const char *multifield_formats = "cxXrRTDF";
63 static const char *ignore_separators = "()";
64 static const char *ignore_extensions = "E0_-O^#";
65 static Datetime_Mod_Api *dt_mod = NULL;
67 static const char SIG_CHANGED[] = "changed";
68 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
70 {SIG_WIDGET_LANG_CHANGED, ""}, /**< handled by elm_widget */
71 {SIG_WIDGET_ACCESS_CHANGED, ""}, /**< handled by elm_widget */
72 {SIG_LAYOUT_FOCUSED, ""}, /**< handled by elm_layout */
73 {SIG_LAYOUT_UNFOCUSED, ""}, /**< handled by elm_layout */
77 static Datetime_Mod_Api *
80 Elm_Module *mod = NULL;
82 if (!(mod = _elm_module_find_as("datetime/api"))) return NULL;
84 mod->api = malloc(sizeof(Datetime_Mod_Api));
85 if (!mod->api) return NULL;
87 ((Datetime_Mod_Api *)(mod->api))->obj_hook =
88 _elm_module_symbol_get(mod, "obj_hook");
89 ((Datetime_Mod_Api *)(mod->api))->obj_unhook =
90 _elm_module_symbol_get(mod, "obj_unhook");
91 ((Datetime_Mod_Api *)(mod->api))->obj_hide =
92 _elm_module_symbol_get(mod, "obj_hide");
93 ((Datetime_Mod_Api *)(mod->api))->field_create =
94 _elm_module_symbol_get(mod, "field_create");
95 ((Datetime_Mod_Api *)(mod->api))->field_value_display =
96 _elm_module_symbol_get(mod, "field_value_display");
97 //TIZEN_ONLY(20151218): Support Mobile UX
98 ((Datetime_Mod_Api *)(mod->api))->field_format_changed =
99 _elm_module_symbol_get(mod, "field_format_changed");
106 _field_list_display(Evas_Object *obj)
108 Datetime_Field *field;
109 unsigned int idx = 0;
111 ELM_DATETIME_DATA_GET(obj, sd);
113 if (!dt_mod || !dt_mod->field_value_display) return;
115 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
117 field = sd->field_list + idx;
118 if (field->fmt_exist && field->visible)
119 dt_mod->field_value_display(sd->mod_data, field->item_obj);
123 // FIXME: provide nl_langinfo on Windows if possible
124 // returns expanded format string for corresponding multi-field format character
126 _expanded_fmt_str_get(char ch)
132 #if defined(HAVE_LANGINFO_H) || defined (HAVE_EVIL)
133 exp_fmt = nl_langinfo(D_T_FMT);
140 #if defined(HAVE_LANGINFO_H) || defined (HAVE_EVIL)
141 exp_fmt = nl_langinfo(D_FMT);
148 #if defined(HAVE_LANGINFO_H) || defined (HAVE_EVIL)
149 exp_fmt = nl_langinfo(T_FMT);
156 #if defined(HAVE_LANGINFO_H) || defined (HAVE_EVIL)
157 exp_fmt = nl_langinfo(T_FMT_AMPM);
168 exp_fmt = "%H:%M:%S";
172 exp_fmt = "%m/%d/%y";
176 exp_fmt = "%Y-%m-%d";
188 _expand_format(char *dt_fmt)
190 char *ptr, *expanded_fmt, ch;
191 unsigned int idx, len = 0;
192 char buf[ELM_DATETIME_MAX_FORMAT_LEN] = {0, };
193 Eina_Bool fmt_char, fmt_expanded;
197 fmt_char = EINA_FALSE;
198 fmt_expanded = EINA_FALSE;
202 if ((fmt_char) && (strchr(multifield_formats, ch)))
204 /* replace the multi-field format characters with
205 * corresponding expanded format */
206 expanded_fmt = _expanded_fmt_str_get(ch);
207 len = strlen(expanded_fmt);
208 if (len > 0) fmt_expanded = EINA_TRUE;
210 strncat(buf, expanded_fmt, len);
213 else buf[idx++] = ch;
215 if (ch == '%') fmt_char = EINA_TRUE;
216 else fmt_char = EINA_FALSE;
222 strncpy(dt_fmt, buf, ELM_DATETIME_MAX_FORMAT_LEN);
223 } while (fmt_expanded);
227 _field_list_arrange(Evas_Object *obj)
229 Datetime_Field *field;
230 char buf[BUFFER_SIZE];
234 ELM_DATETIME_DATA_GET(obj, sd);
236 freeze = sd->freeze_sizing;
237 sd->freeze_sizing = EINA_TRUE;
239 //////////////////////////////////////////////////////////////////////////////
240 //TIZEN_ONLY(20150225): Open source datetime code doesn't consider dynamically
241 // field sequence changing case.
243 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
245 field = sd->field_list + idx;
246 snprintf(buf, sizeof(buf), EDC_PART_FIELD_STR, field->location);
248 if (field->visible && field->fmt_exist)
250 elm_layout_content_unset(obj, buf);
251 elm_layout_content_set(obj, buf, field->item_obj);
254 evas_object_hide(elm_layout_content_unset(obj, buf));
257 // remove all the content widget from the layout
258 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
260 snprintf(buf, sizeof(buf), EDC_PART_FIELD_STR, idx);
261 elm_layout_content_unset(obj, buf);
263 // set as content widget or hide it depending on location
264 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
266 field = sd->field_list + idx;
267 snprintf(buf, sizeof(buf), EDC_PART_FIELD_STR, field->location);
269 if (field->visible && field->fmt_exist)
270 elm_layout_content_set(obj, buf, field->item_obj);
272 evas_object_hide(field->item_obj);
274 //////////////////////////////////////////////////////////////////////////////
276 sd->freeze_sizing = freeze;
278 elm_layout_sizing_eval(obj);
279 _field_list_display(obj);
283 _parse_format(Evas_Object *obj,
286 Eina_Bool fmt_parsing = EINA_FALSE, sep_parsing = EINA_FALSE,
287 sep_lookup = EINA_FALSE;
288 //TIZEN_ONLY(20151216) - swap format locations to support some locale.
289 Eina_Bool location_swap = EINA_FALSE;
291 unsigned int len = 0, idx = 0, location = 0;
292 char separator[MAX_SEPARATOR_LEN];
293 Datetime_Field *field = NULL;
296 ELM_DATETIME_DATA_GET(obj, sd);
298 while ((cur = *fmt_ptr))
302 if (strchr(ignore_extensions, cur))
307 fmt_parsing = EINA_FALSE;
309 //TIZEN_ONLY(20151216) - swap format locations to support some locale.
311 (strchr(mapping[ELM_DATETIME_HOUR].fmt_char, cur) ||
312 strchr(mapping[ELM_DATETIME_MINUTE].fmt_char, cur) ||
313 strchr(mapping[ELM_DATETIME_AMPM].fmt_char, cur)))
314 location_swap = EINA_TRUE;
316 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
318 if (strchr(mapping[idx].fmt_char, cur))
320 field = sd->field_list + idx;
321 /* ignore the fields already have or disabled
322 * valid formats, means already parsed &
323 * repeated, ignore. */
324 if (field->location != -1) break;
326 field->fmt_exist = EINA_TRUE;
327 field->location = location++;
328 sep_lookup = EINA_TRUE;
336 fmt_parsing = EINA_TRUE;
337 sep_parsing = EINA_FALSE;
338 // set the separator to previous field
340 if (field) eina_stringshare_replace(&field->separator, separator);
342 // ignore the set of chars (global, field specific) as field separators
344 (len < MAX_SEPARATOR_LEN - 1) &&
345 (field->type != ELM_DATETIME_AMPM) &&
346 (!strchr(ignore_separators, cur)) &&
347 (!strchr(mapping[idx].ignore_sep, cur)))
348 separator[len++] = cur;
349 if (sep_lookup) sep_parsing = EINA_TRUE;
350 sep_lookup = EINA_FALSE;
354 //TIZEN_ONLY(20151216) - swap format locations to support some locale.
359 time_fmt_count = location - ELM_DATETIME_HOUR;
360 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
362 field = sd->field_list + idx;
363 /* ignore the fields already disabled
364 * valid formats, means already ignore. */
365 if (field->location == -1) continue;
366 if (idx < ELM_DATETIME_HOUR)
367 field->location -= time_fmt_count;
369 field->location += ELM_DATETIME_HOUR;
374 // return the number of valid fields parsed.
378 // TIZEN_ONLY(20151218): Support Mobile UX
380 _notify_format_change(Evas_Object *obj)
382 Datetime_Field *field;
383 unsigned int idx = 0;
385 ELM_DATETIME_DATA_GET(obj, sd);
387 if (!dt_mod || !dt_mod->field_format_changed) return;
389 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
391 field = sd->field_list + idx;
393 dt_mod->field_format_changed(sd->mod_data, field->item_obj);
399 _reload_format(Evas_Object *obj)
401 unsigned int idx, field_count;
402 Datetime_Field *field;
403 char buf[BUFFER_SIZE];
406 ELM_DATETIME_DATA_GET(obj, sd);
407 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
409 // FIXME: provide nl_langinfo on Windows if possible
410 // fetch the default format from Libc.
411 if (!sd->user_format)
412 #if defined(HAVE_LANGINFO_H) || defined (HAVE_EVIL)
413 strncpy(sd->format, nl_langinfo(D_T_FMT), ELM_DATETIME_MAX_FORMAT_LEN);
415 strncpy(sd->format, "", ELM_DATETIME_MAX_FORMAT_LEN);
417 sd->format[ELM_DATETIME_MAX_FORMAT_LEN - 1] = '\0';
419 dt_fmt = (char *)malloc(ELM_DATETIME_MAX_FORMAT_LEN);
422 strncpy(dt_fmt, sd->format, ELM_DATETIME_MAX_FORMAT_LEN);
424 _expand_format(dt_fmt);
426 // reset all the fields to disable state
427 sd->enabled_field_count = 0;
428 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
430 field = sd->field_list + idx;
431 field->fmt_exist = EINA_FALSE;
432 field->location = -1;
435 field_count = _parse_format(obj, dt_fmt);
438 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
440 field = sd->field_list + idx;
441 if (field->fmt_exist && field->visible)
442 sd->enabled_field_count++;
445 // assign locations to disabled fields for uniform usage
446 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
448 field = sd->field_list + idx;
449 if (field->location == -1) field->location = field_count++;
451 if (field->fmt_exist && field->visible)
453 snprintf(buf, sizeof(buf), EDC_PART_FIELD_ENABLE_SIG_STR,
455 elm_layout_signal_emit(obj, buf, "elm");
459 snprintf(buf, sizeof(buf), EDC_PART_FIELD_DISABLE_SIG_STR,
461 elm_layout_signal_emit(obj, buf, "elm");
464 (buf, sizeof(buf), EDC_PART_SEPARATOR_STR, (field->location + 1));
465 elm_layout_text_set(obj, buf, field->separator);
468 edje_object_message_signal_process(wd->resize_obj);
469 _field_list_arrange(obj);
471 //TIZEN_ONLY(20151218): Support Mobile UX
472 _notify_format_change(obj);
476 EOLIAN static Eina_Bool
477 _elm_datetime_elm_widget_translate(Eo *obj, Elm_Datetime_Data *sd)
479 if (!sd->user_format) _reload_format(obj);
480 else _field_list_display(obj);
482 eo_do_super(obj, MY_CLASS, elm_obj_widget_translate());
488 _datetime_items_get(const Evas_Object *obj)
490 Eina_List *items = NULL;
491 Datetime_Field *field;
493 //TIZEN_ONLY(20170818): Prevent Null pointer ref.
494 Datetime_Field *sorted_fields[ELM_DATETIME_TYPE_COUNT] = {0};
495 //Datetime_Field *sorted_fields[ELM_DATETIME_TYPE_COUNT];
498 ELM_DATETIME_DATA_GET(obj, sd);
500 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
502 field = sd->field_list + idx;
503 sorted_fields[field->location] = field;
506 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
508 field = sorted_fields[idx];
509 //TIZEN_ONLY(20170818): Prevent Null pointer ref.
510 if (!field) continue;
512 if (field->fmt_exist && field->visible)
513 items = eina_list_append(items, field->item_obj);
517 if (_elm_config->access_mode == ELM_ACCESS_MODE_ON)
518 items = eina_list_append(items, sd->access_obj);
523 EOLIAN static Eina_Bool
524 _elm_datetime_elm_widget_focus_next_manager_is(Eo *obj EINA_UNUSED, Elm_Datetime_Data *_pd EINA_UNUSED)
529 EOLIAN static Eina_Bool
530 _elm_datetime_elm_widget_focus_next(Eo *obj, Elm_Datetime_Data *_pd EINA_UNUSED, Elm_Focus_Direction dir, Evas_Object **next, Elm_Object_Item **next_item)
532 const Eina_List *items;
533 Eina_List *(*list_free)(Eina_List *list);
534 void *(*list_data_get)(const Eina_List *list);
538 if ((items = elm_widget_focus_custom_chain_get(obj)))
540 list_data_get = eina_list_data_get;
545 items = _datetime_items_get(obj);
546 list_data_get = eina_list_data_get;
547 list_free = eina_list_free;
548 if (!items) return EINA_FALSE;
551 int_ret = elm_widget_focus_list_next_get(obj, items, list_data_get, dir, next, next_item);
552 if (list_free) list_free((Eina_List *)items);
557 EOLIAN static Eina_Bool
558 _elm_datetime_elm_widget_on_focus(Eo *obj, Elm_Datetime_Data *sd, Elm_Object_Item *item EINA_UNUSED)
560 Eina_Bool int_ret = EINA_FALSE;
562 eo_do_super(obj, MY_CLASS, int_ret = elm_obj_widget_on_focus(NULL));
563 if (!int_ret) return EINA_FALSE;
565 if (!elm_widget_focus_get(obj))
567 if ((dt_mod) && (dt_mod->obj_hide))
568 dt_mod->obj_hide(sd->mod_data);
574 EOLIAN static Eina_Bool
575 _elm_datetime_elm_widget_disable(Eo *obj, Elm_Datetime_Data *sd)
577 Datetime_Field *field;
578 unsigned int idx = 0;
579 Eina_Bool int_ret = EINA_FALSE;
581 eo_do_super(obj, MY_CLASS, int_ret = elm_obj_widget_disable());
582 if (!int_ret) return EINA_FALSE;
584 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
586 field = sd->field_list + idx;
587 elm_object_disabled_set(field->item_obj, elm_object_disabled_get(obj));
593 _elm_datetime_elm_layout_sizing_eval(Eo *obj, Elm_Datetime_Data *sd)
595 Evas_Coord minw = -1, minh = -1;
597 if (sd->freeze_sizing) return;
599 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
601 if (sd->enabled_field_count)
602 elm_coords_finger_size_adjust(sd->enabled_field_count, &minw, 1, &minh);
604 edje_object_size_min_restricted_calc
605 (wd->resize_obj, &minw, &minh, minw, minh);
606 evas_object_size_hint_min_set(obj, minw, minh);
607 evas_object_size_hint_max_set(obj, -1, -1);
610 EOLIAN static Elm_Theme_Apply
611 _elm_datetime_elm_widget_theme_apply(Eo *obj, Elm_Datetime_Data *sd)
613 Elm_Theme_Apply int_ret = ELM_THEME_APPLY_FAILED;
615 Datetime_Field *field;
616 char buf[BUFFER_SIZE];
619 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, ELM_THEME_APPLY_FAILED);
621 eo_do_super(obj, MY_CLASS, int_ret = elm_obj_widget_theme_apply());
622 if (!int_ret) return ELM_THEME_APPLY_FAILED;
624 if ((!dt_mod) || (!dt_mod->field_value_display)) return int_ret;
626 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
628 field = sd->field_list + idx;
629 if (field->fmt_exist && field->visible)
631 snprintf(buf, sizeof(buf), EDC_PART_FIELD_ENABLE_SIG_STR,
633 elm_layout_signal_emit(obj, buf, "elm");
636 (buf, sizeof(buf), EDC_PART_SEPARATOR_STR, field->location);
637 elm_layout_text_set(obj, buf, field->separator);
639 dt_mod->field_value_display(sd->mod_data, field->item_obj);
643 snprintf(buf, sizeof(buf), EDC_PART_FIELD_DISABLE_SIG_STR,
645 elm_layout_signal_emit(obj, buf, "elm");
649 edje_object_message_signal_process(wd->resize_obj);
650 elm_layout_sizing_eval(obj);
655 //TIZEN_ONLY(20170807): Apply UI Mirroring for Tizen 4.0 UX
656 EOLIAN static Eina_Bool
657 _elm_datetime_elm_widget_mirrored_get(Eo *obj EINA_UNUSED, Elm_Datetime_Data *sd EINA_UNUSED)
663 _elm_datetime_elm_widget_mirrored_set(Eo *obj EINA_UNUSED, Elm_Datetime_Data *sd EINA_UNUSED, Eina_Bool mirrored EINA_UNUSED)
670 _max_days_get(int year,
678 localtime_r(&t, &time1);
679 time1.tm_year = year;
680 time1.tm_mon = month;
681 for (day = MIN_DAYS_IN_MONTH; day <= mapping[ELM_DATETIME_DATE].def_max;
686 /* To restrict month wrapping because of summer time in some locales,
687 * ignore day light saving mode in mktime(). */
689 if (time1.tm_mday == 1) break;
697 _date_cmp(const struct tm *time1,
698 const struct tm *time2)
702 const DATETIME_TM_ARRAY(timearr1, time1);
703 const DATETIME_TM_ARRAY(timearr2, time2);
705 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
707 if (*timearr1[idx] != *timearr2[idx])
715 _field_cmp(Elm_Datetime_Field_Type field_type,
719 DATETIME_TM_ARRAY(timearr1, time1);
720 DATETIME_TM_ARRAY(timearr2, time2);
722 if (*timearr1[field_type] != *timearr2[field_type])
728 // validates curr_time/min_limt/max_limit according to the newly set value
730 _validate_datetime_limits(struct tm *time1,
737 if (!time1 || !time2) return;
739 t1 = (swap) ? time2 : time1;
740 t2 = (swap) ? time1 : time2;
742 DATETIME_TM_ARRAY(timearr1, time1);
743 DATETIME_TM_ARRAY(timearr2, time2);
744 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT - 1; idx++)
746 if (*timearr1[idx] < *timearr2[idx])
748 memcpy(t1, t2, sizeof(struct tm));
751 else if (*timearr1[idx] > *timearr2[idx])
757 _apply_field_limits(Evas_Object *obj)
759 Datetime_Field *field;
760 unsigned int idx = 0;
763 ELM_DATETIME_DATA_GET(obj, sd);
765 DATETIME_TM_ARRAY(timearr, &sd->curr_time);
766 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT - 1; idx++)
768 field = sd->field_list + idx;
770 if (val < field->min)
771 *timearr[idx] = field->min;
772 else if (val > field->max)
773 *timearr[idx] = field->max;
776 _field_list_display(obj);
780 _apply_range_restrictions(struct tm *tim)
787 DATETIME_TM_ARRAY(timearr, tim);
788 for (idx = ELM_DATETIME_MONTH; idx < ELM_DATETIME_TYPE_COUNT - 1; idx++)
791 min = mapping[idx].def_min;
792 max = mapping[idx].def_max;
793 if (idx == ELM_DATETIME_DATE)
794 max = _max_days_get(tim->tm_year, tim->tm_mon);
803 _field_format_get(Evas_Object *obj,
804 Elm_Datetime_Field_Type field_type)
806 Datetime_Field *field;
808 if (field_type > ELM_DATETIME_AMPM) return NULL;
810 ELM_DATETIME_DATA_GET(obj, sd);
812 field = sd->field_list + field_type;
818 _field_limit_get(Evas_Object *obj,
819 Elm_Datetime_Field_Type field_type,
823 int min, max, max_days;
824 Datetime_Field *field;
827 if (field_type > ELM_DATETIME_MINUTE) return;
829 ELM_DATETIME_DATA_GET(obj, sd);
831 field = sd->field_list + field_type;
836 DATETIME_TM_ARRAY(curr_timearr, &sd->curr_time);
837 DATETIME_TM_ARRAY(min_timearr, &sd->min_limit);
838 DATETIME_TM_ARRAY(max_timearr, &sd->max_limit);
840 for (idx = 0; idx < field->type; idx++)
841 if (*curr_timearr[idx] > *min_timearr[idx]) break;
842 if ((idx == field_type) && (min < *min_timearr[field_type]))
843 min = *min_timearr[field_type];
844 if (field_type == ELM_DATETIME_DATE)
846 max_days = _max_days_get(sd->curr_time.tm_year, sd->curr_time.tm_mon);
847 if (max > max_days) max = max_days;
849 for (idx = 0; idx < field->type; idx++)
850 if (*curr_timearr[idx] < *max_timearr[idx]) break;
851 if ((idx == field_type) && (max > *max_timearr[field_type]))
852 max = *max_timearr[field_type];
858 //TIZEN_ONLY(20151218): Support Mobile UX
860 _field_location_get(Evas_Object *obj, Elm_Datetime_Field_Type field_type,
863 Datetime_Field *field;
865 ELM_DATETIME_DATA_GET(obj, sd);
867 field = sd->field_list + field_type;
868 if (!field) return EINA_FALSE;
870 if (loc) *loc = field->location;
872 return (field->fmt_exist && field->visible);
876 _fields_sorted_get(Evas_Object *obj)
878 Eina_List *items = NULL;
879 Datetime_Field *field;
881 Datetime_Field *sorted_fields[ELM_DATETIME_TYPE_COUNT];
883 ELM_DATETIME_DATA_GET(obj, sd);
885 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
887 field = sd->field_list + idx;
888 sorted_fields[field->location] = field;
891 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
893 field = sorted_fields[idx];
894 if (field->fmt_exist && field->visible)
895 items = eina_list_append(items, field->item_obj);
903 _field_list_init(Evas_Object *obj)
905 Datetime_Field *field;
909 ELM_DATETIME_DATA_GET(obj, sd);
912 localtime_r(&t, &sd->curr_time);
914 mapping[ELM_DATETIME_YEAR].def_min = _elm_config->year_min;
915 mapping[ELM_DATETIME_YEAR].def_max = _elm_config->year_max;
916 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
918 field = sd->field_list + idx;
919 field->type = ELM_DATETIME_YEAR + idx;
921 field->fmt_exist = EINA_FALSE;
922 field->visible = EINA_TRUE;
923 field->min = mapping[idx].def_min;
924 field->max = mapping[idx].def_max;
926 DATETIME_TM_ARRAY(min_timearr, &sd->min_limit);
927 DATETIME_TM_ARRAY(max_timearr, &sd->max_limit);
928 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT - 1; idx++)
930 *min_timearr[idx] = mapping[idx].def_min;
931 *max_timearr[idx] = mapping[idx].def_max;
936 _access_info_cb(void *data, Evas_Object *obj EINA_UNUSED)
940 buf = eina_strbuf_new();
942 ELM_DATETIME_DATA_GET(data, sd);
943 eina_strbuf_append_printf(buf,
944 "%d year, %d month, %d date, %d hour, %d minute",
945 sd->curr_time.tm_year, sd->curr_time.tm_mon + 1,
946 sd->curr_time.tm_mday, sd->curr_time.tm_hour,
947 sd->curr_time.tm_min);
949 ret = eina_strbuf_string_steal(buf);
950 eina_strbuf_free(buf);
955 _elm_datetime_evas_object_smart_add(Eo *obj, Elm_Datetime_Data *priv)
957 Datetime_Field *field;
960 eo_do_super(obj, MY_CLASS, evas_obj_smart_add());
961 elm_widget_sub_object_parent_add(obj);
963 /* TIZEN_ONLY(20180111): elm_widget_can_focus_set before module init for support TV UX */
964 elm_widget_can_focus_set(obj, EINA_TRUE);
967 // module - initialise module for datetime
968 if (!dt_mod) dt_mod = _dt_mod_init();
971 if (dt_mod->obj_hook)
973 priv->mod_data = dt_mod->obj_hook(obj);
975 // update module data
978 priv->mod_data->base = obj;
979 priv->mod_data->field_limit_get = _field_limit_get;
980 priv->mod_data->field_format_get = _field_format_get;
981 //TIZEN_ONLY(20151218): Support Mobile UX
982 priv->mod_data->field_location_get = _field_location_get;
983 priv->mod_data->fields_sorted_get = _fields_sorted_get;
988 if (dt_mod->field_create)
990 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
992 field = priv->field_list + idx;
993 field->item_obj = dt_mod->field_create(priv->mod_data, idx);
994 /* TIZEN_ONLY(20161031): apply color_class parent-child relationship to all widgets */
995 _elm_widget_color_class_parent_set(field->item_obj, obj);
1001 priv->freeze_sizing = EINA_TRUE;
1002 if (!elm_layout_theme_set(obj, "datetime", "base",
1003 elm_widget_style_get(obj)))
1004 CRI("Failed to set layout!");
1006 _field_list_init(obj);
1007 _reload_format(obj);
1009 /* TIZEN_ONLY(20180111): elm_widget_can_focus_set before module init for support TV UX */
1010 //elm_widget_can_focus_set(obj, EINA_TRUE);
1013 priv->freeze_sizing = EINA_FALSE;
1014 elm_layout_sizing_eval(obj);
1017 if (_elm_config->access_mode == ELM_ACCESS_MODE_ON)
1019 Elm_Access_Info *ai;
1021 priv->access_obj = _elm_access_edje_object_part_object_register
1022 (obj, elm_layout_edje_get(obj), "elm.access");
1023 if (!priv->access_obj)
1024 priv->access_obj = _elm_access_edje_object_part_object_register
1025 (obj, elm_layout_edje_get(obj), "access");
1027 ai = _elm_access_info_get(priv->access_obj);
1028 _elm_access_text_set(ai, ELM_ACCESS_TYPE, "date time");
1029 _elm_access_callback_set(ai, ELM_ACCESS_INFO, _access_info_cb, obj);
1034 _elm_datetime_evas_object_smart_del(Eo *obj, Elm_Datetime_Data *sd)
1036 Datetime_Field *tmp;
1039 for (idx = 0; idx < ELM_DATETIME_TYPE_COUNT; idx++)
1041 tmp = sd->field_list + idx;
1042 evas_object_del(tmp->item_obj);
1043 eina_stringshare_del(tmp->separator);
1046 if ((dt_mod) && (dt_mod->obj_unhook))
1047 dt_mod->obj_unhook(sd->mod_data); // module - unhook
1049 eo_do_super(obj, MY_CLASS, evas_obj_smart_del());
1053 elm_datetime_add(Evas_Object *parent)
1055 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
1056 Evas_Object *obj = eo_add(MY_CLASS, parent);
1061 _elm_datetime_eo_base_constructor(Eo *obj, Elm_Datetime_Data *_pd EINA_UNUSED)
1063 obj = eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
1065 evas_obj_type_set(MY_CLASS_NAME_LEGACY),
1066 evas_obj_smart_callbacks_descriptions_set(_smart_callbacks),
1067 elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_DATE_EDITOR));
1072 EOLIAN static const char*
1073 _elm_datetime_format_get(Eo *obj EINA_UNUSED, Elm_Datetime_Data *sd)
1079 _elm_datetime_format_set(Eo *obj, Elm_Datetime_Data *sd, const char *fmt)
1083 strncpy(sd->format, fmt, ELM_DATETIME_MAX_FORMAT_LEN);
1084 sd->format[ELM_DATETIME_MAX_FORMAT_LEN - 1] = '\0';
1085 sd->user_format = EINA_TRUE;
1087 else sd->user_format = EINA_FALSE;
1089 _reload_format(obj);
1092 EOLIAN static Eina_Bool
1093 _elm_datetime_field_visible_get(const Eo *obj EINA_UNUSED, Elm_Datetime_Data *sd, Elm_Datetime_Field_Type fieldtype)
1095 Datetime_Field *field;
1097 if (fieldtype > ELM_DATETIME_AMPM) return EINA_FALSE;
1099 field = sd->field_list + fieldtype;
1101 return field->visible;
1105 _elm_datetime_field_visible_set(Eo *obj, Elm_Datetime_Data *sd, Elm_Datetime_Field_Type fieldtype, Eina_Bool visible)
1107 char buf[BUFFER_SIZE];
1108 Datetime_Field *field;
1110 if (fieldtype > ELM_DATETIME_AMPM) return;
1112 field = sd->field_list + fieldtype;
1113 visible = !!visible;
1114 if (field->visible == visible) return;
1116 field->visible = visible;
1118 sd->freeze_sizing = EINA_TRUE;
1121 sd->enabled_field_count++;
1123 if (!field->fmt_exist) return;
1125 snprintf(buf, sizeof(buf), EDC_PART_FIELD_ENABLE_SIG_STR,
1127 elm_layout_signal_emit(obj, buf, "elm");
1129 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
1130 edje_object_message_signal_process(wd->resize_obj);
1132 snprintf(buf, sizeof(buf), EDC_PART_FIELD_STR, field->location);
1133 elm_layout_content_unset(obj, buf);
1134 elm_layout_content_set(obj, buf, field->item_obj);
1138 sd->enabled_field_count--;
1140 if (!field->fmt_exist) return;
1142 snprintf(buf, sizeof(buf), EDC_PART_FIELD_DISABLE_SIG_STR,
1144 elm_layout_signal_emit(obj, buf, "elm");
1146 ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
1147 edje_object_message_signal_process(wd->resize_obj);
1149 snprintf(buf, sizeof(buf), EDC_PART_FIELD_STR, field->location);
1150 evas_object_hide(elm_layout_content_unset(obj, buf));
1152 sd->freeze_sizing = EINA_FALSE;
1154 elm_layout_sizing_eval(obj);
1156 if (!visible) return;
1157 if (!dt_mod || !dt_mod->field_value_display) return;
1159 dt_mod->field_value_display(sd->mod_data, field->item_obj);
1163 _elm_datetime_field_limit_get(const Eo *obj EINA_UNUSED, Elm_Datetime_Data *sd, Elm_Datetime_Field_Type fieldtype, int *min, int *max)
1165 Datetime_Field *field;
1167 if (fieldtype >= ELM_DATETIME_AMPM) return;
1169 field = sd->field_list + fieldtype;
1170 if (min) *min = field->min;
1171 if (max) *max = field->max;
1175 _elm_datetime_field_limit_set(Eo *obj, Elm_Datetime_Data *sd, Elm_Datetime_Field_Type fieldtype, int min, int max)
1177 Datetime_Field *field;
1180 if (fieldtype >= ELM_DATETIME_AMPM) return;
1182 if (min > max) return;
1184 old_time = sd->curr_time;
1185 field = sd->field_list + fieldtype;
1186 if (((min >= mapping[fieldtype].def_min) &&
1187 (min <= mapping[fieldtype].def_max)) ||
1188 (field->type == ELM_DATETIME_YEAR))
1190 if (((max >= mapping[fieldtype].def_min) &&
1191 (max <= mapping[fieldtype].def_max)) ||
1192 (field->type == ELM_DATETIME_YEAR))
1195 _apply_field_limits(obj);
1197 if (!_field_cmp(fieldtype, &old_time, &sd->curr_time))
1198 eo_do(obj, eo_event_callback_call(ELM_DATETIME_EVENT_CHANGED, NULL));
1202 EOLIAN static Eina_Bool
1203 _elm_datetime_value_get(const Eo *obj EINA_UNUSED, Elm_Datetime_Data *sd, struct tm *currtime)
1205 EINA_SAFETY_ON_NULL_RETURN_VAL(currtime, EINA_FALSE);
1207 *currtime = sd->curr_time;
1211 EOLIAN static Eina_Bool
1212 _elm_datetime_value_set(Eo *obj, Elm_Datetime_Data *sd, const struct tm *newtime)
1214 EINA_SAFETY_ON_NULL_RETURN_VAL(newtime, EINA_FALSE);
1216 if (_date_cmp(&sd->curr_time, newtime)) return EINA_TRUE;
1217 sd->curr_time = *newtime;
1218 // apply default field restrictions for curr_time
1219 _apply_range_restrictions(&sd->curr_time);
1220 // validate the curr_time according to the min_limt and max_limt
1221 _validate_datetime_limits(&sd->curr_time, &sd->min_limit, EINA_FALSE);
1222 _validate_datetime_limits(&sd->max_limit, &sd->curr_time, EINA_TRUE);
1223 _apply_field_limits(obj);
1225 eo_do(obj, eo_event_callback_call(ELM_DATETIME_EVENT_CHANGED, NULL));
1230 EOLIAN static Eina_Bool
1231 _elm_datetime_value_min_get(const Eo *obj EINA_UNUSED, Elm_Datetime_Data *sd, struct tm *mintime)
1233 EINA_SAFETY_ON_NULL_RETURN_VAL(mintime, EINA_FALSE);
1235 *mintime = sd->min_limit;
1239 EOLIAN static Eina_Bool
1240 _elm_datetime_value_min_set(Eo *obj, Elm_Datetime_Data *sd, const struct tm *mintime)
1244 EINA_SAFETY_ON_NULL_RETURN_VAL(mintime, EINA_FALSE);
1246 if (_date_cmp(&sd->min_limit, mintime)) return EINA_TRUE;
1247 sd->min_limit = *mintime;
1248 old_time = sd->curr_time;
1249 // apply default field restrictions for min_limit
1250 _apply_range_restrictions(&sd->min_limit);
1251 // validate curr_time and max_limt according to the min_limit
1252 _validate_datetime_limits(&sd->max_limit, &sd->min_limit, EINA_FALSE);
1253 _validate_datetime_limits(&sd->curr_time, &sd->min_limit, EINA_FALSE);
1254 _apply_field_limits(obj);
1256 if (!_date_cmp(&old_time, &sd->curr_time))
1257 eo_do(obj, eo_event_callback_call(ELM_DATETIME_EVENT_CHANGED, NULL));
1262 EOLIAN static Eina_Bool
1263 _elm_datetime_value_max_get(const Eo *obj EINA_UNUSED, Elm_Datetime_Data *sd, struct tm *maxtime)
1265 EINA_SAFETY_ON_NULL_RETURN_VAL(maxtime, EINA_FALSE);
1267 *maxtime = sd->max_limit;
1271 EOLIAN static Eina_Bool
1272 _elm_datetime_value_max_set(Eo *obj, Elm_Datetime_Data *sd, const struct tm *maxtime)
1276 EINA_SAFETY_ON_NULL_RETURN_VAL(maxtime, EINA_FALSE);
1278 if (_date_cmp(&sd->max_limit, maxtime)) return EINA_TRUE;
1279 sd->max_limit = *maxtime;
1280 old_time = sd->curr_time;
1281 // apply default field restrictions for max_limit
1282 _apply_range_restrictions(&sd->max_limit);
1283 // validate curr_time and min_limt according to the max_limit
1284 _validate_datetime_limits(&sd->max_limit, &sd->min_limit, EINA_TRUE);
1285 _validate_datetime_limits(&sd->max_limit, &sd->curr_time, EINA_TRUE);
1286 _apply_field_limits(obj);
1288 if (!_date_cmp(&old_time, &sd->curr_time))
1289 eo_do(obj, eo_event_callback_call(ELM_DATETIME_EVENT_CHANGED, NULL));
1295 _elm_datetime_class_constructor(Eo_Class *klass)
1297 evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
1300 #include "elm_datetime.eo.c"