[datetime_popup] Fix value min, max does not be set when text is set by entry.
[framework/uifw/elementary.git] / src / modules / datetime_input_popup / datetime_input_popup.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 #define DATETIME_FIELD_COUNT            6
5 #define BUFF_SIZE                       1024
6 #define MONTH_STRING_MAX_SIZE           32
7 #define TOTAL_NUMBER_OF_MONTHS          12
8 #define STRUCT_TM_YEAR_BASE_VALUE       1900
9 #define STRUCT_TM_TIME_12HRS_MAX_VALUE  12
10 #define STRUCT_TM_TIME_24HRS_MAX_VALUE  23
11 #define PICKER_POPUP_FIELD_COUNT        3
12
13 /* struct tm does not define the fields in the order year, month,
14  * date, hour, minute. values are reassigned to an array for easy
15  * handling.
16  */
17 #define DATETIME_MODULE_TM_ARRAY(intptr, tmptr) \
18   int *intptr[] = {                             \
19      &(tmptr)->tm_year,                         \
20      &(tmptr)->tm_mon,                          \
21      &(tmptr)->tm_mday,                         \
22      &(tmptr)->tm_hour,                         \
23      &(tmptr)->tm_min}
24
25 static const char *field_styles[] = {
26                          "year", "month", "date", "hour", "minute", "ampm" };
27
28 static char month_arr[TOTAL_NUMBER_OF_MONTHS][MONTH_STRING_MAX_SIZE];
29
30 static const char SIG_EDIT_START[] = "edit,start";
31 static const char SIG_EDIT_END[] = "edit,end";
32 static const char SIG_PICKER_VALUE_SET[] = "picker,value,set";
33
34 typedef struct _Popup_Module_Data Popup_Module_Data;
35
36 struct _Popup_Module_Data
37 {
38    Elm_Datetime_Module_Data mod_data;
39    Evas_Object *popup;
40    Evas_Object *datepicker_layout, *timepicker_layout;
41    Evas_Object *popup_field[DATETIME_FIELD_COUNT];
42    int field_location[PICKER_POPUP_FIELD_COUNT];
43    Evas_Object *datetime_field[DATETIME_FIELD_COUNT];
44    struct tm set_time;
45    Eina_Bool time_12hr_fmt;
46    Eina_Bool is_pm;
47    Eina_Bool weekday_show;
48    Eina_Bool weekday_loc_first;
49 };
50
51 EAPI void field_value_display(Elm_Datetime_Module_Data *module_data, Evas_Object *obj);
52
53 static int
54 _picker_nextfield_location_get(void *data, int curr)
55 {
56    int idx, next_idx;
57    Popup_Module_Data *popup_mod;
58    popup_mod = (Popup_Module_Data *)data;
59    if (!popup_mod) return ELM_DATETIME_LAST;
60
61    for (idx = 0; idx < PICKER_POPUP_FIELD_COUNT; idx++)
62      if (popup_mod->field_location[idx] == curr) break;
63    if (idx < ELM_DATETIME_DATE)
64      {
65         next_idx = popup_mod->field_location[++idx];
66         return next_idx;
67      }
68    else return ELM_DATETIME_LAST;
69 }
70
71 static int
72 _picker_field_location_get(void *data, int curr)
73 {
74    int idx;
75    Popup_Module_Data *popup_mod;
76    popup_mod = (Popup_Module_Data *)data;
77    if (!popup_mod) return ELM_DATETIME_LAST;
78
79    for (idx = 0; idx < PICKER_POPUP_FIELD_COUNT; idx++)
80      if (popup_mod->field_location[idx] == curr) break;
81
82    return idx;
83 }
84
85 static void
86 _picker_hide_cb(void *data,
87                 Evas_Object *obj __UNUSED__,
88                 const char *emission __UNUSED__,
89                 const char *source __UNUSED__)
90 {
91    Popup_Module_Data *popup_mod;
92    popup_mod = (Popup_Module_Data *)data;
93    if (!popup_mod) return;
94
95    evas_object_smart_callback_call(obj, SIG_EDIT_END, NULL);
96    evas_object_hide(popup_mod->popup);
97 }
98
99 static void
100 _datetime_press_cb(void *data,
101                    Evas_Object *obj __UNUSED__,
102                    const char *emission __UNUSED__,
103                    const char *source)
104 {
105    Popup_Module_Data *popup_mod;
106    int idx;
107
108    popup_mod = (Popup_Module_Data *)data;
109    if (!popup_mod) return;
110
111    if (!strcmp(source, "date.picker.bg"))
112      {
113         for (idx = 0; idx <= ELM_DATETIME_DATE; idx++)
114            elm_object_signal_emit(popup_mod->datetime_field[idx], "elm,state,select", "elm");
115      }
116    else if (!strcmp(source, "time.picker.bg"))
117      {
118         for (idx = ELM_DATETIME_HOUR; idx < DATETIME_FIELD_COUNT; idx++)
119            elm_object_signal_emit(popup_mod->datetime_field[idx], "elm,state,select", "elm");
120      }
121 }
122
123 static void
124 _datetime_unpress_cb(void *data,
125                      Evas_Object *obj __UNUSED__,
126                      const char *emission __UNUSED__,
127                      const char *source)
128 {
129    Popup_Module_Data *popup_mod;
130    int idx;
131
132    popup_mod = (Popup_Module_Data *)data;
133    if (!popup_mod) return;
134
135    if (!strcmp(source, "date.picker.bg"))
136      {
137         for (idx = 0; idx <= ELM_DATETIME_DATE; idx++)
138            elm_object_signal_emit(popup_mod->datetime_field[idx], "elm,state,unselect", "elm");
139      }
140    else if (!strcmp(source, "time.picker.bg"))
141      {
142         for (idx = ELM_DATETIME_HOUR; idx < DATETIME_FIELD_COUNT; idx++)
143            elm_object_signal_emit(popup_mod->datetime_field[idx], "elm,state,unselect", "elm");
144      }
145 }
146
147 static void
148 _set_datepicker_value(Popup_Module_Data *popup_mod)
149 {
150    struct tm set_time;
151
152    if (!popup_mod) return;
153
154    elm_datetime_value_get(popup_mod->mod_data.base, &set_time);
155    set_time.tm_year = (int)elm_spinner_value_get(popup_mod->popup_field[ELM_DATETIME_YEAR]) - STRUCT_TM_YEAR_BASE_VALUE;
156    set_time.tm_mon = (int)elm_spinner_value_get(popup_mod->popup_field[ELM_DATETIME_MONTH]) - 1;
157    set_time.tm_mday = (int)elm_spinner_value_get(popup_mod->popup_field[ELM_DATETIME_DATE]);
158    elm_datetime_value_set(popup_mod->mod_data.base, &set_time);
159 }
160
161 static void
162 _set_timepicker_value(Popup_Module_Data *popup_mod)
163 {
164    struct tm set_time;
165    int hour;
166
167    if (!popup_mod) return;
168
169    elm_datetime_value_get(popup_mod->mod_data.base, &set_time);
170
171    hour = (int)elm_spinner_value_get(popup_mod->popup_field[ELM_DATETIME_HOUR]);
172    if (popup_mod->time_12hr_fmt)
173      {
174         if (popup_mod->is_pm)
175           hour += STRUCT_TM_TIME_12HRS_MAX_VALUE;
176         hour = (hour == STRUCT_TM_TIME_12HRS_MAX_VALUE) ? 0 : hour;
177         hour = (hour == 24) ? STRUCT_TM_TIME_12HRS_MAX_VALUE : hour;
178      }
179    set_time.tm_hour = hour;
180    set_time.tm_min = (int)elm_spinner_value_get(popup_mod->popup_field[ELM_DATETIME_MINUTE]);
181    elm_datetime_value_set(popup_mod->mod_data.base, &set_time);
182 }
183
184 static void
185 _popup_set_btn_clicked_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
186 {
187    Popup_Module_Data *popup_mod;
188    Evas_Object *content, *widget;
189    int idx = 0;
190    Evas_Object *spinner, *entry;
191
192    popup_mod = (Popup_Module_Data *)data;
193    if (!popup_mod) return;
194
195    widget = popup_mod->mod_data.base;
196    if (widget)
197      evas_object_smart_callback_call(widget, SIG_EDIT_END, NULL);
198
199    evas_object_hide(popup_mod->popup);
200    content = elm_object_content_get(popup_mod->popup);
201    if (content == popup_mod->datepicker_layout)
202      {
203         for (idx = 0; idx <= ELM_DATETIME_DATE; idx++)
204           {
205              spinner = popup_mod->popup_field[idx];
206              entry = elm_object_part_content_get(spinner, "elm.swallow.entry");
207              if (!entry) continue;
208              if (elm_object_focus_get(entry))
209                {
210                   elm_layout_signal_emit(spinner, "elm,action,entry,toggle", "elm");
211                   edje_object_message_signal_process(elm_layout_edje_get(spinner));
212                }
213           }
214         _set_datepicker_value(popup_mod);
215      }
216    else if (content == popup_mod->timepicker_layout)
217      {
218         for (idx = ELM_DATETIME_HOUR; idx < ELM_DATETIME_AMPM; idx++)
219           {
220              spinner = popup_mod->popup_field[idx];
221              entry = elm_object_part_content_get(spinner, "elm.swallow.entry");
222              if (!entry) continue;
223              if (elm_object_focus_get(entry))
224                {
225                   elm_layout_signal_emit(spinner, "elm,action,entry,toggle", "elm");
226                   edje_object_message_signal_process(elm_layout_edje_get(spinner));
227                }
228           }
229         _set_timepicker_value(popup_mod);
230      }
231
232    evas_object_smart_callback_call(popup_mod->mod_data.base, SIG_PICKER_VALUE_SET, NULL);
233 }
234
235 static void
236 _popup_cancel_btn_clicked_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
237 {
238    Popup_Module_Data *popup_mod;
239    Evas_Object *content, *widget;
240    int idx = 0;
241    Evas_Object *spinner, *entry;
242
243    popup_mod = (Popup_Module_Data *)data;
244    if (!popup_mod) return;
245
246    widget = popup_mod->mod_data.base;
247    if (widget)
248      evas_object_smart_callback_call(widget, SIG_EDIT_END, NULL);
249
250    evas_object_hide(popup_mod->popup);
251    content = elm_object_content_get(popup_mod->popup);
252    if (content == popup_mod->datepicker_layout)
253      {
254         for (idx = 0; idx <= ELM_DATETIME_DATE; idx++)
255           {
256              spinner = popup_mod->popup_field[idx];
257              entry = elm_object_part_content_get(spinner, "elm.swallow.entry");
258              if (!entry) continue;
259              if (elm_object_focus_get(entry))
260                {
261                   elm_layout_signal_emit(spinner, "elm,action,entry,toggle", "elm");
262                }
263           }
264      }
265    else if (content == popup_mod->timepicker_layout)
266      {
267         for (idx = ELM_DATETIME_HOUR; idx < ELM_DATETIME_AMPM; idx++)
268           {
269              spinner = popup_mod->popup_field[idx];
270              entry = elm_object_part_content_get(spinner, "elm.swallow.entry");
271              if (!entry) continue;
272              if (elm_object_focus_get(entry))
273                {
274                   elm_layout_signal_emit(spinner, "elm,action,entry,toggle", "elm");
275                }
276           }
277      }
278 }
279
280 static void
281 _picker_hide_cb(void *data,
282                    Evas_Object *obj __UNUSED__,
283                    const char *emission __UNUSED__,
284                    const char *source __UNUSED__)
285 {
286    Popup_Module_Data *popup_mod;
287    popup_mod = (Popup_Module_Data *)data;
288    if (!popup_mod) return;
289
290    evas_object_smart_callback_call(obj, SIG_EDIT_END, NULL);
291    evas_object_hide(popup_mod->popup);
292 }
293
294 static void
295 _entry_activated_cb(void *data, Evas_Object *obj, void *event_info __UNUSED__)
296 {
297    Popup_Module_Data *popup_mod;
298    Evas_Object *entry, *en;
299    int idx, next_idx;
300
301    popup_mod = (Popup_Module_Data *)data;
302    if (!popup_mod) return;
303
304    for (idx = 0; idx < PICKER_POPUP_FIELD_COUNT; idx++)
305      {
306         entry = elm_object_part_content_get(popup_mod->popup_field[idx], "elm.swallow.entry");
307         if (obj == entry)
308           {
309              next_idx = _picker_nextfield_location_get(popup_mod, idx);
310              if (next_idx != ELM_DATETIME_LAST)
311                elm_layout_signal_emit(popup_mod->popup_field[next_idx], "elm,action,entry,toggle", "elm");
312              return;
313           }
314      }
315    entry = elm_object_part_content_get(popup_mod->popup_field[ELM_DATETIME_HOUR], "elm.swallow.entry");
316    if (obj == entry)
317      {
318         en = elm_object_part_content_get(popup_mod->popup_field[ELM_DATETIME_MINUTE], "elm.swallow.entry");
319         elm_layout_signal_emit(popup_mod->popup_field[ELM_DATETIME_MINUTE],
320                                "elm,action,entry,toggle", "elm");
321      }
322 }
323
324 static void
325 _entry_clicked_cb(void *data, Evas_Object *obj, void *event_info __UNUSED__)
326 {
327    Popup_Module_Data *popup_mod;
328
329    popup_mod = (Popup_Module_Data *)data;
330    if (!popup_mod || !obj) return;
331 }
332
333 static void
334 _entry_focused_cb(void *data, Evas_Object *obj, void *event_info __UNUSED__)
335 {
336    Popup_Module_Data *popup_mod;
337    Evas_Object *entry;
338    int idx, value;
339
340    popup_mod = (Popup_Module_Data *)data;
341    if (!popup_mod) return;
342
343    entry = elm_object_part_content_get(popup_mod->popup_field[ELM_DATETIME_MONTH],
344                                        "elm.swallow.entry");
345    if (obj == entry)
346      {
347         value = (int)elm_spinner_value_get(popup_mod->popup_field[ELM_DATETIME_MONTH]) - 1;
348         elm_object_text_set(obj, month_arr[value]);
349      }
350    for (idx = 0; idx < DATETIME_FIELD_COUNT -1; idx++)
351      {
352         entry = elm_object_part_content_get(popup_mod->popup_field[idx], "elm.swallow.entry");
353         if ((obj != entry) && elm_object_focus_get(entry))
354           {
355              elm_layout_signal_emit(popup_mod->popup_field[idx],
356                                     "elm,action,entry,toggle", "elm");
357              return;
358           }
359      }
360 }
361
362 static void
363 _entry_unfocused_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
364 {
365    Popup_Module_Data *popup_mod;
366
367    popup_mod = (Popup_Module_Data *)data;
368    if (!popup_mod) return;
369
370    // TODO: entry_unfocused code
371 }
372
373 void
374 _set_datepicker_popup_title_text(Popup_Module_Data *popup_mod)
375 {
376    struct tm set_time;
377    time_t t;
378    char weekday[BUFF_SIZE];
379    if (!popup_mod) return;
380
381    t = time(NULL);
382    localtime_r(&t, &set_time);
383    set_time.tm_year = (popup_mod->set_time).tm_year;
384    set_time.tm_mon = (popup_mod->set_time).tm_mon;
385    set_time.tm_mday = (popup_mod->set_time).tm_mday;
386    /* FIXME: To restrict month wrapping because of summer time in some locales,
387     * ignore day light saving mode in mktime(). */
388    set_time.tm_isdst = -1;
389    mktime(&set_time);
390    strftime(weekday, BUFF_SIZE, "%a", &set_time);
391    elm_object_part_text_set(popup_mod->popup, "elm.text.title2", weekday);
392
393    elm_object_domain_translatable_part_text_set(popup_mod->popup, "title,text", PACKAGE, E_("Set date"));
394 }
395
396 void
397 _set_timepicker_popup_title_text(Popup_Module_Data *popup_mod)
398 {
399    if (!popup_mod) return;
400
401    elm_object_domain_translatable_part_text_set(popup_mod->popup, "title,text", PACKAGE, E_("Set time"));
402    elm_object_part_text_set(popup_mod->popup, "elm.text.title2", "");
403 }
404
405 static void
406 _set_ampm_value(Popup_Module_Data *popup_mod)
407 {
408    char ampm_str[BUFF_SIZE] = {0,};
409    const char *fmt = NULL;
410
411    if (!popup_mod || !popup_mod->time_12hr_fmt) return;
412
413    fmt = popup_mod->mod_data.field_format_get(popup_mod->mod_data.base,
414                                               ELM_DATETIME_AMPM);
415    strftime(ampm_str, BUFF_SIZE, fmt, &(popup_mod->set_time));
416    if (ampm_str[0])
417      elm_object_text_set(popup_mod->popup_field[ELM_DATETIME_AMPM], ampm_str);
418    else if (popup_mod->set_time.tm_hour < STRUCT_TM_TIME_12HRS_MAX_VALUE)
419      elm_object_domain_translatable_text_set(popup_mod->popup_field[ELM_DATETIME_AMPM],
420                                              PACKAGE, E_("AM"));
421    else
422      elm_object_domain_translatable_text_set(popup_mod->popup_field[ELM_DATETIME_AMPM],
423                                              PACKAGE, E_("PM"));
424 }
425
426 static void
427 _datepicker_value_changed_cb(void *data, Evas_Object *obj, void *event_info __UNUSED__)
428 {
429    Popup_Module_Data *popup_mod;
430    struct tm min_values, max_values;
431    int idx, field_idx, min, max;
432
433    popup_mod = (Popup_Module_Data *)data;
434    if (!popup_mod) return;
435
436    for (idx = 0; idx < DATETIME_FIELD_COUNT; idx++)
437      if ((obj == popup_mod->popup_field[idx])) break;
438
439    if (idx > ELM_DATETIME_DATE) return;
440
441    field_idx = idx;
442    DATETIME_MODULE_TM_ARRAY(set_val_arr, &popup_mod->set_time);
443    if (field_idx == ELM_DATETIME_YEAR)
444      *set_val_arr[field_idx] = (int)elm_spinner_value_get(obj) - STRUCT_TM_YEAR_BASE_VALUE;
445    else if (field_idx == ELM_DATETIME_MONTH)
446      *set_val_arr[field_idx] = (int)elm_spinner_value_get(obj) - 1;
447    else
448      *set_val_arr[field_idx] = (int)elm_spinner_value_get(obj);
449
450    elm_datetime_value_set(popup_mod->mod_data.base, &(popup_mod->set_time));
451
452    popup_mod->mod_data.fields_min_max_get(popup_mod->mod_data.base,
453                        &(popup_mod->set_time), &min_values, &max_values);
454
455    DATETIME_MODULE_TM_ARRAY(min_val_arr, &min_values);
456    DATETIME_MODULE_TM_ARRAY(max_val_arr, &max_values);
457
458    for (idx = field_idx; idx <= ELM_DATETIME_DATE; idx++)
459      {
460         min = *min_val_arr[idx];
461         max = *max_val_arr[idx];
462         if (idx == ELM_DATETIME_YEAR)
463           {
464              min += STRUCT_TM_YEAR_BASE_VALUE;
465              max += STRUCT_TM_YEAR_BASE_VALUE;
466           }
467         else if (idx == ELM_DATETIME_MONTH)
468           {
469              min += 1;
470              max += 1;
471           }
472         elm_spinner_min_max_set(popup_mod->popup_field[idx], min, max);
473      }
474    for (idx = field_idx; idx <= ELM_DATETIME_DATE; idx++)
475      {
476         if (idx == ELM_DATETIME_YEAR)
477           *set_val_arr[idx] = (int)elm_spinner_value_get(popup_mod->popup_field[idx]) - STRUCT_TM_YEAR_BASE_VALUE;
478         else if (idx == ELM_DATETIME_MONTH)
479           *set_val_arr[idx] = (int)elm_spinner_value_get(popup_mod->popup_field[idx]) - 1;
480         else
481           *set_val_arr[idx] = (int)elm_spinner_value_get(popup_mod->popup_field[idx]);
482      }
483
484    _set_datepicker_popup_title_text(popup_mod);
485 }
486
487 static void
488 _timepicker_value_changed_cb(void *data, Evas_Object *obj, void *event_info __UNUSED__)
489 {
490    Popup_Module_Data *popup_mod;
491    struct tm min_values, max_values;
492    int hour;
493
494    popup_mod = (Popup_Module_Data *)data;
495    if (!popup_mod) return;
496
497    if (obj == popup_mod->popup_field[ELM_DATETIME_HOUR])
498      {
499         hour = (int)elm_spinner_value_get(obj);
500         if (popup_mod->time_12hr_fmt && popup_mod->is_pm)
501           {
502              if (hour != STRUCT_TM_TIME_12HRS_MAX_VALUE)
503                hour += STRUCT_TM_TIME_12HRS_MAX_VALUE;
504              else
505                hour = 0;
506           }
507         (popup_mod->set_time).tm_hour = hour;
508         popup_mod->mod_data.fields_min_max_get(popup_mod->mod_data.base,
509                             &(popup_mod->set_time), &min_values, &max_values);
510         elm_spinner_min_max_set(popup_mod->popup_field[ELM_DATETIME_MINUTE],
511                                 min_values.tm_min, max_values.tm_min);
512         (popup_mod->set_time).tm_min = (int)elm_spinner_value_get(
513                                  popup_mod->popup_field[ELM_DATETIME_MINUTE]);
514         popup_mod->is_pm = (hour < STRUCT_TM_TIME_12HRS_MAX_VALUE) ? 0 : 1;
515         _set_ampm_value(popup_mod);
516      }
517    else if (obj == popup_mod->popup_field[ELM_DATETIME_MINUTE])
518      (popup_mod->set_time).tm_min = (int)elm_spinner_value_get(obj);
519
520 }
521
522 static void
523 _ampm_clicked_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
524 {
525    Popup_Module_Data *popup_mod;
526    int hour;
527
528    popup_mod = (Popup_Module_Data *)data;
529    if (!popup_mod || !popup_mod->time_12hr_fmt) return;
530
531    hour = (int)elm_spinner_value_get(popup_mod->popup_field[ELM_DATETIME_HOUR]);
532    if (popup_mod->time_12hr_fmt && popup_mod->is_pm && (hour != STRUCT_TM_TIME_12HRS_MAX_VALUE))
533      hour += STRUCT_TM_TIME_12HRS_MAX_VALUE;
534
535    if (hour > STRUCT_TM_TIME_12HRS_MAX_VALUE)
536      hour -= STRUCT_TM_TIME_12HRS_MAX_VALUE;
537    else if (hour < STRUCT_TM_TIME_12HRS_MAX_VALUE)
538      hour += STRUCT_TM_TIME_12HRS_MAX_VALUE;
539    else
540      {
541         if (popup_mod->is_pm) hour = 0;
542         else hour = STRUCT_TM_TIME_12HRS_MAX_VALUE;
543      }
544
545    (popup_mod->set_time).tm_hour = hour;
546    popup_mod->is_pm = (hour < STRUCT_TM_TIME_12HRS_MAX_VALUE) ? 0 : 1;
547    _set_ampm_value(popup_mod);
548 }
549
550 const char *
551 _text_insert(const char *text, char *input, int pos)
552 {
553    char *result;
554    int text_len, input_len;
555
556    text_len = strlen(text);
557    input_len = strlen(input);
558    result = (char *)malloc(sizeof(char) * (text_len + input_len) + 1);
559    memset(result, 0, sizeof(char) * (text_len + input_len) + 1);
560
561    strncpy(result, text, pos);
562    strcpy(result + pos, input);
563    strcpy(result + pos + input_len, text + pos);
564
565    return (const char *)result;
566 }
567
568 static void
569 _year_validity_checking_filter(void *data, Evas_Object *obj, char **text)
570 {
571    Popup_Module_Data *popup_mod;
572    Evas_Object *entry;
573    const char *new_str = NULL;
574    int min, max, val = 0, len;
575    char *insert;
576    const char *curr_str;
577    int next_idx = 0;
578
579    EINA_SAFETY_ON_NULL_RETURN(text);
580    popup_mod = (Popup_Module_Data *)data;
581    if (!popup_mod) return;
582
583    insert = *text;
584    len = strlen(elm_object_text_get(obj));
585    if (len < 3) return;
586
587    curr_str = elm_object_text_get(obj);
588    if (curr_str) new_str = _text_insert(curr_str, insert, elm_entry_cursor_pos_get(obj));
589    if (new_str) val = atoi(new_str);
590
591    popup_mod->mod_data.field_limit_get(popup_mod->mod_data.base, ELM_DATETIME_YEAR, &min, &max);
592    min += STRUCT_TM_YEAR_BASE_VALUE;
593    max += STRUCT_TM_YEAR_BASE_VALUE;
594
595    if (val <= max)
596      {
597         elm_entry_entry_set(obj, new_str);
598         elm_entry_cursor_end_set(obj);
599         next_idx = _picker_nextfield_location_get(popup_mod, ELM_DATETIME_YEAR);
600         if (next_idx != ELM_DATETIME_LAST)
601           {
602              elm_layout_signal_emit(popup_mod->popup_field[ELM_DATETIME_YEAR],
603                                     "elm,action,entry,toggle", "elm");
604              entry = elm_object_part_content_get(popup_mod->popup_field[next_idx],
605                                                 "elm.swallow.entry");
606              if (!elm_object_focus_get(entry))
607                elm_layout_signal_emit(popup_mod->popup_field[next_idx],
608                                       "elm,action,entry,toggle", "elm");
609          }
610      }
611
612    *insert = 0;
613    free((void *)new_str);
614    new_str = NULL;
615 }
616
617 static void
618 _month_validity_checking_filter(void *data, Evas_Object *obj, char **text)
619 {
620    Popup_Module_Data *popup_mod;
621    Evas_Object *entry;
622    const char *new_str = NULL;
623    double min, max;
624    int val = 0, len, max_digits;
625    char *insert;
626    const char *curr_str;
627    int next_idx = 0;
628
629    EINA_SAFETY_ON_NULL_RETURN(text);
630    popup_mod = (Popup_Module_Data *)data;
631    if (!popup_mod) return;
632
633    insert = *text;
634    len = strlen(elm_object_text_get(obj));
635    curr_str = elm_object_text_get(obj);
636    if (curr_str) new_str = _text_insert(curr_str, insert, elm_entry_cursor_pos_get(obj));
637    if (new_str) val = atoi(new_str) - 1;
638
639    elm_spinner_min_max_get(popup_mod->popup_field[ELM_DATETIME_MONTH], &min, &max);
640    min -= 1;
641    max -= 1;
642
643    max_digits = (max >= 10 ? 2 : 1);
644    if (len < 1 && max_digits > 1 && val < 1) return;
645
646    if ((val >= min) && (val <= max))
647      {
648         elm_entry_entry_set(obj, new_str);
649         elm_entry_cursor_end_set(obj);
650         next_idx = _picker_nextfield_location_get(popup_mod, ELM_DATETIME_MONTH);
651         if (next_idx != DATETIME_FIELD_COUNT)
652           {
653              elm_layout_signal_emit(popup_mod->popup_field[ELM_DATETIME_MONTH],
654                                     "elm,action,entry,toggle", "elm");
655              entry = elm_object_part_content_get(popup_mod->popup_field[next_idx],
656                                                  "elm.swallow.entry");
657              if (!elm_object_focus_get(entry))
658                elm_layout_signal_emit(popup_mod->popup_field[next_idx],
659                                       "elm,action,entry,toggle", "elm");
660          }
661      }
662    *insert = 0;
663    free((void *)new_str);
664    new_str = NULL;
665 }
666
667 static void
668 _hour_validity_checking_filter(void *data, Evas_Object *obj, char **text)
669 {
670    Popup_Module_Data *popup_mod;
671    Evas_Object *entry;
672    const char *new_str = NULL;
673    int val = 0, len;
674    char *insert;
675    const char *curr_str;
676
677    EINA_SAFETY_ON_NULL_RETURN(text);
678
679    popup_mod = (Popup_Module_Data *)data;
680    if (!popup_mod) return;
681
682    insert = *text;
683    len = strlen(elm_object_text_get(obj));
684    if (len < 1) return;
685
686    curr_str = elm_object_text_get(obj);
687    if (curr_str) new_str = _text_insert(curr_str, insert, elm_entry_cursor_pos_get(obj));
688    if (new_str) val = atoi(new_str);
689
690    if (popup_mod->time_12hr_fmt && val > STRUCT_TM_TIME_12HRS_MAX_VALUE)
691      {
692         *insert = 0;
693         free((void *)new_str);
694         new_str = NULL;
695         return;
696      }
697    else if (!popup_mod->time_12hr_fmt && val > STRUCT_TM_TIME_24HRS_MAX_VALUE)
698      {
699         *insert = 0;
700         free((void *)new_str);
701         new_str = NULL;
702         return;
703      }
704    elm_entry_entry_set(obj, new_str);
705    elm_layout_signal_emit(popup_mod->popup_field[ELM_DATETIME_HOUR],
706                           "elm,action,entry,toggle", "elm");
707
708     entry = elm_object_part_content_get(popup_mod->popup_field[ELM_DATETIME_MINUTE],
709                                                  "elm.swallow.entry");
710     if (!elm_object_focus_get(entry))
711       {
712          elm_layout_signal_emit(popup_mod->popup_field[ELM_DATETIME_MINUTE],
713                                          "elm,action,entry,toggle", "elm");
714       }
715     *insert = 0;
716     free((void *)new_str);
717     new_str = NULL;
718 }
719
720 static void
721 _date_validity_checking_filter(void *data, Evas_Object *obj, char **text)
722 {
723    Popup_Module_Data *popup_mod;
724    Evas_Object *entry;
725    const char *new_str = NULL;
726    int val = 0, len;
727    const char *curr_str;
728    char *insert;
729    double min, max;
730    int next_idx = 0;
731
732    EINA_SAFETY_ON_NULL_RETURN(text);
733    popup_mod = (Popup_Module_Data *)data;
734    if (!popup_mod) return;
735
736    insert = *text;
737    len = strlen(elm_object_text_get(obj));
738    if (len < 1) return;
739
740    curr_str = elm_object_text_get(obj);
741    if (curr_str) new_str = _text_insert(curr_str, insert, elm_entry_cursor_pos_get(obj));
742    if (new_str) val = atoi(new_str);
743    elm_spinner_min_max_get(popup_mod->popup_field[ELM_DATETIME_DATE], &min, &max);
744
745    if ((val >= min) && (val <= max))
746      {
747        elm_entry_entry_set(obj, new_str);
748        elm_entry_cursor_end_set(obj);
749        next_idx = _picker_nextfield_location_get(popup_mod, ELM_DATETIME_DATE);
750        if (next_idx != ELM_DATETIME_LAST)
751          {
752             elm_layout_signal_emit(popup_mod->popup_field[ELM_DATETIME_DATE],
753                                    "elm,action,entry,toggle", "elm");
754             entry = elm_object_part_content_get(popup_mod->popup_field[next_idx],
755                                                 "elm.swallow.entry");
756             if (!elm_object_focus_get(entry))
757               elm_layout_signal_emit(popup_mod->popup_field[next_idx],
758                                         "elm,action,entry,toggle", "elm");
759          }
760      }
761    *insert = 0;
762    free((void *)new_str);
763    new_str = NULL;
764 }
765
766 static void
767 _minute_validity_checking_filter(void *data, Evas_Object *obj, char **text)
768 {
769    Popup_Module_Data *popup_mod;
770    const char *new_str = NULL;
771    int min, max, val = 0, len;
772    char *insert;
773    const char *curr_str;
774
775    EINA_SAFETY_ON_NULL_RETURN(text);
776    popup_mod = (Popup_Module_Data *)data;
777    if (!popup_mod) return;
778
779    insert = *text;
780    len = strlen(elm_object_text_get(obj));
781    if (len < 1) return;
782
783    curr_str = elm_object_text_get(obj);
784    if (curr_str) new_str = _text_insert(curr_str, insert, elm_entry_cursor_pos_get(obj));
785    if (new_str) val = atoi(new_str);
786
787    popup_mod->mod_data.field_limit_get(popup_mod->mod_data.base, ELM_DATETIME_MINUTE, &min, &max);
788
789    if ((val >= min) && (val <= max))
790      {
791        elm_entry_entry_set(obj, new_str);
792        elm_entry_cursor_end_set(obj);
793      }
794    *insert = 0;
795    free((void *)new_str);
796    new_str = NULL;
797 }
798
799 static void
800 _set_datepicker_entry_filter(Popup_Module_Data *popup_mod)
801 {
802    Evas_Object *spinner, *entry;
803    static Elm_Entry_Filter_Accept_Set digits_filter_data;
804    static Elm_Entry_Filter_Limit_Size limit_filter_data;
805    char buf[BUFF_SIZE];
806    int idx, value;
807
808    if (!popup_mod) return;
809
810    digits_filter_data.accepted = "0123456789";
811    digits_filter_data.rejected = NULL;
812
813    limit_filter_data.max_byte_count = 0;
814
815    for (idx = 0; idx <= ELM_DATETIME_DATE; idx++)
816      {
817        spinner = popup_mod->popup_field[idx];
818        entry = elm_object_part_content_get(spinner, "elm.swallow.entry");
819        if (!entry) continue;
820
821        snprintf(buf, sizeof(buf), "datetime_popup/%s", field_styles[idx]);
822        elm_object_style_set(entry, buf);
823        elm_entry_magnifier_disabled_set(entry, EINA_TRUE);
824        elm_entry_context_menu_disabled_set(entry, EINA_TRUE);
825
826        if (idx == ELM_DATETIME_MONTH)
827          {
828             value = (int)elm_spinner_value_get(popup_mod->popup_field[ELM_DATETIME_MONTH]) - 1;
829             elm_object_text_set(entry, month_arr[value]);
830          }
831
832        elm_entry_markup_filter_append(entry, elm_entry_filter_accept_set, &digits_filter_data);
833
834        elm_entry_input_panel_layout_set(entry, ELM_INPUT_PANEL_LAYOUT_DATETIME);
835
836        if (idx == ELM_DATETIME_YEAR)
837          limit_filter_data.max_char_count = 4;
838        else
839          limit_filter_data.max_char_count = 2;
840
841        elm_entry_markup_filter_append(entry, elm_entry_filter_limit_size, &limit_filter_data);
842
843        evas_object_smart_callback_add(entry, "focused", _entry_focused_cb, popup_mod);
844        evas_object_smart_callback_add(entry, "unfocused", _entry_unfocused_cb, popup_mod);
845        evas_object_smart_callback_add(entry, "activated", _entry_activated_cb, popup_mod);
846        evas_object_smart_callback_add(entry, "clicked", _entry_clicked_cb, popup_mod);
847
848        if (idx == ELM_DATETIME_YEAR)
849          elm_entry_markup_filter_append(entry, _year_validity_checking_filter, popup_mod);
850        else if (idx == ELM_DATETIME_MONTH)
851          elm_entry_markup_filter_append(entry, _month_validity_checking_filter, popup_mod);
852        else if (idx == ELM_DATETIME_DATE)
853          elm_entry_markup_filter_append(entry, _date_validity_checking_filter, popup_mod);
854      }
855 }
856
857 static void
858 _set_timepicker_entry_filter(Popup_Module_Data *popup_mod)
859 {
860    Evas_Object *spinner, *entry;
861    static Elm_Entry_Filter_Accept_Set digits_filter_data;
862    static Elm_Entry_Filter_Limit_Size limit_filter_data;
863    char buf[BUFF_SIZE];
864    int idx;
865
866    if (!popup_mod) return;
867
868    digits_filter_data.accepted = "0123456789";
869    digits_filter_data.rejected = NULL;
870
871    limit_filter_data.max_byte_count = 0;
872
873    for (idx = ELM_DATETIME_HOUR; idx < ELM_DATETIME_AMPM; idx++)
874      {
875        spinner = popup_mod->popup_field[idx];
876        entry = elm_object_part_content_get(spinner, "elm.swallow.entry");
877        if (!entry) continue;
878
879        snprintf(buf, sizeof(buf), "datetime_popup/%s", field_styles[idx]);
880        elm_object_style_set(entry, buf);
881        elm_entry_magnifier_disabled_set(entry, EINA_TRUE);
882        elm_entry_context_menu_disabled_set(entry, EINA_TRUE);
883        elm_entry_input_panel_layout_set(entry, ELM_INPUT_PANEL_LAYOUT_DATETIME);
884        elm_entry_markup_filter_append(entry, elm_entry_filter_accept_set, &digits_filter_data);
885
886        limit_filter_data.max_char_count = 2;
887        elm_entry_markup_filter_append(entry, elm_entry_filter_limit_size, &limit_filter_data);
888
889        evas_object_smart_callback_add(entry, "focused", _entry_focused_cb, popup_mod);
890        evas_object_smart_callback_add(entry, "unfocused", _entry_unfocused_cb, popup_mod);
891        evas_object_smart_callback_add(entry, "activated", _entry_activated_cb, popup_mod);
892        evas_object_smart_callback_add(entry, "clicked", _entry_clicked_cb, popup_mod);
893
894        if (idx == ELM_DATETIME_HOUR)
895          elm_entry_markup_filter_append(entry, _hour_validity_checking_filter, popup_mod);
896        else if (idx == ELM_DATETIME_MINUTE)
897          elm_entry_markup_filter_append(entry, _minute_validity_checking_filter, popup_mod);
898      }
899 }
900
901 static void
902 _show_datepicker_layout(Popup_Module_Data *popup_mod)
903 {
904    Evas_Object *content;
905    struct tm curr_time;
906    int idx, year, month, min, max;
907    Elm_Datetime_Field_Type  field_type = ELM_DATETIME_YEAR;
908
909    if (!popup_mod || !popup_mod->mod_data.base) return;
910
911    content = elm_object_content_get(popup_mod->popup);
912    if (content != popup_mod->datepicker_layout)
913      {
914          elm_object_content_unset(popup_mod->popup);
915          if (content) evas_object_hide(content);
916          elm_object_content_set(popup_mod->popup, popup_mod->datepicker_layout);
917          evas_object_show(popup_mod->datepicker_layout);
918      }
919    elm_datetime_value_get(popup_mod->mod_data.base, &(popup_mod->set_time));
920    _set_datepicker_popup_title_text(popup_mod);
921
922    elm_datetime_value_get(popup_mod->mod_data.base, &curr_time);
923    year = curr_time.tm_year + STRUCT_TM_YEAR_BASE_VALUE;
924    elm_spinner_value_set(popup_mod->popup_field[ELM_DATETIME_YEAR], year);
925    month = curr_time.tm_mon + 1;
926    elm_spinner_value_set(popup_mod->popup_field[ELM_DATETIME_MONTH], month);
927    elm_spinner_value_set(popup_mod->popup_field[ELM_DATETIME_DATE], curr_time.tm_mday);
928
929    for (idx = 0; idx <= ELM_DATETIME_DATE; idx++)
930      {
931          field_type = (Elm_Datetime_Field_Type)idx;
932          popup_mod->mod_data.field_limit_get(popup_mod->mod_data.base, field_type, &min, &max);
933          if (idx == ELM_DATETIME_YEAR)
934            elm_spinner_min_max_set(popup_mod->popup_field[idx], (STRUCT_TM_YEAR_BASE_VALUE + min), (STRUCT_TM_YEAR_BASE_VALUE + max));
935          else if (idx == ELM_DATETIME_MONTH)
936            elm_spinner_min_max_set(popup_mod->popup_field[idx], (1+min), (1+max));
937          else
938            elm_spinner_min_max_set(popup_mod->popup_field[idx], min, max);
939      }
940 }
941
942 static void
943 _show_timepicker_layout(Popup_Module_Data *popup_mod)
944 {
945    Evas_Object *content;
946    struct tm curr_time, min_time, max_time;
947    int hour, hour_min, hour_max;
948
949    if (!popup_mod || !popup_mod->mod_data.base) return;
950
951    content = elm_object_content_get(popup_mod->popup);
952    if (content != popup_mod->timepicker_layout)
953      {
954          elm_object_content_unset(popup_mod->popup);
955          if (content) evas_object_hide(content);
956          elm_object_content_set(popup_mod->popup, popup_mod->timepicker_layout);
957          evas_object_show(popup_mod->timepicker_layout);
958      }
959    elm_datetime_value_get(popup_mod->mod_data.base, &(popup_mod->set_time));
960    _set_timepicker_popup_title_text(popup_mod);
961
962    elm_datetime_value_get(popup_mod->mod_data.base, &curr_time);
963    hour = curr_time.tm_hour;
964    if (popup_mod->time_12hr_fmt)
965      {
966         if (hour >= STRUCT_TM_TIME_12HRS_MAX_VALUE)
967           popup_mod->is_pm = EINA_TRUE;
968         else
969           popup_mod->is_pm = EINA_FALSE;
970         if (hour >= STRUCT_TM_TIME_12HRS_MAX_VALUE)
971           hour -= STRUCT_TM_TIME_12HRS_MAX_VALUE;
972         hour = (hour == 0) ? STRUCT_TM_TIME_12HRS_MAX_VALUE : hour;
973      }
974
975     popup_mod->mod_data.fields_min_max_get(popup_mod->mod_data.base, &curr_time, &min_time, &max_time);
976     hour_min = min_time.tm_hour;
977     hour_max = max_time.tm_hour;
978     if (popup_mod->time_12hr_fmt)
979       {
980          if (hour_min < 1) hour_min = 1;
981          else if (hour_min > STRUCT_TM_TIME_12HRS_MAX_VALUE)
982            hour_min -= STRUCT_TM_TIME_12HRS_MAX_VALUE;
983          if (hour_max > STRUCT_TM_TIME_12HRS_MAX_VALUE)
984            hour_max = STRUCT_TM_TIME_12HRS_MAX_VALUE;
985       }
986     elm_spinner_min_max_set(popup_mod->popup_field[ELM_DATETIME_HOUR], hour_min, hour_max);
987     elm_spinner_min_max_set(popup_mod->popup_field[ELM_DATETIME_MINUTE],
988                             min_time.tm_min, max_time.tm_min);
989
990     elm_spinner_value_set(popup_mod->popup_field[ELM_DATETIME_HOUR], hour);
991     elm_spinner_value_set(popup_mod->popup_field[ELM_DATETIME_MINUTE], curr_time.tm_min);
992     if (popup_mod->time_12hr_fmt)
993       _set_ampm_value(popup_mod);
994 }
995
996 static void
997 _set_month_special_values(Popup_Module_Data *popup_mod)
998 {
999    struct tm curr_time;
1000    const char *fmt = NULL;
1001    int month;
1002
1003    if (!popup_mod) return;
1004
1005    elm_datetime_value_get(popup_mod->mod_data.base, &curr_time);
1006    fmt = popup_mod->mod_data.field_format_get(popup_mod->mod_data.base, ELM_DATETIME_MONTH);
1007    for (month = 0; month < TOTAL_NUMBER_OF_MONTHS; month++)
1008      {
1009          curr_time.tm_mon = month;
1010          strftime(month_arr[month], MONTH_STRING_MAX_SIZE, fmt, &curr_time);
1011      }
1012    for (month = 0; month < 12; month++)
1013      elm_spinner_special_value_add(popup_mod->popup_field[ELM_DATETIME_MONTH],
1014                                    month + 1, month_arr[month]);
1015 }
1016
1017 static void
1018 _create_datetime_popup(Popup_Module_Data *popup_mod)
1019 {
1020    Evas_Object *set_btn, *cancel_btn;
1021    Evas_Object *parent, *widget, *conformant = NULL;
1022    const char *widget_type;
1023
1024    if (!popup_mod) return;
1025
1026    // add popup to the content of elm_conformant
1027    widget = popup_mod->mod_data.base;
1028    while(widget != NULL)
1029      {
1030         parent = elm_widget_parent_get(widget);
1031         widget_type = elm_widget_type_get(widget);
1032         if (!strcmp(widget_type, "elm_conformant"))
1033           {
1034              conformant = widget;
1035              break;
1036           }
1037         widget = parent;
1038      }
1039    if (conformant)
1040      popup_mod->popup = elm_popup_add(elm_object_content_get(conformant));
1041    else
1042      popup_mod->popup = elm_popup_add(elm_widget_top_get(popup_mod->mod_data.base));
1043
1044    evas_object_size_hint_weight_set(popup_mod->popup, EVAS_HINT_EXPAND,
1045                            EVAS_HINT_EXPAND);
1046    evas_object_size_hint_align_set(popup_mod->popup, EVAS_HINT_FILL, 0.5);
1047
1048    cancel_btn = elm_button_add(popup_mod->popup);
1049    elm_object_style_set(cancel_btn, "popup_button/default");
1050    elm_object_domain_translatable_text_set(cancel_btn, PACKAGE, E_("Cancel"));
1051    elm_object_part_content_set(popup_mod->popup, "button1", cancel_btn);
1052    evas_object_smart_callback_add(cancel_btn, "clicked", _popup_cancel_btn_clicked_cb, popup_mod);
1053
1054    set_btn = elm_button_add(popup_mod->popup);
1055    elm_object_style_set(set_btn, "popup_button/default");
1056    elm_object_domain_translatable_text_set(set_btn, PACKAGE, E_("Set"));
1057    elm_object_part_content_set(popup_mod->popup, "button2", set_btn);
1058    evas_object_smart_callback_add(set_btn, "clicked", _popup_set_btn_clicked_cb, popup_mod);
1059 }
1060
1061 static void
1062 _create_datepicker_layout(Popup_Module_Data *popup_mod)
1063 {
1064    Evas_Object *spinner;
1065    char buf[BUFF_SIZE];
1066    int idx, loc;
1067
1068    if (!popup_mod) return;
1069
1070    popup_mod->datepicker_layout = elm_layout_add(popup_mod->popup);
1071    elm_layout_theme_set(popup_mod->datepicker_layout, "layout", "datetime_popup", "date_layout");
1072
1073    for (idx = 0; idx <= ELM_DATETIME_DATE; idx++)
1074      {
1075        spinner = elm_spinner_add(popup_mod->popup);
1076        elm_spinner_editable_set(spinner, EINA_TRUE);
1077        snprintf(buf, sizeof(buf), "datetime_popup/%s", field_styles[idx]);
1078        elm_object_style_set(spinner, buf);
1079        elm_spinner_step_set(spinner, 1);
1080        elm_spinner_wrap_set(spinner, EINA_TRUE);
1081        elm_spinner_label_format_set(spinner, "%02.0f");
1082        snprintf(buf, sizeof(buf), "field%d", idx);
1083        elm_object_part_content_set(popup_mod->datepicker_layout, buf, spinner);
1084
1085        if (idx == ELM_DATETIME_YEAR)
1086          elm_spinner_min_max_set(spinner, 1902, 2037);
1087        else if (idx == ELM_DATETIME_MONTH)
1088          elm_spinner_min_max_set(spinner, 1, 12);
1089        else if (idx == ELM_DATETIME_DATE)
1090          elm_spinner_min_max_set(spinner, 1, 31);
1091
1092        evas_object_smart_callback_add(spinner, "changed", _datepicker_value_changed_cb, popup_mod);
1093        popup_mod->popup_field[idx] = spinner;
1094      }
1095
1096    _set_month_special_values(popup_mod);
1097    _set_datepicker_entry_filter(popup_mod);
1098 }
1099
1100 static void
1101 _create_timepicker_layout(Popup_Module_Data *popup_mod)
1102 {
1103    Evas_Object *spinner, *ampm;
1104    char buf[BUFF_SIZE];
1105    int idx;
1106
1107    if (!popup_mod) return;
1108
1109    popup_mod->timepicker_layout = elm_layout_add(popup_mod->popup);
1110    popup_mod->time_12hr_fmt = popup_mod->mod_data.field_location_get(popup_mod->mod_data.base, ELM_DATETIME_AMPM, NULL);
1111
1112    if (popup_mod->time_12hr_fmt)
1113      elm_layout_theme_set(popup_mod->timepicker_layout, "layout", "datetime_popup", "time_layout");
1114    else
1115      elm_layout_theme_set(popup_mod->timepicker_layout, "layout", "datetime_popup", "time_layout_24hr");
1116
1117    for (idx = ELM_DATETIME_HOUR; idx < ELM_DATETIME_AMPM; idx++)
1118      {
1119        spinner = elm_spinner_add(popup_mod->popup);
1120        elm_spinner_editable_set(spinner, EINA_TRUE);
1121        snprintf(buf, sizeof(buf), "datetime_popup/%s", field_styles[idx]);
1122        elm_object_style_set(spinner, buf);
1123        elm_spinner_step_set(spinner, 1);
1124        elm_spinner_wrap_set(spinner, EINA_TRUE);
1125        elm_spinner_label_format_set(spinner, "%02.0f");
1126        snprintf(buf, sizeof(buf), "field%d", (idx - ELM_DATETIME_HOUR));
1127        elm_object_part_content_set(popup_mod->timepicker_layout, buf, spinner);
1128        evas_object_smart_callback_add(spinner, "changed", _timepicker_value_changed_cb, popup_mod);
1129        popup_mod->popup_field[idx] = spinner;
1130     }
1131
1132    ampm = elm_entry_add(popup_mod->popup);
1133    elm_entry_single_line_set(ampm, EINA_TRUE);
1134    elm_entry_editable_set(ampm, EINA_FALSE);
1135    elm_entry_magnifier_disabled_set(ampm, EINA_TRUE);
1136    elm_entry_context_menu_disabled_set(ampm, EINA_TRUE);
1137    elm_object_style_set(ampm, "datetime_popup/ampm");
1138    evas_object_smart_callback_add(ampm, "clicked", _ampm_clicked_cb, popup_mod);
1139    elm_object_part_content_set(popup_mod->timepicker_layout, "field2",ampm);
1140    popup_mod->popup_field[ELM_DATETIME_AMPM] = ampm;
1141
1142    if (!popup_mod->time_12hr_fmt)
1143      elm_spinner_min_max_set(popup_mod->popup_field[ELM_DATETIME_HOUR], 0, 23);
1144    else
1145      elm_spinner_min_max_set(popup_mod->popup_field[ELM_DATETIME_HOUR], 1, 12);
1146    elm_spinner_min_max_set(popup_mod->popup_field[ELM_DATETIME_MINUTE], 0, 59);
1147
1148    _set_timepicker_entry_filter(popup_mod);
1149 }
1150
1151 static void
1152 _weekday_loc_update(Popup_Module_Data *popup_mod)
1153 {
1154    char *fmt;
1155
1156    if (!popup_mod) return;
1157
1158    fmt = nl_langinfo(D_T_FMT);
1159    if (!strncmp(fmt, "%a", 2) || !strncmp(fmt, "%A", 2))
1160      popup_mod->weekday_loc_first = EINA_TRUE;
1161    else
1162      popup_mod->weekday_loc_first = EINA_FALSE;
1163 }
1164
1165 static void
1166 _module_format_change(Popup_Module_Data *popup_mod)
1167 {
1168    Evas_Object *spinner_field[PICKER_POPUP_FIELD_COUNT];
1169    Evas_Object *datetime, *spinner;
1170    int field_loc[PICKER_POPUP_FIELD_COUNT];
1171    char buf[BUFF_SIZE];
1172    int idx, loc, prev_loc;
1173    Eina_Bool datepicker_bg_show = EINA_FALSE;
1174    Eina_Bool timepicker_bg_show = EINA_FALSE;
1175    Eina_Bool time_12hr;
1176
1177    if (!popup_mod) return;
1178
1179    datetime = popup_mod->mod_data.base;
1180    if (popup_mod->datepicker_layout)
1181      {
1182         for (idx = 0; idx <= ELM_DATETIME_DATE; idx++)
1183           {
1184              popup_mod->mod_data.field_location_get(datetime, idx, &loc);
1185              prev_loc = _picker_field_location_get(popup_mod, idx);
1186              snprintf(buf, sizeof(buf), "field%d", prev_loc);
1187              spinner_field[idx] = elm_object_part_content_unset(popup_mod->datepicker_layout, buf);
1188              field_loc[idx] = loc;
1189           }
1190         for (idx = 0; idx <= ELM_DATETIME_DATE; idx++)
1191           {
1192              snprintf(buf, sizeof(buf), "field%d", field_loc[idx]);
1193              elm_object_part_content_set(popup_mod->datepicker_layout, buf, spinner_field[idx]);
1194              popup_mod->field_location[idx] = field_loc[idx];
1195           }
1196      }
1197    for (idx = 0; idx <= ELM_DATETIME_DATE; idx++)
1198      datepicker_bg_show |= popup_mod->mod_data.field_location_get(datetime, idx, NULL);
1199    if (!datepicker_bg_show)
1200      elm_layout_signal_emit(datetime, "datetime,datepicker,bg,hide", "elm");
1201
1202    for (idx = ELM_DATETIME_HOUR; idx < ELM_DATETIME_AMPM; idx++)
1203      timepicker_bg_show |= popup_mod->mod_data.field_location_get(datetime, idx, NULL);
1204    if (!timepicker_bg_show)
1205      elm_layout_signal_emit(datetime, "datetime,timepicker,bg,hide", "elm");
1206
1207    time_12hr = popup_mod->mod_data.field_location_get(datetime, ELM_DATETIME_AMPM, NULL);
1208    if ((popup_mod->time_12hr_fmt != time_12hr) && (popup_mod->timepicker_layout))
1209      {
1210        for (idx = ELM_DATETIME_HOUR; idx <= ELM_DATETIME_AMPM; idx++)
1211          {
1212             snprintf(buf, sizeof(buf), "field%d", (idx - ELM_DATETIME_HOUR));
1213             spinner = elm_object_part_content_unset(popup_mod->timepicker_layout, buf);
1214             if (spinner) evas_object_hide(spinner);
1215          }
1216         if (time_12hr)
1217           {
1218              elm_layout_theme_set(popup_mod->timepicker_layout, "layout", "datetime_popup", "time_layout");
1219              for (idx = ELM_DATETIME_HOUR; idx <= ELM_DATETIME_AMPM; idx++)
1220                {
1221                   snprintf(buf, sizeof(buf), "field%d", (idx - ELM_DATETIME_HOUR));
1222                   elm_object_part_content_set(popup_mod->timepicker_layout, buf, popup_mod->popup_field[idx]);
1223                }
1224           }
1225         else
1226           {
1227              elm_layout_theme_set(popup_mod->timepicker_layout, "layout", "datetime_popup", "time_layout_24hr");
1228              for (idx = ELM_DATETIME_HOUR; idx <= ELM_DATETIME_MINUTE; idx++)
1229                {
1230                   snprintf(buf, sizeof(buf), "field%d", (idx - ELM_DATETIME_HOUR));
1231                   elm_object_part_content_set(popup_mod->timepicker_layout, buf, popup_mod->popup_field[idx]);
1232                }
1233           }
1234      }
1235    popup_mod->time_12hr_fmt = time_12hr;
1236    _weekday_loc_update(popup_mod);
1237 }
1238
1239 static void
1240 _datepicker_show_cb(void *data,
1241                    Evas_Object *obj,
1242                    const char *emission __UNUSED__,
1243                    const char *source __UNUSED__)
1244 {
1245    Popup_Module_Data *popup_mod;
1246
1247    popup_mod = (Popup_Module_Data *)data;
1248    if (!popup_mod) return;
1249
1250    if (!popup_mod->popup)
1251      _create_datetime_popup(popup_mod);
1252
1253    if (!popup_mod->datepicker_layout)
1254      _create_datepicker_layout(popup_mod);
1255
1256    _show_datepicker_layout(popup_mod);
1257    evas_object_show(popup_mod->popup);
1258    evas_object_smart_callback_call(obj, SIG_EDIT_START, NULL);
1259 }
1260
1261 static void
1262 _timepicker_show_cb(void *data,
1263                    Evas_Object *obj,
1264                    const char *emission __UNUSED__,
1265                    const char *source __UNUSED__)
1266 {
1267    Popup_Module_Data *popup_mod;
1268
1269    popup_mod = (Popup_Module_Data *)data;
1270    if (!popup_mod) return;
1271
1272    if (!popup_mod->popup)
1273      _create_datetime_popup(popup_mod);
1274
1275    if (!popup_mod->timepicker_layout)
1276      _create_timepicker_layout(popup_mod);
1277
1278    _show_timepicker_layout(popup_mod);
1279    evas_object_show(popup_mod->popup);
1280    evas_object_smart_callback_call(obj, SIG_EDIT_START, NULL);
1281 }
1282
1283 static void
1284 _module_language_changed_cb(void *data,
1285                             Evas_Object *obj __UNUSED__,
1286                             void *event_info __UNUSED__)
1287 {
1288    Popup_Module_Data *popup_mod;
1289    Evas_Object *content;
1290    popup_mod = (Popup_Module_Data *)data;
1291    if (!popup_mod || !popup_mod->popup) return;
1292
1293    content = elm_object_content_get(popup_mod->popup);
1294    if (content == popup_mod->datepicker_layout)
1295      _set_datepicker_popup_title_text(popup_mod);
1296    else if (content == popup_mod->timepicker_layout)
1297      _set_timepicker_popup_title_text(popup_mod);
1298
1299    _set_month_special_values(popup_mod);
1300    _set_ampm_value(popup_mod);
1301 }
1302
1303 static void
1304 _weekday_show_cb(void *data,
1305                  Evas_Object *obj __UNUSED__,
1306                  const char *emission __UNUSED__,
1307                  const char *source __UNUSED__)
1308 {
1309    Popup_Module_Data *popup_mod;
1310    int idx, loc, weekday_loc;
1311
1312    popup_mod = (Popup_Module_Data *)data;
1313    if (!popup_mod) return;
1314
1315    popup_mod->weekday_show = EINA_TRUE;
1316
1317    weekday_loc = (popup_mod->weekday_loc_first) ? 0 : 2;
1318    for (idx = 0; idx <= ELM_DATETIME_DATE; idx++)
1319      {
1320         popup_mod->mod_data.field_location_get(popup_mod->mod_data.base, idx, &loc);
1321         if (loc == weekday_loc)
1322          {
1323             field_value_display((Elm_Datetime_Module_Data *)popup_mod,
1324                                 popup_mod->datetime_field[idx]);
1325             break;
1326          }
1327      }
1328 }
1329
1330 static void
1331 _weekday_hide_cb(void *data,
1332                  Evas_Object *obj __UNUSED__,
1333                  const char *emission __UNUSED__,
1334                  const char *source __UNUSED__)
1335 {
1336    Popup_Module_Data *popup_mod;
1337    int idx, loc, weekday_loc;
1338
1339    popup_mod = (Popup_Module_Data *)data;
1340    if (!popup_mod) return;
1341
1342    popup_mod->weekday_show = EINA_FALSE;
1343    weekday_loc = (popup_mod->weekday_loc_first) ? 0 : 2;
1344    for (idx = 0; idx <= ELM_DATETIME_DATE; idx++)
1345      {
1346         popup_mod->mod_data.field_location_get(popup_mod->mod_data.base, idx, &loc);
1347         if (loc == weekday_loc)
1348          {
1349             field_value_display((Elm_Datetime_Module_Data *)popup_mod,
1350                                 popup_mod->datetime_field[idx]);
1351             break;
1352          }
1353      }
1354 }
1355
1356 static void
1357 _access_set(Evas_Object *obj, Elm_Datetime_Field_Type field_type)
1358 {
1359    const char* type = NULL;
1360
1361    switch (field_type)
1362      {
1363        case ELM_DATETIME_YEAR:
1364         type = "datetime field, year";
1365         break;
1366
1367       case ELM_DATETIME_MONTH:
1368         type = "datetime field, month";
1369         break;
1370
1371      case ELM_DATETIME_DATE:
1372         type = "datetime field, date";
1373         break;
1374
1375       case ELM_DATETIME_HOUR:
1376         type = "datetime field, hour";
1377         break;
1378
1379       case ELM_DATETIME_MINUTE:
1380         type = "datetime field, minute";
1381         break;
1382
1383       case ELM_DATETIME_AMPM:
1384         type = "datetime field, AM PM";
1385         break;
1386
1387       default:
1388         break;
1389      }
1390
1391    _elm_access_text_set
1392      (_elm_access_object_get(obj), ELM_ACCESS_TYPE, type);
1393    _elm_access_callback_set
1394      (_elm_access_object_get(obj), ELM_ACCESS_STATE, NULL, NULL);
1395 }
1396
1397 // module functions for the specific module type
1398 EAPI void
1399 field_value_display(Elm_Datetime_Module_Data *module_data, Evas_Object *obj)
1400 {
1401    Popup_Module_Data *popup_mod;
1402    Elm_Datetime_Field_Type  field_type;
1403    struct tm curr_time;
1404    char buf[BUFF_SIZE] = {0,};
1405    char weekday[BUFF_SIZE], label[BUFF_SIZE];
1406    int loc, weekday_loc;
1407    const char *fmt;
1408    Eina_Bool is_weekday_shown;
1409
1410    popup_mod = (Popup_Module_Data *)module_data;
1411    if (!popup_mod || !obj) return;
1412
1413    elm_datetime_value_get(popup_mod->mod_data.base, &curr_time);
1414    field_type = (Elm_Datetime_Field_Type )evas_object_data_get(obj, "_field_type");
1415    fmt = popup_mod->mod_data.field_format_get(popup_mod->mod_data.base, field_type);
1416    strftime(buf, sizeof(buf), fmt, &curr_time);
1417
1418    if ((!buf[0]) && ((!strcmp(fmt, "%p")) || (!strcmp(fmt, "%P"))))
1419      {
1420         if (curr_time.tm_hour < STRUCT_TM_TIME_12HRS_MAX_VALUE)
1421           elm_object_domain_translatable_text_set(obj, PACKAGE, E_("AM"));
1422         else
1423           elm_object_domain_translatable_text_set(obj, PACKAGE, E_("PM"));
1424      }
1425    else if (!popup_mod->weekday_show)
1426      elm_object_text_set(obj, buf);
1427    else
1428      {
1429         /* FIXME: To restrict month wrapping because of summer time in some locales,
1430          * ignore day light saving mode in mktime(). */
1431         curr_time.tm_isdst = -1;
1432         mktime(&curr_time);
1433         strftime(weekday, sizeof(weekday), "%a", &curr_time);
1434         weekday_loc = (popup_mod->weekday_loc_first) ? 0 : 2;
1435         is_weekday_shown = popup_mod->mod_data.field_location_get(
1436                            popup_mod->mod_data.base, field_type, &loc);
1437         if (!is_weekday_shown || (loc != weekday_loc))
1438           elm_object_text_set(obj, buf);
1439         else if (loc == 0)
1440           {
1441              snprintf(label, sizeof(label), "%s %s", weekday, buf);
1442              elm_object_text_set(obj, label);
1443           }
1444         else
1445           {
1446              snprintf(label, sizeof(label), "%s %s", buf, weekday);
1447              elm_object_text_set(obj, label);
1448           }
1449      }
1450 }
1451
1452 EAPI Evas_Object *
1453 field_create(Elm_Datetime_Module_Data *module_data, Elm_Datetime_Field_Type field_type)
1454 {
1455    Popup_Module_Data *popup_mod;
1456    Evas_Object *field_obj;
1457    char buf[BUFF_SIZE];
1458
1459    popup_mod = (Popup_Module_Data *)module_data;
1460    if (!popup_mod) return NULL;
1461
1462    field_obj = elm_label_add(popup_mod->mod_data.base);
1463    snprintf(buf, sizeof(buf), "datetime/%s/default", field_styles[field_type]);
1464    elm_object_style_set(field_obj, buf);
1465    evas_object_data_set(field_obj, "_field_type", (void *)field_type);
1466    popup_mod->datetime_field[field_type] = field_obj;
1467
1468    _access_set(field_obj, field_type);
1469
1470    return field_obj;
1471 }
1472
1473 EAPI Elm_Datetime_Module_Data *
1474 obj_hook(Evas_Object *obj)
1475 {
1476    Popup_Module_Data *popup_mod;
1477
1478    popup_mod = ELM_NEW(Popup_Module_Data);
1479    if (!popup_mod) return NULL;
1480
1481    elm_object_signal_callback_add(obj, "datepicker,show", "",
1482                                   _datepicker_show_cb, popup_mod);
1483    elm_object_signal_callback_add(obj, "timepicker,show", "",
1484                                   _timepicker_show_cb, popup_mod);
1485    elm_object_signal_callback_add(obj, "picker,hide", "",
1486                                   _picker_hide_cb, popup_mod);
1487    elm_object_signal_callback_add(obj, "language,changed", "",
1488                                   _module_language_changed_cb, popup_mod);
1489    elm_object_signal_callback_add(obj, "elm,action,press", "*",
1490                                   _datetime_press_cb, popup_mod);
1491    elm_object_signal_callback_add(obj, "elm,action,unpress", "*",
1492                                   _datetime_unpress_cb, popup_mod);
1493    elm_object_signal_callback_add(obj, "weekday,show", "",
1494                                   _weekday_show_cb, popup_mod);
1495    elm_object_signal_callback_add(obj, "weekday,hide", "",
1496                                   _weekday_hide_cb, popup_mod);
1497
1498    popup_mod->popup = NULL;
1499    popup_mod->datepicker_layout = NULL;
1500    popup_mod->timepicker_layout = NULL;
1501    popup_mod->weekday_show = EINA_FALSE;
1502    popup_mod->weekday_loc_first = EINA_TRUE;
1503
1504    return ((Elm_Datetime_Module_Data*)popup_mod);
1505 }
1506
1507 EAPI void
1508 obj_unhook(Elm_Datetime_Module_Data *module_data)
1509 {
1510    Popup_Module_Data *popup_mod;
1511
1512    popup_mod = (Popup_Module_Data *)module_data;
1513    if (!popup_mod) return;
1514
1515    if (popup_mod->popup)
1516      evas_object_del(popup_mod->popup);
1517
1518    if (popup_mod)
1519      {
1520         free(popup_mod);
1521         popup_mod = NULL;
1522      }
1523 }
1524
1525 EAPI void
1526 obj_format_hook(Elm_Datetime_Module_Data *module_data)
1527 {
1528    Popup_Module_Data *popup_mod;
1529
1530    popup_mod = (Popup_Module_Data *)module_data;
1531    if (!popup_mod) return;
1532
1533    _module_format_change(popup_mod);
1534 }
1535
1536 EAPI void
1537 obj_theme_hook(Elm_Datetime_Module_Data *module_data)
1538 {
1539    Popup_Module_Data *popup_mod;
1540
1541    popup_mod = (Popup_Module_Data *)module_data;
1542    if (!popup_mod) return;
1543
1544    // TODO: function can be improved to provide different popup styles.
1545 }
1546
1547 EAPI void
1548 obj_focus_hook(Elm_Datetime_Module_Data *module_data __UNUSED__)
1549 {
1550    // TODO: Default focus - enhance this func. for obj_show/obj_hide like below
1551 #if 0
1552    Popup_Module_Data *popup_mod;
1553    int idx;
1554    Eina_Bool is_focused = EINA_FALSE; //init with i/p argument
1555
1556    popup_mod = (Popup_Module_Data *)module_data;
1557    if (!popup_mod || popup_mod->popup) return;
1558
1559    for (idx = 0; idx < DATETIME_FIELD_COUNT; idx++)
1560       if (elm_object_focus_get(popup_mod->popup_field[idx]))
1561         is_focused = EINA_TRUE;
1562
1563    if (is_focused)
1564      evas_object_show(popup_mod->popup);
1565    else
1566      evas_object_hide(popup_mod->popup);
1567 #endif
1568 }
1569
1570 // module api funcs needed
1571 EAPI int
1572 elm_modapi_init(void *m __UNUSED__)
1573 {
1574    return 1; // succeed always
1575 }
1576
1577 EAPI int
1578 elm_modapi_shutdown(void *m __UNUSED__)
1579 {
1580    return 1; // succeed always
1581 }