elm_calendar: add APIs for minimum and maximum values for the date 82/109482/1 accepted/tizen/common/20170112.174137 accepted/tizen/ivi/20170111.221558 accepted/tizen/mobile/20170111.221509 accepted/tizen/tv/20170111.221524 accepted/tizen/wearable/20170111.221546 submit/tizen/20170110.235747
authorJEONGHYUN YUN <jh0506.yun@samsung.com>
Tue, 10 Jan 2017 07:22:29 +0000 (16:22 +0900)
committerJEONGHYUN YUN <jh0506.yun@samsung.com>
Tue, 10 Jan 2017 07:23:49 +0000 (16:23 +0900)
elm_calendar already have minimum and maximum year set/get APIs.
I've added new APIs that exapanded from the year to the date.
These APIs help us not only set min/max month but also set min/max day.
If you 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.

Reviewers: woohyun, Hermet, jpeg, CHAN, cedric

Reviewed By: CHAN, cedric

Subscribers: CHAN, cedric, jpeg

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

Change-Id: If93e888eb76e1f84b2601a87b12b8b67f2d4820c
Signed-off-by: JEONGHYUN YUN <jh0506.yun@samsung.com>
src/bin/test_calendar.c
src/lib/elm_calendar.c
src/lib/elm_calendar.eo
src/lib/elm_calendar_legacy.h
src/lib/elm_widget_calendar.h

index 6f3eb56..35e1bf9 100644 (file)
@@ -38,7 +38,6 @@ set_api_state(api_data *api)
            {
               Evas_Object *cal = eina_list_nth(items, 0);
               time_t the_time = (SEC_PER_YEAR * 41) + (SEC_PER_DAY * 9); /* Set date to DEC 31, 2010 */
-              elm_calendar_min_max_year_set(cal, 2010, 2011);
               m = elm_calendar_mark_add(cal, "checked", gmtime(&the_time), ELM_CALENDAR_MONTHLY);
               elm_calendar_selected_time_set(cal, gmtime(&the_time));
            }
@@ -143,7 +142,6 @@ test_calendar(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_
 
    time_t the_time = (SEC_PER_YEAR * 41) + (SEC_PER_DAY * 9); /* Set date to DEC 31, 2010 */
    elm_calendar_selected_time_set(cal, gmtime(&the_time));
-   elm_calendar_min_max_year_set(cal, 2010, 2012);
 
    evas_object_show(cal);
 
@@ -155,25 +153,30 @@ _print_cal_info(Evas_Object *cal, Evas_Object *en)
 {
    char info[1024];
    double interval;
-   int year_min, year_max;
    Eina_Bool sel_enabled;
    const char **wds;
    struct tm stm;
+   const struct tm *mintm, *maxtm;
 
    if (!elm_calendar_selected_time_get(cal, &stm))
      return;
 
    interval = elm_calendar_interval_get(cal);
-   elm_calendar_min_max_year_get(cal, &year_min, &year_max);
+   mintm = elm_calendar_date_min_get(cal);
+   maxtm = elm_calendar_date_max_get(cal);
    sel_enabled = !!(elm_calendar_select_mode_get(cal) != ELM_CALENDAR_SELECT_MODE_NONE);
    wds = elm_calendar_weekdays_names_get(cal);
 
    snprintf(info, sizeof(info),
             "  Day: %i, Mon: %i, Year %i, WeekDay: %i<br/>"
-            "  Interval: %0.2f, Year_Min: %i, Year_Max %i, Sel Enabled : %i<br/>"
+            "  Interval: %0.2f, Sel Enabled : %i<br/>"
+            "  Day_Min : %i, Mon_Min : %i, Year_Min : %i<br/>"
+            "  Day_Max : %i, Mon_Max : %i, Year_Max : %i<br/>"
             "  Weekdays: %s, %s, %s, %s, %s, %s, %s<br/>",
             stm.tm_mday, stm.tm_mon, stm.tm_year + 1900, stm.tm_wday,
-            interval, year_min, year_max, sel_enabled,
+            interval, sel_enabled,
+            mintm->tm_mday, mintm->tm_mon + 1, mintm->tm_year + 1900,
+            maxtm->tm_mday, maxtm->tm_mon + 1, maxtm->tm_year + 1900,
             wds[0], wds[1], wds[2], wds[3], wds[4], wds[5], wds[6]);
 
    elm_object_text_set(en, info);
@@ -231,7 +234,11 @@ _calendar_create(Evas_Object *parent)
    elm_calendar_first_day_of_week_set(cal, ELM_DAY_SATURDAY);
    elm_calendar_interval_set(cal, 0.4);
    elm_calendar_format_function_set(cal, _format_month_year);
-   elm_calendar_min_max_year_set(cal, 2010, 2020);
+
+   time_t the_time = (SEC_PER_YEAR * 40) + (SEC_PER_DAY * 24); /* Set min date to JAN 15, 2010 */
+   elm_calendar_date_min_set(cal, gmtime(&the_time));
+   the_time = (SEC_PER_YEAR * 42) + (SEC_PER_DAY * 3); /* Set max date to DEC 25, 2011 */
+   elm_calendar_date_max_set(cal, gmtime(&the_time));
 
    current_time = time(NULL) + 4 * SEC_PER_DAY;
    localtime_r(&current_time, &selected_time);
@@ -327,7 +334,6 @@ test_calendar2(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event
    elm_calendar_marks_draw(cal3);
    evas_object_show(cal3);
    elm_box_pack_end(bxh, cal3);
-   elm_calendar_min_max_year_set(cal3, -1, -1);
 
    evas_object_show(win);
 }
index 916cfda..994d583 100644 (file)
@@ -446,6 +446,17 @@ _cit_mark(Evas_Object *cal,
           int cit,
           const char *mtype)
 {
+   ELM_CALENDAR_DATA_GET(cal, sd);
+
+   int day = cit - sd->first_day_it + 1;
+   int mon = sd->shown_time.tm_mon;
+   int yr = sd->shown_time.tm_year;
+
+   if (strcmp(mtype, "clear")
+       && (((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))))
+     return;
+
    char sign[64];
 
    snprintf(sign, sizeof(sign), "cit_%i,%s", cit, mtype);
@@ -820,7 +831,12 @@ _populate(Evas_Object *obj)
 
         if ((day) && (day <= maxdays))
           {
-             _enable(sd, i);
+             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), "%i", day++);
           }
         else
@@ -1127,6 +1143,20 @@ _fix_selected_time(Elm_Calendar_Data *sd)
      sd->selected_time.tm_mon = sd->shown_time.tm_mon;
    if (sd->selected_time.tm_year != sd->shown_time.tm_year)
      sd->selected_time.tm_year = sd->shown_time.tm_year;
+
+   if ((sd->selected_time.tm_year == sd->date_min.tm_year)
+       && (sd->selected_time.tm_mon == sd->date_min.tm_mon)
+       && (sd->selected_time.tm_mday < sd->date_min.tm_mday))
+     {
+        sd->selected_time.tm_mday = sd->date_min.tm_mday;
+     }
+   else if ((sd->selected_time.tm_year == sd->date_max.tm_year)
+            && (sd->selected_time.tm_mon == sd->date_max.tm_mon)
+            && (sd->selected_time.tm_mday > sd->date_max.tm_mday))
+     {
+        sd->selected_time.tm_mday = sd->date_max.tm_mday;
+     }
+
    mktime(&sd->selected_time);
 }
 
@@ -1151,35 +1181,55 @@ _update_data(Evas_Object *obj, Eina_Bool month,
    if (month)
      {
         sd->shown_time.tm_mon += delta;
-        if (sd->shown_time.tm_mon < 0)
+        if (delta < 0)
           {
-             if (sd->shown_time.tm_year == sd->year_min)
+             if (sd->shown_time.tm_year == sd->date_min.tm_year)
+               {
+                  if (sd->shown_time.tm_mon < sd->date_min.tm_mon)
+                    {
+                       sd->shown_time.tm_mon = sd->date_min.tm_mon;
+                       return EINA_FALSE;
+                    }
+               }
+             else if (sd->shown_time.tm_mon < 0)
                {
-                  sd->shown_time.tm_mon++;
-                  return EINA_FALSE;
+                  sd->shown_time.tm_mon = 11;
+                  sd->shown_time.tm_year--;
                }
-             sd->shown_time.tm_mon = 11;
-             sd->shown_time.tm_year--;
           }
-        else if (sd->shown_time.tm_mon > 11)
+        else
           {
-             if (sd->shown_time.tm_year == sd->year_max)
+             if (sd->shown_time.tm_year == sd->date_max.tm_year)
                {
-                  sd->shown_time.tm_mon--;
-                  return EINA_FALSE;
+                  if (sd->shown_time.tm_mon > sd->date_max.tm_mon)
+                    {
+                       sd->shown_time.tm_mon = sd->date_max.tm_mon;
+                       return EINA_FALSE;
+                    }
+               }
+             else if (sd->shown_time.tm_mon > 11)
+               {
+                  sd->shown_time.tm_mon = 0;
+                  sd->shown_time.tm_year++;
                }
-             sd->shown_time.tm_mon = 0;
-             sd->shown_time.tm_year++;
           }
      }
    else
      {
         years = sd->shown_time.tm_year + delta;
-        if (((years > sd->year_max) && (sd->year_max != -1)) ||
-            years < sd->year_min)
+        if (((years > sd->date_max.tm_year) && (sd->date_max.tm_year != -1)) ||
+            years < sd->date_min.tm_year)
           return EINA_FALSE;
 
         sd->shown_time.tm_year = years;
+        if ((years == sd->date_min.tm_year) && (sd->shown_time.tm_mon < sd->date_min.tm_mon))
+          {
+             sd->shown_time.tm_mon = sd->date_min.tm_mon;
+          }
+        else if ((years == sd->date_max.tm_year) && (sd->shown_time.tm_mon > sd->date_max.tm_mon))
+          {
+             sd->shown_time.tm_mon = sd->date_max.tm_mon;
+          }
      }
 
    if ((sd->select_mode != ELM_CALENDAR_SELECT_MODE_ONDEMAND)
@@ -1451,6 +1501,19 @@ _get_item_day(Evas_Object *obj,
    if ((day < 0) || (day > _maxdays_get(&sd->shown_time, 0)))
      return 0;
 
+   if ((sd->shown_time.tm_year == sd->date_min.tm_year)
+       && (sd->shown_time.tm_mon == sd->date_min.tm_mon)
+       && (day < sd->date_min.tm_mday))
+     {
+        return 0;
+     }
+   else if ((sd->shown_time.tm_year == sd->date_max.tm_year)
+            && (sd->shown_time.tm_mon == sd->date_max.tm_mon)
+            && (day > sd->date_max.tm_mday))
+     {
+        return 0;
+     }
+
    return day;
 }
 
@@ -1947,8 +2010,12 @@ _elm_calendar_evas_object_smart_add(Eo *obj, Elm_Calendar_Data *priv)
    elm_widget_sub_object_parent_add(obj);
 
    priv->first_interval = 0.85;
-   priv->year_min = 2;
-   priv->year_max = -1;
+   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;
@@ -2242,29 +2309,157 @@ _elm_calendar_interval_get(Eo *obj EINA_UNUSED, Elm_Calendar_Data *sd)
    return sd->first_interval;
 }
 
-EOLIAN static void
-_elm_calendar_min_max_year_set(Eo *obj, Elm_Calendar_Data *sd, int min, int max)
+EAPI void
+elm_calendar_min_max_year_set(Evas_Object *obj, int min, int max)
 {
+   ELM_CALENDAR_DATA_GET(obj, sd);
+
    min -= 1900;
    max -= 1900;
-   if ((sd->year_min == min) && (sd->year_max == max)) return;
-   sd->year_min = min > 2 ? min : 2;
-   if (max > sd->year_min)
-     sd->year_max = max;
+   if ((sd->date_min.tm_year == min) && (sd->date_max.tm_year == max)) return;
+   sd->date_min.tm_year = min > 2 ? min : 2;
+   if (max > sd->date_min.tm_year)
+     sd->date_max.tm_year = max;
    else
-     sd->year_max = sd->year_min;
-   if (sd->shown_time.tm_year > sd->year_max)
-     sd->shown_time.tm_year = sd->year_max;
-   if (sd->shown_time.tm_year < sd->year_min)
-     sd->shown_time.tm_year = sd->year_min;
+     sd->date_max.tm_year = sd->date_min.tm_year;
+   sd->date_min.tm_mon = 0;
+   sd->date_min.tm_mday = 1;
+   sd->date_max.tm_mon = 11;
+   sd->date_max.tm_mday = 31;
+
+   if (sd->shown_time.tm_year > sd->date_max.tm_year)
+     sd->shown_time.tm_year = sd->date_max.tm_year;
+   if (sd->shown_time.tm_year < sd->date_min.tm_year)
+     sd->shown_time.tm_year = sd->date_min.tm_year;
+
    evas_object_smart_changed(obj);
 }
 
+EAPI void
+elm_calendar_min_max_year_get(const Evas_Object *obj, int *min, int *max)
+{
+   ELM_CALENDAR_DATA_GET(obj, sd);
+
+   if (min) *min = sd->date_min.tm_year + 1900;
+   if (max) *max = sd->date_max.tm_year + 1900;
+}
+
 EOLIAN static void
-_elm_calendar_min_max_year_get(Eo *obj EINA_UNUSED, Elm_Calendar_Data *sd, int *min, int *max)
+_elm_calendar_date_min_set(Eo *obj, Elm_Calendar_Data *sd, const struct tm *min)
+{
+   Eina_Bool upper = 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;
+
+   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;
+          }
+     }
+
+   if (sd->shown_time.tm_year <= sd->date_min.tm_year)
+     {
+        sd->shown_time.tm_year = sd->date_min.tm_year;
+        if (sd->shown_time.tm_mon < sd->date_min.tm_mon)
+          sd->shown_time.tm_mon = sd->date_min.tm_mon;
+     }
+
+   _fix_selected_time(sd);
+
+   evas_object_smart_changed(obj);
+}
+
+EOLIAN static const struct tm *
+_elm_calendar_date_min_get(Eo *obj EINA_UNUSED, Elm_Calendar_Data *sd)
+{
+   return &(sd->date_min);
+}
+
+EOLIAN static void
+_elm_calendar_date_max_set(Eo *obj, Elm_Calendar_Data *sd, const struct tm *max)
+{
+   Eina_Bool lower = 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;
+
+   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;
+     }
+
+   if (sd->shown_time.tm_year >= sd->date_max.tm_year)
+     {
+        sd->shown_time.tm_year = sd->date_max.tm_year;
+        if (sd->shown_time.tm_mon > sd->date_max.tm_mon)
+          sd->shown_time.tm_mon = sd->date_max.tm_mon;
+     }
+
+   _fix_selected_time(sd);
+
+   evas_object_smart_changed(obj);
+}
+
+EOLIAN static const struct tm *
+_elm_calendar_date_max_get(Eo *obj EINA_UNUSED, Elm_Calendar_Data *sd)
 {
-   if (min) *min = sd->year_min + 1900;
-   if (max) *max = sd->year_max + 1900;
+   return &(sd->date_max);
 }
 
 EINA_DEPRECATED EAPI void
index 871a1eb..6ec3323 100644 (file)
@@ -263,47 +263,6 @@ class Elm.Calendar (Elm.Layout, Elm_Interface_Atspi_Widget_Action)
             mode: Elm.Calendar.Select.Mode; [[The select mode to use.]]
          }
       }
-      @property min_max_year {
-         set {
-            [[\@MOBILE_ONLY
-
-              Set the minimum and maximum values for the year
-
-              Maximum must be greater than minimum, except if you don't want to set
-              maximum year.
-              Default values are 1902 and -1.
-
-              If the maximum year is a negative value, it will be limited depending
-              on the platform architecture (year 2037 for 32 bits);
-
-              See also @.min_max_year.get.
-
-              \@ref calendar_example_03.
-
-              \@if MOBILE \@since_tizen 2.4
-              \@endif
-            ]]
-         }
-         get {
-            [[\@MOBILE_ONLY
-
-              Get the minimum and maximum values for the year
-
-              Default values are 1902 and -1.
-
-              See also @.min_max_year.set for more details.
-
-              \@ref calendar_example_05.
-
-               \@if MOBILE \@since_tizen 2.4
-               \@endif
-             ]]
-         }
-         values {
-            min: int; [[The minimum year, greater than 1901;]]
-            max: int; [[The maximum year;]]
-         }
-      }
       @property format_function {
          set {
             [[\@MOBILE_ONLY
@@ -341,6 +300,58 @@ class Elm.Calendar (Elm.Layout, Elm_Interface_Atspi_Widget_Action)
             the selected date.]]
          }
       }
+      @property date_min {
+         [[Minimum date on calendar.
+
+           See also @.date_max.set, @.date_max.get
+
+           @since 1.19
+         ]]
+         set {
+            [[Set 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.
+            ]]
+         }
+         get {
+            [[Get minimum date.
+
+              Default value is 1 JAN,1902.
+            ]]
+         }
+         values {
+            min: const(Elm_Calendar_Time)*; [[A tm struct to point to minimum date.]]
+         }
+      }
+      @property date_max {
+         [[Maximum date on calendar.
+
+           See also @.date_min.set, @.date_min.get
+
+           @since 1.19
+         ]]
+         set {
+            [[Set 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.
+            ]]
+         }
+         get {
+            [[Get 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: const(Elm_Calendar_Time)*; [[A tm struct to point to maximum date.]]
+         }
+      }
       @property marks {
          get {
             [[\@MOBILE_ONLY
index 4cdc9f4..942de08 100644 (file)
@@ -1,3 +1,5 @@
+#include "elm_calendar.eo.legacy.h"
+
 /**
  * @MOBILE_ONLY
  *
  */
 EAPI Evas_Object         *elm_calendar_add(Evas_Object *parent);
 
-#include "elm_calendar.eo.legacy.h"
\ No newline at end of file
+/**
+ * Set the minimum and maximum values for the year.
+ *
+ * @param min The minimum year, greater than 1901.
+ * @param max The maximum year.
+ *
+ * Maximum must be greater than minimum, except if you don't want to set maximum year.
+ * Default values are 1902 and -1.
+ * If the maximum year is a negative value, it will be limited depending on the platform architecture. (year 2037 for 32 bits)
+ *
+ * @see elm_calendar_min_max_year_get()
+ *
+ * @ref calendar_example_03
+ */
+EAPI void                 elm_calendar_min_max_year_set(Evas_Object *obj, int min, int max);
+
+/**
+ * Get the minimum and maximum values for the year.
+ *
+ * @param[out] min The minimum year, greater than 1901.
+ * @param[out] max The maximum year.
+ *
+ * Default values are 1902 and -1.
+ *
+ * @see elm_calendar_min_max_year_set()
+ *
+ * @ref calendar_example_05
+ */
+EAPI void                 elm_calendar_min_max_year_get(const Evas_Object *obj, int *min, int *max);
index 36ec378..45a3d1e 100644 (file)
@@ -38,7 +38,7 @@ struct _Elm_Calendar_Data
    Evas_Object             *obj; // the object itself
    Eina_List               *marks;
    double                   interval, first_interval;
-   int                      year_min, year_max, spin_speed;
+   int                      spin_speed;
    //TIZEN_ONLY(20161123): Support Focused UI.
    int                     focused_it;
    //
@@ -46,7 +46,7 @@ struct _Elm_Calendar_Data
    Ecore_Timer             *spin_month, *spin_year, *update_timer;
    Elm_Calendar_Format_Cb   format_func;
    const char              *weekdays[ELM_DAY_LAST];
-   struct tm                current_time, selected_time, shown_time;
+   struct tm                current_time, selected_time, shown_time, date_min, date_max;
    Day_Color                day_color[42]; // EINA_DEPRECATED
    Evas_Object             *inc_btn_month;
    Evas_Object             *dec_btn_month;