diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/elementary/src/lib/elm_datetime.c | 1075 |
1 files changed, 1075 insertions, 0 deletions
diff --git a/libraries/elementary/src/lib/elm_datetime.c b/libraries/elementary/src/lib/elm_datetime.c new file mode 100644 index 0000000..8736e8d --- /dev/null +++ b/libraries/elementary/src/lib/elm_datetime.c | |||
@@ -0,0 +1,1075 @@ | |||
1 | #include <Elementary.h> | ||
2 | #include "elm_priv.h" | ||
3 | |||
4 | #ifdef HAVE_LOCALE_H | ||
5 | # include <locale.h> | ||
6 | #endif | ||
7 | |||
8 | #ifdef HAVE_LANGINFO_H | ||
9 | # include <langinfo.h> | ||
10 | #endif | ||
11 | |||
12 | typedef struct _Widget_Data Widget_Data; | ||
13 | typedef struct _Datetime_Field Datetime_Field; | ||
14 | typedef struct _Datetime_Mod_Api Datetime_Mod_Api; | ||
15 | typedef struct _Format_Map Format_Map; | ||
16 | |||
17 | #define DATETIME_TYPE_COUNT 6 | ||
18 | #define MAX_FORMAT_LEN 64 | ||
19 | #define MAX_SEPARATOR_LEN 6 | ||
20 | #define MAX_FIELD_FORMAT_LEN 3 | ||
21 | #define MIN_DAYS_IN_MONTH 28 | ||
22 | #define BUFFER_SIZE 1024 | ||
23 | |||
24 | // interface between EDC & C code. Field names & signal names. | ||
25 | // values 0 to DATETIME_TYPE_COUNT are valid range, can be substituted for %d. | ||
26 | #define EDC_DATETIME_ENABLE_SIG_STR "elm,state,enabled" | ||
27 | #define EDC_DATETIME_DISABLE_SIG_STR "elm,state,disabled" | ||
28 | #define EDC_DATETIME_FOCUSIN_SIG_STR "elm,action,focus" | ||
29 | #define EDC_DATETIME_FOCUSOUT_SIG_STR "elm,action,unfocus" | ||
30 | #define EDC_PART_FIELD_STR "field%d" | ||
31 | #define EDC_PART_SEPARATOR_STR "separator%d" | ||
32 | #define EDC_PART_FIELD_ENABLE_SIG_STR "field%d,enable" | ||
33 | #define EDC_PART_FIELD_DISABLE_SIG_STR "field%d,disable" | ||
34 | |||
35 | // struct tm does not define the fields in the order from year, month, date, hour, minute. | ||
36 | // values are reassigned to an array for easy handling. | ||
37 | #define DATETIME_TM_ARRAY(intptr, tmptr) int *intptr[] = {&(tmptr)->tm_year, \ | ||
38 | &(tmptr)->tm_mon, &(tmptr)->tm_mday, &(tmptr)->tm_hour, &(tmptr)->tm_min} | ||
39 | |||
40 | struct _Datetime_Field | ||
41 | { | ||
42 | Evas_Object *item_obj; | ||
43 | char fmt[MAX_FIELD_FORMAT_LEN]; | ||
44 | Elm_Datetime_Field_Type type; | ||
45 | const char *separator; | ||
46 | int location; // location of the field as per the current format | ||
47 | int min, max; | ||
48 | Eina_Bool fmt_exist:1; // whether field format is present or not | ||
49 | Eina_Bool visible:1; // whether field can be visible or not | ||
50 | }; | ||
51 | |||
52 | struct _Datetime_Mod_Api | ||
53 | { | ||
54 | Elm_Datetime_Module_Data *(*obj_hook) (Evas_Object *obj); | ||
55 | void (*obj_unhook) (Elm_Datetime_Module_Data *module_data); | ||
56 | Evas_Object *(*field_create) (Elm_Datetime_Module_Data *module_data, | ||
57 | Elm_Datetime_Field_Type field_type); | ||
58 | void (*field_value_display) (Elm_Datetime_Module_Data *module_data, | ||
59 | Evas_Object *obj); | ||
60 | }; | ||
61 | |||
62 | struct _Widget_Data | ||
63 | { | ||
64 | Evas_Object *base; | ||
65 | Datetime_Field field_list[DATETIME_TYPE_COUNT]; // fixed set of fields. | ||
66 | struct tm curr_time, min_limit, max_limit; | ||
67 | Elm_Datetime_Module_Data *mod_data; | ||
68 | char format[MAX_FORMAT_LEN]; | ||
69 | Eina_Bool user_format:1; // whether user set format or default format. | ||
70 | }; | ||
71 | |||
72 | struct _Format_Map | ||
73 | { | ||
74 | char *fmt_char; | ||
75 | int def_min; | ||
76 | int def_max; | ||
77 | char *ignore_sep; | ||
78 | }; | ||
79 | |||
80 | // default limits for individual fields | ||
81 | static Format_Map mapping[DATETIME_TYPE_COUNT] = { | ||
82 | [ELM_DATETIME_YEAR] = { "Yy", -1, -1, "" }, | ||
83 | [ELM_DATETIME_MONTH] = { "mbBh", 0, 11, "" }, | ||
84 | [ELM_DATETIME_DATE] = { "de", 1, 31, "" }, | ||
85 | [ELM_DATETIME_HOUR] = { "IHkl", 0, 23, "" }, | ||
86 | [ELM_DATETIME_MINUTE] = { "M", 0, 59, ":" }, | ||
87 | [ELM_DATETIME_AMPM] = { "pP", 0, 1, "" } | ||
88 | }; | ||
89 | |||
90 | static const char *multifield_formats = "cxXrRTDF"; | ||
91 | static const char *ignore_separators = "()"; | ||
92 | |||
93 | static Datetime_Mod_Api *dt_mod = NULL; | ||
94 | static const char *widtype = NULL; | ||
95 | |||
96 | static void _del_hook(Evas_Object *obj); | ||
97 | static void _disable_hook(Evas_Object *obj); | ||
98 | static void _translate_hook(Evas_Object *obj); | ||
99 | static void _on_focus_hook(void *data __UNUSED__, Evas_Object *obj); | ||
100 | static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl); | ||
101 | static void _sizing_eval(Evas_Object *obj); | ||
102 | static void _theme_hook(Evas_Object *obj); | ||
103 | static void _validate_datetime_limits(struct tm *time1, struct tm *time2, Eina_Bool swap); | ||
104 | static void _apply_field_limits(Evas_Object *obj); | ||
105 | static void _apply_range_restrictions(Evas_Object *obj, struct tm *time); | ||
106 | static const char *_field_format_get(Evas_Object * obj, Elm_Datetime_Field_Type field_type); | ||
107 | static void _field_limit_get(Evas_Object * obj, Elm_Datetime_Field_Type field_type, | ||
108 | int *range_min, int *range_max); | ||
109 | static void _reload_format(Evas_Object *obj); | ||
110 | static void _field_list_display(Evas_Object *obj); | ||
111 | static void _field_list_arrange(Evas_Object *obj); | ||
112 | static void _field_list_init(Evas_Object *obj); | ||
113 | |||
114 | static const char SIG_CHANGED[] = "changed"; | ||
115 | static const char SIG_LANGUAGE_CHANGED[] = "language,changed"; | ||
116 | static const Evas_Smart_Cb_Description _signals[] = { | ||
117 | {SIG_CHANGED, ""}, | ||
118 | {SIG_LANGUAGE_CHANGED, ""}, | ||
119 | {NULL, NULL} | ||
120 | }; | ||
121 | |||
122 | static Datetime_Mod_Api * | ||
123 | _dt_mod_init() | ||
124 | { | ||
125 | Elm_Module *mod = NULL; | ||
126 | if (!(mod = _elm_module_find_as("datetime/api"))) return NULL; | ||
127 | |||
128 | mod->api = malloc(sizeof(Datetime_Mod_Api)); | ||
129 | if (!mod->api) return NULL; | ||
130 | |||
131 | ((Datetime_Mod_Api *)(mod->api))->obj_hook = _elm_module_symbol_get(mod, "obj_hook"); | ||
132 | ((Datetime_Mod_Api *)(mod->api))->obj_unhook = _elm_module_symbol_get(mod, "obj_unhook"); | ||
133 | ((Datetime_Mod_Api *)(mod->api))->field_create = _elm_module_symbol_get(mod, "field_create"); | ||
134 | ((Datetime_Mod_Api *)(mod->api))->field_value_display = _elm_module_symbol_get(mod, "field_value_display"); | ||
135 | |||
136 | return mod->api; | ||
137 | } | ||
138 | |||
139 | static void | ||
140 | _del_hook(Evas_Object *obj) | ||
141 | { | ||
142 | Widget_Data *wd; | ||
143 | Datetime_Field *tmp; | ||
144 | unsigned int idx; | ||
145 | |||
146 | wd = elm_widget_data_get(obj); | ||
147 | if (!wd) return; | ||
148 | |||
149 | for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++) | ||
150 | { | ||
151 | tmp = wd->field_list + idx; | ||
152 | evas_object_del(tmp->item_obj); | ||
153 | eina_stringshare_del(tmp->separator); | ||
154 | } | ||
155 | |||
156 | if ((dt_mod) && (dt_mod->obj_unhook)) | ||
157 | dt_mod->obj_unhook(wd->mod_data); // module - unhook | ||
158 | |||
159 | free(wd); | ||
160 | } | ||
161 | |||
162 | static void | ||
163 | _disable_hook(Evas_Object *obj) | ||
164 | { | ||
165 | Widget_Data *wd; | ||
166 | |||
167 | wd = elm_widget_data_get(obj); | ||
168 | if (!wd || !wd->base) return; | ||
169 | if (elm_widget_disabled_get(obj)) | ||
170 | edje_object_signal_emit(wd->base, EDC_DATETIME_DISABLE_SIG_STR, "elm"); | ||
171 | else | ||
172 | edje_object_signal_emit(wd->base, EDC_DATETIME_ENABLE_SIG_STR, "elm"); | ||
173 | } | ||
174 | |||
175 | static void | ||
176 | _translate_hook(Evas_Object *obj) | ||
177 | { | ||
178 | Widget_Data *wd; | ||
179 | wd = elm_widget_data_get(obj); | ||
180 | if (!wd) return; | ||
181 | |||
182 | if (!wd->user_format) _reload_format(obj); | ||
183 | else _field_list_display(obj); | ||
184 | evas_object_smart_callback_call(obj, SIG_LANGUAGE_CHANGED, NULL); | ||
185 | } | ||
186 | |||
187 | static void | ||
188 | _on_focus_hook(void *data __UNUSED__, Evas_Object *obj) | ||
189 | { | ||
190 | Widget_Data *wd; | ||
191 | |||
192 | wd = elm_widget_data_get(obj); | ||
193 | if (!wd) return; | ||
194 | |||
195 | if (elm_widget_focus_get(obj)) | ||
196 | edje_object_signal_emit(wd->base, EDC_DATETIME_FOCUSIN_SIG_STR, "elm"); | ||
197 | else | ||
198 | edje_object_signal_emit(wd->base, EDC_DATETIME_FOCUSOUT_SIG_STR, "elm"); | ||
199 | } | ||
200 | |||
201 | static Eina_List * | ||
202 | _datetime_items_get(const Evas_Object *obj) | ||
203 | { | ||
204 | Widget_Data *wd; | ||
205 | Eina_List *items = NULL; | ||
206 | Datetime_Field *field; | ||
207 | int loc, count = 0; | ||
208 | unsigned int idx; | ||
209 | |||
210 | wd = elm_widget_data_get(obj); | ||
211 | if (!wd) return NULL; | ||
212 | |||
213 | for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++) | ||
214 | { | ||
215 | field = wd->field_list + idx; | ||
216 | if (field->fmt_exist && field->visible) count++; | ||
217 | } | ||
218 | for (loc = 0; loc < count; loc++) | ||
219 | { | ||
220 | for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++) | ||
221 | { | ||
222 | field = wd->field_list + idx; | ||
223 | if (field->location == loc) | ||
224 | items = eina_list_append(items, field->item_obj); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | return items; | ||
229 | } | ||
230 | |||
231 | static Eina_Bool | ||
232 | _elm_datetime_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next) | ||
233 | { | ||
234 | Widget_Data *wd; | ||
235 | const Eina_List *items; | ||
236 | void *(*list_data_get) (const Eina_List *list); | ||
237 | Eina_List *(*list_free) (Eina_List *list); | ||
238 | Eina_Bool ret; | ||
239 | |||
240 | wd = elm_widget_data_get(obj); | ||
241 | if (!wd) return EINA_FALSE; | ||
242 | |||
243 | if ((items = elm_widget_focus_custom_chain_get(obj))) | ||
244 | { | ||
245 | list_data_get = eina_list_data_get; | ||
246 | list_free = NULL; | ||
247 | } | ||
248 | else | ||
249 | { | ||
250 | items = _datetime_items_get(obj); | ||
251 | list_data_get = eina_list_data_get; | ||
252 | list_free = eina_list_free; | ||
253 | if (!items) return EINA_FALSE; | ||
254 | } | ||
255 | |||
256 | ret = elm_widget_focus_list_next_get(obj, items, list_data_get, dir, next); | ||
257 | if (list_free) list_free((Eina_List *)items); | ||
258 | |||
259 | return ret; | ||
260 | } | ||
261 | |||
262 | static void | ||
263 | _mirrored_set(Evas_Object *obj, Eina_Bool rtl) | ||
264 | { | ||
265 | Widget_Data *wd; | ||
266 | |||
267 | wd = elm_widget_data_get(obj); | ||
268 | if (!wd) return; | ||
269 | |||
270 | edje_object_mirrored_set(wd->base, rtl); | ||
271 | } | ||
272 | |||
273 | static void | ||
274 | _sizing_eval(Evas_Object *obj) | ||
275 | { | ||
276 | Widget_Data *wd; | ||
277 | Datetime_Field *field; | ||
278 | Evas_Coord minw = -1, minh = -1; | ||
279 | unsigned int idx, field_count = 0; | ||
280 | |||
281 | wd = elm_widget_data_get(obj); | ||
282 | if (!wd || !wd->base) return; | ||
283 | for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++) | ||
284 | { | ||
285 | field = wd->field_list + idx; | ||
286 | if ((field->visible) && (field->fmt_exist)) field_count ++; | ||
287 | } | ||
288 | if (field_count) | ||
289 | elm_coords_finger_size_adjust(field_count, &minw, 1, &minh); | ||
290 | edje_object_size_min_restricted_calc(wd->base, &minw, &minh, minw, minh); | ||
291 | evas_object_size_hint_min_set(obj, minw, minh); | ||
292 | evas_object_size_hint_max_set(obj, -1, -1); | ||
293 | } | ||
294 | |||
295 | static void | ||
296 | _theme_hook(Evas_Object *obj) | ||
297 | { | ||
298 | Widget_Data *wd; | ||
299 | Datetime_Field *field; | ||
300 | char buf[BUFFER_SIZE]; | ||
301 | unsigned int idx; | ||
302 | |||
303 | wd = elm_widget_data_get(obj); | ||
304 | if (!wd || !wd->base) return; | ||
305 | |||
306 | _elm_theme_object_set(obj, wd->base, "datetime", "base", | ||
307 | elm_widget_style_get(obj)); | ||
308 | _elm_widget_mirrored_reload(obj); | ||
309 | _mirrored_set(obj, elm_widget_mirrored_get(obj)); | ||
310 | |||
311 | edje_object_scale_set(wd->base, elm_widget_scale_get(obj) * _elm_config->scale); | ||
312 | |||
313 | if (elm_widget_disabled_get(obj)) | ||
314 | edje_object_signal_emit(wd->base, EDC_DATETIME_DISABLE_SIG_STR,"elm"); | ||
315 | else | ||
316 | edje_object_signal_emit(wd->base, EDC_DATETIME_ENABLE_SIG_STR, "elm"); | ||
317 | |||
318 | if ((!dt_mod) || (!dt_mod->field_value_display)) return; | ||
319 | |||
320 | for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++) | ||
321 | { | ||
322 | field = wd->field_list + idx; | ||
323 | if (field->fmt_exist && field->visible) | ||
324 | { | ||
325 | snprintf(buf, sizeof(buf), EDC_PART_FIELD_ENABLE_SIG_STR, field->location); | ||
326 | edje_object_signal_emit(wd->base, buf, "elm"); | ||
327 | snprintf(buf, sizeof(buf), EDC_PART_SEPARATOR_STR, field->location); | ||
328 | edje_object_part_text_escaped_set(wd->base, buf, field->separator); | ||
329 | dt_mod->field_value_display(wd->mod_data, field->item_obj); | ||
330 | } | ||
331 | else | ||
332 | { | ||
333 | snprintf(buf, sizeof(buf),EDC_PART_FIELD_DISABLE_SIG_STR, field->location); | ||
334 | edje_object_signal_emit(wd->base, buf, "elm"); | ||
335 | } | ||
336 | } | ||
337 | edje_object_message_signal_process(wd->base); | ||
338 | _sizing_eval(obj); | ||
339 | } | ||
340 | |||
341 | static int | ||
342 | _max_days_get(int year, int month) | ||
343 | { | ||
344 | struct tm time1; | ||
345 | time_t t; | ||
346 | int day; | ||
347 | |||
348 | t = time(NULL); | ||
349 | localtime_r(&t, &time1); | ||
350 | time1.tm_year = year; | ||
351 | time1.tm_mon = month; | ||
352 | for (day = MIN_DAYS_IN_MONTH; day <= mapping[ELM_DATETIME_DATE].def_max; day++) | ||
353 | { | ||
354 | time1.tm_mday = day; | ||
355 | mktime(&time1); | ||
356 | if (time1.tm_mday == 1) break; | ||
357 | } | ||
358 | day --; | ||
359 | return day; | ||
360 | } | ||
361 | |||
362 | static Eina_Bool | ||
363 | _date_cmp(struct tm *time1, struct tm *time2) | ||
364 | { | ||
365 | unsigned int idx; | ||
366 | DATETIME_TM_ARRAY(timearr1, time1); | ||
367 | DATETIME_TM_ARRAY(timearr2, time2); | ||
368 | |||
369 | for (idx = 0; idx < DATETIME_TYPE_COUNT - 1; idx++) | ||
370 | { | ||
371 | if (*timearr1[idx] != *timearr2[idx]) | ||
372 | return EINA_FALSE; | ||
373 | } | ||
374 | return EINA_TRUE; | ||
375 | } | ||
376 | |||
377 | // validates curr_time/min_limt/max_limit according to the newly set value | ||
378 | static void | ||
379 | _validate_datetime_limits(struct tm *time1, struct tm *time2, Eina_Bool swap) | ||
380 | { | ||
381 | struct tm *t1, *t2; | ||
382 | unsigned int idx; | ||
383 | if (!time1 || !time2) return; | ||
384 | |||
385 | t1 = (swap) ? time2 : time1; | ||
386 | t2 = (swap) ? time1 : time2; | ||
387 | |||
388 | DATETIME_TM_ARRAY(timearr1, time1); | ||
389 | DATETIME_TM_ARRAY(timearr2, time2); | ||
390 | for (idx = 0; idx < DATETIME_TYPE_COUNT - 1; idx++) | ||
391 | { | ||
392 | if (*timearr1[idx] < *timearr2[idx]) | ||
393 | { | ||
394 | memcpy(t1, t2, sizeof(struct tm)); | ||
395 | break; | ||
396 | } | ||
397 | else if (*timearr1[idx] > *timearr2[idx]) | ||
398 | break; | ||
399 | } | ||
400 | } | ||
401 | |||
402 | static void | ||
403 | _apply_field_limits(Evas_Object *obj) | ||
404 | { | ||
405 | Widget_Data *wd; | ||
406 | Datetime_Field *field; | ||
407 | int val; | ||
408 | unsigned int idx = 0; | ||
409 | |||
410 | wd = elm_widget_data_get(obj); | ||
411 | if (!wd) return; | ||
412 | |||
413 | DATETIME_TM_ARRAY(timearr, &wd->curr_time); | ||
414 | for (idx = 0; idx < DATETIME_TYPE_COUNT - 1; idx++) | ||
415 | { | ||
416 | field = wd->field_list + idx; | ||
417 | val = *timearr[idx]; | ||
418 | if (val < field->min) | ||
419 | *timearr[idx] = field->min; | ||
420 | else if (val > field->max) | ||
421 | *timearr[idx] = field->max; | ||
422 | } | ||
423 | _field_list_display(obj); | ||
424 | } | ||
425 | |||
426 | static void | ||
427 | _apply_range_restrictions(Evas_Object *obj, struct tm *tim) | ||
428 | { | ||
429 | Widget_Data *wd; | ||
430 | unsigned int idx; | ||
431 | int val, min, max; | ||
432 | |||
433 | wd = elm_widget_data_get(obj); | ||
434 | if (!wd || !tim) return; | ||
435 | |||
436 | DATETIME_TM_ARRAY(timearr, tim); | ||
437 | for (idx = ELM_DATETIME_MONTH; idx < DATETIME_TYPE_COUNT - 1; idx++) | ||
438 | { | ||
439 | val = *timearr[idx]; | ||
440 | min = mapping[idx].def_min; | ||
441 | max = mapping[idx].def_max; | ||
442 | if (idx == ELM_DATETIME_DATE) | ||
443 | max = _max_days_get(tim->tm_year, tim->tm_mon); | ||
444 | if (val < min) | ||
445 | *timearr[idx] = min; | ||
446 | else if (val > max) | ||
447 | *timearr[idx] = max; | ||
448 | } | ||
449 | } | ||
450 | |||
451 | static const char * | ||
452 | _field_format_get(Evas_Object * obj, Elm_Datetime_Field_Type field_type) | ||
453 | { | ||
454 | Widget_Data *wd; | ||
455 | Datetime_Field *field; | ||
456 | |||
457 | wd = elm_widget_data_get(obj); | ||
458 | if (!wd) return NULL; | ||
459 | |||
460 | field = wd->field_list + field_type; | ||
461 | if (!field) return NULL; | ||
462 | |||
463 | return field->fmt; | ||
464 | } | ||
465 | |||
466 | static void | ||
467 | _field_limit_get(Evas_Object * obj, Elm_Datetime_Field_Type field_type, int *range_min, int *range_max) | ||
468 | { | ||
469 | Widget_Data *wd; | ||
470 | Datetime_Field *field; | ||
471 | int min, max, max_days; | ||
472 | unsigned int idx; | ||
473 | |||
474 | wd = elm_widget_data_get(obj); | ||
475 | if (!wd) return; | ||
476 | |||
477 | field = wd->field_list + field_type; | ||
478 | if (!field) return; | ||
479 | |||
480 | min = field->min; | ||
481 | max = field->max; | ||
482 | |||
483 | DATETIME_TM_ARRAY(curr_timearr, &wd->curr_time); | ||
484 | DATETIME_TM_ARRAY(min_timearr, &wd->min_limit); | ||
485 | DATETIME_TM_ARRAY(max_timearr, &wd->max_limit); | ||
486 | |||
487 | for (idx = 0; idx < field->type; idx++) | ||
488 | if (*curr_timearr[idx] > *min_timearr[idx]) break; | ||
489 | if ((idx == field_type) && (min < *min_timearr[field_type])) | ||
490 | min = *min_timearr[field_type]; | ||
491 | if (field_type == ELM_DATETIME_DATE) | ||
492 | { | ||
493 | max_days = _max_days_get(wd->curr_time.tm_year, wd->curr_time.tm_mon); | ||
494 | if (max > max_days) max = max_days; | ||
495 | } | ||
496 | for (idx = 0; idx < field->type; idx++) | ||
497 | if (*curr_timearr[idx] < *max_timearr[idx]) break; | ||
498 | if ((idx == field_type) && (max > *max_timearr[field_type])) | ||
499 | max = *max_timearr[field_type]; | ||
500 | |||
501 | *range_min = min; | ||
502 | *range_max = max; | ||
503 | } | ||
504 | |||
505 | static void | ||
506 | _field_list_display(Evas_Object *obj) | ||
507 | { | ||
508 | Widget_Data *wd; | ||
509 | Datetime_Field *field; | ||
510 | unsigned int idx= 0; | ||
511 | |||
512 | wd = elm_widget_data_get(obj); | ||
513 | if (!wd) return; | ||
514 | |||
515 | for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++) | ||
516 | { | ||
517 | field = wd->field_list + idx; | ||
518 | if (field->fmt_exist && field->visible) | ||
519 | { | ||
520 | if ((dt_mod) && (dt_mod->field_value_display)) | ||
521 | dt_mod->field_value_display(wd->mod_data, field->item_obj); | ||
522 | } | ||
523 | } | ||
524 | } | ||
525 | |||
526 | static void | ||
527 | _field_list_arrange(Evas_Object *obj) | ||
528 | { | ||
529 | Widget_Data *wd; | ||
530 | Datetime_Field *field; | ||
531 | char buf[BUFFER_SIZE]; | ||
532 | int idx; | ||
533 | |||
534 | wd = elm_widget_data_get(obj); | ||
535 | if (!wd) return; | ||
536 | |||
537 | for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++) | ||
538 | { | ||
539 | field = wd->field_list + idx; | ||
540 | edje_object_part_unswallow(wd->base, field->item_obj); | ||
541 | } | ||
542 | for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++) | ||
543 | { | ||
544 | field = wd->field_list + idx; | ||
545 | if (field->visible && field->fmt_exist) | ||
546 | { | ||
547 | snprintf(buf, sizeof(buf), EDC_PART_FIELD_STR, field->location); | ||
548 | edje_object_part_swallow(wd->base, buf, field->item_obj); | ||
549 | } | ||
550 | else evas_object_hide(field->item_obj); | ||
551 | } | ||
552 | _sizing_eval(obj); | ||
553 | _field_list_display(obj); | ||
554 | } | ||
555 | |||
556 | // FIXME: provide nl_langinfo on Windows if possible | ||
557 | // returns expanded format string for corresponding multi-field format character | ||
558 | static char * | ||
559 | _expanded_fmt_str_get(char ch) | ||
560 | { | ||
561 | char *exp_fmt = ""; | ||
562 | switch (ch) | ||
563 | { | ||
564 | case 'c': | ||
565 | #ifdef HAVE_LANGINFO_H | ||
566 | exp_fmt = nl_langinfo(D_T_FMT); | ||
567 | #else | ||
568 | exp_fmt = ""; | ||
569 | #endif | ||
570 | break; | ||
571 | case 'x': | ||
572 | #ifdef HAVE_LANGINFO_H | ||
573 | exp_fmt = nl_langinfo(D_FMT); | ||
574 | #else | ||
575 | exp_fmt = ""; | ||
576 | #endif | ||
577 | break; | ||
578 | case 'X': | ||
579 | #ifdef HAVE_LANGINFO_H | ||
580 | exp_fmt = nl_langinfo(T_FMT); | ||
581 | #else | ||
582 | exp_fmt = ""; | ||
583 | #endif | ||
584 | break; | ||
585 | case 'r': | ||
586 | #ifdef HAVE_LANGINFO_H | ||
587 | exp_fmt = nl_langinfo(T_FMT_AMPM); | ||
588 | #else | ||
589 | exp_fmt = ""; | ||
590 | #endif | ||
591 | break; | ||
592 | case 'R': | ||
593 | exp_fmt = "%H:%M"; | ||
594 | break; | ||
595 | case 'T': | ||
596 | exp_fmt = "%H:%M:%S"; | ||
597 | break; | ||
598 | case 'D': | ||
599 | exp_fmt = "%m/%d/%y"; | ||
600 | break; | ||
601 | case 'F': | ||
602 | exp_fmt = "%Y-%m-%d"; | ||
603 | break; | ||
604 | default: | ||
605 | exp_fmt = ""; | ||
606 | break; | ||
607 | } | ||
608 | return exp_fmt; | ||
609 | } | ||
610 | |||
611 | static void | ||
612 | _expand_format(char * dt_fmt) | ||
613 | { | ||
614 | char *ptr, *expanded_fmt, ch; | ||
615 | char buf[MAX_FORMAT_LEN] = {0,}; | ||
616 | unsigned int idx = 0, len = 0; | ||
617 | Eina_Bool fmt_char = EINA_FALSE; | ||
618 | |||
619 | ptr = dt_fmt; | ||
620 | while ((ch = *ptr)) | ||
621 | { | ||
622 | if ((fmt_char) && (strchr(multifield_formats, ch))) | ||
623 | { | ||
624 | // replace the multi-field format characters with corresponding expanded format | ||
625 | expanded_fmt = _expanded_fmt_str_get(ch); | ||
626 | len = strlen(expanded_fmt); | ||
627 | buf[--idx] = 0; | ||
628 | strncat(buf, expanded_fmt, len); | ||
629 | idx += len; | ||
630 | } | ||
631 | else buf[idx++] = ch; | ||
632 | if (ch == '%') fmt_char = EINA_TRUE; | ||
633 | else fmt_char = EINA_FALSE; | ||
634 | ptr++; | ||
635 | } | ||
636 | buf[idx] = 0; | ||
637 | strncpy(dt_fmt, buf, MAX_FORMAT_LEN); | ||
638 | } | ||
639 | |||
640 | static unsigned int | ||
641 | _parse_format(Evas_Object *obj, char *fmt_ptr) | ||
642 | { | ||
643 | Widget_Data *wd; | ||
644 | Datetime_Field *field = NULL; | ||
645 | unsigned int len = 0, idx = 0, location = 0; | ||
646 | char separator[MAX_SEPARATOR_LEN]; | ||
647 | char cur; | ||
648 | Eina_Bool fmt_parsing = EINA_FALSE, sep_parsing = EINA_FALSE, | ||
649 | sep_lookup = EINA_FALSE; | ||
650 | |||
651 | wd = elm_widget_data_get(obj); | ||
652 | |||
653 | while ((cur = *fmt_ptr)) | ||
654 | { | ||
655 | if (fmt_parsing) | ||
656 | { | ||
657 | fmt_parsing = EINA_FALSE; | ||
658 | for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++) | ||
659 | { | ||
660 | if (strchr(mapping[idx].fmt_char, cur)) | ||
661 | { | ||
662 | field = wd->field_list + idx; | ||
663 | // ignore the fields already have or disabled | ||
664 | // valid formats, means already parsed & repeated, ignore. | ||
665 | if (!field->visible || field->location != -1) break; | ||
666 | field->fmt[1] = cur; | ||
667 | field->fmt_exist = EINA_TRUE; | ||
668 | field->location = location++; | ||
669 | sep_lookup = EINA_TRUE; | ||
670 | len = 0; | ||
671 | break; | ||
672 | } | ||
673 | } | ||
674 | } | ||
675 | if (cur == '%') | ||
676 | { | ||
677 | fmt_parsing = EINA_TRUE; | ||
678 | sep_parsing = EINA_FALSE; | ||
679 | // set the separator to previous field | ||
680 | separator[len] = 0; | ||
681 | if (field) eina_stringshare_replace(&field->separator, separator); | ||
682 | } | ||
683 | |||
684 | // ignore the set of chars (global, field specific) as field separators. | ||
685 | if (sep_parsing && (len < MAX_SEPARATOR_LEN - 1) && | ||
686 | (field->type != ELM_DATETIME_AMPM) && (!strchr(ignore_separators, cur)) && | ||
687 | (!strchr(mapping[idx].ignore_sep, cur))) | ||
688 | separator[len++] = cur; | ||
689 | if (sep_lookup) sep_parsing = EINA_TRUE; | ||
690 | sep_lookup = EINA_FALSE; | ||
691 | fmt_ptr++; | ||
692 | } | ||
693 | // return the number of valid fields parsed. | ||
694 | return location; | ||
695 | } | ||
696 | |||
697 | static void | ||
698 | _reload_format(Evas_Object *obj) | ||
699 | { | ||
700 | Widget_Data *wd; | ||
701 | Datetime_Field *field; | ||
702 | char buf[BUFFER_SIZE]; | ||
703 | unsigned int idx, field_count; | ||
704 | char *dt_fmt; | ||
705 | |||
706 | wd = elm_widget_data_get(obj); | ||
707 | if (!wd) return; | ||
708 | |||
709 | // FIXME: provide nl_langinfo on Windows if possible | ||
710 | // fetch the default format from Libc. | ||
711 | if (!wd->user_format) | ||
712 | #ifdef HAVE_LANGINFO_H | ||
713 | strncpy(wd->format, nl_langinfo(D_T_FMT), MAX_FORMAT_LEN); | ||
714 | #else | ||
715 | strncpy(wd->format, "", MAX_FORMAT_LEN); | ||
716 | #endif | ||
717 | |||
718 | dt_fmt = (char *)malloc(MAX_FORMAT_LEN); | ||
719 | if (!dt_fmt) return; | ||
720 | strncpy(dt_fmt, wd->format, MAX_FORMAT_LEN); | ||
721 | |||
722 | _expand_format(dt_fmt); | ||
723 | |||
724 | // reset all the fields to disable state | ||
725 | for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++) | ||
726 | { | ||
727 | field = wd->field_list + idx; | ||
728 | field->fmt_exist = EINA_FALSE; | ||
729 | field->location = -1; | ||
730 | } | ||
731 | |||
732 | field_count = _parse_format(obj, dt_fmt); | ||
733 | free(dt_fmt); | ||
734 | |||
735 | // assign locations to disabled fields for uniform usage | ||
736 | for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++) | ||
737 | { | ||
738 | field = wd->field_list + idx; | ||
739 | if (field->location == -1) field->location = field_count++; | ||
740 | |||
741 | if (field->fmt_exist && field->visible) | ||
742 | { | ||
743 | snprintf(buf, sizeof(buf), EDC_PART_FIELD_ENABLE_SIG_STR, | ||
744 | field->location); | ||
745 | edje_object_signal_emit(wd->base, buf, "elm"); | ||
746 | } | ||
747 | else | ||
748 | { | ||
749 | snprintf(buf, sizeof(buf),EDC_PART_FIELD_DISABLE_SIG_STR, | ||
750 | field->location); | ||
751 | edje_object_signal_emit(wd->base, buf, "elm"); | ||
752 | } | ||
753 | snprintf(buf, sizeof(buf), EDC_PART_SEPARATOR_STR, (field->location + 1)); | ||
754 | edje_object_part_text_escaped_set(wd->base, buf, field->separator); | ||
755 | } | ||
756 | edje_object_message_signal_process(wd->base); | ||
757 | _field_list_arrange(obj); | ||
758 | } | ||
759 | |||
760 | static void | ||
761 | _field_list_init(Evas_Object *obj) | ||
762 | { | ||
763 | Widget_Data *wd; | ||
764 | Datetime_Field *field; | ||
765 | unsigned int idx; | ||
766 | time_t t; | ||
767 | |||
768 | wd = elm_widget_data_get(obj); | ||
769 | if (!wd) return; | ||
770 | |||
771 | t = time(NULL); | ||
772 | localtime_r(&t, &wd->curr_time); | ||
773 | |||
774 | mapping[ELM_DATETIME_YEAR].def_min = _elm_config->year_min; | ||
775 | mapping[ELM_DATETIME_YEAR].def_max = _elm_config->year_max; | ||
776 | for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++) | ||
777 | { | ||
778 | field = wd->field_list + idx; | ||
779 | field->type = ELM_DATETIME_YEAR + idx; | ||
780 | field->fmt[0] = '%'; | ||
781 | field->fmt_exist = EINA_FALSE; | ||
782 | field->visible = EINA_TRUE; | ||
783 | field->min = mapping[idx].def_min; | ||
784 | field->max = mapping[idx].def_max; | ||
785 | } | ||
786 | DATETIME_TM_ARRAY(min_timearr, &wd->min_limit); | ||
787 | DATETIME_TM_ARRAY(max_timearr, &wd->max_limit); | ||
788 | for (idx = 0; idx < DATETIME_TYPE_COUNT-1; idx++) | ||
789 | { | ||
790 | *min_timearr[idx] = mapping[idx].def_min; | ||
791 | *max_timearr[idx] = mapping[idx].def_max; | ||
792 | } | ||
793 | } | ||
794 | |||
795 | EAPI Evas_Object * | ||
796 | elm_datetime_add(Evas_Object *parent) | ||
797 | { | ||
798 | Evas_Object *obj; | ||
799 | Evas *e; | ||
800 | Widget_Data *wd; | ||
801 | Datetime_Field *field; | ||
802 | int idx; | ||
803 | |||
804 | ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL); | ||
805 | |||
806 | ELM_SET_WIDTYPE(widtype, "datetime"); | ||
807 | elm_widget_type_set(obj, widtype); | ||
808 | elm_widget_sub_object_add(parent, obj); | ||
809 | elm_widget_data_set(obj, wd); | ||
810 | elm_widget_del_hook_set(obj, _del_hook); | ||
811 | elm_widget_theme_hook_set(obj, _theme_hook); | ||
812 | elm_widget_translate_hook_set(obj, _translate_hook); | ||
813 | elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL); | ||
814 | elm_widget_disable_hook_set(obj, _disable_hook); | ||
815 | elm_widget_can_focus_set(obj, EINA_TRUE); | ||
816 | elm_widget_focus_next_hook_set(obj, _elm_datetime_focus_next_hook); | ||
817 | |||
818 | wd->base = edje_object_add(e); | ||
819 | elm_widget_resize_object_set(obj, wd->base); | ||
820 | _elm_theme_object_set(obj, wd->base, "datetime", "base", "default"); | ||
821 | evas_object_smart_callbacks_descriptions_set(obj, _signals); | ||
822 | |||
823 | // module - initialise module for datetime | ||
824 | if (!dt_mod) dt_mod = _dt_mod_init(); | ||
825 | if ((dt_mod) && (dt_mod->obj_hook)) | ||
826 | wd->mod_data = dt_mod->obj_hook(obj); | ||
827 | // update module data | ||
828 | if (wd->mod_data) | ||
829 | { | ||
830 | wd->mod_data->base = obj; | ||
831 | wd->mod_data->field_limit_get = _field_limit_get; | ||
832 | wd->mod_data->field_format_get = _field_format_get; | ||
833 | } | ||
834 | |||
835 | _field_list_init(obj); | ||
836 | _reload_format(obj); | ||
837 | |||
838 | if ((dt_mod)&&(dt_mod->field_create)) | ||
839 | { | ||
840 | for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++) | ||
841 | { | ||
842 | field = wd->field_list + idx; | ||
843 | field->item_obj = dt_mod->field_create(wd->mod_data, idx); | ||
844 | } | ||
845 | } | ||
846 | _field_list_arrange(obj); | ||
847 | _mirrored_set(obj, elm_widget_mirrored_get(obj)); | ||
848 | |||
849 | return obj; | ||
850 | } | ||
851 | |||
852 | EAPI const char * | ||
853 | elm_datetime_format_get(const Evas_Object *obj) | ||
854 | { | ||
855 | ELM_CHECK_WIDTYPE(obj, widtype) NULL; | ||
856 | Widget_Data *wd; | ||
857 | |||
858 | wd = elm_widget_data_get(obj); | ||
859 | if (!wd) return NULL; | ||
860 | |||
861 | return wd->format; | ||
862 | } | ||
863 | |||
864 | EAPI void | ||
865 | elm_datetime_format_set(Evas_Object *obj, const char *fmt) | ||
866 | { | ||
867 | ELM_CHECK_WIDTYPE(obj, widtype); | ||
868 | Widget_Data *wd; | ||
869 | |||
870 | wd = elm_widget_data_get(obj); | ||
871 | if (!wd) return; | ||
872 | |||
873 | if (fmt) | ||
874 | { | ||
875 | strncpy(wd->format, fmt, MAX_FORMAT_LEN); | ||
876 | wd->user_format = EINA_TRUE; | ||
877 | } | ||
878 | else | ||
879 | wd->user_format = EINA_FALSE; | ||
880 | |||
881 | _reload_format(obj); | ||
882 | } | ||
883 | |||
884 | EAPI Eina_Bool | ||
885 | elm_datetime_field_visible_get(const Evas_Object *obj, Elm_Datetime_Field_Type | ||
886 | fieldtype) | ||
887 | { | ||
888 | ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE; | ||
889 | Widget_Data *wd; | ||
890 | Datetime_Field *field; | ||
891 | |||
892 | wd = elm_widget_data_get(obj); | ||
893 | if (!wd || (fieldtype > ELM_DATETIME_AMPM)) return EINA_FALSE; | ||
894 | |||
895 | field = wd->field_list + fieldtype; | ||
896 | return field->visible; | ||
897 | } | ||
898 | |||
899 | EAPI void | ||
900 | elm_datetime_field_visible_set(Evas_Object *obj, Elm_Datetime_Field_Type fieldtype, | ||
901 | Eina_Bool visible) | ||
902 | { | ||
903 | ELM_CHECK_WIDTYPE(obj, widtype); | ||
904 | Widget_Data *wd; | ||
905 | Datetime_Field *field; | ||
906 | |||
907 | wd = elm_widget_data_get(obj); | ||
908 | if (!wd || (fieldtype > ELM_DATETIME_AMPM)) return; | ||
909 | |||
910 | field = wd->field_list + fieldtype; | ||
911 | if (field->visible == visible) return; | ||
912 | |||
913 | field->visible = visible; | ||
914 | _reload_format(obj); | ||
915 | } | ||
916 | |||
917 | EAPI void | ||
918 | elm_datetime_field_limit_get(const Evas_Object *obj, Elm_Datetime_Field_Type fieldtype, | ||
919 | int *min, int *max) | ||
920 | { | ||
921 | ELM_CHECK_WIDTYPE(obj, widtype); | ||
922 | Widget_Data *wd; | ||
923 | Datetime_Field *field; | ||
924 | |||
925 | wd = elm_widget_data_get(obj); | ||
926 | if (!wd || (fieldtype >= ELM_DATETIME_AMPM)) return; | ||
927 | |||
928 | field = wd->field_list + fieldtype; | ||
929 | if (min) *min = field->min; | ||
930 | if (max) *max = field->max; | ||
931 | } | ||
932 | |||
933 | EAPI void | ||
934 | elm_datetime_field_limit_set(Evas_Object *obj, Elm_Datetime_Field_Type fieldtype, | ||
935 | int min, int max) | ||
936 | { | ||
937 | ELM_CHECK_WIDTYPE(obj, widtype); | ||
938 | Widget_Data *wd; | ||
939 | Datetime_Field *field; | ||
940 | |||
941 | wd = elm_widget_data_get(obj); | ||
942 | if (!wd || (fieldtype >= ELM_DATETIME_AMPM)) return; | ||
943 | |||
944 | if (min > max) return; | ||
945 | |||
946 | field = wd->field_list + fieldtype; | ||
947 | if ((min > mapping[fieldtype].def_min && min < mapping[fieldtype].def_max) | ||
948 | || (field->type == ELM_DATETIME_YEAR)) | ||
949 | field->min = min; | ||
950 | if ((max > mapping[fieldtype].def_min && max < mapping[fieldtype].def_max) | ||
951 | || (field->type == ELM_DATETIME_YEAR)) | ||
952 | field->max = max; | ||
953 | |||
954 | _apply_field_limits(obj); | ||
955 | } | ||
956 | |||
957 | EAPI Eina_Bool | ||
958 | elm_datetime_value_get(const Evas_Object *obj, struct tm *currtime) | ||
959 | { | ||
960 | ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE; | ||
961 | EINA_SAFETY_ON_NULL_RETURN_VAL(currtime, EINA_FALSE); | ||
962 | Widget_Data *wd; | ||
963 | |||
964 | wd = elm_widget_data_get(obj); | ||
965 | if (!wd) return EINA_FALSE; | ||
966 | |||
967 | *currtime = wd->curr_time; | ||
968 | return EINA_TRUE; | ||
969 | } | ||
970 | |||
971 | EAPI Eina_Bool | ||
972 | elm_datetime_value_set(Evas_Object *obj, const struct tm *newtime) | ||
973 | { | ||
974 | ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE; | ||
975 | EINA_SAFETY_ON_NULL_RETURN_VAL(newtime, EINA_FALSE); | ||
976 | Widget_Data *wd; | ||
977 | struct tm old_time; | ||
978 | |||
979 | wd = elm_widget_data_get(obj); | ||
980 | if (!wd) return EINA_FALSE; | ||
981 | |||
982 | old_time = wd->curr_time; | ||
983 | wd->curr_time = *newtime; | ||
984 | // apply default field restrictions for curr_time | ||
985 | _apply_range_restrictions(obj, &wd->curr_time); | ||
986 | // validate the curr_time according to the min_limt and max_limt | ||
987 | _validate_datetime_limits(&wd->curr_time, &wd->min_limit, EINA_FALSE); | ||
988 | _validate_datetime_limits(&wd->max_limit, &wd->curr_time, EINA_TRUE); | ||
989 | _apply_field_limits(obj); | ||
990 | |||
991 | if (!_date_cmp(&old_time, &wd->curr_time)) | ||
992 | evas_object_smart_callback_call(obj, SIG_CHANGED, NULL); | ||
993 | |||
994 | return EINA_TRUE; | ||
995 | } | ||
996 | |||
997 | EAPI Eina_Bool | ||
998 | elm_datetime_value_min_get(const Evas_Object *obj, struct tm *mintime) | ||
999 | { | ||
1000 | ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE; | ||
1001 | EINA_SAFETY_ON_NULL_RETURN_VAL(mintime, EINA_FALSE); | ||
1002 | Widget_Data *wd; | ||
1003 | |||
1004 | wd = elm_widget_data_get(obj); | ||
1005 | if (!wd) return EINA_FALSE; | ||
1006 | |||
1007 | *mintime = wd->min_limit; | ||
1008 | return EINA_TRUE; | ||
1009 | } | ||
1010 | |||
1011 | EAPI Eina_Bool | ||
1012 | elm_datetime_value_min_set(Evas_Object *obj, const struct tm *mintime) | ||
1013 | { | ||
1014 | ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE; | ||
1015 | EINA_SAFETY_ON_NULL_RETURN_VAL(mintime, EINA_FALSE); | ||
1016 | Widget_Data *wd; | ||
1017 | struct tm old_time; | ||
1018 | |||
1019 | wd = elm_widget_data_get(obj); | ||
1020 | if (!wd) return EINA_FALSE; | ||
1021 | |||
1022 | wd->min_limit = *mintime; | ||
1023 | old_time = wd->curr_time; | ||
1024 | // apply default field restrictions for min_limit | ||
1025 | _apply_range_restrictions(obj, &wd->min_limit); | ||
1026 | // validate curr_time and max_limt according to the min_limit | ||
1027 | _validate_datetime_limits(&wd->max_limit, &wd->min_limit, EINA_FALSE); | ||
1028 | _validate_datetime_limits(&wd->curr_time, &wd->min_limit, EINA_FALSE); | ||
1029 | _apply_field_limits(obj); | ||
1030 | |||
1031 | if (!_date_cmp(&old_time, &wd->curr_time)) | ||
1032 | evas_object_smart_callback_call(obj, SIG_CHANGED, NULL); | ||
1033 | |||
1034 | return EINA_TRUE; | ||
1035 | } | ||
1036 | |||
1037 | EAPI Eina_Bool | ||
1038 | elm_datetime_value_max_get(const Evas_Object *obj, struct tm *maxtime) | ||
1039 | { | ||
1040 | ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE; | ||
1041 | EINA_SAFETY_ON_NULL_RETURN_VAL(maxtime, EINA_FALSE); | ||
1042 | Widget_Data *wd; | ||
1043 | |||
1044 | wd = elm_widget_data_get(obj); | ||
1045 | if (!wd) return EINA_FALSE; | ||
1046 | |||
1047 | *maxtime = wd->max_limit; | ||
1048 | return EINA_TRUE; | ||
1049 | } | ||
1050 | |||
1051 | EAPI Eina_Bool | ||
1052 | elm_datetime_value_max_set(Evas_Object *obj, const struct tm *maxtime) | ||
1053 | { | ||
1054 | ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE; | ||
1055 | EINA_SAFETY_ON_NULL_RETURN_VAL(maxtime, EINA_FALSE); | ||
1056 | Widget_Data *wd; | ||
1057 | struct tm old_time; | ||
1058 | |||
1059 | wd = elm_widget_data_get(obj); | ||
1060 | if (!wd) return EINA_FALSE; | ||
1061 | |||
1062 | wd->max_limit = *maxtime; | ||
1063 | old_time = wd->curr_time; | ||
1064 | // apply default field restrictions for max_limit | ||
1065 | _apply_range_restrictions(obj, &wd->max_limit); | ||
1066 | // validate curr_time and min_limt according to the max_limit | ||
1067 | _validate_datetime_limits(&wd->max_limit, &wd->min_limit, EINA_TRUE); | ||
1068 | _validate_datetime_limits(&wd->max_limit, &wd->curr_time, EINA_TRUE); | ||
1069 | _apply_field_limits(obj); | ||
1070 | |||
1071 | if (!_date_cmp(&old_time, &wd->curr_time)) | ||
1072 | evas_object_smart_callback_call(obj, SIG_CHANGED, NULL); | ||
1073 | |||
1074 | return EINA_TRUE; | ||
1075 | } | ||