[datetime_input_ctxpopup.c] change field type from entry to label cause font size...
[framework/uifw/elementary.git] / src / modules / datetime_input_ctxpopup / datetime_input_ctxpopup.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #ifdef HAVE_CONFIG_H
4 #include "elementary_config.h"
5 #endif
6
7 #define DATETIME_FIELD_COUNT    6
8 #define FIELD_FORMAT_LEN        3
9 #define DISKSELECTOR_MIN_ITEMS  4
10 #define BUFF_SIZE               1024
11
12 typedef struct _Ctxpopup_Module_Data Ctxpopup_Module_Data;
13 typedef struct _DiskItem_Data DiskItem_Data;
14
15 struct _Ctxpopup_Module_Data
16 {
17    Elm_Datetime_Module_Data mod_data;
18    Evas_Object *ctxpopup;
19    unsigned char still_in  : 1;
20 };
21
22 struct _DiskItem_Data
23 {
24    Ctxpopup_Module_Data *ctx_mod;
25    Elm_Datetime_Field_Type  sel_field_type;
26    unsigned int sel_field_value;
27 };
28
29 static void
30 _diskselector_item_free_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
31 {
32    if (data) free(data);
33 }
34
35 static void
36 _ctxpopup_dismissed_cb(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__ )
37 {
38    Evas_Object *diskselector;
39
40    diskselector = elm_object_content_unset(obj);
41    if (diskselector) evas_object_del(diskselector);
42 }
43
44 static void
45 _datetime_resize_cb(void *data, Evas *e __UNUSED__,Evas_Object *obj __UNUSED__,
46                     void *event_info __UNUSED__)
47 {
48    Ctxpopup_Module_Data *ctx_mod;
49
50    ctx_mod = (Ctxpopup_Module_Data *)data;
51    if (!ctx_mod) return;
52
53    evas_object_hide(ctx_mod->ctxpopup);
54 }
55
56 static void
57 _ctxpopup_parent_resize_cb(void *data, Evas *e __UNUSED__,Evas_Object *obj __UNUSED__,
58                             void *event_info __UNUSED__)
59 {
60    Ctxpopup_Module_Data *ctx_mod;
61
62    ctx_mod = (Ctxpopup_Module_Data *)data;
63    if (!ctx_mod) return;
64    elm_ctxpopup_hover_parent_set(ctx_mod->ctxpopup, elm_widget_top_get(ctx_mod->mod_data.base));
65 }
66
67 static void
68 _datetime_move_cb(void *data, Evas *e __UNUSED__,Evas_Object *obj __UNUSED__,
69                   void *event_info __UNUSED__)
70 {
71    Ctxpopup_Module_Data *ctx_mod;
72
73    ctx_mod = (Ctxpopup_Module_Data *)data;
74    if (!ctx_mod) return;
75
76    evas_object_hide(ctx_mod->ctxpopup);
77 }
78
79 static void
80 _field_value_set(struct tm *tim, Elm_Datetime_Field_Type  field_type, int val)
81 {
82    if (field_type >= DATETIME_FIELD_COUNT - 1) return;
83
84    int *timearr[]= { &tim->tm_year, &tim->tm_mon, &tim->tm_mday, &tim->tm_hour, &tim->tm_min };
85    *timearr[field_type] = val;
86 }
87
88 static int
89 _field_value_get(struct tm *tim, Elm_Datetime_Field_Type  field_type)
90 {
91    if (field_type >= DATETIME_FIELD_COUNT - 1) return -1;
92
93    int *timearr[]= { &tim->tm_year, &tim->tm_mon, &tim->tm_mday, &tim->tm_hour, &tim->tm_min };
94    return (*timearr[field_type]);
95 }
96
97 static void
98 _diskselector_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
99 {
100    DiskItem_Data *disk_data;
101    struct tm curr_time;
102    const char *fmt;
103
104    disk_data = (DiskItem_Data *)data;
105    if (!disk_data || !(disk_data->ctx_mod)) return;
106
107    elm_datetime_value_get(disk_data->ctx_mod->mod_data.base, &curr_time);
108    fmt = disk_data->ctx_mod->mod_data.field_format_get(disk_data->ctx_mod->mod_data.base, disk_data->sel_field_type);
109    if ((disk_data->sel_field_type == ELM_DATETIME_HOUR) && ((!strncmp(fmt, "%I", FIELD_FORMAT_LEN)) ||
110         (!strncmp(fmt, "%l", FIELD_FORMAT_LEN))) && (curr_time.tm_hour >= 12))
111      disk_data->sel_field_value += 12;
112    _field_value_set(&curr_time, disk_data->sel_field_type, disk_data->sel_field_value);
113    elm_datetime_value_set(disk_data->ctx_mod->mod_data.base, &curr_time);
114    evas_object_hide(disk_data->ctx_mod->ctxpopup);
115 }
116
117 static void
118 _ampm_clicked_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
119 {
120    Ctxpopup_Module_Data *ctx_mod;
121    struct tm curr_time;
122
123    ctx_mod = (Ctxpopup_Module_Data *)data;
124    if (!ctx_mod) return;
125
126    elm_datetime_value_get(ctx_mod->mod_data.base, &curr_time);
127    if (curr_time.tm_hour >= 12) curr_time.tm_hour -= 12;
128    else curr_time.tm_hour += 12;
129    elm_datetime_value_set(ctx_mod->mod_data.base, &curr_time);
130 }
131
132 static void
133 _field_clicked_cb(void *data, Evas_Object *obj)
134 {
135    Ctxpopup_Module_Data *ctx_mod;
136    Evas_Object *diskselector;
137    Elm_Object_Item *item;
138    DiskItem_Data *disk_data;
139    Elm_Datetime_Field_Type  field_type;
140    time_t t;
141    struct tm time1;
142    char buf[BUFF_SIZE], label[BUFF_SIZE];
143    const char *fmt;
144    int idx, min, max, val;
145    unsigned int display_item_num, text_len = 0;
146    Evas_Coord x = 0, y = 0, w = 0, h = 0, width;
147
148    ctx_mod = (Ctxpopup_Module_Data *)data;
149    if (!ctx_mod || !ctx_mod->ctxpopup) return;
150
151    // because of the diskselector behaviour, it is being recreated
152    diskselector = elm_diskselector_add(elm_widget_top_get(ctx_mod->mod_data.base));
153    snprintf(buf, sizeof(buf), "datetime/%s", elm_object_style_get(obj));
154    elm_object_style_set(diskselector, buf);
155    elm_object_content_set(ctx_mod->ctxpopup, diskselector);
156
157    t = time(NULL);
158    localtime_r(&t, &time1);
159
160    field_type = (Elm_Datetime_Field_Type )evas_object_data_get(obj, "_field_type");
161    fmt = ctx_mod->mod_data.field_format_get(ctx_mod->mod_data.base, field_type);
162    elm_datetime_value_get(ctx_mod->mod_data.base, &time1);
163    val = _field_value_get(&time1, field_type);
164    ctx_mod->mod_data.field_limit_get(ctx_mod->mod_data.base, field_type, &min, &max);
165
166    time1.tm_mday = 1;   // To avoid month wrapping, set the first day of the month to start with.
167
168    if ((field_type == ELM_DATETIME_HOUR) && ((!strncmp(fmt, "%I", FIELD_FORMAT_LEN)) ||
169         (!strncmp(fmt, "%l", FIELD_FORMAT_LEN))))
170      {
171         if (max >= 12) max -= 12;
172         if (val >= 12) val -= 12;
173         if (min >= 12) min -= 12;
174      }
175    for (idx = min; idx <= max; idx++)
176      {
177         _field_value_set(&time1, field_type, idx);
178         strftime(label, BUFF_SIZE, fmt, &time1);
179         if (strlen(label) > text_len) text_len = strlen(label);
180         if (idx == val)
181           {
182              item = elm_diskselector_item_append(diskselector, label, NULL, NULL, NULL);
183              elm_diskselector_item_selected_set(item, EINA_TRUE);
184           }
185         else
186           {
187              disk_data = (DiskItem_Data *) malloc (sizeof(DiskItem_Data));
188              disk_data->ctx_mod = ctx_mod;
189              disk_data->sel_field_type = field_type;
190              disk_data->sel_field_value = idx;
191              item = elm_diskselector_item_append(diskselector, label, NULL, _diskselector_cb, disk_data);
192              elm_object_item_del_cb_set(item, _diskselector_item_free_cb);
193           }
194      }
195    elm_diskselector_side_text_max_length_set(diskselector, text_len);
196
197    evas_object_geometry_get(obj, &x, &y, &w, &h);
198    evas_object_geometry_get(elm_widget_top_get(ctx_mod->mod_data.base), NULL, NULL, &width, NULL);
199    evas_object_size_hint_min_set(ctx_mod->ctxpopup, width, -1);
200    display_item_num = width / (w + elm_config_finger_size_get());
201    // always display even number of items to avoid autoselection
202    if (display_item_num % 2) display_item_num -= 1;
203    if (display_item_num < DISKSELECTOR_MIN_ITEMS)
204      display_item_num = DISKSELECTOR_MIN_ITEMS;
205    elm_diskselector_display_item_num_set(diskselector, display_item_num);
206    elm_diskselector_round_enabled_set(diskselector, EINA_TRUE);
207
208    elm_ctxpopup_direction_priority_set(ctx_mod->ctxpopup, ELM_CTXPOPUP_DIRECTION_DOWN,
209                                        ELM_CTXPOPUP_DIRECTION_UP, -1, -1);
210    evas_object_move(ctx_mod->ctxpopup, (x+w/2), (y+h));
211
212    // if the direction of Ctxpopup is upwards, move it to the top of datetime
213    if (elm_ctxpopup_direction_get (ctx_mod->ctxpopup) == ELM_CTXPOPUP_DIRECTION_UP)
214      {
215         elm_ctxpopup_direction_priority_set(ctx_mod->ctxpopup, ELM_CTXPOPUP_DIRECTION_UP,
216                                             ELM_CTXPOPUP_DIRECTION_DOWN, -1, -1);
217         evas_object_move(ctx_mod->ctxpopup, (x+w/2), y);
218      }
219    evas_object_show(ctx_mod->ctxpopup);
220 }
221
222 static void
223 _field_mouse_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
224 {
225    Evas_Event_Mouse_Down *ev;
226    Ctxpopup_Module_Data *ctx_mod;
227
228    ev = event_info;
229    ctx_mod = (Ctxpopup_Module_Data *)data;
230    if (!ctx_mod || !ctx_mod->ctxpopup) return;
231
232    if (!(ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD))
233      {
234         ctx_mod->still_in = 1;
235      }
236 }
237
238 static void
239 _field_mouse_move_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info)
240 {
241    Evas_Event_Mouse_Move *ev;
242    Ctxpopup_Module_Data *ctx_mod;
243
244    ev = event_info;
245    ctx_mod = (Ctxpopup_Module_Data *)data;
246    if (!ctx_mod || !ctx_mod->ctxpopup) return;
247
248    if (ctx_mod->still_in)
249      {
250
251         if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
252           ctx_mod->still_in = 0;
253         else
254           {
255              Evas_Coord x, y, w, h;
256
257              evas_object_geometry_get(obj, &x, &y, &w, &h);
258              if ((ev->cur.canvas.x < x) || (ev->cur.canvas.y < y) ||
259                  (ev->cur.canvas.x >= (x + w)) || (ev->cur.canvas.y >= (y + h)))
260                ctx_mod->still_in = 0;
261           }
262      }
263    else
264      {
265         if (!(ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD))
266           {
267              Evas_Coord x, y, w, h;
268
269              evas_object_geometry_get(obj, &x, &y, &w, &h);
270              if ((ev->cur.canvas.x >= x) && (ev->cur.canvas.y >= y) &&
271                  (ev->cur.canvas.x < (x + w)) && (ev->cur.canvas.y < (y + h)))
272                ctx_mod->still_in = 1;
273           }
274      }
275 }
276
277 static void
278 _field_mouse_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info)
279 {
280    Evas_Event_Mouse_Up *ev;
281    Ctxpopup_Module_Data *ctx_mod;
282
283    ev = event_info;
284    ctx_mod = (Ctxpopup_Module_Data *)data;
285    if (!ctx_mod || !ctx_mod->ctxpopup) return;
286
287    if (ctx_mod->still_in)
288      {
289         _field_clicked_cb(ctx_mod, obj);
290      }
291    ctx_mod->still_in = 0;
292 }
293
294 // module fucns for the specific module type
295 EAPI void
296 field_value_display(Elm_Datetime_Module_Data *module_data, Evas_Object *obj)
297 {
298    Ctxpopup_Module_Data *ctx_mod;
299    Elm_Datetime_Field_Type  field_type;
300    struct tm tim;
301    char buf[BUFF_SIZE] = {0};
302    const char *fmt;
303
304    ctx_mod = (Ctxpopup_Module_Data *)module_data;
305    if (!ctx_mod || !obj) return;
306
307    elm_datetime_value_get(ctx_mod->mod_data.base, &tim);
308    field_type = (Elm_Datetime_Field_Type )evas_object_data_get(obj, "_field_type");
309    fmt = ctx_mod->mod_data.field_format_get(ctx_mod->mod_data.base, field_type);
310    strftime(buf, sizeof(buf), fmt, &tim);
311
312    // If a locale doesn't support AM/PM strings, set the default values
313    if ((buf[0] == 0) && (!strncmp(fmt, "%p", BUFF_SIZE) || strncmp(fmt, "%P", BUFF_SIZE)))
314      {
315          if (tim.tm_hour < 12) strncpy(buf, "AM", BUFF_SIZE);
316          else strncpy(buf, "PM", BUFF_SIZE);
317      }
318
319    elm_object_text_set(obj, buf);
320 }
321
322 EAPI Evas_Object *
323 field_create(Elm_Datetime_Module_Data *module_data, Elm_Datetime_Field_Type  field_type)
324 {
325    Ctxpopup_Module_Data *ctx_mod;
326    Evas_Object *field_obj;
327
328    ctx_mod = (Ctxpopup_Module_Data *)module_data;
329    if (!ctx_mod) return NULL;
330
331    if (field_type == ELM_DATETIME_AMPM)
332      {
333         field_obj = elm_button_add(ctx_mod->mod_data.base);
334         elm_object_style_set(field_obj, "datetime_ampm/default");
335         evas_object_smart_callback_add(field_obj, "clicked", _ampm_clicked_cb, ctx_mod);
336      }
337    else
338      {
339         field_obj = elm_label_add(ctx_mod->mod_data.base);
340         evas_object_event_callback_add(field_obj, EVAS_CALLBACK_MOUSE_DOWN, _field_mouse_down_cb, ctx_mod);
341         evas_object_event_callback_add(field_obj, EVAS_CALLBACK_MOUSE_MOVE, _field_mouse_move_cb, ctx_mod);
342         evas_object_event_callback_add(field_obj, EVAS_CALLBACK_MOUSE_UP, _field_mouse_up_cb, ctx_mod);
343         elm_object_style_set(field_obj,"datetime");
344      }
345    evas_object_data_set(field_obj, "_field_type", (void *)field_type);
346    return field_obj;
347 }
348
349 EAPI Elm_Datetime_Module_Data *
350 obj_hook(Evas_Object *obj)
351 {
352    Ctxpopup_Module_Data *ctx_mod;
353    char buf[BUFF_SIZE];
354
355    ctx_mod = ELM_NEW(Ctxpopup_Module_Data);
356    if (!ctx_mod) return NULL;
357
358    ctx_mod->ctxpopup = elm_ctxpopup_add(elm_widget_top_get(obj));
359    snprintf(buf, sizeof(buf), "datetime/%s", elm_object_style_get(obj));
360    elm_object_style_set(ctx_mod->ctxpopup, buf);
361    elm_ctxpopup_horizontal_set(ctx_mod->ctxpopup, EINA_TRUE);
362    evas_object_size_hint_weight_set(ctx_mod->ctxpopup, EVAS_HINT_EXPAND,
363                                     EVAS_HINT_EXPAND);
364    evas_object_size_hint_align_set(ctx_mod->ctxpopup, EVAS_HINT_FILL, 0.5);
365    evas_object_smart_callback_add(ctx_mod->ctxpopup, "dismissed",
366                                   _ctxpopup_dismissed_cb, ctx_mod);
367    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE,
368                                   _datetime_resize_cb, ctx_mod);
369    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE,
370                                   _datetime_move_cb, ctx_mod);
371    evas_object_event_callback_add(elm_widget_top_get(obj), EVAS_CALLBACK_RESIZE,
372                                   _ctxpopup_parent_resize_cb, ctx_mod);
373
374    return ((Elm_Datetime_Module_Data*)ctx_mod);
375 }
376
377 EAPI void
378 obj_unhook(Elm_Datetime_Module_Data *module_data)
379 {
380    Ctxpopup_Module_Data *ctx_mod;
381
382    ctx_mod = (Ctxpopup_Module_Data *)module_data;
383    if (!ctx_mod) return;
384
385    evas_object_event_callback_del_full(elm_widget_top_get(module_data->base),
386                                        EVAS_CALLBACK_RESIZE,
387                                        _ctxpopup_parent_resize_cb, ctx_mod);
388    if (ctx_mod->ctxpopup)
389      evas_object_del(ctx_mod->ctxpopup);
390
391    if (ctx_mod)
392      {
393           free(ctx_mod);
394           ctx_mod = NULL;
395       }
396 }
397
398 // module api funcs needed
399 EAPI int
400 elm_modapi_init(void *m __UNUSED__)
401 {
402    return 1; // succeed always
403 }
404
405 EAPI int
406 elm_modapi_shutdown(void *m __UNUSED__)
407 {
408    return 1; // succeed always
409 }