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*/