15c1c18d59c00848dd625ffb1b57c8047f426afc
[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 };
20
21 struct _DiskItem_Data
22 {
23    Ctxpopup_Module_Data *ctx_mod;
24    Elm_Datetime_Field_Type  sel_field_type;
25    unsigned int sel_field_value;
26 };
27
28 static void
29 _diskselector_item_free_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
30 {
31    if (data) free(data);
32 }
33
34 static void
35 _ctxpopup_dismissed_cb(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__ )
36 {
37    Evas_Object *diskselector;
38
39    diskselector = elm_object_content_unset(obj);
40    if (diskselector) evas_object_del(diskselector);
41 }
42
43 static void
44 _datetime_resize_cb(void *data, Evas *e __UNUSED__,Evas_Object *obj __UNUSED__,
45                     void *event_info __UNUSED__)
46 {
47    Ctxpopup_Module_Data *ctx_mod;
48
49    ctx_mod = (Ctxpopup_Module_Data *)data;
50    if (!ctx_mod) return;
51
52    evas_object_hide(ctx_mod->ctxpopup);
53 }
54
55 static void
56 _ctxpopup_parent_resize_cb(void *data, Evas *e __UNUSED__,Evas_Object *obj __UNUSED__,
57                             void *event_info __UNUSED__)
58 {
59    Ctxpopup_Module_Data *ctx_mod;
60
61    ctx_mod = (Ctxpopup_Module_Data *)data;
62    if (!ctx_mod) return;
63    elm_ctxpopup_hover_parent_set(ctx_mod->ctxpopup, elm_widget_top_get(ctx_mod->mod_data.base));
64 }
65
66 static void
67 _datetime_move_cb(void *data, Evas *e __UNUSED__,Evas_Object *obj __UNUSED__,
68                   void *event_info __UNUSED__)
69 {
70    Ctxpopup_Module_Data *ctx_mod;
71
72    ctx_mod = (Ctxpopup_Module_Data *)data;
73    if (!ctx_mod) return;
74
75    evas_object_hide(ctx_mod->ctxpopup);
76 }
77
78 static void
79 _field_value_set(struct tm *tim, Elm_Datetime_Field_Type  field_type, int val)
80 {
81    if (field_type >= DATETIME_FIELD_COUNT - 1) return;
82
83    int *timearr[]= { &tim->tm_year, &tim->tm_mon, &tim->tm_mday, &tim->tm_hour, &tim->tm_min };
84    *timearr[field_type] = val;
85 }
86
87 static int
88 _field_value_get(struct tm *tim, Elm_Datetime_Field_Type  field_type)
89 {
90    if (field_type >= DATETIME_FIELD_COUNT - 1) return -1;
91
92    int *timearr[]= { &tim->tm_year, &tim->tm_mon, &tim->tm_mday, &tim->tm_hour, &tim->tm_min };
93    return (*timearr[field_type]);
94 }
95
96 static void
97 _diskselector_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
98 {
99    DiskItem_Data *disk_data;
100    struct tm curr_time;
101    const char *fmt;
102
103    disk_data = (DiskItem_Data *)data;
104    if (!disk_data || !(disk_data->ctx_mod)) return;
105
106    elm_datetime_value_get(disk_data->ctx_mod->mod_data.base, &curr_time);
107    fmt = disk_data->ctx_mod->mod_data.field_format_get(disk_data->ctx_mod->mod_data.base, disk_data->sel_field_type);
108    if ((disk_data->sel_field_type == ELM_DATETIME_HOUR) && ((!strncmp(fmt, "%I", FIELD_FORMAT_LEN)) ||
109         (!strncmp(fmt, "%l", FIELD_FORMAT_LEN))) && (curr_time.tm_hour >= 12))
110      disk_data->sel_field_value += 12;
111    _field_value_set(&curr_time, disk_data->sel_field_type, disk_data->sel_field_value);
112    elm_datetime_value_set(disk_data->ctx_mod->mod_data.base, &curr_time);
113    evas_object_hide(disk_data->ctx_mod->ctxpopup);
114 }
115
116 static void
117 _ampm_clicked_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
118 {
119    Ctxpopup_Module_Data *ctx_mod;
120    struct tm curr_time;
121
122    ctx_mod = (Ctxpopup_Module_Data *)data;
123    if (!ctx_mod) return;
124
125    elm_datetime_value_get(ctx_mod->mod_data.base, &curr_time);
126    if (curr_time.tm_hour >= 12) curr_time.tm_hour -= 12;
127    else curr_time.tm_hour += 12;
128    elm_datetime_value_set(ctx_mod->mod_data.base, &curr_time);
129 }
130
131 static void
132 _field_clicked_cb(void *data, Evas_Object *obj, void *event_info __UNUSED__)
133 {
134    Ctxpopup_Module_Data *ctx_mod;
135    Evas_Object *diskselector;
136    Elm_Object_Item *item;
137    DiskItem_Data *disk_data;
138    Elm_Datetime_Field_Type  field_type;
139    time_t t;
140    struct tm time1;
141    char buf[BUFF_SIZE], label[BUFF_SIZE];
142    const char *fmt;
143    int idx, min, max, val;
144    unsigned int display_item_num, text_len = 0;
145    Evas_Coord x = 0, y = 0, w = 0, h = 0, width;
146
147    ctx_mod = (Ctxpopup_Module_Data *)data;
148    if (!ctx_mod || !ctx_mod->ctxpopup) return;
149
150    // because of the diskselector behaviour, it is being recreated
151    diskselector = elm_diskselector_add(elm_widget_top_get(ctx_mod->mod_data.base));
152    snprintf(buf, sizeof(buf), "datetime/%s", elm_object_style_get(obj));
153    elm_object_style_set(diskselector, buf);
154    elm_object_content_set(ctx_mod->ctxpopup, diskselector);
155
156    t = time(NULL);
157    localtime_r(&t, &time1);
158
159    field_type = (Elm_Datetime_Field_Type )evas_object_data_get(obj, "_field_type");
160    fmt = ctx_mod->mod_data.field_format_get(ctx_mod->mod_data.base, field_type);
161    elm_datetime_value_get(ctx_mod->mod_data.base, &time1);
162    val = _field_value_get(&time1, field_type);
163    ctx_mod->mod_data.field_limit_get(ctx_mod->mod_data.base, field_type, &min, &max);
164
165    time1.tm_mday = 1;   // To avoid month wrapping, set the first day of the month to start with.
166
167    if ((field_type == ELM_DATETIME_HOUR) && ((!strncmp(fmt, "%I", FIELD_FORMAT_LEN)) ||
168         (!strncmp(fmt, "%l", FIELD_FORMAT_LEN))))
169      {
170         if (max >= 12) max -= 12;
171         if (val >= 12) val -= 12;
172         if (min >= 12) min -= 12;
173      }
174    for (idx = min; idx <= max; idx++)
175      {
176         _field_value_set(&time1, field_type, idx);
177         strftime(label, BUFF_SIZE, fmt, &time1);
178         if (strlen(label) > text_len) text_len = strlen(label);
179         if (idx == val)
180           {
181              item = elm_diskselector_item_append(diskselector, label, NULL, NULL, NULL);
182              elm_diskselector_item_selected_set(item, EINA_TRUE);
183           }
184         else
185           {
186              disk_data = (DiskItem_Data *) malloc (sizeof(DiskItem_Data));
187              disk_data->ctx_mod = ctx_mod;
188              disk_data->sel_field_type = field_type;
189              disk_data->sel_field_value = idx;
190              item = elm_diskselector_item_append(diskselector, label, NULL, _diskselector_cb, disk_data);
191              elm_object_item_del_cb_set(item, _diskselector_item_free_cb);
192           }
193      }
194    elm_diskselector_side_text_max_length_set(diskselector, text_len);
195
196    evas_object_geometry_get(obj, &x, &y, &w, &h);
197    evas_object_geometry_get(elm_widget_top_get(ctx_mod->mod_data.base), NULL, NULL, &width, NULL);
198    evas_object_size_hint_min_set(ctx_mod->ctxpopup, width, -1);
199    display_item_num = width / (w + elm_config_finger_size_get());
200    // always display even number of items to avoid autoselection
201    if (display_item_num % 2) display_item_num -= 1;
202    if (display_item_num < DISKSELECTOR_MIN_ITEMS)
203      display_item_num = DISKSELECTOR_MIN_ITEMS;
204    elm_diskselector_display_item_num_set(diskselector, display_item_num);
205    elm_diskselector_round_enabled_set(diskselector, EINA_TRUE);
206
207    elm_ctxpopup_direction_priority_set(ctx_mod->ctxpopup, ELM_CTXPOPUP_DIRECTION_DOWN,
208                                        ELM_CTXPOPUP_DIRECTION_UP, -1, -1);
209    evas_object_move(ctx_mod->ctxpopup, (x+w/2), (y+h));
210
211    // if the direction of Ctxpopup is upwards, move it to the top of datetime
212    if (elm_ctxpopup_direction_get (ctx_mod->ctxpopup) == ELM_CTXPOPUP_DIRECTION_UP)
213      {
214         elm_ctxpopup_direction_priority_set(ctx_mod->ctxpopup, ELM_CTXPOPUP_DIRECTION_UP,
215                                             ELM_CTXPOPUP_DIRECTION_DOWN, -1, -1);
216         evas_object_move(ctx_mod->ctxpopup, (x+w/2), y);
217      }
218    evas_object_show(ctx_mod->ctxpopup);
219 }
220
221 // module fucns for the specific module type
222 EAPI void
223 field_value_display(Elm_Datetime_Module_Data *module_data, Evas_Object *obj)
224 {
225    Ctxpopup_Module_Data *ctx_mod;
226    Elm_Datetime_Field_Type  field_type;
227    struct tm tim;
228    char buf[BUFF_SIZE];
229    const char *fmt;
230
231    ctx_mod = (Ctxpopup_Module_Data *)module_data;
232    if (!ctx_mod || !obj) return;
233
234    elm_datetime_value_get(ctx_mod->mod_data.base, &tim);
235    field_type = (Elm_Datetime_Field_Type )evas_object_data_get(obj, "_field_type");
236    fmt = ctx_mod->mod_data.field_format_get(ctx_mod->mod_data.base, field_type);
237    strftime(buf, sizeof(buf), fmt, &tim);
238    elm_object_text_set(obj, buf);
239 }
240
241 EAPI Evas_Object *
242 field_create(Elm_Datetime_Module_Data *module_data, Elm_Datetime_Field_Type  field_type)
243 {
244    Ctxpopup_Module_Data *ctx_mod;
245    Evas_Object *field_obj;
246
247    ctx_mod = (Ctxpopup_Module_Data *)module_data;
248    if (!ctx_mod) return NULL;
249
250    if (field_type == ELM_DATETIME_AMPM)
251      {
252         field_obj = elm_button_add(ctx_mod->mod_data.base);
253         elm_object_style_set(field_obj, "datetime_ampm/default");
254         evas_object_smart_callback_add(field_obj, "clicked", _ampm_clicked_cb, ctx_mod);
255      }
256    else
257      {
258         field_obj = elm_entry_add(ctx_mod->mod_data.base);
259         elm_entry_single_line_set(field_obj, EINA_TRUE);
260         elm_entry_editable_set(field_obj, EINA_FALSE);
261         elm_entry_input_panel_enabled_set(field_obj, EINA_FALSE);
262         elm_entry_context_menu_disabled_set(field_obj, EINA_TRUE);
263         evas_object_smart_callback_add(field_obj, "clicked", _field_clicked_cb, ctx_mod);
264      }
265    evas_object_data_set(field_obj, "_field_type", (void *)field_type);
266    return field_obj;
267 }
268
269 EAPI Elm_Datetime_Module_Data *
270 obj_hook(Evas_Object *obj)
271 {
272    Ctxpopup_Module_Data *ctx_mod;
273    char buf[BUFF_SIZE];
274
275    ctx_mod = ELM_NEW(Ctxpopup_Module_Data);
276    if (!ctx_mod) return NULL;
277
278    ctx_mod->ctxpopup = elm_ctxpopup_add(elm_widget_top_get(obj));
279    snprintf(buf, sizeof(buf), "datetime/%s", elm_object_style_get(obj));
280    elm_object_style_set(ctx_mod->ctxpopup, buf);
281    elm_ctxpopup_horizontal_set(ctx_mod->ctxpopup, EINA_TRUE);
282    evas_object_size_hint_weight_set(ctx_mod->ctxpopup, EVAS_HINT_EXPAND,
283                                     EVAS_HINT_EXPAND);
284    evas_object_size_hint_align_set(ctx_mod->ctxpopup, EVAS_HINT_FILL, 0.5);
285    evas_object_smart_callback_add(ctx_mod->ctxpopup, "dismissed",
286                                   _ctxpopup_dismissed_cb, ctx_mod);
287    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE,
288                                   _datetime_resize_cb, ctx_mod);
289    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE,
290                                   _datetime_move_cb, ctx_mod);
291    evas_object_event_callback_add(elm_widget_top_get(obj), EVAS_CALLBACK_RESIZE,
292                                   _ctxpopup_parent_resize_cb, ctx_mod);
293
294    return ((Elm_Datetime_Module_Data*)ctx_mod);
295 }
296
297 EAPI void
298 obj_unhook(Elm_Datetime_Module_Data *module_data)
299 {
300    Ctxpopup_Module_Data *ctx_mod;
301
302    ctx_mod = (Ctxpopup_Module_Data *)module_data;
303    if (!ctx_mod) return;
304
305    evas_object_event_callback_del_full(elm_widget_top_get(module_data->base),
306                                        EVAS_CALLBACK_RESIZE,
307                                        _ctxpopup_parent_resize_cb, ctx_mod);
308    if (ctx_mod->ctxpopup)
309      evas_object_del(ctx_mod->ctxpopup);
310
311    if (ctx_mod)
312      {
313           free(ctx_mod);
314           ctx_mod = NULL;
315       }
316 }
317
318 // module api funcs needed
319 EAPI int
320 elm_modapi_init(void *m __UNUSED__)
321 {
322    return 1; // succeed always
323 }
324
325 EAPI int
326 elm_modapi_shutdown(void *m __UNUSED__)
327 {
328    return 1; // succeed always
329 }