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_tabview.c (10041B)

      1 /**
      2  * @file lv_tabview.c
      3  *
      4  */
      5 
      6 /*********************
      7  *      INCLUDES
      8  *********************/
      9 #include "lv_tabview.h"
     10 #if LV_USE_TABVIEW
     11 
     12 #include "../../../misc/lv_assert.h"
     13 
     14 /*********************
     15  *      DEFINES
     16  *********************/
     17 #define MY_CLASS    &lv_tabview_class
     18 
     19 /**********************
     20  *      TYPEDEFS
     21  **********************/
     22 
     23 /**********************
     24  *  STATIC PROTOTYPES
     25  **********************/
     26 static void lv_tabview_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
     27 static void lv_tabview_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
     28 static void lv_tabview_event(const lv_obj_class_t * class_p, lv_event_t * e);
     29 static void btns_value_changed_event_cb(lv_event_t * e);
     30 static void cont_scroll_end_event_cb(lv_event_t * e);
     31 
     32 /**********************
     33  *  STATIC VARIABLES
     34  **********************/
     35 const lv_obj_class_t lv_tabview_class = {
     36     .constructor_cb = lv_tabview_constructor,
     37     .destructor_cb = lv_tabview_destructor,
     38     .event_cb = lv_tabview_event,
     39     .width_def = LV_PCT(100),
     40     .height_def = LV_PCT(100),
     41     .base_class = &lv_obj_class,
     42     .instance_size = sizeof(lv_tabview_t)
     43 };
     44 
     45 static lv_dir_t tabpos_create;
     46 static lv_coord_t tabsize_create;
     47 
     48 /**********************
     49  *      MACROS
     50  **********************/
     51 
     52 /**********************
     53  *   GLOBAL FUNCTIONS
     54  **********************/
     55 
     56 lv_obj_t * lv_tabview_create(lv_obj_t * parent, lv_dir_t tab_pos, lv_coord_t tab_size)
     57 {
     58     LV_LOG_INFO("begin");
     59     tabpos_create = tab_pos;
     60     tabsize_create = tab_size;
     61 
     62     lv_obj_t * obj = lv_obj_class_create_obj(&lv_tabview_class, parent);
     63     lv_obj_class_init_obj(obj);
     64     return obj;
     65 }
     66 
     67 lv_obj_t * lv_tabview_add_tab(lv_obj_t * obj, const char * name)
     68 {
     69     LV_ASSERT_OBJ(obj, MY_CLASS);
     70     lv_tabview_t * tabview = (lv_tabview_t *)obj;
     71     lv_obj_t * cont = lv_tabview_get_content(obj);
     72 
     73     lv_obj_t * page = lv_obj_create(cont);
     74     lv_obj_set_size(page, LV_PCT(100), LV_PCT(100));
     75     lv_obj_clear_flag(page, LV_OBJ_FLAG_CLICK_FOCUSABLE);
     76     uint32_t tab_id = lv_obj_get_child_cnt(cont);
     77 
     78     lv_obj_t * btns = lv_tabview_get_tab_btns(obj);
     79 
     80     char ** old_map = tabview->map;
     81     char ** new_map;
     82 
     83     /*top or bottom dir*/
     84     if(tabview->tab_pos & LV_DIR_VER) {
     85         new_map = lv_mem_alloc((tab_id + 1) * sizeof(const char *));
     86         lv_memcpy_small(new_map, old_map, sizeof(const char *) * (tab_id - 1));
     87         new_map[tab_id - 1] = lv_mem_alloc(strlen(name) + 1);
     88         strcpy((char *)new_map[tab_id - 1], name);
     89         new_map[tab_id] = "";
     90     }
     91     /*left or right dir*/
     92     else {
     93         new_map = lv_mem_alloc((tab_id * 2) * sizeof(const char *));
     94         lv_memcpy_small(new_map, old_map, sizeof(const char *) * (tab_id - 1) * 2);
     95         if(tabview->tab_cnt == 0) {
     96             new_map[0] = lv_mem_alloc(strlen(name) + 1);
     97             strcpy((char *)new_map[0], name);
     98             new_map[1] = "";
     99         }
    100         else {
    101             new_map[tab_id * 2 - 3] = "\n";
    102             new_map[tab_id * 2 - 2] = lv_mem_alloc(strlen(name) + 1);
    103             new_map[tab_id * 2 - 1] = "";
    104             strcpy((char *)new_map[(tab_id * 2) - 2], name);
    105         }
    106     }
    107     tabview->map = new_map;
    108     lv_btnmatrix_set_map(btns, (const char **)new_map);
    109     lv_mem_free(old_map);
    110 
    111     lv_btnmatrix_set_btn_ctrl_all(btns, LV_BTNMATRIX_CTRL_CHECKABLE | LV_BTNMATRIX_CTRL_CLICK_TRIG |
    112                                   LV_BTNMATRIX_CTRL_NO_REPEAT);
    113 
    114     tabview->tab_cnt++;
    115     if(tabview->tab_cnt == 1) {
    116         lv_tabview_set_act(obj, 0, LV_ANIM_OFF);
    117     }
    118 
    119     lv_btnmatrix_set_btn_ctrl(btns, tabview->tab_cur, LV_BTNMATRIX_CTRL_CHECKED);
    120 
    121     return page;
    122 }
    123 
    124 void lv_tabview_set_act(lv_obj_t * obj, uint32_t id, lv_anim_enable_t anim_en)
    125 {
    126     LV_ASSERT_OBJ(obj, MY_CLASS);
    127     lv_tabview_t * tabview = (lv_tabview_t *)obj;
    128 
    129     if(id >= tabview->tab_cnt) {
    130         id = tabview->tab_cnt - 1;
    131     }
    132 
    133     /*To be sure lv_obj_get_content_width will return valid value*/
    134     lv_obj_update_layout(obj);
    135 
    136     lv_obj_t * cont = lv_tabview_get_content(obj);
    137     if(cont == NULL) return;
    138 
    139     if((tabview->tab_pos & LV_DIR_VER) != 0) {
    140         lv_coord_t gap = lv_obj_get_style_pad_column(cont, LV_PART_MAIN);
    141         lv_coord_t w = lv_obj_get_content_width(cont);
    142         if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) != LV_BASE_DIR_RTL) {
    143             lv_obj_scroll_to_x(cont, id * (gap + w), anim_en);
    144         }
    145         else {
    146             int32_t id_rtl = -(int32_t)id;
    147             lv_obj_scroll_to_x(cont, (gap + w) * id_rtl, anim_en);
    148         }
    149     }
    150     else {
    151         lv_coord_t gap = lv_obj_get_style_pad_row(cont, LV_PART_MAIN);
    152         lv_coord_t h = lv_obj_get_content_height(cont);
    153         lv_obj_scroll_to_y(cont, id * (gap + h), anim_en);
    154     }
    155 
    156     lv_obj_t * btns = lv_tabview_get_tab_btns(obj);
    157     lv_btnmatrix_set_btn_ctrl(btns, id, LV_BTNMATRIX_CTRL_CHECKED);
    158     tabview->tab_cur = id;
    159 }
    160 
    161 uint16_t lv_tabview_get_tab_act(lv_obj_t * obj)
    162 {
    163     LV_ASSERT_OBJ(obj, MY_CLASS);
    164     lv_tabview_t * tabview = (lv_tabview_t *)obj;
    165     return tabview->tab_cur;
    166 }
    167 
    168 lv_obj_t * lv_tabview_get_content(lv_obj_t * tv)
    169 {
    170     return lv_obj_get_child(tv, 1);
    171 }
    172 
    173 lv_obj_t * lv_tabview_get_tab_btns(lv_obj_t * tv)
    174 {
    175     return lv_obj_get_child(tv, 0);
    176 }
    177 
    178 /**********************
    179  *   STATIC FUNCTIONS
    180  **********************/
    181 
    182 static void lv_tabview_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
    183 {
    184     LV_UNUSED(class_p);
    185     lv_tabview_t * tabview = (lv_tabview_t *)obj;
    186 
    187     tabview->tab_pos = tabpos_create;
    188 
    189     switch(tabview->tab_pos) {
    190         case LV_DIR_TOP:
    191             lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN);
    192             break;
    193         case LV_DIR_BOTTOM:
    194             lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN_REVERSE);
    195             break;
    196         case LV_DIR_LEFT:
    197             lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW);
    198             break;
    199         case LV_DIR_RIGHT:
    200             lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW_REVERSE);
    201             break;
    202     }
    203 
    204     lv_obj_set_size(obj, LV_PCT(100), LV_PCT(100));
    205 
    206     lv_obj_t * btnm;
    207     lv_obj_t * cont;
    208 
    209     btnm = lv_btnmatrix_create(obj);
    210     cont = lv_obj_create(obj);
    211 
    212     lv_btnmatrix_set_one_checked(btnm, true);
    213     tabview->map = lv_mem_alloc(sizeof(const char *));
    214     tabview->map[0] = "";
    215     lv_btnmatrix_set_map(btnm, (const char **)tabview->map);
    216     lv_obj_add_event_cb(btnm, btns_value_changed_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
    217     lv_obj_add_flag(btnm, LV_OBJ_FLAG_EVENT_BUBBLE);
    218 
    219     lv_obj_add_event_cb(cont, cont_scroll_end_event_cb, LV_EVENT_ALL, NULL);
    220     lv_obj_set_scrollbar_mode(cont, LV_SCROLLBAR_MODE_OFF);
    221 
    222     switch(tabview->tab_pos) {
    223         case LV_DIR_TOP:
    224         case LV_DIR_BOTTOM:
    225             lv_obj_set_size(btnm, LV_PCT(100), tabsize_create);
    226             lv_obj_set_width(cont, LV_PCT(100));
    227             lv_obj_set_flex_grow(cont, 1);
    228             break;
    229         case LV_DIR_LEFT:
    230         case LV_DIR_RIGHT:
    231             lv_obj_set_size(btnm, tabsize_create, LV_PCT(100));
    232             lv_obj_set_height(cont, LV_PCT(100));
    233             lv_obj_set_flex_grow(cont, 1);
    234             break;
    235     }
    236 
    237     lv_group_t * g = lv_group_get_default();
    238     if(g) lv_group_add_obj(g, btnm);
    239 
    240     if((tabview->tab_pos & LV_DIR_VER) != 0) {
    241         lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW);
    242         lv_obj_set_scroll_snap_x(cont, LV_SCROLL_SNAP_CENTER);
    243     }
    244     else {
    245         lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN);
    246         lv_obj_set_scroll_snap_y(cont, LV_SCROLL_SNAP_CENTER);
    247     }
    248     lv_obj_add_flag(cont, LV_OBJ_FLAG_SCROLL_ONE);
    249     lv_obj_clear_flag(cont, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
    250 }
    251 
    252 static void lv_tabview_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
    253 {
    254     LV_UNUSED(class_p);
    255     lv_tabview_t * tabview = (lv_tabview_t *)obj;
    256 
    257     uint32_t i;
    258     if(tabview->tab_pos & LV_DIR_VER) {
    259         for(i = 0; i < tabview->tab_cnt; i++) {
    260             lv_mem_free(tabview->map[i]);
    261             tabview->map[i] = NULL;
    262         }
    263     }
    264     if(tabview->tab_pos & LV_DIR_HOR) {
    265         for(i = 0; i < tabview->tab_cnt; i++) {
    266             lv_mem_free(tabview->map[i * 2]);
    267             tabview->map[i * 2] = NULL;
    268         }
    269     }
    270 
    271 
    272     lv_mem_free(tabview->map);
    273     tabview->map = NULL;
    274 }
    275 
    276 static void lv_tabview_event(const lv_obj_class_t * class_p, lv_event_t * e)
    277 {
    278     LV_UNUSED(class_p);
    279     lv_res_t res = lv_obj_event_base(&lv_tabview_class, e);
    280     if(res != LV_RES_OK) return;
    281 
    282     lv_event_code_t code = lv_event_get_code(e);
    283     lv_obj_t * target = lv_event_get_target(e);
    284 
    285     if(code == LV_EVENT_SIZE_CHANGED) {
    286         lv_tabview_set_act(target, lv_tabview_get_tab_act(target), LV_ANIM_OFF);
    287     }
    288 }
    289 
    290 
    291 static void btns_value_changed_event_cb(lv_event_t * e)
    292 {
    293     lv_obj_t * btns = lv_event_get_target(e);
    294 
    295     lv_obj_t * tv = lv_obj_get_parent(btns);
    296     uint32_t id = lv_btnmatrix_get_selected_btn(btns);
    297     lv_tabview_set_act(tv, id, LV_ANIM_ON);
    298 }
    299 
    300 static void cont_scroll_end_event_cb(lv_event_t * e)
    301 {
    302     lv_obj_t * cont = lv_event_get_target(e);
    303     lv_event_code_t code = lv_event_get_code(e);
    304 
    305     lv_obj_t * tv = lv_obj_get_parent(cont);
    306     lv_tabview_t * tv_obj = (lv_tabview_t *)tv;
    307     if(code == LV_EVENT_LAYOUT_CHANGED) {
    308         lv_tabview_set_act(tv, lv_tabview_get_tab_act(tv), LV_ANIM_OFF);
    309     }
    310     else if(code == LV_EVENT_SCROLL_END) {
    311         lv_point_t p;
    312         lv_obj_get_scroll_end(cont, &p);
    313 
    314         lv_coord_t t;
    315         if((tv_obj->tab_pos & LV_DIR_VER) != 0) {
    316             lv_coord_t w = lv_obj_get_content_width(cont);
    317             if(lv_obj_get_style_base_dir(tv, LV_PART_MAIN) == LV_BASE_DIR_RTL)  t = -(p.x - w / 2) / w;
    318             else t = (p.x + w / 2) / w;
    319         }
    320         else {
    321             lv_coord_t h = lv_obj_get_content_height(cont);
    322             t = (p.y + h / 2) / h;
    323         }
    324 
    325         if(t < 0) t = 0;
    326         bool new_tab = false;
    327         if(t != lv_tabview_get_tab_act(tv)) new_tab = true;
    328         lv_tabview_set_act(tv, t, LV_ANIM_ON);
    329 
    330         if(new_tab) lv_event_send(tv, LV_EVENT_VALUE_CHANGED, NULL);
    331     }
    332 }
    333 #endif /*LV_USE_TABVIEW*/