From: Sumanth Krishna Mannam <sumanth.m@samsung.com>
authorraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Mon, 5 Mar 2012 11:07:05 +0000 (11:07 +0000)
committerraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Mon, 5 Mar 2012 11:07:05 +0000 (11:07 +0000)
Subject: [E-devel]  [Patch] Elementary : New widget Elm_datetime patch

Attached to the mail is the patch for new elementary widget elm_datetime.
Refer to the below EFL post history for more details.

The datetime widget provides an option to display Date & time based on
current locale format and the user can edit them through dynamic Modules.
Dynamic modules can be based on 1. Content Popup/diskselector based
list   2. Elm_entry with ISE based input   3. Elm_Spinner based  etc.
Refer to the Screenshots:  <1.ctxpopup_diskselector_UI>
<2.entry_ise_UI>   <3.spinner_selection_UI>

Can someone review and push this patch to EFL repository?

Change description:
New widget Elm_datetime is added.
Datetime widget displays the Date &Time fields and provides a
customizable way to edit them.
The widget is implemented in a modular fashion for date/time field inputs.
Ctxpopup based input is proposed as the default selection module.
Localization support based on Libc is also supported.

Sign-Off By:  Sumanth M.V.K  <sumanth.m@samsug.com>

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/elementary@68696 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

25 files changed:
AUTHORS
config/default/base.src
config/illume/base.src
configure.ac
data/themes/default.edc
data/themes/widgets/datetime.edc [new file with mode: 0644]
doc/Makefile.am
doc/examples.dox
doc/index.doxy
doc/widgets/Makefile.am
doc/widgets/widget_preview_datetime1.c [new file with mode: 0644]
doc/widgets/widget_preview_datetime2.c [new file with mode: 0644]
doc/widgets/widget_preview_datetime3.c [new file with mode: 0644]
src/bin/Makefile.am
src/bin/test.c
src/bin/test_datetime.c [new file with mode: 0644]
src/examples/Makefile.am
src/lib/Elementary.h.in
src/lib/Makefile.am
src/lib/elm_datetime.c [new file with mode: 0644]
src/lib/elm_datetime.h [new file with mode: 0644]
src/lib/elm_priv.h
src/modules/Makefile.am
src/modules/datetime_input_ctxpopup/Makefile.am [new file with mode: 0644]
src/modules/datetime_input_ctxpopup/datetime_input_ctxpopup.c [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
index dab5202..9bad23e 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -53,3 +53,4 @@ Hyunsil Park <hyunsil.park@samsung.com>
 Goun Lee <gouni.lee@samsung.com>
 Mikael Sans <sans.mikael@gmail.com>
 Doyoun Kang <doyoun.kang@samsung.com>
+M.V.K. Sumanth <sumanth.m@samsung.com> <mvksumanth@gmail.com>
index 7d5f0c6..59a40a2 100644 (file)
@@ -26,7 +26,7 @@ group "Elm_Config" struct {
   value "finger_size" int: 40;
   value "fps" double: 60.0;
   value "theme" string: "default";
-  value "modules" string: "";
+  value "modules" string: "datetime_input_ctxpopup>datetime/api";
   value "tooltip_delay" double: 1.0;
   value "cursor_engine_only" uchar: 1;
   value "focus_highlight_enable" uchar: 0;
index 688dfd8..7c87276 100644 (file)
@@ -30,7 +30,7 @@ group "Elm_Config" struct {
   value "finger_size" int: 40;
   value "fps" double: 60.0;
   value "theme" string: "default";
-  value "modules" string: "";
+  value "modules" string: "datetime_input_ctxpopup>datetime/api";
   value "tooltip_delay" double: 1.0;
   value "cursor_engine_only" uchar: 1;
   value "focus_highlight_enable" uchar: 0;
index bcf85e2..0045d84 100644 (file)
@@ -711,6 +711,7 @@ src/lib/Elementary.h
 src/bin/Makefile
 src/modules/Makefile
 src/modules/access_output/Makefile
+src/modules/datetime_input_ctxpopup/Makefile
 src/modules/test_entry/Makefile
 src/modules/test_map/Makefile
 src/edje_externals/Makefile
index 555cb7b..5111d77 100644 (file)
@@ -324,6 +324,7 @@ collections {
 #include "widgets/button.edc"
 #include "widgets/toggle.edc"
 #include "widgets/clock.edc"
+#include "widgets/datetime.edc"
 #include "widgets/menu.edc"
 #include "widgets/frame.edc"
 #include "widgets/tooltip.edc"
diff --git a/data/themes/widgets/datetime.edc b/data/themes/widgets/datetime.edc
new file mode 100644 (file)
index 0000000..fe68ab3
--- /dev/null
@@ -0,0 +1,349 @@
+///////////////////////////////////////////////////////////////////////////////
+// datetime
+///////////////////////////////////////////////////////////////////////////////
+
+#define DATETIME_FIELD(_pos) \
+   part {\
+      name: "field"#_pos; \
+      type: SWALLOW; \
+      scale: 1;\
+      clip_to: "clipper";\
+      description { state: "default" 0.0; \
+         visible: 0;\
+         min: 0 0;\
+         align: 0.0 0.5;\
+         fixed: 1 0;\
+         rel1 {\
+            relative: 1.0 0.0;\
+            to: "separator"#_pos;\
+         }\
+         rel2 {\
+            relative: 1.0 1.0;\
+            to: "separator"#_pos;\
+         }\
+      }\
+      description { state: "enable" 0.0;\
+         inherit: "default" 0.0;\
+         visible: 1;\
+         min: 25 25;\
+      }\
+   }\
+   programs{\
+      program {\
+         name: "field_"#_pos"enabled";\
+         signal: "field"#_pos",enable";\
+         source: "elm";\
+         action: STATE_SET "enable" 0.0;\
+         target: "field"#_pos;\
+      }\
+      program {\
+         name: "field_"#_pos"disabled";\
+         signal: "field"#_pos",disable";\
+         source: "elm";\
+         action: STATE_SET "default" 0.0;\
+         target: "field"#_pos;\
+      }\
+    }
+
+#define DATETIME_SEPARATOR(_pos,_after) \
+   part {\
+      name: "separator"#_pos; \
+      type: TEXT;\
+      scale: 1;\
+      description {\
+         state: "default" 0.0;\
+         visible: 0;\
+         min: 0 0;\
+         align: 0.0 0.5;\
+         fixed: 1 0;\
+         rel1 {\
+            relative: 1.0 0.0;\
+            to: "field"#_after;\
+         }\
+         rel2 {\
+            relative: 1.0 1.0;\
+            to: "field"#_after;\
+         }\
+         color: 100 100 100 255;\
+         text {\
+            font: "SLP:style=Roman";\
+            size: 13;\
+            min:  1 0;\
+            align: 0.2 0.5;\
+         }\
+      }\
+      description { state: "enable" 0.0;\
+         inherit: "default" 0.0;\
+         visible: 1;\
+         min: 13 25;\
+      }\
+   }\
+   programs {\
+      program {\
+         name: "separator"#_pos",enabled";\
+         signal: "field"#_after",enable";\
+         source: "elm";\
+         action: STATE_SET "enable" 0.0;\
+         target: "separator"#_pos;\
+      }\
+      program {\
+         name: "separator"#_pos",disabled";\
+         signal: "field"#_after",disable";\
+         source: "elm";\
+         action: STATE_SET "default" 0.0;\
+         target: "separator"#_pos;\
+      }\
+   }
+
+
+group { name: "elm/datetime/base/default";
+   parts {
+      part {
+         name: "bg";
+         type: RECT;
+         scale: 1;
+         description {
+            state: "default" 0.0;
+            color: 0 0 0 0;
+         }
+      }
+      part {
+         name: "separator0";
+         type: RECT;
+         scale: 1;
+         description {
+            state: "default" 0.0;
+            visible: 0;
+            min: 13 25;
+            align: 0.0 0.5;
+            fixed: 1 0;
+            rel2 {
+               relative: 0.0 1.0;
+               to: "bg";
+            }
+         }
+      }
+      DATETIME_FIELD(0)
+      DATETIME_SEPARATOR(1,0)
+      DATETIME_FIELD(1)
+      DATETIME_SEPARATOR(2,1)
+      DATETIME_FIELD(2)
+      DATETIME_SEPARATOR(3,2)
+      DATETIME_FIELD(3)
+      DATETIME_SEPARATOR(4,3)
+      DATETIME_FIELD(4)
+      DATETIME_SEPARATOR(5,4)
+      DATETIME_FIELD(5)
+      DATETIME_SEPARATOR(6,5)
+      part {
+         name: "clipper";
+         type: RECT;
+         description { state: "default" 0.0;
+            rel1 {
+               relative: 0.0 0.0;
+               to: "separator0";
+            }
+            rel2 {
+               relative: 1.0 1.0;
+               to: "separator6";
+            }
+            color: 255 255 255 255;
+         }
+         description { state: "enable" 0.0;
+            inherit: "default" 0.0;
+            color: 255 255 255 127;
+         }
+      }
+      part {
+         name: "disabler";
+         type: RECT;
+         description { state: "default" 0.0;
+            color: 0 0 0 0;
+            visible: 0;
+         }
+         description { state: "visible" 0.0;
+            inherit: "default" 0.0;
+            visible: 1;
+         }
+      }
+   }
+   programs {
+      program {
+         name: "disble_datetime";
+         signal: "elm,state,disabled";
+         source: "elm";
+         action: STATE_SET "visible" 0.0;
+         target: "disabler";
+         target: "clipper";
+      }
+      program {
+         name: "enable_datetime";
+         signal: "elm,state,enabled";
+         source: "elm";
+         action: STATE_SET "default" 0.0;
+         target: "disabler";
+         target: "clipper";
+      }
+   }
+}//end datetime group
+
+///////////////////////////////////////////////////////////////////////////////
+// diskselector item : datetime style
+///////////////////////////////////////////////////////////////////////////////
+group { name: "elm/diskselector/item/datetime/default";
+   data {
+      item: "len_threshold" "10";
+      item: "min_height" "-1";
+      item: "min_width" "-1";
+   }
+   parts {
+     part {
+        name: "elm.text";
+        type: TEXT;
+        mouse_events: 0;
+        scale: 1;
+        description {
+           state: "default" 0.0;
+           min: 25 25;
+           fixed: 1 1;
+           align: 0.0 0.0;
+           color: 172 172 172 255;
+           visible: 1;
+           text {
+              font: "Sans,Edje-Vera";
+              size: 13;
+              min: 1 1;
+           }
+        }
+        description {
+           state: "center_sel" 0.0;
+           inherit: "default" 0.0;
+           color: 255 255 255 255;
+        }
+        description { state: "left_side" 0.0;
+           inherit: "default" 0.0;
+           color: 152 152 152 255;
+           text.size: 10;
+           text.align: 0.2 0.5;
+        }
+        description { state: "left_side_sel" 0.0;
+           inherit: "default" 0.0;
+           color: 255 255 255 255;
+           text.size: 10;
+           text.align: 0.2 0.5;
+        }
+        description { state: "right_side" 0.0;
+           inherit: "default" 0.0;
+           color: 152 152 152 255;
+           text.size: 10;
+           text.align: 0.8 0.5;
+        }
+        description { state: "right_side_sel" 0.0;
+           inherit: "default" 0.0;
+           color: 255 255 255 255;
+           text.size: 10;
+           text.align: 0.8 0.5;
+        }
+     }
+     part {
+        name: "over1";
+        mouse_events: 1;
+        repeat_events: 1;
+        ignore_flags: ON_HOLD;
+        description {
+           state: "default" 0.0;
+        }
+     }
+   }
+   programs {
+      script {
+         public field_pos; // center = 0,left = 1, right =2.
+         public field_selected; //field is selected(1) or not(0).
+
+         public update_state() {
+            new pos, is_sel;
+            pos = get_int(field_pos)
+            is_sel = get_int(field_selected);
+
+            if (is_sel == 1)
+              {
+                 if (pos == 0)
+                   set_state(PART:"elm.text", "center_sel", 0.0);
+                 else if (pos == 1)
+                   set_state(PART:"elm.text", "left_side_sel", 0.0);
+                 else if (pos == 2)
+                   set_state(PART:"elm.text", "right_side_sel", 0.0);
+              }
+            else if (is_sel == 0)
+              {
+                 if (pos == 0)
+                   set_state(PART:"elm.text", "default", 0.0);
+                 else if (pos == 1)
+                   set_state(PART:"elm.text", "left_side", 0.0);
+                 else if (pos == 2)
+                   set_state(PART:"elm.text", "right_side", 0.0);
+              }
+         }
+      }
+      program {
+         name: "selected_text";
+         signal: "elm,state,selected";
+         source: "elm";
+         script {
+            set_int(field_selected, 1);
+            update_state();
+         }
+      }
+      program {
+         name: "default_text";
+         signal: "elm,state,default";
+         source: "elm";
+         script {
+            set_int(field_selected, 0);
+            update_state();
+         }
+      }
+      program { name: "center_text";
+         signal: "elm,state,center";
+         source: "elm";
+         script {
+            set_int(field_pos, 0);
+            update_state();
+         }
+      }
+      program { name: "center_small_text";
+         signal: "elm,state,center_small";
+         source: "elm";
+         script {
+            set_int(field_pos, 0);
+            update_state();
+         }
+      }
+      program { name: "l_side_text";
+         signal: "elm,state,left_side";
+         source: "elm";
+         script {
+            set_int(field_pos, 1);
+            update_state();
+         }
+      }
+      program { name: "r_side_text";
+         signal: "elm,state,right_side";
+         source: "elm";
+         script {
+            set_int(field_pos, 2);
+            update_state();
+         }
+      }
+      program {
+         name: "field_click";
+         signal: "mouse,clicked,1";
+         source: "over1";
+         action: SIGNAL_EMIT "elm,action,click" "";
+      }
+   }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// end of datetime style
+///////////////////////////////////////////////////////////////////////////////
index 942e09c..bdb4731 100644 (file)
@@ -33,6 +33,9 @@ WGT_PREVIEW = \
        frame:preview-00.png:widget_preview_frame:100:50 \
        label:preview-00.png:widget_preview_label:70:30 \
        clock:preview-00.png:widget_preview_clock:200:100 \
+       datetime:preview-00.png:widget_preview_datetime1:360:60 \
+       datetime:preview-01.png:widget_preview_datetime2:200:60 \
+       datetime:preview-02.png:widget_preview_datetime3:200:60 \
        slider:preview-00.png:widget_preview_slider:200:100 \
        panes:preview-00.png:widget_preview_panes:200:100 \
        toolbar:preview-00.png:widget_preview_toolbar:300:100 \
index fda24f3..3b02358 100644 (file)
@@ -37,6 +37,8 @@
  *
  * @ref clock_example
  *
+ * @ref datetime_example
+ *
  * @ref mapbuf_example
 
  * @ref map_example_01
  */
 
 /**
+ * @page datetime_example Datetime widget example
+ *
+ * This code places three Elementary Datetime widgets on a window, each of
+ * them exemplifying the widget's different usage.
+ *
+ * The first of them is <b>"only Date display"</b>:
+ * @dontinclude datetime_example.c
+ * @skip only DATE
+ * @until evas_object_show
+ *
+ * For <b>"only Time display"</b>, see the second datetime:
+ * @dontinclude datetime_example.c
+ * @skip only TIME
+ * @until evas_object_show
+ *
+ * The third one will display datetime shows both <b>Date and Time</b>, corresponding format will be
+ * taken from system @b locale. Note, besides, that the strings are different
+ *  for different language settings.
+ *
+ * <b>Datetime format</b> can be programmatically set by using 
+ * elm_datetime_format_set():
+ * @dontinclude datetime_example.c
+ * @skip DATE and TIME
+ * @until evas_object_show
+ * The default format of any locale consists:
+ * - Year Field
+ * - Month Field
+ * - Date Field
+ * - Hour Field(12hr/24hr format)
+ * - Minute Field
+ * - AM/PM (if exists).
+ *
+ * This is how the example program's window looks like with the datetime widget
+ * showing only date, only time and both date & time:
+ *
+ * @image html screenshots/datetime_example.png
+ * @image latex screenshots/datetime_example.eps width=\textwidth
+ *
+ * See the full @ref datetime_example_c "source code" for
+ * this example.
+ *
+ * @example datetime_example.c
+ */
+
+/**
  * @page mapbuf_example Mapbuf Widget Example
  *
  * This code places a Elementary mapbuf widget on a window,
  * @example clock_example.c
  */
 
+ /**
+ * @page datetime_example_c Datetime example
+ * @include datetime_example.c
+ * @example datetime_example.c
+ */
+
 /**
  * @page flipselector_example_c Flipselector example
  * @include flipselector_example.c
index e787b19..61c42ca 100644 (file)
  *
  * @image html img/widget/ctxpopup/preview-00.png
  * @image latex img/widget/ctxpopup/preview-00.eps
+ * @li @ref Datetime
+ *
+ * @image html img/widget/datetime/preview-00.png
+ * @image latex img/widget/datetime/preview-00.eps
  * @li @ref Diskselector
  *
  * @image html img/widget/diskselector/preview-00.png
index 0bbb0b7..d9ec6e0 100644 (file)
@@ -32,6 +32,9 @@ widget_preview_spinner \
 widget_preview_bubble1 \
 widget_preview_bubble2 \
 widget_preview_bubble3 \
+widget_preview_datetime1 \
+widget_preview_datetime2 \
+widget_preview_datetime3 \
 widget_preview_fileselector_button1 \
 widget_preview_fileselector_button2 \
 widget_preview_fileselector_button3 \
@@ -122,6 +125,9 @@ EXTRA_DIST = \
        widget_preview_mapbuf.c \
        widget_preview_map.c \
        widget_preview_ctxpopup.c \
+       widget_preview_datetime1.c \
+       widget_preview_datetime2.c \
+       widget_preview_datetime3.c \
        widget_preview_diskselector.c \
        widget_preview_entry1.c \
        widget_preview_entry2.c \
diff --git a/doc/widgets/widget_preview_datetime1.c b/doc/widgets/widget_preview_datetime1.c
new file mode 100644 (file)
index 0000000..359753f
--- /dev/null
@@ -0,0 +1,16 @@
+#include "widget_preview_tmpl_head.c"
+
+Evas_Object *bx = elm_box_add(win);
+evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+elm_win_resize_object_add(win, bx);
+evas_object_show(bx);
+evas_object_size_hint_min_set(bx, 360, 60);
+
+Evas_Object *datetime = elm_datetime_add(win);
+evas_object_size_hint_weight_set(datetime, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+evas_object_size_hint_align_set(datetime, EVAS_HINT_FILL, EVAS_HINT_FILL);
+elm_box_pack_end(bx, datetime);
+evas_object_show(datetime);
+
+#include "widget_preview_tmpl_foot.c"
diff --git a/doc/widgets/widget_preview_datetime2.c b/doc/widgets/widget_preview_datetime2.c
new file mode 100644 (file)
index 0000000..59e9aa0
--- /dev/null
@@ -0,0 +1,19 @@
+#include "widget_preview_tmpl_head.c"
+
+Evas_Object *bx = elm_box_add(win);
+evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+elm_win_resize_object_add(win, bx);
+evas_object_show(bx);
+evas_object_size_hint_min_set(bx, 200, 60);
+
+Evas_Object *datetime = elm_datetime_add(win);
+evas_object_size_hint_weight_set(datetime, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+evas_object_size_hint_align_set(datetime, EVAS_HINT_FILL, EVAS_HINT_FILL);
+elm_datetime_field_visible_set(datetime, ELM_DATETIME_HOUR, EINA_FALSE);
+elm_datetime_field_visible_set(datetime, ELM_DATETIME_MINUTE, EINA_FALSE);
+elm_datetime_field_visible_set(datetime, ELM_DATETIME_AMPM, EINA_FALSE);
+elm_box_pack_end(bx, datetime);
+evas_object_show(datetime);
+
+#include "widget_preview_tmpl_foot.c"
diff --git a/doc/widgets/widget_preview_datetime3.c b/doc/widgets/widget_preview_datetime3.c
new file mode 100644 (file)
index 0000000..bf51f7f
--- /dev/null
@@ -0,0 +1,19 @@
+#include "widget_preview_tmpl_head.c"
+
+Evas_Object *bx = elm_box_add(win);
+evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+elm_win_resize_object_add(win, bx);
+evas_object_show(bx);
+evas_object_size_hint_min_set(bx, 200, 60);
+
+Evas_Object *datetime = elm_datetime_add(win);
+evas_object_size_hint_weight_set(datetime, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+evas_object_size_hint_align_set(datetime, EVAS_HINT_FILL, EVAS_HINT_FILL);
+elm_datetime_field_visible_set(datetime, ELM_DATETIME_YEAR, EINA_FALSE);
+elm_datetime_field_visible_set(datetime, ELM_DATETIME_MONTH, EINA_FALSE);
+elm_datetime_field_visible_set(datetime, ELM_DATETIME_DATE, EINA_FALSE);
+elm_box_pack_end(bx, datetime);
+evas_object_show(datetime);
+
+#include "widget_preview_tmpl_foot.c"
index 9718e55..85ae36e 100644 (file)
@@ -48,6 +48,7 @@ test_colorselector.c \
 test_conform.c \
 test_ctxpopup.c \
 test_cursor.c \
+test_datetime.c \
 test_diskselector.c \
 test_entry.c \
 test_factory.c \
index 30271e7..1c965d2 100644 (file)
@@ -163,6 +163,7 @@ void test_glview(void *data, Evas_Object *obj, void *event_info);
 void test_3d(void *data, Evas_Object *obj, void *event_info);
 void test_naviframe(void *data, Evas_Object *obj, void *event_info);
 void test_factory(void *data, Evas_Object *obj, void *event_info);
+void test_datetime(void *data, Evas_Object *obj, void *event_info);
 #ifdef HAVE_EMOTION
 void test_video(void *data, Evas_Object *obj, void *event_info);
 #endif
@@ -508,6 +509,7 @@ add_tests:
    ADD_TEST(NULL, "Times & Dates", "Clock", test_clock);
    ADD_TEST(NULL, "Times & Dates", "Clock 2", test_clock2);
    ADD_TEST(NULL, "Times & Dates", "Clock 3", test_clock3);
+   ADD_TEST(NULL, "Times & Dates", "Datetime", test_datetime);
 
    //------------------------------//
    ADD_TEST(NULL, "Text", "Anchorview", test_anchorview);
diff --git a/src/bin/test_datetime.c b/src/bin/test_datetime.c
new file mode 100644 (file)
index 0000000..d549702
--- /dev/null
@@ -0,0 +1,81 @@
+#include <Elementary.h>
+#ifdef HAVE_CONFIG_H
+#include "elementary_config.h"
+#endif
+#ifndef ELM_LIB_QUICKLAUNCH
+
+/* A simple test, just displaying datetime in its default format */
+
+static void
+_changed_cb(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   printf("Datetime value is changed\n");
+}
+
+void
+test_datetime(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   Evas_Object *win, *bg, *bx, *datetime;
+   time_t t;
+   struct tm time1;
+
+   win = elm_win_add(NULL, "Datetime", ELM_WIN_BASIC);
+   elm_win_title_set(win, "Datetime");
+   elm_win_autodel_set(win, 1);
+
+   bg = elm_bg_add(win);
+   elm_win_resize_object_add(win, bg);
+   evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_show(bg);
+
+   bx = elm_box_add(win);
+   evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_win_resize_object_add(win, bx);
+   elm_box_horizontal_set(bx, EINA_FALSE);
+   evas_object_show(bx);
+   evas_object_size_hint_min_set(bx, 360, 240);
+
+   datetime = elm_datetime_add(bx);
+   evas_object_size_hint_weight_set(datetime, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(datetime, EVAS_HINT_FILL, 0.5);
+   elm_datetime_field_visible_set(datetime, ELM_DATETIME_HOUR, EINA_FALSE);
+   elm_datetime_field_visible_set(datetime, ELM_DATETIME_MINUTE, EINA_FALSE);
+   elm_datetime_field_visible_set(datetime, ELM_DATETIME_AMPM, EINA_FALSE);
+   elm_box_pack_end(bx, datetime);
+   evas_object_show(datetime);
+
+   datetime = elm_datetime_add(bx);
+   evas_object_size_hint_weight_set(datetime, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(datetime, EVAS_HINT_FILL, 0.5);
+   elm_datetime_field_visible_set(datetime, ELM_DATETIME_YEAR, EINA_FALSE);
+   elm_datetime_field_visible_set(datetime, ELM_DATETIME_MONTH, EINA_FALSE);
+   elm_datetime_field_visible_set(datetime, ELM_DATETIME_DATE, EINA_FALSE);
+   elm_box_pack_end(bx, datetime);
+   evas_object_show(datetime);
+
+   datetime = elm_datetime_add(bx);
+   evas_object_size_hint_weight_set(datetime, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(datetime, EVAS_HINT_FILL, 0.5);
+
+   // get the current local time
+   t = time(NULL);
+   localtime_r(&t, &time1);
+   // set the max year as 2030 and the remaining fields are equal to current time values
+   time1.tm_year = 130;
+   elm_datetime_value_max_set(datetime, &time1);
+   // set the min time limit as "1980 January 10th 02:30 PM"
+   time1.tm_year = 80;
+   time1.tm_mon = 4;
+   time1.tm_mday = 10;
+   time1.tm_hour = 14;
+   time1.tm_min = 30;
+   elm_datetime_value_min_set(datetime, &time1);
+   // minutes can be input only in between 15 and 45
+   elm_datetime_field_limit_set(datetime, ELM_DATETIME_MINUTE, 15, 45);
+   evas_object_smart_callback_add(datetime, "changed", _changed_cb, datetime);
+   elm_box_pack_end(bx, datetime);
+   evas_object_show(datetime);
+
+   evas_object_show(win);
+}
+#endif
index 4acc8eb..4747336 100644 (file)
@@ -61,6 +61,7 @@ SRCS = \
        calendar_example_04.c \
        calendar_example_05.c \
        calendar_example_06.c \
+       datetime_example.c \
        map_example_01.c \
        map_example_02.c \
        map_example_03.c \
@@ -170,6 +171,7 @@ examples_PROGRAMS += \
        calendar_example_04 \
        calendar_example_05 \
        calendar_example_06 \
+       datetime_example \
        map_example_01 \
        map_example_02 \
        map_example_03 \
@@ -259,6 +261,7 @@ SCREENSHOTS = \
        calendar_example_04:calendar_example_04.png:0.0 \
        calendar_example_05:calendar_example_05.png:0.0 \
        calendar_example_06:calendar_example_06.png:0.0 \
+       datetime_example:datetime_example.png:0.0 \
        map_example_01:map_example_01.png:2 \
        map_example_02:map_example_02.png:2.5 \
        map_example_03:map_example_03.png:2 \
index 3f9b9c7..57a9756 100644 (file)
@@ -189,6 +189,7 @@ EAPI extern Elm_Version *elm_version;
 #include <elm_config.h>
 #include <elm_conform.h> // XXX: comments in elm_conform.h
 #include <elm_cursor.h> // XXX: comments in elm_cursor.h. review was not finished.
+#include <elm_datetime.h>
 #include <elm_debug.h> // OK
 #include <elm_diskselector.h>
 
index c7a3756..ac58bc0 100644 (file)
@@ -70,6 +70,7 @@ elm_colorselector.h \
 elm_config.h \
 elm_conform.h \
 elm_cursor.h \
+elm_datetime.h \
 elm_debug.h \
 elm_deprecated.h \
 elm_deprecated_before.h \
@@ -162,6 +163,7 @@ elm_cnp.c \
 elm_colorselector.c \
 elm_config.c \
 elm_conform.c \
+elm_datetime.c \
 elm_diskselector.c \
 elm_entry.c \
 elm_factory.c \
diff --git a/src/lib/elm_datetime.c b/src/lib/elm_datetime.c
new file mode 100644 (file)
index 0000000..1edbae7
--- /dev/null
@@ -0,0 +1,1039 @@
+#include <locale.h>
+#include <langinfo.h>
+#include <Elementary.h>
+#include "elm_priv.h"
+
+typedef struct _Widget_Data Widget_Data;
+typedef struct _Datetime_Field Datetime_Field;
+typedef struct _Datetime_Mod_Api Datetime_Mod_Api;
+typedef struct _Format_Map Format_Map;
+
+#define DATETIME_TYPE_COUNT         6
+#define MAX_FORMAT_LEN              64
+#define MAX_SEPARATOR_LEN           6
+#define MAX_FIELD_FORMAT_LEN        3
+#define MIN_DAYS_IN_MONTH           28
+#define BUFFER_SIZE                 1024
+
+// interface between EDC & C code. Field names & signal names.
+// values 0 to DATETIME_TYPE_COUNT are valid range, can be substituted for %d.
+#define EDC_DATETIME_ENABLE_SIG_STR          "elm,state,enabled"
+#define EDC_DATETIME_DISABLE_SIG_STR         "elm,state,disabled"
+#define EDC_DATETIME_FOCUSIN_SIG_STR         "elm,action,focus"
+#define EDC_DATETIME_FOCUSOUT_SIG_STR        "elm,action,unfocus"
+#define EDC_PART_FIELD_STR                   "field%d"
+#define EDC_PART_SEPARATOR_STR               "separator%d"
+#define EDC_PART_FIELD_ENABLE_SIG_STR        "field%d,enable"
+#define EDC_PART_FIELD_DISABLE_SIG_STR       "field%d,disable"
+
+// struct tm  does not define the fields in the order from year, month, date, hour, minute.
+// values are reassigned to an array for easy handling.
+#define DATETIME_TM_ARRAY(intptr, tmptr) int *intptr[] = {&(tmptr)->tm_year, \
+           &(tmptr)->tm_mon, &(tmptr)->tm_mday, &(tmptr)->tm_hour, &(tmptr)->tm_min}
+
+struct _Datetime_Field
+{
+   Evas_Object *item_obj;
+   char fmt[MAX_FIELD_FORMAT_LEN];
+   Elm_Datetime_Field_Type type;
+   const char *separator;
+   int location;          // location of the field as per the current format
+   int min, max;
+   Eina_Bool fmt_exist:1;  // whether field format is present or not
+   Eina_Bool visible:1;    // whether field can be visible or not
+};
+
+struct _Datetime_Mod_Api
+{
+   Elm_Datetime_Module_Data *(*obj_hook) (Evas_Object *obj);
+   void (*obj_unhook) (Elm_Datetime_Module_Data *module_data);
+   Evas_Object *(*field_create) (Elm_Datetime_Module_Data *module_data,
+                                     Elm_Datetime_Field_Type field_type);
+   void (*field_value_display) (Elm_Datetime_Module_Data *module_data,
+                                    Evas_Object *obj);
+};
+
+struct _Widget_Data
+{
+   Evas_Object *base;
+   Datetime_Field field_list[DATETIME_TYPE_COUNT]; // fixed set of fields.
+   struct tm curr_time, min_limit, max_limit;
+   Elm_Datetime_Module_Data *mod_data;
+   char format[MAX_FORMAT_LEN];
+   Eina_Bool user_format:1; // whether user set format or default format.
+};
+
+struct _Format_Map
+{
+   char *fmt_char;
+   int def_min;
+   int def_max;
+};
+
+// default limits for individual fields
+static const Format_Map mapping[DATETIME_TYPE_COUNT] = {
+   [ELM_DATETIME_YEAR]   =  { "Yy",   0, 137 },
+   [ELM_DATETIME_MONTH]  =  { "mbBh", 0,  11  },
+   [ELM_DATETIME_DATE]   =  { "de",   1,  31  },
+   [ELM_DATETIME_HOUR]   =  { "IHkl", 0,  23  },
+   [ELM_DATETIME_MINUTE] =  { "M",    0,  59  },
+   [ELM_DATETIME_AMPM]   =  { "pP",   0,  1   }
+};
+
+static const char *multifield_formats = "cxXrRTDF";
+
+static Datetime_Mod_Api *dt_mod = NULL;
+static const char *widtype = NULL;
+
+static void _del_hook(Evas_Object *obj);
+static void _disable_hook(Evas_Object *obj);
+static void _translate_hook(Evas_Object *obj);
+static void _on_focus_hook(void *data __UNUSED__, Evas_Object *obj);
+static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl);
+static void _sizing_eval(Evas_Object *obj);
+static void _theme_hook(Evas_Object *obj);
+static void _validate_datetime_limits(struct tm *time1, struct tm *time2, Eina_Bool swap);
+static void _apply_field_limits(Evas_Object *obj);
+static void _apply_range_restrictions(Evas_Object *obj, struct tm *time);
+static const char *_field_format_get(Evas_Object * obj, Elm_Datetime_Field_Type field_type);
+static void _field_limit_get(Evas_Object * obj, Elm_Datetime_Field_Type field_type,
+                             int *range_min, int *range_max);
+static void _reload_format(Evas_Object *obj);
+static void _field_list_display(Evas_Object *obj);
+static void _field_list_arrange(Evas_Object *obj);
+static void _field_list_init(Evas_Object *obj);
+
+static const char SIG_CHANGED[] = "changed";
+static const char SIG_LANGUAGE_CHANGED[] = "language,changed";
+static const Evas_Smart_Cb_Description _signals[] = {
+       {SIG_CHANGED, ""},
+       {SIG_LANGUAGE_CHANGED, ""},
+       {NULL, NULL}
+};
+
+static Datetime_Mod_Api *
+_dt_mod_init()
+{
+   Elm_Module *mod = NULL;
+   if (!(mod = _elm_module_find_as("datetime/api"))) return NULL;
+
+   mod->api = malloc(sizeof(Datetime_Mod_Api));
+   if (!mod->api) return NULL;
+
+   ((Datetime_Mod_Api *)(mod->api))->obj_hook            =   _elm_module_symbol_get(mod, "obj_hook");
+   ((Datetime_Mod_Api *)(mod->api))->obj_unhook          =   _elm_module_symbol_get(mod, "obj_unhook");
+   ((Datetime_Mod_Api *)(mod->api))->field_create        =   _elm_module_symbol_get(mod, "field_create");
+   ((Datetime_Mod_Api *)(mod->api))->field_value_display =   _elm_module_symbol_get(mod, "field_value_display");
+
+   return mod->api;
+}
+
+static void
+_del_hook(Evas_Object *obj)
+{
+   Widget_Data *wd;
+   Datetime_Field *tmp;
+   unsigned int idx;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd) return;
+
+   for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++)
+     {
+        tmp = wd->field_list + idx;
+        evas_object_del(tmp->item_obj);
+        eina_stringshare_del(tmp->separator);
+     }
+
+   if ((dt_mod) && (dt_mod->obj_unhook))
+     dt_mod->obj_unhook(wd->mod_data); // module - unhook
+
+   free(wd);
+}
+
+static void
+_disable_hook(Evas_Object *obj)
+{
+   Widget_Data *wd;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd || !wd->base) return;
+   if (elm_widget_disabled_get(obj))
+     edje_object_signal_emit(wd->base, EDC_DATETIME_DISABLE_SIG_STR, "elm");
+   else
+     edje_object_signal_emit(wd->base, EDC_DATETIME_ENABLE_SIG_STR, "elm");
+}
+
+static void
+_translate_hook(Evas_Object *obj)
+{
+   Widget_Data *wd;
+   wd = elm_widget_data_get(obj);
+   if (!wd) return;
+
+   if (!wd->user_format) _reload_format(obj);
+   else _field_list_display(obj);
+   evas_object_smart_callback_call(obj, SIG_LANGUAGE_CHANGED, NULL);
+}
+
+static void
+_on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
+{
+   Widget_Data *wd;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd) return;
+
+   if (elm_widget_focus_get(obj))
+     edje_object_signal_emit(wd->base, EDC_DATETIME_FOCUSIN_SIG_STR, "elm");
+   else
+     edje_object_signal_emit(wd->base, EDC_DATETIME_FOCUSOUT_SIG_STR, "elm");
+}
+
+static Eina_List *
+_datetime_items_get(const Evas_Object *obj)
+{
+   Widget_Data *wd;
+   Eina_List *items;
+   Datetime_Field *field;
+   int loc, count = 0;
+   unsigned int idx;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd) return NULL;
+
+   for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++)
+     {
+        field = wd->field_list + idx;
+        if (field->fmt_exist && field->visible) count++;
+     }
+   for (loc = 0; loc < count; loc++)
+     for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++)
+       {
+          field = wd->field_list + idx;
+          if (field->location == loc)
+            items = eina_list_append(items, field->item_obj);
+       }
+
+   return items;
+}
+
+static Eina_Bool
+_elm_datetime_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next)
+{
+   Widget_Data *wd;
+   const Eina_List *items;
+   void *(*list_data_get) (const Eina_List *list);
+   Eina_List *(*list_free) (Eina_List *list);
+   Eina_Bool ret;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd) return EINA_FALSE;
+
+   if ((items = elm_widget_focus_custom_chain_get(obj)))
+     {
+        list_data_get = eina_list_data_get;
+        list_free = NULL;
+     }
+   else
+     {
+        items = _datetime_items_get(obj);
+        list_data_get = eina_list_data_get;
+        list_free = eina_list_free;
+        if (!items) return EINA_FALSE;
+     }
+
+   ret = elm_widget_focus_list_next_get(obj, items, list_data_get, dir, next);
+   if (list_free) list_free((Eina_List *)items);
+
+   return ret;
+}
+
+static void
+_mirrored_set(Evas_Object *obj, Eina_Bool rtl)
+{
+   Widget_Data *wd;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd) return;
+
+   edje_object_mirrored_set(wd->base, rtl);
+}
+
+static void
+_sizing_eval(Evas_Object *obj)
+{
+   Widget_Data *wd;
+   Datetime_Field *field;
+   Evas_Coord minw = -1, minh = -1;
+   unsigned int idx, field_count = 0;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd || !wd->base) return;
+   for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++)
+     {
+        field = wd->field_list + idx;
+        if ((field->visible) && (field->fmt_exist)) field_count ++;
+     }
+   if (field_count)
+     elm_coords_finger_size_adjust(field_count, &minw, 1, &minh);
+   edje_object_size_min_restricted_calc(wd->base, &minw, &minh, minw, minh);
+   evas_object_size_hint_min_set(obj, minw, minh);
+   evas_object_size_hint_max_set(obj, -1, -1);
+}
+
+static void
+_theme_hook(Evas_Object *obj)
+{
+   Widget_Data *wd;
+   Datetime_Field *field;
+   char buf[BUFFER_SIZE];
+   unsigned int idx;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd || !wd->base) return;
+
+   _elm_theme_object_set(obj, wd->base, "datetime", "base",
+                         elm_widget_style_get(obj));
+   _elm_widget_mirrored_reload(obj);
+   _mirrored_set(obj, elm_widget_mirrored_get(obj));
+
+   edje_object_scale_set(wd->base, elm_widget_scale_get(obj) * _elm_config->scale);
+
+   if (elm_widget_disabled_get(obj))
+     edje_object_signal_emit(wd->base, EDC_DATETIME_DISABLE_SIG_STR,"elm");
+   else
+     edje_object_signal_emit(wd->base, EDC_DATETIME_ENABLE_SIG_STR, "elm");
+
+   if ((!dt_mod) || (!dt_mod->field_value_display)) return;
+
+   for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++)
+     {
+        field = wd->field_list + idx;
+        if (field->fmt_exist && field->visible)
+          {
+             snprintf(buf, sizeof(buf), EDC_PART_FIELD_ENABLE_SIG_STR, field->location);
+             edje_object_signal_emit(wd->base, buf, "elm");
+             snprintf(buf, sizeof(buf), EDC_PART_SEPARATOR_STR, field->location);
+             edje_object_part_text_set(wd->base, buf, field->separator);
+             dt_mod->field_value_display(wd->mod_data, field->item_obj);
+          }
+        else
+          {
+             snprintf(buf, sizeof(buf),EDC_PART_FIELD_DISABLE_SIG_STR, field->location);
+             edje_object_signal_emit(wd->base, buf, "elm");
+          }
+     }
+   edje_object_message_signal_process(wd->base);
+   _sizing_eval(obj);
+}
+
+static int
+_max_days_get(int year, int month)
+{
+   struct tm time1;
+   time_t t;
+   int day;
+
+   t = time(NULL);
+   localtime_r(&t, &time1);
+   time1.tm_year = year;
+   time1.tm_mon = month;
+   for(day = MIN_DAYS_IN_MONTH; day <= mapping[ELM_DATETIME_DATE].def_max; day++)
+     {
+        time1.tm_mday = day;
+        mktime(&time1);
+        if (time1.tm_mday == 1) break;
+     }
+   day --;
+   return day;
+}
+
+static Eina_Bool
+_date_cmp(struct tm *time1, struct tm *time2)
+{
+   unsigned int idx;
+   DATETIME_TM_ARRAY(timearr1, time1);
+   DATETIME_TM_ARRAY(timearr2, time2);
+
+   for (idx = 0; idx < DATETIME_TYPE_COUNT - 1; idx++)
+     {
+        if (*timearr1[idx] != *timearr2[idx])
+          return EINA_FALSE;
+     }
+   return EINA_TRUE;
+}
+
+// validates curr_time/min_limt/max_limit according to the newly set value
+static void
+_validate_datetime_limits(struct tm *time1, struct tm *time2, Eina_Bool swap)
+{
+   struct tm *t1, *t2;
+   unsigned int idx;
+   if (!time1 || !time2) return;
+
+   t1 = (swap) ? time2 : time1;
+   t2 = (swap) ? time1 : time2;
+
+   DATETIME_TM_ARRAY(timearr1, time1);
+   DATETIME_TM_ARRAY(timearr2, time2);
+   for (idx = 0; idx < DATETIME_TYPE_COUNT - 1; idx++)
+     {
+       if (*timearr1[idx] < *timearr2[idx])
+         {
+            memcpy(t1, t2, sizeof(struct tm));
+            break;
+         }
+       else if (*timearr1[idx] > *timearr2[idx])
+         break;
+     }
+}
+
+static void
+_apply_field_limits(Evas_Object *obj)
+{
+   Widget_Data *wd;
+   Datetime_Field *field;
+   int val;
+   unsigned int idx = 0;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd) return;
+
+   DATETIME_TM_ARRAY(timearr, &wd->curr_time);
+   for (idx = 0; idx < DATETIME_TYPE_COUNT - 1; idx++)
+     {
+        field = wd->field_list + idx;
+        val = *timearr[idx];
+        if (val < field->min)
+          *timearr[idx] = field->min;
+        else if (val > field->max)
+          *timearr[idx] = field->max;
+     }
+   _field_list_display(obj);
+}
+
+static void
+_apply_range_restrictions(Evas_Object *obj, struct tm *time)
+{
+   Widget_Data *wd;
+   unsigned int idx;
+   int val, min, max;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd || !time) return;
+
+   DATETIME_TM_ARRAY(timearr, time);
+   for (idx = ELM_DATETIME_MONTH; idx < DATETIME_TYPE_COUNT - 1; idx++)
+     {
+        val = *timearr[idx];
+        min = mapping[idx].def_min;
+        max = mapping[idx].def_max;
+        if (idx == ELM_DATETIME_DATE)
+          max = _max_days_get(time->tm_year, time->tm_mon);
+        if (val < min)
+          *timearr[idx] = min;
+        else if (val > max)
+          *timearr[idx] = max;
+     }
+}
+
+static const char *
+_field_format_get(Evas_Object * obj, Elm_Datetime_Field_Type field_type)
+{
+   Widget_Data *wd;
+   Datetime_Field *field;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd) return NULL;
+
+   field = wd->field_list + field_type;
+   if (!field) return NULL;
+
+   return field->fmt;
+}
+
+static void
+_field_limit_get(Evas_Object * obj, Elm_Datetime_Field_Type field_type, int *range_min, int *range_max)
+{
+   Widget_Data *wd;
+   Datetime_Field *field;
+   int min, max, max_days;
+   unsigned int idx;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd) return;
+
+   field = wd->field_list + field_type;
+   if (!field) return;
+
+   min = field->min;
+   max = field->max;
+
+   DATETIME_TM_ARRAY(curr_timearr, &wd->curr_time);
+   DATETIME_TM_ARRAY(min_timearr, &wd->min_limit);
+   DATETIME_TM_ARRAY(max_timearr, &wd->max_limit);
+
+   for (idx = 0; idx < field->type; idx++)
+     if (*curr_timearr[idx] > *min_timearr[idx]) break;
+   if ((idx == field_type) && (min < *min_timearr[field_type]))
+     min = *min_timearr[field_type];
+   if (field_type == ELM_DATETIME_DATE)
+     {
+        max_days = _max_days_get(wd->curr_time.tm_year, wd->curr_time.tm_mon);
+        if (max > max_days) max = max_days;
+     }
+   for (idx = 0; idx < field->type; idx++)
+     if (*curr_timearr[idx] < *max_timearr[idx]) break;
+   if ((idx == field_type) && (max > *max_timearr[field_type]))
+     max = *max_timearr[field_type];
+
+   *range_min = min;
+   *range_max = max;
+}
+
+static void
+_field_list_display(Evas_Object *obj)
+{
+   Widget_Data *wd;
+   Datetime_Field *field;
+   unsigned int idx= 0;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd) return;
+
+   for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++)
+     {
+        field = wd->field_list + idx;
+        if (field->fmt_exist && field->visible)
+          {
+             if ((dt_mod) && (dt_mod->field_value_display))
+               dt_mod->field_value_display(wd->mod_data, field->item_obj);
+          }
+     }
+}
+
+static void
+_field_list_arrange(Evas_Object *obj)
+{
+   Widget_Data *wd;
+   Datetime_Field *field;
+   char buf[BUFFER_SIZE];
+   int idx;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd) return;
+
+   for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++)
+     {
+        field = wd->field_list + idx;
+        edje_object_part_unswallow(wd->base, field->item_obj);
+     }
+   for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++)
+     {
+        field = wd->field_list + idx;
+        if (field->visible && field->fmt_exist)
+          {
+             snprintf(buf, sizeof(buf), EDC_PART_FIELD_STR, field->location);
+             edje_object_part_swallow(wd->base, buf, field->item_obj);
+          }
+        else evas_object_hide(field->item_obj);
+     }
+   _sizing_eval(obj);
+   _field_list_display(obj);
+}
+
+// returns expanded format string for corresponding multi-field format character
+static char *
+_expanded_fmt_str_get(char ch)
+{
+   char *exp_fmt = "";
+   switch (ch)
+     {
+      case 'c':
+         exp_fmt = nl_langinfo(D_T_FMT);
+         break;
+      case 'x':
+         exp_fmt = nl_langinfo(D_FMT);
+         break;
+      case 'X':
+         exp_fmt = nl_langinfo(T_FMT);
+         break;
+      case 'r':
+         exp_fmt = nl_langinfo(T_FMT_AMPM);
+         break;
+      case 'R':
+         exp_fmt =  "%H:%M";
+         break;
+      case 'T':
+         exp_fmt =  "%H:%M:%S";
+         break;
+      case 'D':
+         exp_fmt =  "%m/%d/%y";
+         break;
+      case 'F':
+         exp_fmt =  "%Y-%m-%d";
+         break;
+      default:
+         exp_fmt =  "";
+         break;
+     }
+   return exp_fmt;
+}
+
+static void
+_expand_format(char * dt_fmt)
+{
+   char *ptr, *expanded_fmt, ch;
+   char buf[MAX_FORMAT_LEN] = {0,};
+   unsigned int idx = 0, len = 0;
+   Eina_Bool fmt_char = EINA_FALSE;
+
+   ptr = dt_fmt;
+   while ((ch = *ptr))
+     {
+        if ((fmt_char) && (strchr(multifield_formats, ch)))
+          {
+             // replace the multi-field format characters with corresponding expanded format
+             expanded_fmt = _expanded_fmt_str_get(ch);
+             len = strlen(expanded_fmt);
+             buf[--idx] = 0;
+             strncat(buf, expanded_fmt, len);
+             idx += len;
+          }
+        else buf[idx++] = ch;
+        if (ch == '%') fmt_char = EINA_TRUE;
+        else fmt_char = EINA_FALSE;
+        ptr++;
+     }
+   buf[idx] = 0;
+   strncpy(dt_fmt, buf, MAX_FORMAT_LEN);
+}
+
+static unsigned int
+_parse_format(Evas_Object *obj, char *fmt_ptr)
+{
+   Widget_Data *wd;
+   Datetime_Field *field = NULL;
+   unsigned int len = 0, idx, location = 0;
+   char separator[MAX_SEPARATOR_LEN];
+   char cur;
+   Eina_Bool fmt_parsing = EINA_FALSE, sep_parsing = EINA_FALSE,
+             sep_lookup = EINA_FALSE;
+
+   wd = elm_widget_data_get(obj);
+
+   while ((cur = *fmt_ptr))
+     {
+        if (fmt_parsing)
+          {
+             for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++)
+               {
+                  if (strchr(mapping[idx].fmt_char, cur))
+                    {
+                       field = wd->field_list + idx;
+                       // ignore the fields already have or disabled
+                       // valid formats, means already parsed & repeated, ignore.
+                       if (!field->visible || field->location != -1) break;
+                       field->fmt[1] = cur;
+                       field->fmt_exist = EINA_TRUE;
+                       field->location = location++;
+                       fmt_parsing = EINA_FALSE;
+                       sep_lookup = EINA_TRUE;
+                       len = 0;
+                       break;
+                    }
+               }
+          }
+        if (cur == ' ') separator[len++] = cur;
+        else if (cur == '%') fmt_parsing = EINA_TRUE;
+        if ((cur == ' ') || (cur == '%'))
+          {
+             sep_parsing = EINA_FALSE;
+             // set the separator to previous field
+             separator[len] = 0;
+             if (field) eina_stringshare_replace(&field->separator, separator);
+          }
+        if (sep_parsing && (len < MAX_SEPARATOR_LEN-1) &&
+            (field->type != ELM_DATETIME_AMPM) &&
+            (!((field->type == ELM_DATETIME_MINUTE) && (cur ==':'))))
+           separator[len++] = cur;
+        if (sep_lookup) sep_parsing = EINA_TRUE;
+        sep_lookup = EINA_FALSE;
+        fmt_ptr++;
+   }
+   // return the number of valid fields parsed.
+   return location;
+}
+
+static void
+_reload_format(Evas_Object *obj)
+{
+   Widget_Data *wd;
+   Datetime_Field *field;
+   char buf[BUFFER_SIZE];
+   unsigned int idx, field_count;
+   char *dt_fmt;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd) return;
+
+   // fetch the default format from Libc.
+   if (!wd->user_format)
+     strncpy(wd->format, nl_langinfo(D_T_FMT), MAX_FORMAT_LEN);
+
+   dt_fmt = (char *)malloc(MAX_FORMAT_LEN);
+   strncpy(dt_fmt, wd->format, MAX_FORMAT_LEN);
+
+   _expand_format(dt_fmt);
+
+   // reset all the fields to disable state
+   for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++)
+     {
+        field = wd->field_list + idx;
+        field->fmt_exist = EINA_FALSE;
+        field->location = -1;
+     }
+
+   field_count = _parse_format(obj, dt_fmt);
+   free(dt_fmt);
+
+   // assign locations to disabled fields for uniform usage
+   for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++)
+     {
+        field = wd->field_list + idx;
+        if (field->location == -1) field->location = field_count++;
+
+        if (field->fmt_exist && field->visible)
+          {
+             snprintf(buf, sizeof(buf), EDC_PART_FIELD_ENABLE_SIG_STR,
+                      field->location);
+             edje_object_signal_emit(wd->base, buf, "elm");
+          }
+        else
+          {
+             snprintf(buf, sizeof(buf),EDC_PART_FIELD_DISABLE_SIG_STR,
+                      field->location);
+             edje_object_signal_emit(wd->base, buf, "elm");
+          }
+        snprintf(buf, sizeof(buf), EDC_PART_SEPARATOR_STR, (field->location + 1));
+        edje_object_part_text_set(wd->base, buf, field->separator);
+     }
+   edje_object_message_signal_process(wd->base);
+   _field_list_arrange(obj);
+}
+
+static void
+_field_list_init(Evas_Object *obj)
+{
+   Widget_Data *wd;
+   Datetime_Field *field;
+   unsigned int idx;
+   time_t t;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd) return;
+
+   t = time(NULL);
+   localtime_r(&t, &wd->curr_time);
+
+   for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++)
+     {
+        field = wd->field_list + idx;
+        field->type = ELM_DATETIME_YEAR + idx;
+        field->fmt[0] = '%';
+        field->fmt_exist = EINA_FALSE;
+        field->visible  = EINA_TRUE;
+        field->min = mapping[idx].def_min;
+        field->max = mapping[idx].def_max;
+     }
+   DATETIME_TM_ARRAY(min_timearr, &wd->min_limit);
+   DATETIME_TM_ARRAY(max_timearr, &wd->max_limit);
+   for (idx = 0; idx < DATETIME_TYPE_COUNT-1; idx++)
+     {
+        *min_timearr[idx] = mapping[idx].def_min;
+        *max_timearr[idx] = mapping[idx].def_max;
+     }
+}
+
+EAPI Evas_Object *
+elm_datetime_add(Evas_Object *parent)
+{
+   Evas_Object *obj;
+   Evas *e;
+   Widget_Data *wd;
+   Datetime_Field *field;
+   int idx;
+
+   ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
+
+   ELM_SET_WIDTYPE(widtype, "datetime");
+   elm_widget_type_set(obj, widtype);
+   elm_widget_sub_object_add(parent, obj);
+   elm_widget_data_set(obj, wd);
+   elm_widget_del_hook_set(obj, _del_hook);
+   elm_widget_theme_hook_set(obj, _theme_hook);
+   elm_widget_translate_hook_set(obj, _translate_hook);
+   elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
+   elm_widget_disable_hook_set(obj, _disable_hook);
+   elm_widget_can_focus_set(obj, EINA_TRUE);
+   elm_widget_focus_next_hook_set(obj, _elm_datetime_focus_next_hook);
+
+   wd->base = edje_object_add(e);
+   elm_widget_resize_object_set(obj, wd->base);
+   _elm_theme_object_set(obj, wd->base, "datetime", "base", "default");
+   evas_object_smart_callbacks_descriptions_set(obj, _signals);
+
+   // module - initialise module for datetime
+   if (!dt_mod) dt_mod = _dt_mod_init();
+   if ((dt_mod) && (dt_mod->obj_hook))
+     wd->mod_data = dt_mod->obj_hook(obj);
+   // update module data
+   if (wd->mod_data)
+     {
+        wd->mod_data->base = obj;
+        wd->mod_data->field_limit_get = _field_limit_get;
+        wd->mod_data->field_format_get = _field_format_get;
+     }
+
+   _field_list_init(obj);
+   _reload_format(obj);
+
+   if ((dt_mod)&&(dt_mod->field_create))
+     {
+        for (idx = 0; idx < DATETIME_TYPE_COUNT; idx++)
+          {
+             field = wd->field_list + idx;
+             field->item_obj = dt_mod->field_create(wd->mod_data, idx);
+          }
+     }
+   _field_list_arrange(obj);
+   _mirrored_set(obj, elm_widget_mirrored_get(obj));
+
+   return obj;
+}
+
+EAPI const char *
+elm_datetime_format_get(const Evas_Object *obj)
+{
+   ELM_CHECK_WIDTYPE(obj, widtype) NULL;
+   Widget_Data *wd;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd) return NULL;
+
+   return wd->format;
+}
+
+EAPI void
+elm_datetime_format_set(Evas_Object *obj, const char *fmt)
+{
+   ELM_CHECK_WIDTYPE(obj, widtype);
+   Widget_Data *wd;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd) return;
+
+   if (fmt)
+     {
+        strncpy(wd->format, fmt, MAX_FORMAT_LEN);
+        wd->user_format = EINA_TRUE;
+     }
+   else
+     wd->user_format = EINA_FALSE;
+
+   _reload_format(obj);
+}
+
+EAPI Eina_Bool
+elm_datetime_field_visible_get(const Evas_Object *obj, Elm_Datetime_Field_Type
+                               fieldtype)
+{
+   ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
+   Widget_Data *wd;
+   Datetime_Field *field;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd || (fieldtype > ELM_DATETIME_AMPM)) return EINA_FALSE;
+
+   field = wd->field_list + fieldtype;
+   return field->visible;
+}
+
+EAPI void
+elm_datetime_field_visible_set(Evas_Object *obj, Elm_Datetime_Field_Type fieldtype,
+                              Eina_Bool visible)
+{
+   ELM_CHECK_WIDTYPE(obj, widtype);
+   Widget_Data *wd;
+   Datetime_Field *field;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd || (fieldtype > ELM_DATETIME_AMPM)) return;
+
+   field = wd->field_list + fieldtype;
+   if (field->visible == visible) return;
+
+   field->visible = visible;
+   _reload_format(obj);
+}
+
+EAPI void
+elm_datetime_field_limit_get(const Evas_Object *obj, Elm_Datetime_Field_Type fieldtype,
+                             int *min, int *max)
+{
+   ELM_CHECK_WIDTYPE(obj, widtype);
+   Widget_Data *wd;
+   Datetime_Field *field;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd || (fieldtype >= ELM_DATETIME_AMPM)) return;
+
+   field = wd->field_list + fieldtype;
+   if (min) *min = field->min;
+   if (max) *max = field->max;
+}
+
+EAPI void
+elm_datetime_field_limit_set(Evas_Object *obj, Elm_Datetime_Field_Type fieldtype,
+                             int min, int max)
+{
+   ELM_CHECK_WIDTYPE(obj, widtype);
+   Widget_Data *wd;
+   Datetime_Field *field;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd || (fieldtype >= ELM_DATETIME_AMPM)) return;
+
+   if (min > max) return;
+
+   field = wd->field_list + fieldtype;
+   if ((min > mapping[fieldtype].def_min && min < mapping[fieldtype].def_max)
+        || (field->type == ELM_DATETIME_YEAR))
+     field->min = min;
+   if ((max > mapping[fieldtype].def_min && max < mapping[fieldtype].def_max)
+        || (field->type == ELM_DATETIME_YEAR))
+     field->max = max;
+
+   _apply_field_limits(obj);
+}
+
+EAPI Eina_Bool
+elm_datetime_value_get(const Evas_Object *obj, struct tm *currtime)
+{
+   ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(currtime, EINA_FALSE);
+   Widget_Data *wd;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd) return EINA_FALSE;
+
+   *currtime = wd->curr_time;
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+elm_datetime_value_set(Evas_Object *obj, const struct tm *newtime)
+{
+   ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(newtime, EINA_FALSE);
+   Widget_Data *wd;
+   struct tm old_time;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd) return EINA_FALSE;
+
+   old_time = wd->curr_time;
+   wd->curr_time = *newtime;
+   // apply default field restrictions for curr_time
+   _apply_range_restrictions(obj, &wd->curr_time);
+   // validate the curr_time according to the min_limt and max_limt
+   _validate_datetime_limits(&wd->curr_time, &wd->min_limit, EINA_FALSE);
+   _validate_datetime_limits(&wd->max_limit, &wd->curr_time, EINA_TRUE);
+   _apply_field_limits(obj);
+
+   if (!_date_cmp(&old_time, &wd->curr_time))
+     evas_object_smart_callback_call(obj, SIG_CHANGED, NULL);
+
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+elm_datetime_value_min_get(const Evas_Object *obj, struct tm *mintime)
+{
+   ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(mintime, EINA_FALSE);
+   Widget_Data *wd;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd) return EINA_FALSE;
+
+   *mintime = wd->min_limit;
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+elm_datetime_value_min_set(Evas_Object *obj, const struct tm *mintime)
+{
+   ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(mintime, EINA_FALSE);
+   Widget_Data *wd;
+   struct tm old_time;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd) return EINA_FALSE;
+
+   wd->min_limit = *mintime;
+   old_time = wd->curr_time;
+   // apply default field restrictions for min_limit
+   _apply_range_restrictions(obj, &wd->min_limit);
+   // validate curr_time and max_limt according to the min_limit
+   _validate_datetime_limits(&wd->max_limit, &wd->min_limit, EINA_FALSE);
+   _validate_datetime_limits(&wd->curr_time, &wd->min_limit, EINA_FALSE);
+   _apply_field_limits(obj);
+
+   if (!_date_cmp(&old_time, &wd->curr_time))
+     evas_object_smart_callback_call(obj, SIG_CHANGED, NULL);
+
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+elm_datetime_value_max_get(const Evas_Object *obj, struct tm *maxtime)
+{
+   ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(maxtime, EINA_FALSE);
+   Widget_Data *wd;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd) return EINA_FALSE;
+
+   *maxtime = wd->max_limit;
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+elm_datetime_value_max_set(Evas_Object *obj, const struct tm *maxtime)
+{
+   ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(maxtime, EINA_FALSE);
+   Widget_Data *wd;
+   struct tm old_time;
+
+   wd = elm_widget_data_get(obj);
+   if (!wd) return EINA_FALSE;
+
+   wd->max_limit = *maxtime;
+   old_time = wd->curr_time;
+   // apply default field restrictions for max_limit
+   _apply_range_restrictions(obj, &wd->max_limit);
+   // validate curr_time and min_limt according to the max_limit
+   _validate_datetime_limits(&wd->max_limit, &wd->min_limit, EINA_TRUE);
+   _validate_datetime_limits(&wd->max_limit, &wd->curr_time, EINA_TRUE);
+   _apply_field_limits(obj);
+
+   if (!_date_cmp(&old_time, &wd->curr_time))
+     evas_object_smart_callback_call(obj, SIG_CHANGED, NULL);
+
+   return EINA_TRUE;
+}
diff --git a/src/lib/elm_datetime.h b/src/lib/elm_datetime.h
new file mode 100644 (file)
index 0000000..a4cf388
--- /dev/null
@@ -0,0 +1,596 @@
+
+   /**
+    * @defgroup Datetime Datetime
+    *
+    *
+    * @image html img/widget/datetime/preview-00.png
+    * @image latex img/widget/datetime/preview-00.eps
+    *
+    * @image html img/widget/datetime/preview-01.png
+    * @image latex img/widget/datetime/preview-01.eps
+    *
+    * @image html img/widget/datetime/preview-02.png
+    * @image latex img/widget/datetime/preview-02.eps
+    *
+    * Datetime widget is used to display and input date & time values.
+    * This widget displays date and time as per the <b>system's locale</b> settings (Date
+    * includes Day, Month & Year along with the defined separators and
+    * Time includes Hour, Minute & AM/PM fields. Separator for AM/PM field is ignored.
+    *
+    * The corresponding Month, AM/PM strings are displayed according to the
+    * system’s language settings.
+    *
+    * Datetime format is a combination of LIBC standard characters like
+    * “%%d %%b %%Y %%I : %%M  %%p” which, as a whole represents both Date as well as Time
+    * format.
+    *
+    * Elm_datetime supports only the following sub set of libc date format specifiers:
+    *
+    * @b %%Y : The year as a decimal number including the century (example: 2011).
+    *
+    * @b %%y : The year as a decimal number without a century (range 00 to 99)
+    *
+    * @b %%m : The month as a decimal number (range 01 to 12).
+    *
+    * @b %%b : The abbreviated month name according to the current locale.
+    *
+    * @b %%B : The full month name according to the current locale.
+    *
+    * @b %%h : The abbreviated month name according to the current locale(same as %%b).
+    *
+    * @b %%d : The day of the month as a decimal number (range 01 to 31).
+    *
+    * @b %%e : The day of the month as a decimal number (range 1 to 31). single
+    * digits are preceded by a blank.
+    *
+    * @b %%I : The hour as a decimal number using a 12-hour clock (range 01 to 12).
+    *
+    * @b %%H : The hour as a decimal number using a 24-hour clock (range 00 to 23).
+    *
+    * @b %%k : The hour (24-hour clock) as a decimal number (range 0 to 23). single
+    * digits are preceded by a blank.
+    *
+    * @b %%l : The hour (12-hour clock) as a decimal number (range 1 to 12); single
+    * digits are preceded by a blank.
+    *
+    * @b %%M : The minute as a decimal number (range 00 to 59).
+    *
+    * @b %%p : Either 'AM' or 'PM' according to the given time value, or the
+    * corresponding strings for the current locale. Noon is treated as 'PM'
+    * and midnight as 'AM'
+    *
+    * @b %%P : Like %p but in lower case: 'am' or 'pm' or a corresponding string for
+    * the current locale.
+    *
+    * @b %%c : The preferred date and time representation for the current locale.
+    *
+    * @b %%x : The preferred date representation for the current locale without the time.
+    *
+    * @b %%X : The preferred time representation for the current locale without the date.
+    *
+    * @b %%r : The complete calendar time using the AM/PM format of the current locale.
+    *
+    * @b %%R : The hour and minute in decimal numbers using the format %H:%M.
+    *
+    * @b %%T : The time of day in decimal numbers using the format %H:%M:%S.
+    *
+    * @b %%D : The date using the format %%m/%%d/%%y.
+    *
+    * @b %%F : The date using the format %%Y-%%m-%%d.
+    *
+    * (For more reference on the available <b>LIBC date format specifiers</b>, please
+    * visit the link:
+    * http://www.gnu.org/s/hello/manual/libc.html#Formatting-Calendar-Time )
+    *
+    * Datetime widget can provide Unicode @b separators in between its fields
+    * except for AM/PM field.
+    * A separator can be any <b>Unicode character</b> other than the LIBC standard
+    * date format specifiers.( Example: In the format %%b %%d @b , %%y %%H @b : %%M
+    * comma(,) is separator for date field %%d and colon(:) is separator for
+    * hour field %%H ).
+    *
+    * The default format is a predefined one, based on the system Locale.
+    *
+    * Hour format 12hr(1-12) or 24hr(0-23) display can be selected by setting
+    * the corresponding user format.
+    *
+    * Datetime supports six fields: Year, Month, Date, Hour, Minute, AM/PM.
+    * Depending on the Datetime module that is loaded, the user can see
+    * different UI to select the individual field values.
+    *
+    * The individual fields of Datetime can be arranged in any order according to the format
+    * set by application.
+    *
+    * There is a provision to set the visibility of a particular field as TRUE/ FALSE
+    * so that <b>only time/ only date / only required fields</b> will be displayed.
+    *
+    * Each field is having a default minimum and maximum values just like the daily
+    * calendar information. These min/max values can be modified as per the application usage.
+    *
+    * User can enter the values only in between the range of maximum and minimum.
+    * Apart from these APIs, there is a provision to display only a limited set of
+    * values out of the possible values. APIs to select the individual field limits
+    * are intended for this purpose.
+    *
+    * The whole widget is left aligned and its size grows horizontally depending
+    * on the current format and each field's visible/disabled state.
+    *
+    * Datetime individual field selection is implemented in a modular style.
+    * Module can be implemented as a Ctxpopup based selection or an ISE based
+    * selection or even a spinner like selection etc.
+    *
+    * <b>Datetime Module design:</b>
+    *
+    * The following functions are expected to be implemented in a Datetime module:
+    *
+    * <b>Field creation:</b>
+    * <pre>
+    *
+    *  __________                                            __________
+    * |          |----- obj_hook() ---------------------->>>|          |
+    * |          |<<<----------------returns Mod_data ------|          |
+    * | Datetime |_______                                   |          |
+    * |  widget  |       |Assign module call backs          |  Module  |
+    * |   base   |<<<____|                                  |          |
+    * |          |                                          |          |
+    * |          |----- field_create() ------------------>>>|          |
+    * |__________|<<<----------------returns field_obj -----|__________|
+    *
+    * </pre>
+    *
+    * <b>Field value setting:</b>
+    * <pre>
+    *
+    *  __________                                          __________
+    * |          |                                        |          |
+    * | Datetime |<<<----------elm_datetime_value_set()---|          |
+    * |  widget  |                                        |  Module  |
+    * |   base   |----display_field_value()------------>>>|          |
+    * |__________|                                        |__________|
+    *
+    * </pre>
+    *
+    * <b>del_hook:</b>
+    * <pre>
+    *  __________                                          __________
+    * |          |                                        |          |
+    * | Datetime |----obj_unhook()-------------------->>>>|          |
+    * |  widget  |                                        |  Module  |
+    * |   base   |         <<<-----frees mod_data---------|          |
+    * |__________|                                        |__________|
+    *
+    * </pre>
+    *
+    *
+    * Any module can use the following shared functions that are implemented in elm_datetime.c :
+    *
+    * <b>field_format_get()</b> - gives the field format.
+    *
+    * <b>field_limit_get()</b>  - gives the field minimum, maximum limits.
+    *
+    * To enable a module, set the ELM_MODULES environment variable as shown:
+    *
+    * <b>export ELM_MODULES="datetime_input_ctxpopup>datetime/api"</b>
+    *
+    *
+    * Datetime widgets emits the following signals:
+    *
+    * @li @b "changed" - whenever Datetime field value is changed, this signal is sent.
+    *
+    * @li @b "language,changed" - whenever system locale changes, this signal is sent.
+    *
+    * Here is an example on its usage:
+    * @li @ref datetime_example
+    *
+   */
+
+   /**
+    * @addtogroup Datetime
+    * @{
+    */
+
+   /**
+    * Identifies a Datetime field, The widget supports 6 fields : Year, month,
+    * Date, Hour, Minute, AM/PM
+    *
+    */
+   typedef enum _Elm_Datetime_Field_Type
+     {
+        ELM_DATETIME_YEAR    = 0, /**< Indicates Year field */
+        ELM_DATETIME_MONTH   = 1, /**< Indicates Month field */
+        ELM_DATETIME_DATE    = 2, /**< Indicates Date field */
+        ELM_DATETIME_HOUR    = 3, /**< Indicates Hour field */
+        ELM_DATETIME_MINUTE  = 4, /**< Indicates Minute field */
+        ELM_DATETIME_AMPM    = 5, /**< Indicates AM/PM field */
+     } Elm_Datetime_Field_Type;
+
+   /**
+    * @brief Adds a new datetime Widget
+    *
+    * The default datetime format and corresponding strings are based on current locale.
+    *
+    * @param parent The parent object
+    * @return The new object or NULL if it cannot be created
+    *
+    * This function inserts a new datetime widget on the canvas.
+    *
+    * @ingroup Datetime
+    */
+      EAPI Evas_Object *elm_datetime_add(Evas_Object *parent);
+
+   /**
+    * Get the datetime format. Format is a combination of allowed Libc date format
+    * specifiers like: "%b %d, %Y %I : %M %p".
+    *
+    * Maximum allowed format length is 64 chars.
+    *
+    * Format can include separators for each individual datetime field except
+    * for AM/PM field.
+    *
+    * Each separator can be a maximum of 6 UTF-8 bytes.
+    * Space is also taken as a separator but it can come only once for each field.
+    *
+    * Following are the allowed set of format specifiers for each datetime field.
+    *
+    * @b %%Y : The year as a decimal number including the century.
+    *
+    * @b %%y : The year as a decimal number without a century (range 00 to 99).
+    *
+    * @b %%m : The month as a decimal number (range 01 to 12).
+    *
+    * @b %%b : The abbreviated month name according to the current locale.
+    *
+    * @b %%B : The full month name according to the current locale.
+    *
+    * @b %%h : The abbreviated month name according to the current locale(same as %%b).
+    *
+    * @b %%d : The day of the month as a decimal number (range 01 to 31).
+    *
+    * @b %%e : The day of the month as a decimal number (range 1 to 31). single
+    *      digits are preceded by a blank.
+    *
+    * @b %%I : The hour as a decimal number using a 12-hour clock (range 01 to 12).
+    *
+    * @b %%H : The hour as a decimal number using a 24-hour clock (range 00 to 23).
+    *
+    * @b %%k : The hour (24-hour clock) as a decimal number (range 0 to 23). single
+    *      digits are preceded by a blank.
+    *
+    * @b %%l : The hour (12-hour clock) as a decimal number (range 1 to 12); single
+    *      digits are preceded by a blank.
+    *
+    * @b %%M : The minute as a decimal number (range 00 to 59).
+    *
+    * @b %%p : Either 'AM' or 'PM' according to the given time value, or the
+    *      corresponding strings for the current locale. Noon is treated as 'PM'
+    *      and midnight as 'AM'.
+    *
+    * @b %%P : Like %p but in lower case: 'am' or 'pm' or a corresponding string for
+    *      the current locale.
+    *
+    * @b %%c : The preferred date and time representation for the current locale.
+    *
+    * @b %%x : The preferred date representation for the current locale without the time.
+    *
+    * @b %%X : The preferred time representation for the current locale without the date.
+    *
+    * @b %%r : The complete calendar time using the AM/PM format of the current locale.
+    *
+    * @b %%R : The hour and minute in decimal numbers using the format %H:%M.
+    *
+    * @b %%T : The time of day in decimal numbers using the format %H:%M:%S.
+    *
+    * @b %%D : The date using the format %%m/%%d/%%y.
+    *
+    * @b %%F : The date using the format %%Y-%%m-%%d.
+    *
+    * These specifiers can be arranged in any order and the widget will display the
+    * fields accordingly.
+    *
+    * Default format is taken as per the system locale settings.
+    *
+    * @param obj The datetime object
+    * @return The datetime format string. Example: "%b %d, %Y %I : %M %p"
+    *
+    * @see elm_datetime_format_set()
+    * @ingroup Datetime
+    */
+      EAPI const char *elm_datetime_format_get(const Evas_Object *obj);
+
+   /**
+    * Set the datetime format. Format is a combination of allowed Libc date format
+    * specifiers like: "%b %d, %Y %I : %M %p".
+    *
+    * Maximum allowed format length is 64 chars.
+    *
+    * Format can include separators for each individual datetime field except
+    * for AM/PM field.
+    *
+    * Each separator can be a maximum of 6 UTF-8 bytes.
+    * Space is also taken as a separator but it can come only once for each field.
+    *
+    * Following are the allowed set of format specifiers for each datetime field.
+    *
+    * @b %%Y : The year as a decimal number including the century.
+    *
+    * @b %%y : The year as a decimal number without a century (range 00 to 99).
+    *
+    * @b %%m : The month as a decimal number (range 01 to 12).
+    *
+    * @b %%b : The abbreviated month name according to the current locale.
+    *
+    * @b %%B : The full month name according to the current locale.
+    *
+    * @b %%h : The abbreviated month name according to the current locale(same as %%b).
+    *
+    * @b %%d : The day of the month as a decimal number (range 01 to 31).
+    *
+    * @b %%e : The day of the month as a decimal number (range 1 to 31). single
+    *      digits are preceded by a blank.
+    *
+    * @b %%I : The hour as a decimal number using a 12-hour clock (range 01 to 12).
+    *
+    * @b %%H : The hour as a decimal number using a 24-hour clock (range 00 to 23).
+    *
+    * @b %%k : The hour (24-hour clock) as a decimal number (range 0 to 23). single
+    *      digits are preceded by a blank.
+    *
+    * @b %%l : The hour (12-hour clock) as a decimal number (range 1 to 12); single
+    *      digits are preceded by a blank.
+    *
+    * @b %%M : The minute as a decimal number (range 00 to 59).
+    *
+    * @b %%p : Either 'AM' or 'PM' according to the given time value, or the
+    *      corresponding strings for the current locale. Noon is treated as 'PM'
+    *      and midnight as 'AM'.
+    *
+    * @b %%P : Like %p but in lower case: 'am' or 'pm' or a corresponding string for
+    *      the current locale.
+    *
+    * @b %%c : The preferred date and time representation for the current locale.
+    *
+    * @b %%x : The preferred date representation for the current locale without the time.
+    *
+    * @b %%X : The preferred time representation for the current locale without the date.
+    *
+    * @b %%r : The complete calendar time using the AM/PM format of the current locale.
+    *
+    * @b %%R : The hour and minute in decimal numbers using the format %H:%M.
+    *
+    * @b %%T : The time of day in decimal numbers using the format %H:%M:%S.
+    *
+    * @b %%D : The date using the format %%m/%%d/%%y.
+    *
+    * @b %%F : The date using the format %%Y-%%m-%%d.
+    *
+    * These specifiers can be arranged in any order and the widget will display the
+    * fields accordingly.
+    *
+    * Default format is taken as per the system locale settings.
+    *
+    * @param obj The datetime object
+    * @param fmt The datetime format
+    *
+    * @see elm_datetime_format_get()
+    * @ingroup Datetime
+    */
+      EAPI void elm_datetime_format_set(Evas_Object *obj, const char *fmt);
+
+   /**
+    * @brief Get the upper boundary of a field.
+    *
+    * Year: years since 1900. Negative value represents year below 1900 (year
+    * value -30 represents 1870). Year default range is from 70 to 137.
+    *
+    * Month: default value range is from 0 to 11.
+    *
+    * Date: default value range is from 1 to 31 according to the month value.
+    *
+    * Hour: default value will be in terms of 24 hr format (0~23)
+    *
+    * Minute: default value range is from 0 to 59.
+    *
+    * @param obj The datetime object
+    * @param maxtime Time structure containing the maximum time value.
+    * @return int The maximum value of the field.
+    *
+    * @see elm_datetime_value_max_set()
+    * @ingroup Datetime
+    */
+      EAPI Eina_Bool elm_datetime_value_max_get(const Evas_Object *obj, struct tm *maxtime);
+
+   /**
+    * @brief Set the upper boundary of a field.
+    *
+    * Year: years since 1900. Negative value represents year below 1900 (year
+    * value -30 represents 1870). Year default range is from 70 to 137.
+    *
+    * Month: default value range is from 0 to 11.
+    *
+    * Date: default value range is from 1 to 31 according to the month value.
+    *
+    * Hour: default value will be in terms of 24 hr format (0~23)
+    *
+    * Minute: default value range is from 0 to 59.
+    *
+    * @param obj The datetime object
+    * @param maxtime Time structure containing the maximum time value.
+    * @return EINA_TRUE if maximum value is accepted.
+    *
+    * @see elm_datetime_value_max_get()
+    * @ingroup Datetime
+    */
+      EAPI Eina_Bool elm_datetime_value_max_set(Evas_Object *obj, const struct tm *maxtime);
+
+   /**
+    * @brief Get the lower boundary of a field.
+    *
+    * Year: years since 1900. Negative value represents year below 1900 (year
+    * value -30 represents 1870). Year default range is from 70 to 137.
+    *
+    * Month: default value range is from 0 to 11.
+    *
+    * Date: default value range is from 1 to 31 according to the month value.
+    *
+    * Hour: default value will be in terms of 24 hr format (0~23)
+    *
+    * Minute: default value range is from 0 to 59.
+    *
+    * @param obj The datetime object
+    * @param mintime Time structure.
+    * @return EINA_TRUE if minimum value is successfully returned.
+    *
+    * @see elm_datetime_value_min_set()
+    * @ingroup Datepicker
+    */
+      EAPI Eina_Bool elm_datetime_value_min_get(const Evas_Object *obj, struct tm *mintime);
+
+   /**
+    * @brief Set the lower boundary of a field.
+    *
+    * Year: years since 1900. Negative value represents year below 1900 (year
+    * value -30 represents 1870). Year default range is from 70 to 137.
+    *
+    * Month: default value range is from 0 to 11.
+    *
+    * Date: default value range is from 1 to 31 according to the month value.
+    *
+    * Hour: default value will be in terms of 24 hr format (0~23)
+    *
+    * Minute: default value range is from 0 to 59.
+    *
+    * @param obj The datetime object.
+    * @param mintime Time structure containing the minimum time value.
+    * @return EINA_TRUE if minimum value is accepted.
+    *
+    * @see elm_datetime_value_min_get()
+    * @ingroup Datetime
+    */
+      EAPI Eina_Bool elm_datetime_value_min_set(Evas_Object *obj, const struct tm *mintime);
+
+   /**
+    * @brief Get the field limits of a field.
+    *
+    * Limits can be set to individual fields, independently, except for AM/PM field.
+    * Any field can display the values only in between these Minimum and Maximum limits unless
+    * the corresponding time value is restricted from MinTime to MaxTime.
+    * That is, Min/ Max field limits always works under the limitations of MinTime/ MaxTime.
+    *
+    * There is no provision to set the limits of AM/PM field.
+    *
+    * @param obj The datetime object
+    * @param fieldtype Type of the field. ELM_DATETIME_YEAR etc.
+    * @param min Reference to field's minimum value
+    * @param max Reference to field's maximum value
+    *
+    * @see elm_datetime_field_limit_set()
+    * @ingroup Datetime
+    */
+      EAPI void      elm_datetime_field_limit_get(const Evas_Object *obj, Elm_Datetime_Field_Type fieldtype, int *min, int *max);
+
+   /**
+    * @brief Set the field limits of a field.
+    *
+    * Limits can be set to individual fields, independently, except for AM/PM field.
+    * Any field can display the values only in between these Minimum and Maximum limits unless
+    * the corresponding time value is restricted from MinTime to MaxTime.
+    * That is, Min/ Max field limits always works under the limitations of MinTime/ MaxTime.
+    *
+    * There is no provision to set the limits of AM/PM field.
+    *
+    * @param obj The datetime object
+    * @param fieldtype Type of the field. ELM_DATETIME_YEAR etc.
+    * @param min Reference to field's minimum value
+    * @param max Reference to field's maximum value
+    *
+    * @see elm_datetime_field_limit_set()
+    * @ingroup Datetime
+    */
+      EAPI void      elm_datetime_field_limit_set(Evas_Object *obj, Elm_Datetime_Field_Type fieldtype, int min, int max);
+
+   /**
+    * @brief Get the current value of a field.
+    *
+    * Year: years since 1900. Negative value represents year below 1900 (year
+    * value -30 represents 1870). Year default range is from 70 to 137.
+    *
+    * Month: default value range is from 0 to 11.
+    *
+    * Date: default value range is from 1 to 31 according to the month value.
+    *
+    * Hour: default value will be in terms of 24 hr format (0~23)
+    *
+    * Minute: default value range is from 0 to 59.
+    *
+    * @param obj The datetime object.
+    * @param currtime Time structure.
+    * @return EINA_TRUE if current time is returned successfully.
+    *
+    * @see elm_datetime_field_value_set()
+    * @ingroup Datetime
+    */
+      EAPI Eina_Bool elm_datetime_value_get(const Evas_Object *obj, struct tm *currtime);
+
+   /**
+    * @brief Set the current value of a Datetime object.
+    *
+    * Year: years since 1900. Negative value represents year below 1900 (year
+    * value -30 represents 1870). Year default range is from 70 to 137.
+    *
+    * Month: default value range is from 0 to 11.
+    *
+    * Date: default value range is from 1 to 31 according to the month value.
+    *
+    * Hour: default value will be in terms of 24 hr format (0~23)
+    *
+    * Minute: default value range is from 0 to 59.
+    *
+    *
+    * @param obj The datetime object.
+    * @param newtime Time structure filled with values to be set.
+    * @return EINA_TRUE if current time is set successfully.
+    *
+    * @see elm_datetime_value_set()
+    * @ingroup Datetime
+    */
+      EAPI Eina_Bool elm_datetime_value_set(Evas_Object *obj, const struct tm *newtime);
+
+   /**
+    * @brief Get whether a field can be visible/not
+    *
+    * @param obj The datetime object
+    * @param fieldtype Type of the field. ELM_DATETIME_YEAR etc
+    * @return bool @c EINA_TRUE, if field can be visible. @c EINA_FALSE otherwise.
+    *
+    * @see elm_datetime_field_visible_set()
+    * @ingroup Datetime
+    */
+      EAPI Eina_Bool elm_datetime_field_visible_get(const Evas_Object *obj, Elm_Datetime_Field_Type fieldtype);
+
+   /**
+    * @brief Set a field to be visible or not.
+    * Setting this API True does not ensure that the field is visible, apart from
+    * this, the field's format must be present in Datetime overall format.
+    * If a field's visibility is set to False then it won't appear even though
+    * its format is present in overall format.
+    * So if and only if this API is set true and the corresponding field's format
+    * is present in Datetime format, the field is visible.
+    *
+    * By default the field visibility is set to True.
+    *
+    * @param obj The datetime object
+    * @param fieldtype Type of the field. ELM_DATETIME_YEAR etc.
+    * @param visible @c EINA_TRUE field can be visible, @c EINA_FALSE otherwise.
+    *
+    * @see elm_datetime_field_visible_get()
+    * @ingroup Datetime
+    */
+      EAPI void elm_datetime_field_visible_set(Evas_Object *obj, Elm_Datetime_Field_Type fieldtype, Eina_Bool visible);
+
+   /**
+    * @}
+    */
+
+#ifdef __cplusplus
+}
+#endif
index ce266f4..94e64aa 100644 (file)
@@ -43,6 +43,7 @@
 
 typedef struct _Elm_Config Elm_Config;
 typedef struct _Elm_Module Elm_Module;
+typedef struct _Elm_Datetime_Module_Data Elm_Datetime_Module_Data;
 
 struct _Elm_Theme
 {
@@ -186,6 +187,13 @@ struct _Elm_Module
    int          references;
 };
 
+struct _Elm_Datetime_Module_Data
+{
+   Evas_Object *base;
+   void (*field_limit_get)(Evas_Object *obj, Elm_Datetime_Field_Type  field_type, int *range_min, int *range_max);
+   const char *(*field_format_get)(Evas_Object * obj, Elm_Datetime_Field_Type  field_type);
+};
+
 int                  _elm_ews_wm_init(void);
 void                 _elm_ews_wm_shutdown(void);
 void                 _elm_ews_wm_rescale(Elm_Theme *th, Eina_Bool use_theme);
index 9354af6..e435e37 100644 (file)
@@ -4,4 +4,5 @@ MAINTAINERCLEANFILES = Makefile.in
 SUBDIRS = \
 test_entry \
 test_map \
-access_output
+access_output \
+datetime_input_ctxpopup
diff --git a/src/modules/datetime_input_ctxpopup/Makefile.am b/src/modules/datetime_input_ctxpopup/Makefile.am
new file mode 100644 (file)
index 0000000..73be6a7
--- /dev/null
@@ -0,0 +1,33 @@
+
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-DELM_INTERNAL_API_ARGESFSDFEFC=1 \
+-I. \
+-I$(top_builddir) \
+-I$(top_srcdir) \
+-I$(top_srcdir)/src/lib \
+-I$(top_builddir)/src/lib \
+-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \
+-DPACKAGE_LIB_DIR=\"$(libdir)\" \
+@ELEMENTARY_CFLAGS@ \
+@ELEMENTARY_X_CFLAGS@ \
+@ELEMENTARY_FB_CFLAGS@ \
+@ELEMENTARY_WIN32_CFLAGS@ \
+@ELEMENTARY_WINCE_CFLAGS@ \
+@ELEMENTARY_EDBUS_CFLAGS@ \
+@ELEMENTARY_EFREET_CFLAGS@ \
+@ELEMENTARY_ETHUMB_CFLAGS@
+
+if ELEMENTARY_WINDOWS_BUILD
+AM_CPPFLAGS += -DELEMENTARY_BUILD
+endif
+
+pkgdir = $(libdir)/elementary/modules/datetime_input_ctxpopup/$(MODULE_ARCH)
+pkg_LTLIBRARIES = module.la
+
+module_la_SOURCES = datetime_input_ctxpopup.c
+
+module_la_LIBADD = @ELEMENTARY_LIBS@ $(top_builddir)/src/lib/libelementary.la
+module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version
+module_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/src/modules/datetime_input_ctxpopup/datetime_input_ctxpopup.c b/src/modules/datetime_input_ctxpopup/datetime_input_ctxpopup.c
new file mode 100644 (file)
index 0000000..485d0f5
--- /dev/null
@@ -0,0 +1,325 @@
+#include <Elementary.h>
+#include "elm_priv.h"
+#ifdef HAVE_CONFIG_H
+#include "elementary_config.h"
+#endif
+
+#define DATETIME_FIELD_COUNT    6
+#define FIELD_FORMAT_LEN        3
+#define DISKSELECTOR_MIN_ITEMS  4
+#define BUFF_SIZE               1024
+
+typedef struct _Ctxpopup_Module_Data Ctxpopup_Module_Data;
+typedef struct _DiskItem_Data DiskItem_Data;
+
+struct _Ctxpopup_Module_Data
+{
+   Elm_Datetime_Module_Data mod_data;
+   Evas_Object *ctxpopup;
+};
+
+struct _DiskItem_Data
+{
+   Ctxpopup_Module_Data *ctx_mod;
+   Elm_Datetime_Field_Type  sel_field_type;
+   unsigned int sel_field_value;
+};
+
+static void
+_diskselector_item_free_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   if (data) free(data);
+}
+
+static void
+_ctxpopup_dismissed_cb(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__ )
+{
+   Evas_Object *diskselector;
+
+   diskselector = elm_object_content_unset(obj);
+   if (diskselector) evas_object_del(diskselector);
+}
+
+static void
+_datetime_resize_cb(void *data, Evas *e __UNUSED__,Evas_Object *obj __UNUSED__,
+                    void *event_info __UNUSED__)
+{
+   Ctxpopup_Module_Data *ctx_mod;
+
+   ctx_mod = (Ctxpopup_Module_Data *)data;
+   if (!ctx_mod) return;
+
+   evas_object_hide(ctx_mod->ctxpopup);
+}
+
+static void
+_ctxpopup_parent_resize_cb(void *data, Evas *e __UNUSED__,Evas_Object *obj __UNUSED__,
+                            void *event_info __UNUSED__)
+{
+   Ctxpopup_Module_Data *ctx_mod;
+
+   ctx_mod = (Ctxpopup_Module_Data *)data;
+   if (!ctx_mod) return;
+   elm_ctxpopup_hover_parent_set(ctx_mod->ctxpopup, elm_widget_top_get(ctx_mod->mod_data.base));
+}
+
+static void
+_datetime_move_cb(void *data, Evas *e __UNUSED__,Evas_Object *obj __UNUSED__,
+                  void *event_info __UNUSED__)
+{
+   Ctxpopup_Module_Data *ctx_mod;
+
+   ctx_mod = (Ctxpopup_Module_Data *)data;
+   if (!ctx_mod) return;
+
+   evas_object_hide(ctx_mod->ctxpopup);
+}
+
+static void
+_field_value_set(struct tm *time, Elm_Datetime_Field_Type  field_type, int val)
+{
+   if (field_type >= DATETIME_FIELD_COUNT - 1) return;
+
+   int *timearr[]= { &time->tm_year, &time->tm_mon, &time->tm_mday, &time->tm_hour, &time->tm_min };
+   *timearr[field_type] = val;
+}
+
+static int
+_field_value_get(struct tm *time, Elm_Datetime_Field_Type  field_type)
+{
+   if (field_type >= DATETIME_FIELD_COUNT - 1) return -1;
+
+   int *timearr[]= { &time->tm_year, &time->tm_mon, &time->tm_mday, &time->tm_hour, &time->tm_min };
+   return (*timearr[field_type]);
+}
+
+static void
+_diskselector_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   DiskItem_Data *disk_data;
+   struct tm curr_time;
+   const char *fmt;
+
+   disk_data = (DiskItem_Data *)data;
+   if (!disk_data || !(disk_data->ctx_mod)) return;
+
+   elm_datetime_value_get(disk_data->ctx_mod->mod_data.base, &curr_time);
+   fmt = disk_data->ctx_mod->mod_data.field_format_get(disk_data->ctx_mod->mod_data.base, disk_data->sel_field_type);
+   if ((disk_data->sel_field_type == ELM_DATETIME_HOUR) && ((!strncmp(fmt, "%I", FIELD_FORMAT_LEN)) ||
+        (!strncmp(fmt, "%l", FIELD_FORMAT_LEN))) && (curr_time.tm_hour >= 12))
+     disk_data->sel_field_value += 12;
+   _field_value_set(&curr_time, disk_data->sel_field_type, disk_data->sel_field_value);
+   elm_datetime_value_set(disk_data->ctx_mod->mod_data.base, &curr_time);
+   evas_object_hide(disk_data->ctx_mod->ctxpopup);
+}
+
+static void
+_ampm_clicked_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   Ctxpopup_Module_Data *ctx_mod;
+   struct tm curr_time;
+
+   ctx_mod = (Ctxpopup_Module_Data *)data;
+   if (!ctx_mod) return;
+
+   elm_datetime_value_get(ctx_mod->mod_data.base, &curr_time);
+   if (curr_time.tm_hour >= 12) curr_time.tm_hour -= 12;
+   else curr_time.tm_hour += 12;
+   elm_datetime_value_set(ctx_mod->mod_data.base, &curr_time);
+}
+
+static void
+_field_clicked_cb(void *data, Evas_Object *obj, void *event_info __UNUSED__)
+{
+   Ctxpopup_Module_Data *ctx_mod;
+   Evas_Object *diskselector;
+   Elm_Object_Item *item;
+   DiskItem_Data *disk_data;
+   Elm_Datetime_Field_Type  field_type;
+   time_t t;
+   struct tm time1;
+   char buf[BUFF_SIZE], label[BUFF_SIZE];
+   const char *fmt;
+   int idx, min, max, val;
+   unsigned int display_item_num, text_len = 0;
+   Evas_Coord x = 0, y = 0, w = 0, h = 0, width;
+
+   ctx_mod = (Ctxpopup_Module_Data *)data;
+   if (!ctx_mod || !ctx_mod->ctxpopup) return;
+
+   // because of the diskselector behaviour, it is being recreated
+   diskselector = elm_diskselector_add(elm_widget_top_get(ctx_mod->mod_data.base));
+   snprintf(buf, sizeof(buf), "datetime/%s", elm_object_style_get(obj));
+   elm_object_style_set(diskselector, buf);
+   elm_object_content_set(ctx_mod->ctxpopup, diskselector);
+
+   t = time(NULL);
+   localtime_r(&t, &time1);
+
+   field_type = (Elm_Datetime_Field_Type )evas_object_data_get(obj, "_field_type");
+   fmt = ctx_mod->mod_data.field_format_get(ctx_mod->mod_data.base, field_type);
+   elm_datetime_value_get(ctx_mod->mod_data.base, &time1);
+   val = _field_value_get(&time1, field_type);
+   ctx_mod->mod_data.field_limit_get(ctx_mod->mod_data.base, field_type, &min, &max);
+
+   time1.tm_mday = 1;   // To avoid month wrapping, set the first day of the month to start with.
+
+   if ((field_type == ELM_DATETIME_HOUR) && ((!strncmp(fmt, "%I", FIELD_FORMAT_LEN)) ||
+        (!strncmp(fmt, "%l", FIELD_FORMAT_LEN))))
+     {
+        if (max >= 12) max -= 12;
+        if (val >= 12) val -= 12;
+        if (min >= 12) min -= 12;
+     }
+   for (idx = min; idx <= max; idx++)
+     {
+        _field_value_set(&time1, field_type, idx);
+        strftime(label, BUFF_SIZE, fmt, &time1);
+        if (strlen(label) > text_len) text_len = strlen(label);
+        if (idx == val)
+          {
+             item = elm_diskselector_item_append(diskselector, label, NULL, NULL, NULL);
+             elm_diskselector_item_selected_set(item, EINA_TRUE);
+          }
+        else
+          {
+             disk_data = (DiskItem_Data *) malloc (sizeof(DiskItem_Data));
+             disk_data->ctx_mod = ctx_mod;
+             disk_data->sel_field_type = field_type;
+             disk_data->sel_field_value = idx;
+             item = elm_diskselector_item_append(diskselector, label, NULL, _diskselector_cb, disk_data);
+             elm_object_item_del_cb_set(item, _diskselector_item_free_cb);
+          }
+     }
+   elm_diskselector_side_label_length_set(diskselector, text_len);
+
+   evas_object_geometry_get(obj, &x, &y, &w, &h);
+   evas_object_geometry_get(elm_widget_top_get(ctx_mod->mod_data.base), NULL, NULL, &width, NULL);
+   evas_object_size_hint_min_set(ctx_mod->ctxpopup, width, -1);
+   display_item_num = width / (w + elm_finger_size_get());
+   // always display even number of items to avoid autoselection
+   if (display_item_num % 2) display_item_num -= 1;
+   if (display_item_num < DISKSELECTOR_MIN_ITEMS)
+     display_item_num = DISKSELECTOR_MIN_ITEMS;
+   elm_diskselector_display_item_num_set(diskselector, display_item_num);
+   elm_diskselector_round_set(diskselector, EINA_TRUE);
+
+   elm_ctxpopup_direction_priority_set(ctx_mod->ctxpopup, ELM_CTXPOPUP_DIRECTION_DOWN,
+                                       ELM_CTXPOPUP_DIRECTION_UP, -1, -1);
+   evas_object_move(ctx_mod->ctxpopup, (x+w/2), (y+h));
+
+   // if the direction of Ctxpopup is upwards, move it to the top of datetime
+   if (elm_ctxpopup_direction_get (ctx_mod->ctxpopup) == ELM_CTXPOPUP_DIRECTION_UP)
+     {
+        elm_ctxpopup_direction_priority_set(ctx_mod->ctxpopup, ELM_CTXPOPUP_DIRECTION_UP,
+                                            ELM_CTXPOPUP_DIRECTION_DOWN, -1, -1);
+        evas_object_move(ctx_mod->ctxpopup, (x+w/2), y);
+     }
+   evas_object_show(ctx_mod->ctxpopup);
+}
+
+// module fucns for the specific module type
+EAPI void
+field_value_display(Elm_Datetime_Module_Data *module_data, Evas_Object *obj)
+{
+   Ctxpopup_Module_Data *ctx_mod;
+   Elm_Datetime_Field_Type  field_type;
+   struct tm time;
+   char buf[BUFF_SIZE];
+   const char *fmt;
+
+   ctx_mod = (Ctxpopup_Module_Data *)module_data;
+   if (!ctx_mod || !obj) return;
+
+   elm_datetime_value_get(ctx_mod->mod_data.base, &time);
+   field_type = (Elm_Datetime_Field_Type )evas_object_data_get(obj, "_field_type");
+   fmt = ctx_mod->mod_data.field_format_get(ctx_mod->mod_data.base, field_type);
+   strftime(buf, sizeof(buf), fmt, &time);
+   elm_object_text_set(obj, buf);
+}
+
+EAPI Evas_Object *
+field_create(Elm_Datetime_Module_Data *module_data, Elm_Datetime_Field_Type  field_type)
+{
+   Ctxpopup_Module_Data *ctx_mod;
+   Evas_Object *field_obj;
+
+   ctx_mod = (Ctxpopup_Module_Data *)module_data;
+   if (!ctx_mod) return NULL;
+
+   if (field_type == ELM_DATETIME_AMPM)
+     {
+        field_obj = elm_button_add(ctx_mod->mod_data.base);
+        evas_object_smart_callback_add(field_obj, "clicked", _ampm_clicked_cb, ctx_mod);
+     }
+   else
+     {
+        field_obj = elm_entry_add(ctx_mod->mod_data.base);
+        elm_entry_single_line_set(field_obj, EINA_TRUE);
+        elm_entry_editable_set(field_obj, EINA_FALSE);
+        elm_entry_input_panel_enabled_set(field_obj, EINA_FALSE);
+        elm_entry_context_menu_disabled_set(field_obj, EINA_TRUE);
+        evas_object_smart_callback_add(field_obj, "clicked", _field_clicked_cb, ctx_mod);
+     }
+   evas_object_data_set(field_obj, "_field_type", (void *)field_type);
+   return field_obj;
+}
+
+EAPI Elm_Datetime_Module_Data *
+obj_hook(Evas_Object *obj)
+{
+   Ctxpopup_Module_Data *ctx_mod;
+   char buf[BUFF_SIZE];
+
+   ctx_mod = ELM_NEW(Ctxpopup_Module_Data);
+   if (!ctx_mod) return NULL;
+
+   ctx_mod->ctxpopup = elm_ctxpopup_add(elm_widget_top_get(obj));
+   snprintf(buf, sizeof(buf), "datetime/%s", elm_object_style_get(obj));
+   elm_object_style_set(ctx_mod->ctxpopup, buf);
+   elm_ctxpopup_horizontal_set(ctx_mod->ctxpopup, EINA_TRUE);
+   evas_object_size_hint_weight_set(ctx_mod->ctxpopup, EVAS_HINT_EXPAND,
+                                    EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(ctx_mod->ctxpopup, EVAS_HINT_FILL, 0.5);
+   evas_object_smart_callback_add(ctx_mod->ctxpopup, "dismissed",
+                                  _ctxpopup_dismissed_cb, ctx_mod);
+   evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE,
+                                  _datetime_resize_cb, ctx_mod);
+   evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE,
+                                  _datetime_move_cb, ctx_mod);
+   evas_object_event_callback_add(elm_widget_top_get(obj), EVAS_CALLBACK_RESIZE,
+                                  _ctxpopup_parent_resize_cb, ctx_mod);
+
+   return ((Elm_Datetime_Module_Data*)ctx_mod);
+}
+
+EAPI void
+obj_unhook(Elm_Datetime_Module_Data *module_data)
+{
+   Ctxpopup_Module_Data *ctx_mod;
+
+   ctx_mod = (Ctxpopup_Module_Data *)module_data;
+   if (!ctx_mod) return;
+
+   if (ctx_mod->ctxpopup)
+     evas_object_del(ctx_mod->ctxpopup);
+
+   if (ctx_mod)
+     {
+          free(ctx_mod);
+          ctx_mod = NULL;
+      }
+}
+
+// module api funcs needed
+EAPI int
+elm_modapi_init(void *m __UNUSED__)
+{
+   return 1; // succeed always
+}
+
+EAPI int
+elm_modapi_shutdown(void *m __UNUSED__)
+{
+   return 1; // succeed always
+}