diff --git a/applications/services/gui/modules/submenu.c b/applications/services/gui/modules/submenu.c index 648e213c0..0668db531 100644 --- a/applications/services/gui/modules/submenu.c +++ b/applications/services/gui/modules/submenu.c @@ -7,6 +7,7 @@ struct Submenu { View* view; + FuriTimer* locked_timer; }; @@ -19,6 +20,7 @@ typedef struct { }; void* callback_context; bool has_extended_events; + bool locked; FuriString* locked_message; } SubmenuItem; @@ -68,6 +70,7 @@ typedef struct { FuriString* header; size_t position; size_t window_position; + bool locked_message_visible; bool is_vertical; } SubmenuModel; @@ -76,9 +79,9 @@ static void submenu_process_up(Submenu* submenu); static void submenu_process_down(Submenu* submenu); static void submenu_process_ok(Submenu* submenu, InputType input_type); -static size_t submenu_items_on_screen(bool header, bool vertical) { - size_t res = (vertical) ? 8 : 4; - return (header) ? res - 1 : res; +static size_t submenu_items_on_screen(SubmenuModel* model) { + size_t res = (model->is_vertical) ? 8 : 4; + return (furi_string_empty(model->header)) ? res : res - 1; } static void submenu_view_draw_callback(Canvas* canvas, void* _model) { @@ -101,9 +104,9 @@ static void submenu_view_draw_callback(Canvas* canvas, void* _model) { for(SubmenuItemArray_it(it, model->items); !SubmenuItemArray_end_p(it); SubmenuItemArray_next(it)) { const size_t item_position = position - model->window_position; - const size_t items_on_screen = - submenu_items_on_screen(!furi_string_empty(model->header), model->is_vertical); - uint8_t y_offset = furi_string_empty(model->header) ? 0 : 16; + const size_t items_on_screen = submenu_items_on_screen(model); + uint8_t y_offset = furi_string_empty(model->header) ? 0 : item_height; + bool is_locked = SubmenuItemArray_cref(it)->locked; if(item_position < items_on_screen) { if(position == model->position) { @@ -119,7 +122,7 @@ static void submenu_view_draw_callback(Canvas* canvas, void* _model) { canvas_set_color(canvas, ColorBlack); } - if(SubmenuItemArray_cref(it)->locked) { + if(is_locked) { canvas_draw_icon( canvas, item_width - 10, @@ -127,10 +130,8 @@ static void submenu_view_draw_callback(Canvas* canvas, void* _model) { &I_Lock_7x8); } - FuriString* disp_str; - disp_str = furi_string_alloc_set(SubmenuItemArray_cref(it)->label); - elements_string_fit_width( - canvas, disp_str, item_width - (SubmenuItemArray_cref(it)->locked ? 21 : 11)); + FuriString* disp_str = furi_string_alloc_set(SubmenuItemArray_cref(it)->label); + elements_string_fit_width(canvas, disp_str, item_width - (is_locked ? 21 : 11)); canvas_draw_str( canvas, @@ -161,25 +162,14 @@ static void submenu_view_draw_callback(Canvas* canvas, void* _model) { canvas_draw_rframe(canvas, frame_x, frame_y, frame_width, frame_height, 3); canvas_draw_rframe(canvas, frame_x + 1, frame_y + 1, frame_width - 2, frame_height - 2, 2); - if(model->is_vertical) { - elements_multiline_text_aligned( - canvas, - 32, - 42, - AlignCenter, - AlignCenter, - furi_string_get_cstr( - SubmenuItemArray_get(model->items, model->position)->locked_message)); - } else { - elements_multiline_text_aligned( - canvas, - 84, - 32, - AlignCenter, - AlignCenter, - furi_string_get_cstr( - SubmenuItemArray_get(model->items, model->position)->locked_message)); - } + elements_multiline_text_aligned( + canvas, + (model->is_vertical) ? 32 : 84, + (model->is_vertical) ? 42 : 32, + AlignCenter, + AlignCenter, + furi_string_get_cstr( + SubmenuItemArray_get(model->items, model->position)->locked_message)); } } @@ -195,8 +185,7 @@ static bool submenu_view_input_callback(InputEvent* event, void* context) { { locked_message_visible = model->locked_message_visible; }, false); - if((!(event->type == InputTypePress) && !(event->type == InputTypeRelease)) && - locked_message_visible) { + if(locked_message_visible && (event->type == InputTypeShort || event->type == InputTypeLong)) { with_view_model( submenu->view, SubmenuModel * model, { model->locked_message_visible = false; }, true); consumed = true; @@ -303,6 +292,9 @@ void submenu_add_lockable_item( SubmenuItem* item = NULL; furi_check(label); furi_check(submenu); + if(locked) { + furi_check(locked_message); + } with_view_model( submenu->view, @@ -366,6 +358,25 @@ void submenu_change_item_label(Submenu* submenu, uint32_t index, const char* lab true); } +void submenu_remove_item(Submenu* submenu, uint32_t index) { + furi_check(submenu); + + with_view_model( + submenu->view, + SubmenuModel * model, + { + SubmenuItemArray_it_t it; + for(SubmenuItemArray_it(it, model->items); !SubmenuItemArray_end_p(it); + SubmenuItemArray_next(it)) { + if(index == SubmenuItemArray_cref(it)->index) { + SubmenuItemArray_remove(model->items, it); + break; + } + } + }, + true); +} + void submenu_reset(Submenu* submenu) { furi_check(submenu); view_set_orientation(submenu->view, ViewOrientationHorizontal); @@ -431,8 +442,7 @@ void submenu_set_selected_item(Submenu* submenu, uint32_t index) { model->window_position -= 1; } - const size_t items_on_screen = - submenu_items_on_screen(!furi_string_empty(model->header), model->is_vertical); + const size_t items_on_screen = submenu_items_on_screen(model); if(items_size <= items_on_screen) { model->window_position = 0; @@ -451,8 +461,7 @@ void submenu_process_up(Submenu* submenu) { submenu->view, SubmenuModel * model, { - const size_t items_on_screen = - submenu_items_on_screen(!furi_string_empty(model->header), model->is_vertical); + const size_t items_on_screen = submenu_items_on_screen(model); const size_t items_size = SubmenuItemArray_size(model->items); if(model->position > 0) { @@ -475,8 +484,7 @@ void submenu_process_down(Submenu* submenu) { submenu->view, SubmenuModel * model, { - const size_t items_on_screen = - submenu_items_on_screen(!furi_string_empty(model->header), model->is_vertical); + const size_t items_on_screen = submenu_items_on_screen(model); const size_t items_size = SubmenuItemArray_size(model->items); if(model->position < items_size - 1) { @@ -504,7 +512,8 @@ void submenu_process_ok(Submenu* submenu, InputType input_type) { if(model->position < items_size) { item = SubmenuItemArray_get(model->items, model->position); } - if(item && item->locked) { + if(item && item->locked && + (input_type == InputTypeShort || input_type == InputTypeLong)) { model->locked_message_visible = true; furi_timer_start(submenu->locked_timer, furi_kernel_get_tick_frequency() * 3); } @@ -540,11 +549,9 @@ void submenu_set_header(Submenu* submenu, const char* header) { } void submenu_set_orientation(Submenu* submenu, ViewOrientation orientation) { - furi_assert(submenu); - const bool is_vertical = - (orientation == ViewOrientationVertical || orientation == ViewOrientationVerticalFlip) ? - true : - false; + furi_check(submenu); + const bool is_vertical = orientation == ViewOrientationVertical || + orientation == ViewOrientationVerticalFlip; view_set_orientation(submenu->view, orientation); @@ -558,8 +565,7 @@ void submenu_set_orientation(Submenu* submenu, ViewOrientation orientation) { // Need if _set_orientation is called after _set_selected_item size_t position = model->position; const size_t items_size = SubmenuItemArray_size(model->items); - const size_t items_on_screen = - submenu_items_on_screen(!furi_string_empty(model->header), model->is_vertical); + const size_t items_on_screen = submenu_items_on_screen(model); if(position >= items_size) { position = 0; diff --git a/applications/services/gui/modules/submenu.h b/applications/services/gui/modules/submenu.h index 750167543..64ba650ee 100644 --- a/applications/services/gui/modules/submenu.h +++ b/applications/services/gui/modules/submenu.h @@ -98,6 +98,14 @@ void submenu_add_item_ex( */ void submenu_change_item_label(Submenu* submenu, uint32_t index, const char* label); +/** Remove item from submenu + * + * @param submenu Submenu instance + * @param index menu item index, used for callback, may be + * the same with other items, first one is removed + */ +void submenu_remove_item(Submenu* submenu, uint32_t index); + /** Remove all items from submenu * * @param submenu Submenu instance @@ -120,13 +128,14 @@ uint32_t submenu_get_selected_item(Submenu* submenu); void submenu_set_selected_item(Submenu* submenu, uint32_t index); /** Set optional header for submenu + * Must be called before adding items OR after adding items and before set_selected_item() * * @param submenu Submenu instance * @param header header to set */ void submenu_set_header(Submenu* submenu, const char* header); -/** Set Orientation +/** Set submenu orientation * * @param submenu Submenu instance * @param orientation either vertical or horizontal diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index c5d417f3e..e2aa3d897 100755 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,86.1,, +Version,+,86.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, @@ -3660,6 +3660,7 @@ Function,+,submenu_change_item_label,void,"Submenu*, uint32_t, const char*" Function,+,submenu_free,void,Submenu* Function,+,submenu_get_selected_item,uint32_t,Submenu* Function,+,submenu_get_view,View*,Submenu* +Function,+,submenu_remove_item,void,"Submenu*, uint32_t" Function,+,submenu_reset,void,Submenu* Function,+,submenu_set_header,void,"Submenu*, const char*" Function,+,submenu_set_orientation,void,"Submenu*, ViewOrientation"