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