diff --git a/radio/src/gui/colorlcd/LvglWrapper.cpp b/radio/src/gui/colorlcd/LvglWrapper.cpp index 5876248c3..eb29fb087 100644 --- a/radio/src/gui/colorlcd/LvglWrapper.cpp +++ b/radio/src/gui/colorlcd/LvglWrapper.cpp @@ -97,6 +97,9 @@ static void dispatch_kb_event(Window* w, event_t evt) w->onCancel(); } else if (key != KEY_ENTER /*&& key != KEY_EXIT*/) { w->onEvent(evt); + } else if (evt == EVT_KEY_LONG(KEY_ENTER)) { + killEvents(KEY_ENTER); + lv_event_send(w->getLvObj(), LV_EVENT_LONG_PRESSED, nullptr); } } diff --git a/radio/src/gui/colorlcd/view_main.cpp b/radio/src/gui/colorlcd/view_main.cpp index 4ea98a28e..a2b7cea85 100644 --- a/radio/src/gui/colorlcd/view_main.cpp +++ b/radio/src/gui/colorlcd/view_main.cpp @@ -68,6 +68,7 @@ ViewMain::ViewMain(): lv_obj_add_flag(tile_view, LV_OBJ_FLAG_EVENT_BUBBLE); lv_obj_set_user_data(tile_view, this); lv_obj_add_event_cb(tile_view, tile_view_scroll, LV_EVENT_SCROLL, nullptr); + lv_obj_add_event_cb(lvobj, ViewMain::long_pressed, LV_EVENT_LONG_PRESSED, nullptr); // create last to be on top topbar = dynamic_cast(TopbarFactory::create(this)); @@ -119,7 +120,6 @@ rect_t ViewMain::getMainZone(rect_t zone, bool hasTopbar) const unsigned ViewMain::getCurrentMainView() const { return lv_obj_get_scroll_x(tile_view) / width(); - // return g_model.view; } void ViewMain::setCurrentMainView(unsigned viewId) @@ -218,27 +218,6 @@ void ViewMain::updateTopbarVisibility() } } -// #if defined(HARDWARE_TOUCH) - -//#define DEBUG_SLIDE - - -// bool ViewMain::onTouchEnd(coord_t x, coord_t y) -// { -// openMenu(); - -// // TODO: remove this hack to preset -// // the scrolling on the main menu -// int x1 = x; -// int w1 = getParent()->width(); -// while (x1 > w1) x1 -= w1; -// if (x1 > w1 / 2) -// pushEvent(EVT_ROTARY_LEFT); - -// return true; -// } -// #endif - void ViewMain::onEvent(event_t event) { #if defined(HARDWARE_KEYS) @@ -251,6 +230,10 @@ void ViewMain::onEvent(event_t event) new ModelSelectMenu(); break; + // TODO: + // - use BREAK instead + // - use LONG for "Tools" page + // case EVT_KEY_FIRST(KEY_RADIO): new RadioMenu(); break; @@ -264,7 +247,7 @@ void ViewMain::onEvent(event_t event) #else case EVT_KEY_BREAK(KEY_PGDN): #endif - nextMainView(); + if (!widget_select) nextMainView(); break; //TODO: these need to go away! @@ -275,19 +258,8 @@ void ViewMain::onEvent(event_t event) case EVT_KEY_LONG(KEY_PGDN): #endif killEvents(event); - previousMainView(); + if (!widget_select) previousMainView(); break; - - // TODO: find something to activate widget selection via keys - - // case EVT_ROTARY_LEFT: - // // decrement - // case EVT_ROTARY_RIGHT: - // // increment - // if (customScreens[g_model.view]) { - // customScreens[g_model.view]->setFocus(); - // } - // break; } #endif } @@ -297,6 +269,63 @@ void ViewMain::onClicked() openMenu(); } +void ViewMain::onCancel() +{ + if (widget_select) { + enableWidgetSelect(false); + } +} + +void ViewMain::refreshWidgetSelectTimer() +{ + if (!widget_select_timer) { + widget_select_timer = lv_timer_create(ViewMain::ws_timer, 10 * 1000, this); + } else { + lv_timer_reset(widget_select_timer); + } +} + +bool ViewMain::enableWidgetSelect(bool enable) +{ + TRACE("enableWidgetSelect(%d)", enable); + // TODO: start timer + if (widget_select == enable) return false; + widget_select = enable; + + lv_obj_t* tile = lv_tileview_get_tile_act(tile_view); + auto cont_obj = lv_obj_get_child(tile, 0); + auto cont = (WidgetsContainer*)lv_obj_get_user_data(cont_obj); + + for (uint32_t i = 0; i < cont->getZonesCount(); i++) { + Widget* widget = cont->getWidget(i); + if (!widget) continue; + if (enable) { + widget->setFocusHandler([=](bool) { refreshWidgetSelectTimer(); }); + lv_group_add_obj(lv_group_get_default(), widget->getLvObj()); + } else { + widget->setFocusHandler(nullptr); + lv_group_remove_obj(widget->getLvObj()); + } + } + + if (enable) { + lv_obj_clear_flag(tile_view, LV_OBJ_FLAG_SCROLLABLE); + lv_obj_clear_flag(tile_view, LV_OBJ_FLAG_SCROLL_CHAIN_HOR); + lv_obj_clear_flag(tile_view, LV_OBJ_FLAG_SCROLL_CHAIN_VER); + } else { + lv_obj_add_flag(tile_view, LV_OBJ_FLAG_SCROLLABLE); + lv_obj_add_flag(tile_view, LV_OBJ_FLAG_SCROLL_CHAIN_HOR); + lv_obj_add_flag(tile_view, LV_OBJ_FLAG_SCROLL_CHAIN_VER); + + if (widget_select_timer) { + lv_timer_del(widget_select_timer); + widget_select_timer = nullptr; + } + } + + return true; +} + void ViewMain::openMenu() { new ViewMainMenu(this); @@ -307,9 +336,31 @@ void ViewMain::paint(BitmapBuffer * dc) TRACE_WINDOWS("### ViewMain::paint(offset_x=%d;offset_y=%d) ###", dc->getOffsetX(), dc->getOffsetY()); + // TODO: set it as "window background" w/ LVGL OpenTxTheme::instance()->drawBackground(dc); + // TODO: move to "screen setup" if (g_model.view >= getMainViewsCount()) { g_model.view = 0; } } + +void ViewMain::ws_timer(lv_timer_t* t) +{ + ViewMain* view = (ViewMain*)t->user_data; + if (!view) return; + view->enableWidgetSelect(false); +} + +void ViewMain::long_pressed(lv_event_t* e) +{ + auto obj = lv_event_get_target(e); + auto view = (ViewMain*)lv_obj_get_user_data(obj); + if (!view) return; + + if (view->enableWidgetSelect(true)) { + // kill subsequent CLICKED event + lv_obj_clear_state(obj, LV_STATE_PRESSED); + lv_indev_wait_release(lv_indev_get_act()); + } +} diff --git a/radio/src/gui/colorlcd/view_main.h b/radio/src/gui/colorlcd/view_main.h index 113e52de6..c92d278cc 100644 --- a/radio/src/gui/colorlcd/view_main.h +++ b/radio/src/gui/colorlcd/view_main.h @@ -76,6 +76,7 @@ class ViewMain: public Window void onEvent(event_t event) override; void onClicked() override; + void onCancel() override; protected: static ViewMain * _instance; @@ -83,7 +84,10 @@ class ViewMain: public Window unsigned views = 0; lv_obj_t* tile_view = nullptr; TopbarImpl* topbar = nullptr; + bool widget_select = false; + lv_timer_t* widget_select_timer = nullptr; + void paint(BitmapBuffer * dc) override; void deleteLater(bool detach = true, bool trash = true) override; // Widget setup requires special permissions ;-) @@ -93,16 +97,12 @@ class ViewMain: public Window // Set topbar visibility [0.0 -> 1.0] void setTopbarVisible(float visible); -// #if defined(HARDWARE_TOUCH) -// unsigned char prevSlideState = 0; -// unsigned int startSlidePage = 0; - -// bool onTouchEnd(coord_t x, coord_t y) override; -// #endif - - void paint(BitmapBuffer * dc) override; - void openMenu(); + bool enableWidgetSelect(bool enable); + void refreshWidgetSelectTimer(); + + static void long_pressed(lv_event_t* e); + static void ws_timer(lv_timer_t* t); }; #endif // _VIEW_MAIN_H_ diff --git a/radio/src/gui/colorlcd/widget.cpp b/radio/src/gui/colorlcd/widget.cpp index ea0746f7e..56b6f1b21 100644 --- a/radio/src/gui/colorlcd/widget.cpp +++ b/radio/src/gui/colorlcd/widget.cpp @@ -47,7 +47,18 @@ Widget::Widget(const WidgetFactory* factory, Window* parent, factory(factory), persistentData(persistentData) { + lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_SCROLLABLE); + lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICK_FOCUSABLE); + setPressHandler([&]() -> uint8_t { + // When ViewMain is in "widget select mode", + // the widget is added to a focus group + if (!fullscreen && lv_obj_get_group(lvobj)) + openWidgetMenu(this); + return 0; + }); + + setLongPressHandler([&]() -> uint8_t { if (!fullscreen) openWidgetMenu(this); return 0; }); @@ -130,10 +141,13 @@ void Widget::setFullscreen(bool enable) // and give up focus ViewMain::instance()->enableTopbar(); - // ViewMain::instance()->setFocus(); fullscreen = false; lv_group_remove_obj(lvobj); + + // re-enable scroll chaining (sliding main view) + lv_obj_add_flag(lvobj, LV_OBJ_FLAG_SCROLL_CHAIN_HOR); + lv_obj_add_flag(lvobj, LV_OBJ_FLAG_SCROLL_CHAIN_VER); } // Enter Fullscreen Mode else { @@ -149,6 +163,10 @@ void Widget::setFullscreen(bool enable) if (!lv_obj_get_group(lvobj)) { lv_group_add_obj(lv_group_get_default(), lvobj); } + + // disable scroll chaining (sliding main view) + lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_SCROLL_CHAIN_HOR); + lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_SCROLL_CHAIN_VER); } } diff --git a/radio/src/thirdparty/libopenui b/radio/src/thirdparty/libopenui index 29dd3f3ec..098b943bf 160000 --- a/radio/src/thirdparty/libopenui +++ b/radio/src/thirdparty/libopenui @@ -1 +1 @@ -Subproject commit 29dd3f3ec154dccbe507001424a86fa70e9835f6 +Subproject commit 098b943bf207497bafad12eb61d48244477a5351