efl_ui_calendar: create new efl_ui_calendar
authorWooHyun Jung <wh0705.jung@samsung.com>
Wed, 25 Oct 2017 07:42:39 +0000 (16:42 +0900)
committerJean-Philippe Andre <jp.andre@samsung.com>
Wed, 25 Oct 2017 07:50:01 +0000 (16:50 +0900)
Summary:
This calendar widget will support basic functionality of calendar.
I've separated this widget from elm_calendar since elm_calendar had
lots of unuseful things inside.

Reviewers: jpeg, singh.amitesh, cedric, CHAN, Jaehyun_Cho

Subscribers: cedric, jpeg

Differential Revision: https://phab.enlightenment.org/D5346

13 files changed:
config/default/base.src.in
config/mobile/base.src.in
config/standard/base.src.in
po/POTFILES.in
src/Makefile_Elementary.am
src/bin/elementary/test.c
src/bin/elementary/test_calendar.c
src/lib/elementary/Elementary.h
src/lib/elementary/efl_ui_calendar.c [new file with mode: 0644]
src/lib/elementary/efl_ui_calendar.eo [new file with mode: 0644]
src/lib/elementary/efl_ui_calendar.h [new file with mode: 0644]
src/lib/elementary/efl_ui_calendar_common.h [new file with mode: 0644]
src/lib/elementary/efl_ui_calendar_private.h [new file with mode: 0644]

index 510e5a0..10d7d0e 100644 (file)
@@ -749,6 +749,101 @@ group "Elm_Config" struct {
         }
      }
      group "Elm_Config_Bindings_Widget" struct {
+        value "name" string: "Efl.Ui.Calendar";
+        group "key_bindings" list {
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "Prior";
+              value "action" string: "move";
+              value "params" string: "prior";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "KP_Prior";
+              value "action" string: "move";
+              value "params" string: "prior";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "Next";
+              value "action" string: "move";
+              value "params" string: "next";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "KP_Next";
+              value "action" string: "move";
+              value "params" string: "next";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "Left";
+              value "action" string: "move";
+              value "params" string: "left";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "KP_Left";
+              value "action" string: "move";
+              value "params" string: "left";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "Right";
+              value "action" string: "move";
+              value "params" string: "right";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "KP_Right";
+              value "action" string: "move";
+              value "params" string: "right";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "Up";
+              value "action" string: "move";
+              value "params" string: "up";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "KP_Up";
+              value "action" string: "move";
+              value "params" string: "up";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "Down";
+              value "action" string: "move";
+              value "params" string: "down";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "KP_Down";
+              value "action" string: "move";
+              value "params" string: "down";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "Return";
+              value "action" string: "activate";
+              value "params" string: "";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "KP_Enter";
+              value "action" string: "activate";
+              value "params" string: "";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "space";
+              value "action" string: "activate";
+              value "params" string: "";
+           }
+        }
+     }
+     group "Elm_Config_Bindings_Widget" struct {
         value "name" string: "Efl.Ui.Check";
         group "key_bindings" list {
            group "Elm_Config_Binding_Key" struct {
index abc3a3d..5f5b5dd 100644 (file)
@@ -753,6 +753,101 @@ group "Elm_Config" struct {
         }
      }
      group "Elm_Config_Bindings_Widget" struct {
+        value "name" string: "Efl.Ui.Calendar";
+        group "key_bindings" list {
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "Prior";
+              value "action" string: "move";
+              value "params" string: "prior";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "KP_Prior";
+              value "action" string: "move";
+              value "params" string: "prior";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "Next";
+              value "action" string: "move";
+              value "params" string: "next";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "KP_Next";
+              value "action" string: "move";
+              value "params" string: "next";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "Left";
+              value "action" string: "move";
+              value "params" string: "left";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "KP_Left";
+              value "action" string: "move";
+              value "params" string: "left";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "Right";
+              value "action" string: "move";
+              value "params" string: "right";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "KP_Right";
+              value "action" string: "move";
+              value "params" string: "right";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "Up";
+              value "action" string: "move";
+              value "params" string: "up";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "KP_Up";
+              value "action" string: "move";
+              value "params" string: "up";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "Down";
+              value "action" string: "move";
+              value "params" string: "down";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "KP_Down";
+              value "action" string: "move";
+              value "params" string: "down";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "Return";
+              value "action" string: "activate";
+              value "params" string: "";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "KP_Enter";
+              value "action" string: "activate";
+              value "params" string: "";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "space";
+              value "action" string: "activate";
+              value "params" string: "";
+           }
+        }
+     }
+     group "Elm_Config_Bindings_Widget" struct {
         value "name" string: "Efl.Ui.Check";
         group "key_bindings" list {
            group "Elm_Config_Binding_Key" struct {
index c3a3b22..1349791 100644 (file)
@@ -750,6 +750,101 @@ group "Elm_Config" struct {
         }
      }
      group "Elm_Config_Bindings_Widget" struct {
+        value "name" string: "Efl.Ui.Calendar";
+        group "key_bindings" list {
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "Prior";
+              value "action" string: "move";
+              value "params" string: "prior";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "KP_Prior";
+              value "action" string: "move";
+              value "params" string: "prior";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "Next";
+              value "action" string: "move";
+              value "params" string: "next";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "KP_Next";
+              value "action" string: "move";
+              value "params" string: "next";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "Left";
+              value "action" string: "move";
+              value "params" string: "left";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "KP_Left";
+              value "action" string: "move";
+              value "params" string: "left";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "Right";
+              value "action" string: "move";
+              value "params" string: "right";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "KP_Right";
+              value "action" string: "move";
+              value "params" string: "right";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "Up";
+              value "action" string: "move";
+              value "params" string: "up";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "KP_Up";
+              value "action" string: "move";
+              value "params" string: "up";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "Down";
+              value "action" string: "move";
+              value "params" string: "down";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "KP_Down";
+              value "action" string: "move";
+              value "params" string: "down";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "Return";
+              value "action" string: "activate";
+              value "params" string: "";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "KP_Enter";
+              value "action" string: "activate";
+              value "params" string: "";
+           }
+           group "Elm_Config_Binding_Key" struct {
+              value "context" int: 0;
+              value "key" string: "space";
+              value "action" string: "activate";
+              value "params" string: "";
+           }
+        }
+     }
+     group "Elm_Config_Bindings_Widget" struct {
         value "name" string: "Efl.Ui.Check";
         group "key_bindings" list {
            group "Elm_Config_Binding_Key" struct {
index 27588cc..06b1e60 100644 (file)
@@ -108,6 +108,7 @@ src/lib/elementary/elm_box.c
 src/lib/elementary/elm_bubble.c
 src/lib/elementary/efl_ui_button.c
 src/lib/elementary/elm_calendar.c
+src/lib/elementary/efl_ui_calendar.c
 src/lib/elementary/efl_ui_check.c
 src/lib/elementary/elm_clock.c
 src/lib/elementary/elm_cnp.c
index e9c10db..b83482e 100644 (file)
@@ -7,6 +7,7 @@ elm_public_eolian_files = \
        lib/elementary/efl_ui_bg.eo \
        lib/elementary/efl_ui_button.eo \
        lib/elementary/elm_calendar.eo \
+       lib/elementary/efl_ui_calendar.eo \
        lib/elementary/efl_ui_check.eo \
        lib/elementary/elm_clock.eo \
        lib/elementary/elm_colorselector.eo \
@@ -247,6 +248,7 @@ includesunstable_HEADERS = \
        lib/elementary/efl_ui_button_private.h \
        lib/elementary/efl_ui_bg_private.h \
        lib/elementary/elm_widget_calendar.h \
+       lib/elementary/efl_ui_calendar_private.h \
        lib/elementary/efl_ui_check_private.h \
        lib/elementary/elm_widget_clock.h \
        lib/elementary/elm_widget_colorselector.h \
@@ -370,6 +372,8 @@ includesub_HEADERS = \
        lib/elementary/elm_calendar_eo.h \
        lib/elementary/elm_calendar_legacy.h \
        lib/elementary/elm_calendar_common.h \
+       lib/elementary/efl_ui_calendar.h \
+       lib/elementary/efl_ui_calendar_common.h \
        lib/elementary/elm_check.h \
        lib/elementary/efl_ui_check_eo.h \
        lib/elementary/elm_check_legacy.h \
@@ -584,6 +588,7 @@ lib_elementary_libelementary_la_SOURCES = \
        lib/elementary/elm_bubble.c \
        lib/elementary/efl_ui_button.c \
        lib/elementary/elm_calendar.c \
+       lib/elementary/efl_ui_calendar.c \
        lib/elementary/efl_ui_check.c \
        lib/elementary/elm_clock.c \
        lib/elementary/elm_cnp.c \
index 2abfdf8..14fa889 100644 (file)
@@ -200,6 +200,7 @@ void test_panes_minsize(void *data, Evas_Object *obj, void *event_info);
 void test_calendar(void *data, Evas_Object *obj, void *event_info);
 void test_calendar2(void *data, Evas_Object *obj, void *event_info);
 void test_calendar3(void *data, Evas_Object *obj, void *event_info);
+void test_efl_ui_calendar(void *data, Evas_Object *obj, void *event_info);
 void test_map(void *data, Evas_Object *obj, void *event_info);
 void test_weather(void *data, Evas_Object *obj, void *event_info);
 void test_flip(void *data, Evas_Object *obj, void *event_info);
@@ -1002,6 +1003,7 @@ add_tests:
    ADD_TEST(NULL, "Times & Dates", "Calendar", test_calendar);
    ADD_TEST(NULL, "Times & Dates", "Calendar 2", test_calendar2);
    ADD_TEST(NULL, "Times & Dates", "Calendar 3", test_calendar3);
+   ADD_TEST(NULL, "Times & Dates", "Efl Ui Calendar", test_efl_ui_calendar);
    ADD_TEST(NULL, "Times & Dates", "Clock", test_clock);
    ADD_TEST(NULL, "Times & Dates", "Clock Edit", test_clock_edit);
    ADD_TEST(NULL, "Times & Dates", "Clock Edit 2", test_clock_edit2);
index 35e1bf9..2bcfc17 100644 (file)
@@ -379,3 +379,59 @@ test_calendar3(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event
 
    evas_object_show(win);
 }
+
+static void
+_cal_changed_cb(void *data EINA_UNUSED, const Efl_Event *ev)
+{
+   struct tm selected_date;
+   struct tm max_date;
+   struct tm min_date;
+
+   selected_date = efl_ui_calendar_date_get(ev->object);
+   min_date = efl_ui_calendar_date_min_get(ev->object);
+   max_date = efl_ui_calendar_date_max_get(ev->object);
+   printf("Selected Date is %i/%i/%i\n",
+          selected_date.tm_mday,
+          selected_date.tm_mon + 1,
+          selected_date.tm_year + 1900);
+   printf("Minimum Date is %i/%i/%i\n",
+          min_date.tm_mday,
+          min_date.tm_mon + 1,
+          min_date.tm_year + 1900);
+   printf("Max Date is %i/%i/%i\n",
+          max_date.tm_mday,
+          max_date.tm_mon + 1,
+          max_date.tm_year + 1900);
+}
+
+void
+test_efl_ui_calendar(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+   Evas_Object *win, *box;
+   struct tm selected_date, min_date, max_date;
+   time_t current_date;
+
+   current_date = time(NULL) + SEC_PER_DAY;
+   localtime_r(&current_date, &selected_date);
+   current_date = time(NULL) - SEC_PER_YEAR;
+   localtime_r(&current_date, &min_date);
+   current_date = time(NULL) + SEC_PER_YEAR;
+   localtime_r(&current_date, &max_date);
+
+   win = efl_add(EFL_UI_WIN_CLASS, NULL,
+                 efl_text_set(efl_added, "Efl Ui Calendar"),
+                efl_ui_win_autodel_set(efl_added, EINA_TRUE));
+
+   box = efl_add(EFL_UI_BOX_CLASS, win,
+                 efl_ui_direction_set(efl_added, EFL_UI_DIR_HORIZONTAL),
+                 efl_content_set(win, efl_added));
+
+   efl_add(EFL_UI_CALENDAR_CLASS, win,
+           efl_ui_calendar_date_set(efl_added, selected_date),
+           efl_ui_calendar_date_min_set(efl_added, min_date),
+           efl_ui_calendar_date_max_set(efl_added, max_date),
+           efl_event_callback_add(efl_added, EFL_UI_CALENDAR_EVENT_CHANGED, _cal_changed_cb, NULL),
+           efl_pack(box, efl_added));
+
+   efl_gfx_size_set(win, EINA_SIZE2D(300, 300));
+}
index c1065ec..4d22b69 100644 (file)
@@ -197,6 +197,7 @@ EAPI extern Elm_Version *elm_version;
 #include <elm_button.h>
 #include <elm_cache.h>
 #include <elm_calendar.h>
+#include <efl_ui_calendar.h>
 #include <elm_check.h>
 #include <elm_clock.h>
 #include <elm_cnp.h>
diff --git a/src/lib/elementary/efl_ui_calendar.c b/src/lib/elementary/efl_ui_calendar.c
new file mode 100644 (file)
index 0000000..66ca500
--- /dev/null
@@ -0,0 +1,1214 @@
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+
+#define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED
+#define ELM_INTERFACE_ATSPI_WIDGET_ACTION_PROTECTED
+
+#include <Elementary.h>
+#include "elm_priv.h"
+#include "efl_ui_calendar_private.h"
+
+#define MY_CLASS EFL_UI_CALENDAR_CLASS
+
+#define MY_CLASS_NAME "Efl.Ui.Calendar"
+#define MY_CLASS_PFX efl_ui_calendar
+
+#define EFL_UI_CALENDAR_BUTTON_LEFT "elm,calendar,button,left"
+#define EFL_UI_CALENDAR_BUTTON_RIGHT "elm,calendar,button,right"
+#define EFL_UI_CALENDAR_BUTTON_YEAR_LEFT "elm,calendar,button_year,left"
+#define EFL_UI_CALENDAR_BUTTON_YEAR_RIGHT "elm,calendar,button_year,right"
+
+static const char SIG_CHANGED[] = "changed";
+
+static const Evas_Smart_Cb_Description _smart_callbacks[] = {
+   {SIG_CHANGED, ""},
+   {SIG_WIDGET_LANG_CHANGED, ""}, /**< handled by elm_widget */
+   {SIG_WIDGET_ACCESS_CHANGED, ""}, /**< handled by elm_widget */
+   {SIG_LAYOUT_FOCUSED, ""}, /**< handled by elm_layout */
+   {SIG_LAYOUT_UNFOCUSED, ""}, /**< handled by elm_layout */
+   {NULL, NULL}
+};
+
+static void
+_button_widget_month_inc_start_click(void *data,
+                                     Evas_Object *obj EINA_UNUSED,
+                                     void *event_info EINA_UNUSED);
+static void
+_button_widget_month_inc_start(void *data,
+                              Evas_Object *obj EINA_UNUSED,
+                              void *event_info EINA_UNUSED);
+static void
+_button_widget_month_dec_start_click(void *data,
+                                    Evas_Object *obj EINA_UNUSED,
+                                    void *event_info EINA_UNUSED);
+static void
+_button_widget_month_dec_start(void *data,
+                              Evas_Object *obj EINA_UNUSED,
+                              void *event_info EINA_UNUSED);
+
+static Eina_Bool _key_action_activate(Evas_Object *obj, const char *params);
+
+static const Elm_Action key_actions[] = {
+   {"activate", _key_action_activate},
+   {NULL, NULL}
+};
+
+/* Should not be translated, it's used if we failed
+ * getting from locale. */
+static const char *_days_abbrev[] =
+{
+   "Sun", "Mon", "Tue", "Wed",
+   "Thu", "Fri", "Sat"
+};
+
+static int _days_in_month[2][12] =
+{
+   {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+   {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+};
+
+static Eina_Bool _efl_ui_calendar_smart_focus_next_enable = EINA_FALSE;
+
+EOLIAN static void
+_efl_ui_calendar_elm_layout_sizing_eval(Eo *obj, Efl_Ui_Calendar_Data *_pd EINA_UNUSED)
+{
+   Evas_Coord minw = -1, minh = -1;
+   EFL_UI_CALENDAR_DATA_GET(obj, sd);
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+
+   if (sd->filling) return;
+   // 7x8 (1 month+year, days, 6 dates.)
+   elm_coords_finger_size_adjust(7, &minw, 8, &minh);
+   edje_object_size_min_restricted_calc
+     (wd->resize_obj, &minw, &minh, minw, minh);
+   evas_object_size_hint_min_set(obj, minw, minh);
+   evas_object_size_hint_max_set(obj, -1, -1);
+}
+
+// Get the max day number for each month
+static inline int
+_maxdays_get(struct tm *date, int month_offset)
+{
+   int month, year;
+
+   month = (date->tm_mon + month_offset) % 12;
+   year = date->tm_year + 1900;
+
+   if (month < 0) month += 12;
+
+   return _days_in_month
+          [((!(year % 4)) && ((!(year % 400)) || (year % 100)))][month];
+}
+
+static inline void
+_unselect(Evas_Object *obj,
+          int selected)
+{
+   char emission[32];
+
+   snprintf(emission, sizeof(emission), "cit_%d,unselected", selected);
+   elm_layout_signal_emit(obj, emission, "elm");
+}
+
+static inline void
+_select(Evas_Object *obj,
+        int selected)
+{
+   char emission[32];
+
+   EFL_UI_CALENDAR_DATA_GET(obj, sd);
+
+   sd->focused_it = sd->selected_it = selected;
+   snprintf(emission, sizeof(emission), "cit_%d,selected", selected);
+   elm_layout_signal_emit(obj, emission, "elm");
+}
+
+static inline void
+_not_today(Efl_Ui_Calendar_Data *sd)
+{
+   char emission[32];
+
+   snprintf(emission, sizeof(emission), "cit_%d,not_today", sd->today_it);
+   elm_layout_signal_emit(sd->obj, emission, "elm");
+   sd->today_it = -1;
+}
+
+static inline void
+_today(Efl_Ui_Calendar_Data *sd,
+       int it)
+{
+   char emission[32];
+
+   snprintf(emission, sizeof(emission), "cit_%d,today", it);
+   elm_layout_signal_emit(sd->obj, emission, "elm");
+   sd->today_it = it;
+}
+
+static inline void
+_enable(Efl_Ui_Calendar_Data *sd,
+        int it)
+{
+   char emission[32];
+
+   snprintf(emission, sizeof(emission), "cit_%d,enable", it);
+   elm_layout_signal_emit(sd->obj, emission, "elm");
+}
+
+static inline void
+_disable(Efl_Ui_Calendar_Data *sd,
+         int it)
+{
+   char emission[32];
+
+   snprintf(emission, sizeof(emission), "cit_%d,disable", it);
+   elm_layout_signal_emit(sd->obj, emission, "elm");
+}
+
+static char *
+_format_month_year(struct tm *date)
+{
+   return eina_strftime(E_("%B %Y"), date);
+}
+
+static void
+_set_month_year(Efl_Ui_Calendar_Data *sd)
+{
+   char *buf;
+
+   sd->filling = EINA_TRUE;
+
+   buf = sd->format_func(&sd->shown_date);
+
+   if (buf)
+     {
+        elm_layout_text_set(sd->obj, "month_text", buf);
+        free(buf);
+     }
+   else elm_layout_text_set(sd->obj, "month_text", "");
+
+   sd->filling = EINA_FALSE;
+}
+
+static char *
+_access_info_cb(void *data EINA_UNUSED, Evas_Object *obj)
+{
+   char *ret;
+   Eina_Strbuf *buf;
+   buf = eina_strbuf_new();
+
+   eina_strbuf_append_printf(buf, "day %s", elm_widget_access_info_get(obj));
+
+   ret = eina_strbuf_string_steal(buf);
+   eina_strbuf_free(buf);
+   return ret;
+}
+
+static void
+_access_calendar_item_register(Evas_Object *obj)
+{
+   unsigned int maxdays, i;
+   char day_s[13], pname[14];
+   unsigned day = 0;
+   Evas_Object *ao;
+
+   EFL_UI_CALENDAR_DATA_GET(obj, sd);
+
+   maxdays = _maxdays_get(&sd->shown_date, 0);
+   for (i = 0; i < 42; i++)
+     {
+        if ((!day) && (i == sd->first_day_it)) day = 1;
+        if ((day) && (day <= maxdays))
+          {
+             snprintf(pname, sizeof(pname), "cit_%d.access", i);
+
+             ao = _elm_access_edje_object_part_object_register
+                        (obj, elm_layout_edje_get(obj), pname);
+             _elm_access_text_set(_elm_access_info_get(ao),
+                         ELM_ACCESS_TYPE, E_("calendar item"));
+             _elm_access_callback_set(_elm_access_info_get(ao),
+                           ELM_ACCESS_INFO, _access_info_cb, NULL);
+
+             snprintf(day_s, sizeof(day_s), "%d", (int) (day++));
+             elm_widget_access_info_set(ao, (const char*)day_s);
+          }
+        else
+          {
+             snprintf(pname, sizeof(pname), "cit_%d.access", i);
+             _elm_access_edje_object_part_object_unregister
+                     (obj, elm_layout_edje_get(obj), pname);
+          }
+     }
+}
+
+static void
+_access_calendar_spinner_register(Evas_Object *obj)
+{
+   Evas_Object *po;
+   Elm_Access_Info *ai;
+   EFL_UI_CALENDAR_DATA_GET(obj, sd);
+
+   if (!sd->dec_btn_month)
+     sd->dec_btn_month = _elm_access_edje_object_part_object_register
+        (obj, elm_layout_edje_get(obj), "left_bt");
+   ai = _elm_access_info_get(sd->dec_btn_month);
+   _elm_access_text_set(ai, ELM_ACCESS_TYPE, E_("calendar decrement month button"));
+
+   if (!sd->inc_btn_month)
+     sd->inc_btn_month = _elm_access_edje_object_part_object_register
+        (obj, elm_layout_edje_get(obj), "right_bt");
+   ai = _elm_access_info_get(sd->inc_btn_month);
+   _elm_access_text_set(ai, ELM_ACCESS_TYPE, E_("calendar increment month button"));
+
+   sd->month_access = _elm_access_edje_object_part_object_register
+                          (obj, elm_layout_edje_get(obj), "text_month");
+   ai = _elm_access_info_get(sd->month_access);
+   _elm_access_text_set(ai, ELM_ACCESS_TYPE, E_("calendar month"));
+
+   ai = _elm_access_info_get(sd->year_access);
+   _elm_access_text_set(ai, ELM_ACCESS_TYPE, E_("calendar year"));
+
+   po = (Evas_Object *)edje_object_part_object_get
+          (elm_layout_edje_get(obj), "month_text");
+   evas_object_pass_events_set(po, EINA_FALSE);
+}
+
+static void
+_access_calendar_register(Evas_Object *obj)
+{
+   _access_calendar_spinner_register(obj);
+   _access_calendar_item_register(obj);
+}
+
+static void
+_populate(Evas_Object *obj)
+{
+   int maxdays, prev_month_maxdays, day, mon, yr, i;
+   char part[12], day_s[3];
+   struct tm first_day;
+
+   EFL_UI_CALENDAR_DATA_GET(obj, sd);
+
+   elm_layout_freeze(obj);
+
+   sd->filling = EINA_FALSE;
+   if (sd->today_it > 0) _not_today(sd);
+
+   maxdays = _maxdays_get(&sd->shown_date, 0);
+   prev_month_maxdays = _maxdays_get(&sd->shown_date, -1);
+   mon = sd->shown_date.tm_mon;
+   yr = sd->shown_date.tm_year;
+
+   _set_month_year(sd);
+   sd->filling = EINA_TRUE;
+
+   /* Set days */
+   day = 0;
+   first_day = sd->shown_date;
+   first_day.tm_mday = 1;
+   if (mktime(&first_day) == -1)
+     {
+        ERR("mktime can not give week day for this month properly. Please check year or month is proper.");
+        return;
+     }
+
+   // Layout of the calendar is changed for removing the unfilled last row.
+   if (first_day.tm_wday < (int)sd->first_week_day)
+     sd->first_day_it = first_day.tm_wday + ELM_DAY_LAST - sd->first_week_day;
+   else
+     sd->first_day_it = first_day.tm_wday - sd->first_week_day;
+
+   for (i = 0; i < 42; i++)
+     {
+        if ((!day) && (i == sd->first_day_it)) day = 1;
+
+        if ((day == sd->current_date.tm_mday)
+            && (mon == sd->current_date.tm_mon)
+            && (yr == sd->current_date.tm_year))
+          _today(sd, i);
+
+        if (day == sd->date.tm_mday)
+          {
+             if ((sd->selected_it > -1) && (sd->selected_it != i))
+               _unselect(obj, sd->selected_it);
+
+             if ((mon == sd->date.tm_mon) && (yr == sd->date.tm_year))
+               _select(obj, i);
+          }
+
+        if ((day) && (day <= maxdays))
+          {
+             if (((yr == sd->date_min.tm_year) && (mon == sd->date_min.tm_mon) && (day < sd->date_min.tm_mday))
+                 || ((yr == sd->date_max.tm_year) && (mon == sd->date_max.tm_mon) && (day > sd->date_max.tm_mday)))
+               _disable(sd, i);
+             else
+               _enable(sd, i);
+
+             snprintf(day_s, sizeof(day_s), "%d", day++);
+          }
+        else
+          {
+             _disable(sd, i);
+
+             if (day <= maxdays)
+               snprintf(day_s, sizeof(day_s), "%d", prev_month_maxdays - sd->first_day_it + i + 1);
+             else
+               snprintf(day_s, sizeof(day_s), "%d", i - sd->first_day_it - maxdays + 1);
+          }
+
+        snprintf(part, sizeof(part), "cit_%d.text", i);
+        elm_layout_text_set(obj, part, day_s);
+     }
+
+   // ACCESS
+   if ((_elm_config->access_mode != ELM_ACCESS_MODE_OFF))
+     _access_calendar_item_register(obj);
+
+   sd->filling = EINA_FALSE;
+
+   elm_layout_thaw(obj);
+   edje_object_message_signal_process(elm_layout_edje_get(obj));
+}
+
+static void
+_set_headers(Evas_Object *obj)
+{
+   static char part[] = "ch_0.text";
+   int i;
+   struct tm *t;
+   time_t temp = 259200; // the first sunday since epoch
+   EFL_UI_CALENDAR_DATA_GET(obj, sd);
+
+   elm_layout_freeze(obj);
+
+   sd->filling = EINA_TRUE;
+
+   t = gmtime(&temp);
+   if (t)
+     {
+        t->tm_wday = 0;
+        for (i = 0; i < ELM_DAY_LAST; i++)
+          {
+             char *buf;
+             buf = eina_strftime("%a", t);
+             if (buf)
+               {
+                  sd->weekdays[i] = eina_stringshare_add(buf);
+                  free(buf);
+               }
+             else
+               {
+                  /* If we failed getting day, get a default value */
+                  sd->weekdays[i] = _days_abbrev[i];
+                  WRN("Failed getting weekday name for '%s' from locale.",
+                      _days_abbrev[i]);
+               }
+             t->tm_wday++;
+          }
+     }
+
+   for (i = 0; i < ELM_DAY_LAST; i++)
+     {
+        part[3] = i + '0';
+        elm_layout_text_set(obj, part, sd->weekdays[(i + sd->first_week_day) % ELM_DAY_LAST]);
+     }
+
+   sd->filling = EINA_FALSE;
+
+   elm_layout_thaw(obj);
+}
+
+static void
+_spinner_buttons_add(Evas_Object *obj, Efl_Ui_Calendar_Data *sd)
+{
+   char left_buf[255] = { 0 };
+   char right_buf[255] = { 0 };
+
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+
+   snprintf(left_buf, sizeof(left_buf), "calendar/decrease/%s", elm_object_style_get(obj));
+   snprintf(right_buf, sizeof(right_buf), "calendar/increase/%s", elm_object_style_get(obj));
+
+   if (edje_object_part_exists(wd->resize_obj, EFL_UI_CALENDAR_BUTTON_LEFT))
+     {
+        if (sd->dec_btn_month && efl_isa(sd->dec_btn_month, ELM_ACCESS_CLASS))
+          {
+             _elm_access_edje_object_part_object_unregister
+               (obj, elm_layout_edje_get(obj), "left_bt");
+             sd->dec_btn_month = NULL;
+          }
+
+        if (!sd->dec_btn_month)
+          {
+             sd->dec_btn_month = elm_button_add(obj);
+             elm_button_autorepeat_set(sd->dec_btn_month, EINA_TRUE);
+             elm_button_autorepeat_initial_timeout_set(sd->dec_btn_month, 0.5);
+             elm_button_autorepeat_gap_timeout_set(sd->dec_btn_month, 0.2);
+             evas_object_smart_callback_add(sd->dec_btn_month, "clicked", _button_widget_month_dec_start_click, obj);
+             evas_object_smart_callback_add(sd->dec_btn_month, "repeated", _button_widget_month_dec_start, obj);
+          }
+
+        elm_object_style_set(sd->dec_btn_month, left_buf);
+        elm_layout_content_set(obj, EFL_UI_CALENDAR_BUTTON_LEFT, sd->dec_btn_month);
+     }
+   else if (sd->dec_btn_month && !efl_isa(sd->dec_btn_month, ELM_ACCESS_CLASS))
+     {
+        evas_object_del(sd->dec_btn_month);
+        sd->dec_btn_month = NULL;
+     }
+
+   if (edje_object_part_exists(wd->resize_obj, EFL_UI_CALENDAR_BUTTON_RIGHT))
+     {
+        if (sd->inc_btn_month && efl_isa(sd->inc_btn_month, ELM_ACCESS_CLASS))
+          {
+             _elm_access_edje_object_part_object_unregister
+               (obj, elm_layout_edje_get(obj), "right_bt");
+             sd->inc_btn_month = NULL;
+          }
+
+        if (!sd->inc_btn_month)
+          {
+             sd->inc_btn_month = elm_button_add(obj);
+             elm_button_autorepeat_set(sd->inc_btn_month, EINA_TRUE);
+             elm_button_autorepeat_initial_timeout_set(sd->inc_btn_month, 0.5);
+             elm_button_autorepeat_gap_timeout_set(sd->inc_btn_month, 0.2);
+             evas_object_smart_callback_add(sd->inc_btn_month, "clicked", _button_widget_month_inc_start_click, obj);
+             evas_object_smart_callback_add(sd->inc_btn_month, "repeated", _button_widget_month_inc_start, obj);
+          }
+
+        elm_object_style_set(sd->inc_btn_month, right_buf);
+        elm_layout_content_set(obj, EFL_UI_CALENDAR_BUTTON_RIGHT, sd->inc_btn_month);
+     }
+   else if (sd->inc_btn_month && !efl_isa(sd->inc_btn_month, ELM_ACCESS_CLASS))
+     {
+        evas_object_del(sd->inc_btn_month);
+        sd->inc_btn_month = NULL;
+     }
+}
+
+EOLIAN static Efl_Ui_Theme_Apply
+_efl_ui_calendar_elm_widget_theme_apply(Eo *obj, Efl_Ui_Calendar_Data *sd)
+{
+   Efl_Ui_Theme_Apply int_ret = EFL_UI_THEME_APPLY_FAILED;
+
+   int_ret = efl_ui_widget_theme_apply(efl_super(obj, MY_CLASS));
+   if (!int_ret) return EFL_UI_THEME_APPLY_FAILED;
+
+   _spinner_buttons_add(obj, sd);
+
+   evas_object_smart_changed(obj);
+   return int_ret;
+}
+
+/* Set correct tm_wday and tm_yday after other fields changes*/
+static inline Eina_Bool
+_fix_date(Efl_Ui_Calendar_Data *sd)
+{
+   Eina_Bool fixed = EINA_FALSE;
+
+   if ((sd->date.tm_year < sd->date_min.tm_year) ||
+       ((sd->date.tm_year == sd->date_min.tm_year) &&
+        (sd->date.tm_mon < sd->date_min.tm_mon)) ||
+       ((sd->date.tm_year == sd->date_min.tm_year) &&
+        (sd->date.tm_mon == sd->date_min.tm_mon) &&
+        (sd->date.tm_mday < sd->date_min.tm_mday)))
+     {
+        sd->date.tm_year = sd->shown_date.tm_year = sd->date_min.tm_year;
+        sd->date.tm_mon = sd->shown_date.tm_mon = sd->date_min.tm_mon;
+        sd->date.tm_mday = sd->shown_date.tm_mday = sd->date_min.tm_mday;
+        fixed = EINA_TRUE;
+     }
+   else if ((sd->date_max.tm_year != -1) &&
+            ((sd->date.tm_year > sd->date_max.tm_year) ||
+            ((sd->date.tm_year == sd->date_max.tm_year) &&
+             (sd->date.tm_mon > sd->date_max.tm_mon)) ||
+            ((sd->date.tm_year == sd->date_max.tm_year) &&
+             (sd->date.tm_mon == sd->date_max.tm_mon) &&
+             (sd->date.tm_mday > sd->date_max.tm_mday))))
+     {
+        sd->date.tm_year = sd->shown_date.tm_year = sd->date_max.tm_year;
+        sd->date.tm_mon = sd->shown_date.tm_mon = sd->date_max.tm_mon;
+        sd->date.tm_mday = sd->shown_date.tm_mday = sd->date_max.tm_mday;
+        fixed = EINA_TRUE;
+     }
+   else
+     {
+        if (sd->date.tm_mon != sd->shown_date.tm_mon)
+          sd->date.tm_mon = sd->shown_date.tm_mon;
+        if (sd->date.tm_year != sd->shown_date.tm_year)
+          sd->date.tm_year = sd->shown_date.tm_year;
+     }
+
+   return fixed;
+}
+
+static Eina_Bool
+_update_data(Evas_Object *obj, int delta)
+{
+   struct tm time_check;
+   int maxdays;
+
+   EFL_UI_CALENDAR_DATA_GET(obj, sd);
+
+   /* check if it's a valid time. for 32 bits, year greater than 2037 is not */
+   time_check = sd->shown_date;
+   time_check.tm_mon += delta;
+
+   if (mktime(&time_check) == -1)
+     {
+        ERR("mktime can not give week day for the next month. Please check what is wrong with udpate date.");
+        return EINA_FALSE;
+     }
+
+   sd->shown_date.tm_mon += delta;
+
+   if (delta < 0)
+     {
+        if (sd->shown_date.tm_year == sd->date_min.tm_year)
+          {
+             if (sd->shown_date.tm_mon < sd->date_min.tm_mon)
+               {
+                  sd->shown_date.tm_mon = sd->date_min.tm_mon;
+                  return EINA_FALSE;
+               }
+          }
+        else if (sd->shown_date.tm_mon < 0)
+          {
+             sd->shown_date.tm_mon = 11;
+             sd->shown_date.tm_year--;
+          }
+     }
+   else
+     {
+        if (sd->shown_date.tm_year == sd->date_max.tm_year)
+          {
+             if (sd->shown_date.tm_mon > sd->date_max.tm_mon)
+               {
+                  sd->shown_date.tm_mon = sd->date_max.tm_mon;
+                  return EINA_FALSE;
+               }
+          }
+        else if (sd->shown_date.tm_mon > 11)
+          {
+             sd->shown_date.tm_mon = 0;
+             sd->shown_date.tm_year++;
+          }
+     }
+
+   maxdays = _maxdays_get(&sd->shown_date, 0);
+   if (sd->date.tm_mday > maxdays)
+     sd->date.tm_mday = maxdays;
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_spin_month_value(void *data)
+{
+   EFL_UI_CALENDAR_DATA_GET(data, sd);
+
+   if (_update_data(data, sd->spin_speed))
+     evas_object_smart_changed(data);
+
+   sd->interval = sd->interval / 1.05;
+   ecore_timer_interval_set(sd->spin_month, sd->interval);
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_button_widget_month_inc_start_click(void *data,
+                                    Evas_Object *obj EINA_UNUSED,
+                                    void *event_info EINA_UNUSED)
+{
+   EFL_UI_CALENDAR_DATA_GET(data, sd);
+   if (sd->month_repeated)
+     {
+        sd->month_repeated = EINA_FALSE;
+        return;
+     }
+
+   sd->interval = sd->first_interval;
+   sd->spin_speed = 1;
+   _spin_month_value(data);
+}
+
+static void
+_button_widget_month_inc_start(void *data,
+                              Evas_Object *obj EINA_UNUSED,
+                              void *event_info EINA_UNUSED)
+{
+   EFL_UI_CALENDAR_DATA_GET(data, sd);
+
+   sd->spin_speed = 1;
+   if (!sd->month_repeated)
+     sd->interval = sd->first_interval;
+   sd->month_repeated = EINA_TRUE;
+   _spin_month_value(data);
+
+}
+
+static void
+_button_widget_month_dec_start_click(void *data,
+                                    Evas_Object *obj EINA_UNUSED,
+                                    void *event_info EINA_UNUSED)
+{
+   EFL_UI_CALENDAR_DATA_GET(data, sd);
+   if (sd->month_repeated)
+     {
+        sd->month_repeated = EINA_FALSE;
+        return;
+     }
+
+   sd->interval = sd->first_interval;
+   sd->spin_speed = -1;
+   _spin_month_value(data);
+}
+
+static void
+_button_widget_month_dec_start(void *data,
+                              Evas_Object *obj EINA_UNUSED,
+                              void *event_info EINA_UNUSED)
+{
+   EFL_UI_CALENDAR_DATA_GET(data, sd);
+
+   sd->spin_speed = -1;
+   if (!sd->month_repeated)
+     sd->interval = sd->first_interval;
+   sd->month_repeated = EINA_TRUE;
+   _spin_month_value(data);
+}
+
+static int
+_get_item_day(Evas_Object *obj,
+              int selected_it)
+{
+   int day;
+
+   EFL_UI_CALENDAR_DATA_GET(obj, sd);
+
+   day = selected_it - sd->first_day_it + 1;
+   if ((day < 0) || (day > _maxdays_get(&sd->shown_date, 0)))
+     return 0;
+
+   if ((sd->shown_date.tm_year == sd->date_min.tm_year)
+       && (sd->shown_date.tm_mon == sd->date_min.tm_mon)
+       && (day < sd->date_min.tm_mday))
+     {
+        return 0;
+     }
+   else if ((sd->shown_date.tm_year == sd->date_max.tm_year)
+            && (sd->shown_date.tm_mon == sd->date_max.tm_mon)
+            && (day > sd->date_max.tm_mday))
+     {
+        return 0;
+     }
+
+   return day;
+}
+
+static void
+_update_unfocused_it(Evas_Object *obj, int unfocused_it)
+{
+   int day;
+   char emission[32];
+
+   EFL_UI_CALENDAR_DATA_GET(obj, sd);
+
+   day = _get_item_day(obj, unfocused_it);
+   if (!day)
+     return;
+
+   sd->focused_it = -1;
+
+   snprintf(emission, sizeof(emission), "cit_%d,unfocused", unfocused_it);
+   elm_layout_signal_emit(obj, emission, "elm");
+}
+
+static Eina_Bool
+_update_focused_it(Evas_Object *obj, int focused_it)
+{
+   int day;
+   char emission[32];
+
+   EFL_UI_CALENDAR_DATA_GET(obj, sd);
+
+   day = _get_item_day(obj, focused_it);
+   if (!day)
+     return EINA_FALSE;
+
+   snprintf(emission, sizeof(emission), "cit_%d,unfocused", sd->focused_it);
+   elm_layout_signal_emit(obj, emission, "elm");
+
+   sd->focused_it = focused_it;
+
+   snprintf(emission, sizeof(emission), "cit_%d,focused", sd->focused_it);
+   elm_layout_signal_emit(obj, emission, "elm");
+
+   return EINA_TRUE;
+}
+
+static void
+_update_sel_it(Evas_Object *obj,
+               int sel_it)
+{
+   int day;
+
+   EFL_UI_CALENDAR_DATA_GET(obj, sd);
+
+   day = _get_item_day(obj, sel_it);
+   if (!day)
+     return;
+
+   _unselect(obj, sd->selected_it);
+   if (!sd->selected)
+     sd->selected = EINA_TRUE;
+   if (sd->focused_it)
+     _update_unfocused_it(obj, sd->focused_it);
+
+   sd->date.tm_mday = day;
+   _fix_date(sd);
+   _select(obj, sel_it);
+   efl_event_callback_legacy_call(obj, EFL_UI_CALENDAR_EVENT_CHANGED, NULL);
+}
+
+static void
+_day_selected(void *data,
+              Evas_Object *obj EINA_UNUSED,
+              const char *emission EINA_UNUSED,
+              const char *source)
+{
+   int sel_it;
+
+   sel_it = atoi(source);
+
+   _update_sel_it(data, sel_it);
+}
+
+static inline int
+_time_to_next_day(struct tm *t)
+{
+   return ((((24 - t->tm_hour) * 60) - t->tm_min) * 60) - t->tm_sec;
+}
+
+static Eina_Bool
+_update_cur_date(void *data)
+{
+   time_t current_date;
+   int t, day;
+   EFL_UI_CALENDAR_DATA_GET(data, sd);
+
+   if (sd->today_it > 0) _not_today(sd);
+
+   current_date = time(NULL);
+   localtime_r(&current_date, &sd->current_date);
+   t = _time_to_next_day(&sd->current_date);
+   ecore_timer_interval_set(sd->update_timer, t);
+
+   if ((sd->current_date.tm_mon != sd->shown_date.tm_mon) ||
+       (sd->current_date.tm_year != sd->shown_date.tm_year))
+     return ECORE_CALLBACK_RENEW;
+
+   day = sd->current_date.tm_mday + sd->first_day_it - 1;
+   _today(sd, day);
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_key_action_activate(Evas_Object *obj, const char *params EINA_UNUSED)
+{
+   EFL_UI_CALENDAR_DATA_GET(obj, sd);
+
+   _update_sel_it(obj, sd->focused_it);
+
+   return EINA_TRUE;
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_calendar_elm_widget_on_focus_update(Eo *obj, Efl_Ui_Calendar_Data *sd, Elm_Object_Item *item EINA_UNUSED)
+{
+   Eina_Bool int_ret = EINA_FALSE;
+
+   int_ret = efl_ui_widget_on_focus_update(efl_super(obj, MY_CLASS), NULL);
+   if (!int_ret) return EINA_FALSE;
+
+   // FIXME : Currently, focused item is same with selected item.
+   //         After arrenging focus logic in this widget, we need to make
+   //         focused item which is for indicating direction key input movement
+   //         on the calendar widget.
+   if (elm_widget_focus_get(obj))
+     _update_focused_it(obj, sd->selected_it);
+   else
+     _update_unfocused_it(obj, sd->focused_it);
+
+   return EINA_TRUE;
+}
+
+EOLIAN static void
+_efl_ui_calendar_efl_canvas_group_group_calculate(Eo *obj, Efl_Ui_Calendar_Data *_pd EINA_UNUSED)
+{
+   elm_layout_freeze(obj);
+
+   _set_headers(obj);
+   _populate(obj);
+
+   elm_layout_thaw(obj);
+}
+
+EOLIAN static void
+_efl_ui_calendar_efl_object_destructor(Eo *obj, Efl_Ui_Calendar_Data *sd)
+{
+   int i;
+
+   ecore_timer_del(sd->spin_month);
+   ecore_timer_del(sd->spin_year);
+   ecore_timer_del(sd->update_timer);
+
+   for (i = 0; i < ELM_DAY_LAST; i++)
+     eina_stringshare_del(sd->weekdays[i]);
+
+   efl_destructor(efl_super(obj, MY_CLASS));
+}
+
+static void
+_access_obj_process(Evas_Object *obj, Eina_Bool is_access)
+{
+   int maxdays, day, i;
+
+   EFL_UI_CALENDAR_DATA_GET(obj, sd);
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+
+   if (is_access)
+     _access_calendar_register(obj);
+   else
+     {
+        day = 0;
+        maxdays = _maxdays_get(&sd->shown_date, 0);
+        for (i = 0; i < 42; i++)
+          {
+             if ((!day) && (i == sd->first_day_it)) day = 1;
+             if ((day) && (day <= maxdays))
+               {
+                  char pname[14];
+                  snprintf(pname, sizeof(pname), "cit_%d.access", i);
+
+                  _elm_access_edje_object_part_object_unregister
+                          (obj, elm_layout_edje_get(obj), pname);
+               }
+          }
+
+        if (sd->dec_btn_month && efl_isa(sd->dec_btn_month, ELM_ACCESS_CLASS))
+          {
+             _elm_access_edje_object_part_object_unregister
+               (obj, elm_layout_edje_get(obj), "left_bt");
+             sd->dec_btn_month = NULL;
+          }
+        if (sd->inc_btn_month && efl_isa(sd->inc_btn_month, ELM_ACCESS_CLASS))
+          {
+             _elm_access_edje_object_part_object_unregister
+               (obj, elm_layout_edje_get(obj), "right_bt");
+             sd->inc_btn_month = NULL;
+          }
+        if (sd->month_access)
+          _elm_access_edje_object_part_object_unregister
+            (obj, elm_layout_edje_get(obj), "month_text");
+     }
+}
+
+EOLIAN static void
+_efl_ui_calendar_elm_widget_on_access_update(Eo *obj EINA_UNUSED, Efl_Ui_Calendar_Data *_pd EINA_UNUSED, Eina_Bool acs)
+{
+   _efl_ui_calendar_smart_focus_next_enable = acs;
+   _access_obj_process(obj, _efl_ui_calendar_smart_focus_next_enable);
+}
+
+static Eo *
+_efl_ui_calendar_constructor_internal(Eo *obj, Efl_Ui_Calendar_Data *priv)
+{
+   time_t current_date;
+   int t;
+
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL);
+
+   elm_widget_sub_object_parent_add(obj);
+
+   priv->first_interval = 0.85;
+   priv->date_min.tm_year = 2;
+   priv->date_min.tm_mon = 0;
+   priv->date_min.tm_mday = 1;
+   priv->date_max.tm_year = -1;
+   priv->date_max.tm_mon = 11;
+   priv->date_max.tm_mday = 31;
+   priv->today_it = -1;
+   priv->selected_it = -1;
+   priv->first_day_it = -1;
+   priv->format_func = _format_month_year;
+
+   edje_object_signal_callback_add
+     (wd->resize_obj, "elm,action,selected", "*",
+     _day_selected, obj);
+
+   current_date = time(NULL);
+   localtime_r(&current_date, &priv->shown_date);
+   priv->current_date = priv->shown_date;
+   priv->date = priv->shown_date;
+   t = _time_to_next_day(&priv->current_date);
+   priv->update_timer = ecore_timer_add(t, _update_cur_date, obj);
+
+   elm_widget_can_focus_set(obj, EINA_TRUE);
+
+   if (!elm_layout_theme_set(obj, "calendar", "base",
+                             elm_object_style_get(obj)))
+     CRI("Failed to set layout!");
+
+   _spinner_buttons_add(obj, priv);
+
+   evas_object_smart_changed(obj);
+
+   // ACCESS
+   if ((_elm_config->access_mode != ELM_ACCESS_MODE_OFF))
+      _access_calendar_spinner_register(obj);
+
+   return obj;
+}
+
+EOLIAN static Eo *
+_efl_ui_calendar_efl_object_constructor(Eo *obj, Efl_Ui_Calendar_Data *sd)
+{
+   obj = efl_constructor(efl_super(obj, MY_CLASS));
+   sd->obj = obj;
+   evas_object_smart_callbacks_descriptions_set(obj, _smart_callbacks);
+   efl_access_role_set(obj, EFL_ACCESS_ROLE_DATE_EDITOR);
+
+   obj = _efl_ui_calendar_constructor_internal(obj, sd);
+
+   return obj;
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_calendar_date_min_set(Eo *obj, Efl_Ui_Calendar_Data *sd, Efl_Time min)
+{
+   Eina_Bool upper = EINA_FALSE;
+   struct tm temp;
+
+   temp = min;
+   if (mktime(&temp) == -1)
+     {
+        ERR("mktime can not give week day for your minimum date. Please check the date.");
+        return EINA_FALSE;
+     }
+
+   if ((sd->date_min.tm_year == min.tm_year)
+       && (sd->date_min.tm_mon == min.tm_mon)
+       && (sd->date_min.tm_mday == min.tm_mday))
+     return EINA_TRUE;
+
+   if (min.tm_year < 2)
+     {
+        sd->date_min.tm_year = 2;
+        sd->date_min.tm_mon = 0;
+        sd->date_min.tm_mday = 1;
+     }
+   else
+     {
+        if (sd->date_max.tm_year != -1)
+          {
+             if (min.tm_year > sd->date_max.tm_year)
+               {
+                  upper = EINA_TRUE;
+               }
+             else if (min.tm_year == sd->date_max.tm_year)
+               {
+                  if (min.tm_mon > sd->date_max.tm_mon)
+                    upper = EINA_TRUE;
+                  else if ((min.tm_mon == sd->date_max.tm_mon) && (min.tm_mday > sd->date_max.tm_mday))
+                    upper = EINA_TRUE;
+               }
+          }
+
+        if (upper)
+          {
+             sd->date_min.tm_year = sd->date_max.tm_year;
+             sd->date_min.tm_mon = sd->date_max.tm_mon;
+             sd->date_min.tm_mday = sd->date_max.tm_mday;
+          }
+        else
+          {
+             sd->date_min.tm_year = min.tm_year;
+             sd->date_min.tm_mon = min.tm_mon;
+             sd->date_min.tm_mday = min.tm_mday;
+          }
+     }
+
+   _fix_date(sd);
+
+   evas_object_smart_changed(obj);
+
+   if (upper)
+     {
+        ERR("Your minimum date is greater than current maximum date.");
+        return EINA_FALSE;
+     }
+   return EINA_TRUE;
+}
+
+EOLIAN static Efl_Time
+_efl_ui_calendar_date_min_get(Eo *obj EINA_UNUSED, Efl_Ui_Calendar_Data *sd)
+{
+   return sd->date_min;
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_calendar_date_max_set(Eo *obj, Efl_Ui_Calendar_Data *sd, Efl_Time max)
+{
+   Eina_Bool lower = EINA_FALSE;
+   struct tm temp;
+
+   temp = max;
+   if (mktime(&temp) == -1)
+     {
+        ERR("mktime can not give week day for your maximum date. Please check the date.");
+        return EINA_FALSE;
+     }
+
+   if ((sd->date_max.tm_year == max.tm_year)
+       && (sd->date_max.tm_mon == max.tm_mon)
+       && (sd->date_max.tm_mday == max.tm_mday))
+     return EINA_TRUE;
+
+   if (max.tm_year < sd->date_min.tm_year)
+     {
+        lower = EINA_TRUE;
+     }
+   else if (max.tm_year == sd->date_min.tm_year)
+     {
+        if (max.tm_mon < sd->date_min.tm_mon)
+          lower = EINA_TRUE;
+        else if ((max.tm_mon == sd->date_min.tm_mon) && (max.tm_mday < sd->date_min.tm_mday))
+          lower = EINA_TRUE;
+     }
+
+   if (lower)
+     {
+        sd->date_max.tm_year = sd->date_min.tm_year;
+        sd->date_max.tm_mon = sd->date_min.tm_mon;
+        sd->date_max.tm_mday = sd->date_min.tm_mday;
+     }
+   else
+     {
+        sd->date_max.tm_year = max.tm_year;
+        sd->date_max.tm_mon = max.tm_mon;
+        sd->date_max.tm_mday = max.tm_mday;
+     }
+
+   _fix_date(sd);
+
+   evas_object_smart_changed(obj);
+
+   if (lower)
+     {
+        ERR("Your maximum date is less than current minimum date.");
+        return EINA_FALSE;
+     }
+   return EINA_TRUE;
+}
+
+EOLIAN static Efl_Time
+_efl_ui_calendar_date_max_get(Eo *obj EINA_UNUSED, Efl_Ui_Calendar_Data *sd)
+{
+   return sd->date_max;
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_calendar_date_set(Eo *obj, Efl_Ui_Calendar_Data *sd, Efl_Time date)
+{
+   Eina_Bool ret = EINA_TRUE;
+   struct tm temp;
+
+   temp = date;
+   if (mktime(&temp) == -1)
+     {
+        ERR("mktime can not give week day for your new date. Please check the date.");
+        return EINA_FALSE;
+     }
+
+   sd->date.tm_year = date.tm_year;
+   sd->date.tm_mon = date.tm_mon;
+   sd->date.tm_mday = date.tm_mday;
+   if (!sd->selected)
+     sd->selected = EINA_TRUE;
+
+   if (sd->date.tm_year != sd->shown_date.tm_year)
+     sd->shown_date.tm_year = sd->date.tm_year;
+   if (sd->date.tm_mon != sd->shown_date.tm_mon)
+     sd->shown_date.tm_mon = sd->date.tm_mon;
+
+   ret = _fix_date(sd);
+
+   evas_object_smart_changed(obj);
+
+   if (!ret)
+     ERR("The current date is greater than the maximum date or less than the minimum date.");
+
+   return ret;
+}
+
+EOLIAN static Efl_Time
+_efl_ui_calendar_date_get(Eo *obj EINA_UNUSED, Efl_Ui_Calendar_Data *sd)
+{
+   return sd->date;
+}
+
+EOLIAN static void
+_efl_ui_calendar_format_function_set(Eo *obj EINA_UNUSED, Efl_Ui_Calendar_Data *sd, Efl_Ui_Calendar_Format_Cb format_function)
+{
+   sd->format_func = format_function;
+}
+
+EOLIAN static void
+_efl_ui_calendar_first_day_of_week_set(Eo *obj, Efl_Ui_Calendar_Data *sd, Efl_Ui_Calendar_Weekday day)
+{
+   if (day >= EFL_UI_CALENDAR_WEEKDAY_LAST) return;
+   if (sd->first_week_day != day)
+     {
+        sd->first_week_day = day;
+        evas_object_smart_changed(obj);
+     }
+}
+
+EOLIAN static Efl_Ui_Calendar_Weekday
+_efl_ui_calendar_first_day_of_week_get(Eo *obj EINA_UNUSED, Efl_Ui_Calendar_Data *sd)
+{
+   return sd->first_week_day;
+}
+
+static void
+_efl_ui_calendar_class_constructor(Efl_Class *klass)
+{
+   evas_smart_legacy_type_register(MY_CLASS_NAME, klass);
+
+   if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
+      _efl_ui_calendar_smart_focus_next_enable = EINA_TRUE;
+}
+
+EOLIAN static const Elm_Atspi_Action*
+_efl_ui_calendar_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNUSED, Efl_Ui_Calendar_Data *sd EINA_UNUSED)
+{
+   static Elm_Atspi_Action atspi_actions[] = {
+          { "activate", "activate", NULL, _key_action_activate},
+          { NULL, NULL, NULL, NULL }
+   };
+   return &atspi_actions[0];
+}
+
+/* Standard widget overrides */
+
+ELM_WIDGET_KEY_DOWN_DEFAULT_IMPLEMENT(efl_ui_calendar, Efl_Ui_Calendar_Data)
+
+/* Internal EO APIs and hidden overrides */
+
+#define EFL_UI_CALENDAR_EXTRA_OPS \
+   ELM_LAYOUT_SIZING_EVAL_OPS(efl_ui_calendar)
+
+#include "efl_ui_calendar.eo.c"
diff --git a/src/lib/elementary/efl_ui_calendar.eo b/src/lib/elementary/efl_ui_calendar.eo
new file mode 100644 (file)
index 0000000..6615fa9
--- /dev/null
@@ -0,0 +1,149 @@
+import efl_types;
+
+type Efl_Ui_Calendar_Format_Cb: __undefined_type; [[Elementary calendar format callback type]]
+
+enum Efl.Ui.Calendar.Weekday
+{
+   [[A weekday
+
+   See also @Efl.Ui.Calendar.first_day_of_week.set.
+   ]]
+   sunday, [[Sunday weekday]]
+   monday, [[Monday weekday]]
+   tuesday, [[Tusday weekday]]
+   wednesday, [[Wednesday weekday]]
+   thursday, [[Thursday weekday]]
+   friday, [[Friday weekday]]
+   saturday, [[Saturday weekday]]
+   last  [[Sentinel value to indicate last enum field during iteration]]
+}
+
+class Efl.Ui.Calendar (Efl.Ui.Layout, Efl.Ui.Focus.Composition, Elm.Interface.Atspi_Widget_Action)
+{
+   [[Calendar widget
+
+   It helps applications to flexibly display a calendar with day of the week,
+   date, year and month. Applications are able to set specific dates to be
+   reported back, when selected, in the smart callbacks of the calendar widget.
+   ]]
+   methods {
+      @property first_day_of_week {
+         [[The first day of week to use on calendar widgets'.]]
+         set {
+         }
+         get {
+         }
+         values {
+            day: Efl.Ui.Calendar.Weekday(Efl.Ui.Calendar.Weekday.sunday); [[Weekday enum value, see @Elm.Calendar.Weekday]]
+         }
+      }
+      @property format_function {
+         set {
+            [[Set a function to format the string that will be used to display
+              month and year;
+
+              By default it uses strftime with "%B %Y" format string.
+              It should allocate the memory that will be used by the string,
+              that will be freed by the widget after usage.
+              A pointer to the string and a pointer to the time struct will be provided.
+            ]]
+              /* FIXME-doc
+               * Example:
+               * @code
+               * static char
+               * _format_month_year(struct tm *selected_time)
+               * {
+               * char buf[32];
+               * if (!strftime(buf, sizeof(buf), "%B %Y", selected_time)) return NULL;
+               *   return strdup(buf);
+               * }
+               *
+               * efl_ui_calendar_format_function_set(calendar, _format_month_year);
+               * @endcode
+               */
+         }
+         values {
+            format_function: Efl_Ui_Calendar_Format_Cb; [[Function to set the month-year string given
+            the selected date.]]
+         }
+      }
+      @property date_min {
+         [[Minimum date on calendar.]]
+         set {
+            [[Set the minimum date on calendar.
+
+              Set the minimum date, changing the displayed month or year if needed.
+              Displayed day also to be disabled if it is smaller than minimum date.
+              If the minimum date is greater than current maximum date, the minimum
+              date would be changed to the maximum date with returning $false.
+            ]]
+            return: bool; [[$true, on success, $false otherwise]]
+         }
+         get {
+            [[Get the minimum date.
+
+              Default value is 1 JAN,1902.
+            ]]
+         }
+         values {
+            min: Efl.Time; [[Time structure containing the minmum date.]]
+         }
+      }
+      @property date_max {
+         [[Maximum date on calendar.]]
+         set {
+            [[Set the maximum date on calendar.
+
+              Set the maximum date, changing the displayed month or year if needed.
+              Displayed day also to be disabled if it is bigger than maximum date.
+              If the maximum date is less than current minimum date, the maximum date
+              would be changed to the minimum date with returning $false.
+            ]]
+            return: bool; [[$true, on success, $false otherwise]]
+         }
+         get {
+            [[Get the maximum date.
+
+              Default maximum year is -1.
+              Default maximum day and month are 31 and DEC.
+
+              If the maximum year is a negative value, it will be limited depending
+              on the platform architecture (year 2037 for 32 bits);
+            ]]
+         }
+         values {
+            max: Efl.Time; [[Time structure containing the maximum date.]]
+         }
+      }
+      @property date {
+         [[The selected date on calendar.]]
+         set {
+            [[Set the selected date. If the date is greater than the maximum date,
+              the date would be changed to the maximum date with returning $false.
+              In the opposite case with the minimum date,
+                         this would give the same result.
+            ]]
+             return: bool; [[$true, on success, $false otherwise]]
+         }
+         get {
+         }
+         values {
+            date: Efl.Time; [[Time structure containing the selected date.]]
+         }
+      }
+   }
+   implements {
+      class.constructor;
+      Efl.Object.constructor;
+      Efl.Object.destructor;
+      Efl.Canvas.Group.group_calculate;
+      Elm.Widget.theme_apply;
+      Elm.Widget.on_access_update;
+      Elm.Widget.on_focus_update;
+      Elm.Widget.widget_event;
+      Elm.Interface.Atspi_Widget_Action.elm_actions { get; }
+   }
+   events {
+      changed; [[Emitted when the selected date in the calendar is changed]]
+   }
+}
diff --git a/src/lib/elementary/efl_ui_calendar.h b/src/lib/elementary/efl_ui_calendar.h
new file mode 100644 (file)
index 0000000..9c71188
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * @defgroup Elm_Calendar Calendar
+ * @ingroup Elementary
+ *
+ * @image html calendar_inheritance_tree.png
+ * @image latex calendar_inheritance_tree.eps
+ *
+ * This is a calendar widget. It helps applications to flexibly
+ * display a calendar with day of the week, date, year and
+ * month. Applications are able to set specific dates to be reported
+ * back, when selected, in the smart callbacks of the calendar
+ * widget. The API of this widget lets the applications perform other
+ * functions, like:
+ *
+ * - placing marks on specific dates
+ * - setting the bounds for the calendar (minimum and maximum years)
+ * - setting the day names of the week (e.g. "Thu" or "Thursday")
+ * - setting the year and month format.
+ *
+ * This widget inherits from the @ref Layout one, so that all the
+ * functions acting on it also work for calendar objects.
+ *
+ * This widget emits the following signals, besides the ones sent from
+ * @ref Layout:
+ * - @c "changed" - emitted when the date in the calendar is changed.
+ * - @c "display,changed" - emitted when the current month displayed in the
+ * calendar is changed.
+ * - @c "focused" - When the calendar has received focus. (since 1.8)
+ * - @c "unfocused" - When the calendar has lost focus. (since 1.8)
+ * - @c "language,changed" - the program's language changed (since 1.9)
+ *
+ * Supported elm_object common APIs.
+ * @li @ref elm_object_signal_emit
+ * @li @ref elm_object_signal_callback_add
+ * @li @ref elm_object_signal_callback_del
+ *
+ * Here is some sample code using it:
+ * @li @ref calendar_example_01
+ * @li @ref calendar_example_02
+ * @li @ref calendar_example_03
+ * @li @ref calendar_example_04
+ * @li @ref calendar_example_05
+ * @li @ref calendar_example_06
+ */
+
+/**
+ * @addtogroup Elm_Calendar
+ * @{
+ */
+
+#include "efl_ui_calendar_common.h"
+#ifdef EFL_EO_API_SUPPORT
+#include "efl_ui_calendar.eo.h"
+#endif
+/**
+ * @}
+ */
diff --git a/src/lib/elementary/efl_ui_calendar_common.h b/src/lib/elementary/efl_ui_calendar_common.h
new file mode 100644 (file)
index 0000000..70a95ad
--- /dev/null
@@ -0,0 +1,21 @@
+/**
+ * @addtogroup Elm_Calendar
+ *
+ * @{
+ */
+
+/**
+ * This callback type is used to format the string that will be used
+ * to display month and year.
+ *
+ * @param stime Struct representing time.
+ * @return String representing time that will be set to calendar's text.
+ *
+ * @see elm_calendar_format_function_set()
+ */
+typedef char * (*Efl_Ui_Calendar_Format_Cb)(struct tm *stime);
+
+
+/**
+ * @}
+ */
diff --git a/src/lib/elementary/efl_ui_calendar_private.h b/src/lib/elementary/efl_ui_calendar_private.h
new file mode 100644 (file)
index 0000000..7ae261c
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef EFL_UI_CALENDAR_PRIVATE_H
+#define ELM_WIDGET_CALENDAR_H
+
+#include "Elementary.h"
+
+/* DO NOT USE THIS HEADER UNLESS YOU ARE PREPARED FOR BREAKING OF YOUR
+ * CODE. THIS IS ELEMENTARY'S INTERNAL WIDGET API (for now) AND IS NOT
+ * FINAL. CALL elm_widget_api_check(ELM_INTERNAL_API_VERSION) TO CHECK
+ * IT AT RUNTIME.
+ */
+
+/**
+ * @addtogroup Widget
+ * @{
+ *
+ * @section elm-calendar-class The Elementary Calendar Class
+ *
+ * Elementary, besides having the @ref Calendar widget, exposes its
+ * foundation -- the Elementary Calendar Class -- in order to create other
+ * widgets which are a calendar with some more logic on top.
+ */
+
+/**
+ * Base layout smart data extended with calendar instance data.
+ */
+typedef struct _Efl_Ui_Calendar_Data Efl_Ui_Calendar_Data;
+
+struct _Efl_Ui_Calendar_Data
+{
+   Evas_Object             *obj; // the object itself
+   double                   interval, first_interval;
+   int                      spin_speed;
+   int                      today_it, selected_it, focused_it;
+   Ecore_Timer             *spin_month, *spin_year, *update_timer;
+   Efl_Ui_Calendar_Format_Cb   format_func;
+   const char              *weekdays[ELM_DAY_LAST];
+   struct tm                current_date, shown_date, date, date_min, date_max;
+   Evas_Object             *inc_btn_month;
+   Evas_Object             *dec_btn_month;
+   Evas_Object             *month_access;
+   Evas_Object             *inc_btn_year;
+   Evas_Object             *dec_btn_year;
+   Evas_Object             *year_access;
+   Eo                      *items[42];
+
+   Efl_Ui_Calendar_Weekday     first_week_day;
+
+   unsigned char            first_day_it;
+
+   Eina_Bool                selected : 1;
+   Eina_Bool                double_spinners : 1;
+   Eina_Bool                filling : 1;
+   Eina_Bool                weekdays_set : 1;
+   Eina_Bool                month_repeated : 1;
+   Eina_Bool                year_repeated : 1;
+};
+
+/**
+ * @}
+ */
+
+#define EFL_UI_CALENDAR_DATA_GET(o, sd) \
+  Efl_Ui_Calendar_Data * sd = efl_data_scope_get(o, EFL_UI_CALENDAR_CLASS)
+
+#endif