acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

lv_calendar.c (12553B)

      1 /**
      2  * @file lv_calendar.c
      3  *
      4  */
      5 
      6 /*********************
      7  *      INCLUDES
      8  *********************/
      9 #include "lv_calendar.h"
     10 #include "../../../lvgl.h"
     11 #if LV_USE_CALENDAR
     12 
     13 #include "../../../misc/lv_assert.h"
     14 
     15 /*********************
     16  *      DEFINES
     17  *********************/
     18 #define LV_CALENDAR_CTRL_TODAY      LV_BTNMATRIX_CTRL_CUSTOM_1
     19 #define LV_CALENDAR_CTRL_HIGHLIGHT  LV_BTNMATRIX_CTRL_CUSTOM_2
     20 
     21 #define MY_CLASS &lv_calendar_class
     22 
     23 /**********************
     24  *      TYPEDEFS
     25  **********************/
     26 
     27 /**********************
     28  *  STATIC PROTOTYPES
     29  **********************/
     30 static void lv_calendar_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
     31 static void draw_part_begin_event_cb(lv_event_t * e);
     32 
     33 static uint8_t get_day_of_week(uint32_t year, uint32_t month, uint32_t day);
     34 static uint8_t get_month_length(int32_t year, int32_t month);
     35 static uint8_t is_leap_year(uint32_t year);
     36 static void highlight_update(lv_obj_t * calendar);
     37 
     38 /**********************
     39  *  STATIC VARIABLES
     40  **********************/
     41 const lv_obj_class_t lv_calendar_class = {
     42     .constructor_cb = lv_calendar_constructor,
     43     .width_def = (LV_DPI_DEF * 3) / 2,
     44     .height_def = (LV_DPI_DEF * 3) / 2,
     45     .group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE,
     46     .instance_size = sizeof(lv_calendar_t),
     47     .base_class = &lv_obj_class
     48 };
     49 
     50 static const char * day_names_def[7] = LV_CALENDAR_DEFAULT_DAY_NAMES;
     51 
     52 /**********************
     53  *      MACROS
     54  **********************/
     55 
     56 /**********************
     57  *   GLOBAL FUNCTIONS
     58  **********************/
     59 
     60 lv_obj_t * lv_calendar_create(lv_obj_t * parent)
     61 {
     62     LV_LOG_INFO("begin");
     63     lv_obj_t * obj = lv_obj_class_create_obj(&lv_calendar_class, parent);
     64     lv_obj_class_init_obj(obj);
     65     return obj;
     66 }
     67 
     68 /*=====================
     69  * Setter functions
     70  *====================*/
     71 
     72 void lv_calendar_set_day_names(lv_obj_t * obj, const char * day_names[])
     73 {
     74     LV_ASSERT_OBJ(obj, MY_CLASS);
     75     lv_calendar_t * calendar = (lv_calendar_t *)obj;
     76 
     77     uint32_t i;
     78     for(i = 0; i < 7; i++) {
     79         calendar->map[i] = day_names[i];
     80     }
     81     lv_obj_invalidate(obj);
     82 }
     83 
     84 void lv_calendar_set_today_date(lv_obj_t * obj, uint32_t year, uint32_t month, uint32_t day)
     85 {
     86     LV_ASSERT_OBJ(obj, MY_CLASS);
     87     lv_calendar_t * calendar = (lv_calendar_t *)obj;
     88 
     89     calendar->today.year         = year;
     90     calendar->today.month        = month;
     91     calendar->today.day          = day;
     92 
     93     highlight_update(obj);
     94 }
     95 
     96 void lv_calendar_set_highlighted_dates(lv_obj_t * obj, lv_calendar_date_t highlighted[], uint16_t date_num)
     97 {
     98     LV_ASSERT_NULL(highlighted);
     99 
    100     LV_ASSERT_OBJ(obj, MY_CLASS);
    101     lv_calendar_t * calendar = (lv_calendar_t *)obj;
    102 
    103     calendar->highlighted_dates     = highlighted;
    104     calendar->highlighted_dates_num = date_num;
    105 
    106     highlight_update(obj);
    107 }
    108 
    109 void lv_calendar_set_showed_date(lv_obj_t * obj, uint32_t year, uint32_t month)
    110 {
    111     LV_ASSERT_OBJ(obj, MY_CLASS);
    112     lv_calendar_t * calendar = (lv_calendar_t *)obj;
    113 
    114     calendar->showed_date.year   = year;
    115     calendar->showed_date.month  = month;
    116     calendar->showed_date.day    = 1;
    117 
    118     lv_calendar_date_t d;
    119     d.year = calendar->showed_date.year;
    120     d.month = calendar->showed_date.month;
    121     d.day = calendar->showed_date.day;
    122 
    123     uint32_t i;
    124 
    125     /*Remove the disabled state but revert it for day names*/
    126     lv_btnmatrix_clear_btn_ctrl_all(calendar->btnm, LV_BTNMATRIX_CTRL_DISABLED);
    127     for(i = 0; i < 7; i++) {
    128         lv_btnmatrix_set_btn_ctrl(calendar->btnm, i, LV_BTNMATRIX_CTRL_DISABLED);
    129     }
    130 
    131     uint8_t act_mo_len = get_month_length(d.year, d.month);
    132     uint8_t day_first = get_day_of_week(d.year, d.month, 1);
    133     uint8_t c;
    134     for(i = day_first, c = 1; i < act_mo_len + day_first; i++, c++) {
    135         lv_snprintf(calendar->nums[i], sizeof(calendar->nums[0]), "%d", c);
    136     }
    137 
    138     uint8_t prev_mo_len = get_month_length(d.year, d.month - 1);
    139     for(i = 0, c = prev_mo_len - day_first + 1; i < day_first; i++, c++) {
    140         lv_snprintf(calendar->nums[i], sizeof(calendar->nums[0]), "%d", c);
    141         lv_btnmatrix_set_btn_ctrl(calendar->btnm, i + 7, LV_BTNMATRIX_CTRL_DISABLED);
    142     }
    143 
    144     for(i = day_first + act_mo_len, c = 1; i < 6 * 7; i++, c++) {
    145         lv_snprintf(calendar->nums[i], sizeof(calendar->nums[0]), "%d", c);
    146         lv_btnmatrix_set_btn_ctrl(calendar->btnm, i + 7, LV_BTNMATRIX_CTRL_DISABLED);
    147     }
    148 
    149     highlight_update(obj);
    150 
    151     /*Reset the focused button if the days changes*/
    152     if(lv_btnmatrix_get_selected_btn(calendar->btnm) != LV_BTNMATRIX_BTN_NONE) {
    153         lv_btnmatrix_set_selected_btn(calendar->btnm, day_first + 7);
    154     }
    155 
    156     lv_obj_invalidate(obj);
    157 
    158     /* The children of the calendar are probably headers.
    159      * Notify them to let the headers updated to the new date*/
    160     uint32_t child_cnt = lv_obj_get_child_cnt(obj);
    161     for(i = 0; i < child_cnt; i++) {
    162         lv_obj_t * child = lv_obj_get_child(obj, i);
    163         if(child == calendar->btnm) continue;
    164         lv_event_send(child, LV_EVENT_VALUE_CHANGED, obj);
    165     }
    166 }
    167 
    168 /*=====================
    169  * Getter functions
    170  *====================*/
    171 
    172 lv_obj_t * lv_calendar_get_btnmatrix(const lv_obj_t * obj)
    173 {
    174     LV_ASSERT_OBJ(obj, MY_CLASS);
    175     const lv_calendar_t * calendar = (lv_calendar_t *)obj;
    176     return calendar->btnm;
    177 }
    178 
    179 const lv_calendar_date_t * lv_calendar_get_today_date(const lv_obj_t * obj)
    180 {
    181     LV_ASSERT_OBJ(obj, MY_CLASS);
    182     const lv_calendar_t * calendar = (lv_calendar_t *)obj;
    183 
    184     return &calendar->today;
    185 }
    186 
    187 const lv_calendar_date_t * lv_calendar_get_showed_date(const lv_obj_t * obj)
    188 {
    189     LV_ASSERT_OBJ(obj, MY_CLASS);
    190     const lv_calendar_t * calendar = (lv_calendar_t *)obj;
    191 
    192     return &calendar->showed_date;
    193 }
    194 
    195 lv_calendar_date_t * lv_calendar_get_highlighted_dates(const lv_obj_t * obj)
    196 {
    197     LV_ASSERT_OBJ(obj, MY_CLASS);
    198     lv_calendar_t * calendar = (lv_calendar_t *)obj;
    199 
    200     return calendar->highlighted_dates;
    201 }
    202 
    203 uint16_t lv_calendar_get_highlighted_dates_num(const lv_obj_t * obj)
    204 {
    205     LV_ASSERT_OBJ(obj, MY_CLASS);
    206     lv_calendar_t * calendar = (lv_calendar_t *)obj;
    207 
    208     return calendar->highlighted_dates_num;
    209 }
    210 
    211 lv_res_t lv_calendar_get_pressed_date(const lv_obj_t * obj, lv_calendar_date_t * date)
    212 {
    213     LV_ASSERT_OBJ(obj, MY_CLASS);
    214     lv_calendar_t * calendar = (lv_calendar_t *)obj;
    215 
    216     uint16_t d = lv_btnmatrix_get_selected_btn(calendar->btnm);
    217     if(d == LV_BTNMATRIX_BTN_NONE) {
    218         date->year = 0;
    219         date->month = 0;
    220         date->day = 0;
    221         return LV_RES_INV;
    222     }
    223 
    224     const char * txt = lv_btnmatrix_get_btn_text(calendar->btnm, lv_btnmatrix_get_selected_btn(calendar->btnm));
    225 
    226     if(txt[1] == 0) date->day = txt[0] - '0';
    227     else date->day = (txt[0] - '0') * 10 + (txt[1] - '0');
    228 
    229     date->year = calendar->showed_date.year;
    230     date->month = calendar->showed_date.month;
    231 
    232     return LV_RES_OK;
    233 }
    234 
    235 
    236 /**********************
    237  *  STATIC FUNCTIONS
    238  **********************/
    239 
    240 static void lv_calendar_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
    241 {
    242     LV_UNUSED(class_p);
    243     lv_calendar_t * calendar = (lv_calendar_t *)obj;
    244 
    245     /*Initialize the allocated 'ext'*/
    246     calendar->today.year  = 2020;
    247     calendar->today.month = 1;
    248     calendar->today.day   = 1;
    249 
    250     calendar->showed_date.year  = 2020;
    251     calendar->showed_date.month = 1;
    252     calendar->showed_date.day   = 1;
    253 
    254     calendar->highlighted_dates      = NULL;
    255     calendar->highlighted_dates_num  = 0;
    256 
    257     lv_memset_00(calendar->nums, sizeof(calendar->nums));
    258     uint8_t i;
    259     uint8_t j = 0;
    260     for(i = 0; i < 8 * 7; i++) {
    261         /*Every 8th string is "\n"*/
    262         if(i != 0 && (i + 1) % 8 == 0) {
    263             calendar->map[i] = "\n";
    264         }
    265         else if(i < 7) {
    266             calendar->map[i] = day_names_def[i];
    267         }
    268         else {
    269             calendar->nums[j][0] = 'x';
    270             calendar->map[i] = calendar->nums[j];
    271             j++;
    272         }
    273     }
    274     calendar->map[8 * 7 - 1] = "";
    275 
    276     calendar->btnm = lv_btnmatrix_create(obj);
    277     lv_btnmatrix_set_map(calendar->btnm, calendar->map);
    278     lv_btnmatrix_set_btn_ctrl_all(calendar->btnm, LV_BTNMATRIX_CTRL_CLICK_TRIG | LV_BTNMATRIX_CTRL_NO_REPEAT);
    279     lv_obj_add_event_cb(calendar->btnm, draw_part_begin_event_cb, LV_EVENT_DRAW_PART_BEGIN, NULL);
    280     lv_obj_set_width(calendar->btnm, lv_pct(100));
    281 
    282     lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN);
    283     lv_obj_set_flex_grow(calendar->btnm, 1);
    284 
    285     lv_calendar_set_showed_date(obj, calendar->showed_date.year, calendar->showed_date.month);
    286     lv_calendar_set_today_date(obj, calendar->today.year, calendar->today.month, calendar->today.day);
    287 
    288     lv_obj_add_flag(calendar->btnm, LV_OBJ_FLAG_EVENT_BUBBLE);
    289 }
    290 
    291 static void draw_part_begin_event_cb(lv_event_t * e)
    292 {
    293     lv_obj_t * obj = lv_event_get_target(e);
    294     lv_obj_draw_part_dsc_t * dsc = lv_event_get_param(e);
    295     if(dsc->part == LV_PART_ITEMS) {
    296         /*Day name styles*/
    297         if(dsc->id < 7) {
    298             dsc->rect_dsc->bg_opa = LV_OPA_TRANSP;
    299             dsc->rect_dsc->border_opa = LV_OPA_TRANSP;
    300         }
    301         else if(lv_btnmatrix_has_btn_ctrl(obj, dsc->id, LV_BTNMATRIX_CTRL_DISABLED)) {
    302             dsc->rect_dsc->bg_opa = LV_OPA_TRANSP;
    303             dsc->rect_dsc->border_opa = LV_OPA_TRANSP;
    304             dsc->label_dsc->color = lv_palette_main(LV_PALETTE_GREY);
    305         }
    306 
    307         if(lv_btnmatrix_has_btn_ctrl(obj, dsc->id, LV_CALENDAR_CTRL_HIGHLIGHT)) {
    308             dsc->rect_dsc->bg_opa = LV_OPA_40;
    309             dsc->rect_dsc->bg_color = lv_theme_get_color_primary(obj);
    310             if(lv_btnmatrix_get_selected_btn(obj) == dsc->id) {
    311                 dsc->rect_dsc->bg_opa = LV_OPA_70;
    312             }
    313         }
    314 
    315         if(lv_btnmatrix_has_btn_ctrl(obj, dsc->id, LV_CALENDAR_CTRL_TODAY)) {
    316             dsc->rect_dsc->border_opa = LV_OPA_COVER;
    317             dsc->rect_dsc->border_color = lv_theme_get_color_primary(obj);
    318             dsc->rect_dsc->border_width += 1;
    319         }
    320 
    321     }
    322 }
    323 
    324 /**
    325  * Get the number of days in a month
    326  * @param year a year
    327  * @param month a month. The range is basically [1..12] but [-11..0] or [13..24] is also
    328  *              supported to handle next/prev. year
    329  * @return [28..31]
    330  */
    331 static uint8_t get_month_length(int32_t year, int32_t month)
    332 {
    333     month--;
    334     if(month < 0) {
    335         year--;             /*Already in the previous year (won't be less then -12 to skip a whole year)*/
    336         month = 12 + month; /*`month` is negative, the result will be < 12*/
    337     }
    338     if(month >= 12) {
    339         year++;
    340         month -= 12;
    341     }
    342 
    343     /*month == 1 is february*/
    344     return (month == 1) ? (28 + is_leap_year(year)) : 31 - month % 7 % 2;
    345 }
    346 
    347 /**
    348  * Tells whether a year is leap year or not
    349  * @param year a year
    350  * @return 0: not leap year; 1: leap year
    351  */
    352 static uint8_t is_leap_year(uint32_t year)
    353 {
    354     return (year % 4) || ((year % 100 == 0) && (year % 400)) ? 0 : 1;
    355 }
    356 
    357 /**
    358  * Get the day of the week
    359  * @param year a year
    360  * @param month a  month [1..12]
    361  * @param day a day [1..32]
    362  * @return [0..6] which means [Sun..Sat] or [Mon..Sun] depending on LV_CALENDAR_WEEK_STARTS_MONDAY
    363  */
    364 static uint8_t get_day_of_week(uint32_t year, uint32_t month, uint32_t day)
    365 {
    366     uint32_t a = month < 3 ? 1 : 0;
    367     uint32_t b = year - a;
    368 
    369 #if LV_CALENDAR_WEEK_STARTS_MONDAY
    370     uint32_t day_of_week = (day + (31 * (month - 2 + 12 * a) / 12) + b + (b / 4) - (b / 100) + (b / 400) - 1) % 7;
    371 #else
    372     uint32_t day_of_week = (day + (31 * (month - 2 + 12 * a) / 12) + b + (b / 4) - (b / 100) + (b / 400)) % 7;
    373 #endif
    374 
    375     return day_of_week  ;
    376 }
    377 
    378 static void highlight_update(lv_obj_t * obj)
    379 {
    380     lv_calendar_t * calendar = (lv_calendar_t *)obj;
    381     uint16_t i;
    382 
    383     /*Clear all kind of selection*/
    384     lv_btnmatrix_clear_btn_ctrl_all(calendar->btnm, LV_CALENDAR_CTRL_TODAY | LV_CALENDAR_CTRL_HIGHLIGHT);
    385 
    386     uint8_t day_first = get_day_of_week(calendar->showed_date.year, calendar->showed_date.month, 1);
    387     if(calendar->highlighted_dates) {
    388         for(i = 0; i < calendar->highlighted_dates_num; i++) {
    389             if(calendar->highlighted_dates[i].year == calendar->showed_date.year &&
    390                calendar->highlighted_dates[i].month == calendar->showed_date.month) {
    391                 lv_btnmatrix_set_btn_ctrl(calendar->btnm, calendar->highlighted_dates[i].day - 1 + day_first + 7,
    392                                           LV_CALENDAR_CTRL_HIGHLIGHT);
    393             }
    394         }
    395     }
    396 
    397     if(calendar->showed_date.year == calendar->today.year && calendar->showed_date.month == calendar->today.month) {
    398         lv_btnmatrix_set_btn_ctrl(calendar->btnm, calendar->today.day - 1 + day_first + 7, LV_CALENDAR_CTRL_TODAY);
    399     }
    400 }
    401 
    402 #endif  /*LV_USE_CALENDAR*/