Replaced focus handling with LVGL groups
This commit is contained in:
committed by
Raphael Coeffic
parent
866bc46d4d
commit
25715ed648
+3
-1
@@ -35,7 +35,9 @@ set(LIBOPENUI_SRC
|
||||
table.cpp
|
||||
modal_window.cpp
|
||||
dialog.cpp
|
||||
expansion_panel.cpp
|
||||
# LVGL widgets
|
||||
widgets/window_base.c
|
||||
widgets/simple_btn.c
|
||||
)
|
||||
|
||||
if(SOFTWARE_KEYBOARD)
|
||||
|
||||
+7
-50
@@ -22,14 +22,7 @@
|
||||
#include "font.h"
|
||||
#include "theme.h"
|
||||
|
||||
static void lvglEvent(lv_event_t* e)
|
||||
{
|
||||
Button* btn = (Button*)lv_event_get_user_data(e);
|
||||
if(btn->deleted())
|
||||
return;
|
||||
|
||||
btn->onEvent(e);
|
||||
}
|
||||
#include "widgets/simple_btn.h"
|
||||
|
||||
static void update_checked_flag(lv_obj_t* obj, WindowFlags flags)
|
||||
{
|
||||
@@ -43,11 +36,10 @@ Button::Button(Window* parent, const rect_t& rect,
|
||||
std::function<uint8_t(void)> pressHandler,
|
||||
WindowFlags windowFlag, LcdFlags textFlags,
|
||||
LvglCreate objConstruct) :
|
||||
FormField(parent, rect, windowFlag, textFlags, objConstruct),
|
||||
FormField(parent, rect, windowFlag, textFlags,
|
||||
objConstruct ? objConstruct : simple_btn_create),
|
||||
pressHandler(std::move(pressHandler))
|
||||
{
|
||||
lv_obj_add_event_cb(lvobj, lvglEvent, LV_EVENT_CLICKED, this);
|
||||
|
||||
if (windowFlag & BUTTON_CHECKED)
|
||||
lv_obj_add_state(lvobj, LV_STATE_CHECKED);
|
||||
}
|
||||
@@ -78,55 +70,20 @@ void Button::onPress()
|
||||
update_checked_flag(lvobj, windowFlags);
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void Button::onEvent(event_t event)
|
||||
void Button::onClicked()
|
||||
{
|
||||
auto indev_act = lv_indev_get_act();
|
||||
switch (event) {
|
||||
case EVT_KEY_FIRST(KEY_ENTER):
|
||||
lv_event_send(lvobj, LV_EVENT_PRESSED, indev_act);
|
||||
break;
|
||||
|
||||
case EVT_KEY_BREAK(KEY_ENTER):
|
||||
lv_event_send(lvobj, LV_EVENT_RELEASED, indev_act);
|
||||
lv_event_send(lvobj, LV_EVENT_CLICKED, indev_act);
|
||||
break;
|
||||
|
||||
default:
|
||||
FormField::onEvent(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void Button::onEvent(lv_event_t* event)
|
||||
{
|
||||
lv_event_code_t code = lv_event_get_code(event);
|
||||
|
||||
TRACE_WINDOWS("%s received lvgl event code 0x%X", getWindowDebugString("Button").c_str(), code);
|
||||
|
||||
if (enabled && code == LV_EVENT_CLICKED) {
|
||||
if (!(windowFlags & NO_FOCUS)) {
|
||||
setFocus(SET_FOCUS_DEFAULT);
|
||||
}
|
||||
onKeyPress();
|
||||
onPress();
|
||||
}
|
||||
onPress();
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
// this needs to stay so that viewmain doesnt get the touch event
|
||||
bool Button::onTouchEnd(coord_t x, coord_t y)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool Button::onTouchEnd(coord_t x, coord_t y) { return true; }
|
||||
#endif
|
||||
|
||||
void Button::checkEvents()
|
||||
{
|
||||
Window::checkEvents();
|
||||
if (checkHandler)
|
||||
checkHandler();
|
||||
if (checkHandler) checkHandler();
|
||||
}
|
||||
|
||||
TextButton::TextButton(Window* parent, const rect_t& rect, std::string text,
|
||||
|
||||
+8
-8
@@ -40,6 +40,10 @@ class Button: public FormField
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual void onPress();
|
||||
void onClicked() override;
|
||||
void checkEvents() override;
|
||||
|
||||
void check(bool checked = true);
|
||||
bool checked() const;
|
||||
|
||||
@@ -53,22 +57,18 @@ class Button: public FormField
|
||||
checkHandler = std::move(handler);
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void onEvent(event_t event) override;
|
||||
#endif
|
||||
void onEvent(lv_event_t* e);// override;
|
||||
// #if defined(HARDWARE_KEYS)
|
||||
// void onEvent(event_t event) override;
|
||||
// #endif
|
||||
// void onEvent(lv_event_t* e);// override;
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool onTouchEnd(coord_t x, coord_t y) override;
|
||||
#endif
|
||||
|
||||
void checkEvents() override;
|
||||
|
||||
protected:
|
||||
std::function<uint8_t(void)> pressHandler;
|
||||
std::function<void(void)> checkHandler;
|
||||
|
||||
virtual void onPress();
|
||||
};
|
||||
|
||||
|
||||
|
||||
+27
-59
@@ -28,38 +28,47 @@ static const char _map_end[] = "";
|
||||
|
||||
static void btn_matrix_event(lv_event_t *e)
|
||||
{
|
||||
static lv_area_t draw_area;
|
||||
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
|
||||
if (code == LV_EVENT_VALUE_CHANGED) {
|
||||
lv_obj_t* obj = lv_event_get_target(e);
|
||||
auto btn_id = (uint32_t *)lv_event_get_param(e);
|
||||
auto btnm = (ButtonMatrix*)lv_event_get_user_data(e);
|
||||
|
||||
btnm->onPress((uint8_t)*btn_id);
|
||||
bool edited = lv_obj_has_state(obj, LV_STATE_EDITED);
|
||||
bool is_pointer = lv_indev_get_type(lv_indev_get_act()) == LV_INDEV_TYPE_POINTER;
|
||||
if (edited || is_pointer)
|
||||
btnm->onPress((uint8_t)*btn_id);
|
||||
}
|
||||
else if (code == LV_EVENT_DRAW_PART_BEGIN) {
|
||||
|
||||
lv_obj_draw_part_dsc_t* dsc = lv_event_get_draw_part_dsc(e);
|
||||
if (dsc->part != LV_PART_ITEMS) return;
|
||||
|
||||
auto btnm = (ButtonMatrix*)lv_event_get_user_data(e);
|
||||
if (btnm->isActive((uint8_t)dsc->id)) {
|
||||
dsc->rect_dsc->bg_color = makeLvColor(COLOR_THEME_ACTIVE);
|
||||
dsc->label_dsc->color = makeLvColor(COLOR_THEME_PRIMARY2);
|
||||
} else {
|
||||
dsc->rect_dsc->bg_color = makeLvColor(COLOR_THEME_PRIMARY2);
|
||||
dsc->label_dsc->color = makeLvColor(COLOR_THEME_SECONDARY1);
|
||||
if (dsc->part == LV_PART_ITEMS) {
|
||||
auto btnm = (ButtonMatrix*)lv_event_get_user_data(e);
|
||||
if (btnm->isActive((uint8_t)dsc->id)) {
|
||||
dsc->rect_dsc->bg_color = makeLvColor(COLOR_THEME_ACTIVE);
|
||||
dsc->label_dsc->color = makeLvColor(COLOR_THEME_PRIMARY2);
|
||||
} else {
|
||||
dsc->rect_dsc->bg_color = makeLvColor(COLOR_THEME_PRIMARY2);
|
||||
dsc->label_dsc->color = makeLvColor(COLOR_THEME_SECONDARY1);
|
||||
}
|
||||
} else if (dsc->part == LV_PART_MAIN) {
|
||||
lv_obj_t* obj = lv_event_get_target(e);
|
||||
if (lv_obj_has_state(obj, LV_STATE_FOCUS_KEY) &&
|
||||
!lv_obj_has_state(obj, LV_STATE_EDITED)) {
|
||||
dsc->rect_dsc->bg_color = makeLvColor(COLOR_THEME_FOCUS);
|
||||
dsc->rect_dsc->bg_opa = LV_OPA_20;
|
||||
}
|
||||
}
|
||||
|
||||
// backup draw area as it gets modified for the label
|
||||
lv_area_copy(&draw_area, dsc->draw_area);
|
||||
}
|
||||
}
|
||||
|
||||
ButtonMatrix::ButtonMatrix(Window* parent, const rect_t& r) :
|
||||
FormField(parent, r, 0, 0, lv_btnmatrix_create)
|
||||
{
|
||||
lv_obj_add_flag(lvobj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
|
||||
lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICK_FOCUSABLE);
|
||||
|
||||
lv_obj_add_event_cb(lvobj, btn_matrix_event, LV_EVENT_ALL, this);
|
||||
}
|
||||
|
||||
@@ -132,49 +141,8 @@ void ButtonMatrix::update()
|
||||
lv_btnmatrix_set_btn_ctrl_all(lvobj, ctrl);
|
||||
}
|
||||
|
||||
void ButtonMatrix::onEvent(event_t event)
|
||||
void ButtonMatrix::onClicked()
|
||||
{
|
||||
char c = 0;
|
||||
lv_event_code_t code = LV_EVENT_ALL;
|
||||
|
||||
#if defined (HARDWARE_KEYS)
|
||||
switch (event) {
|
||||
case EVT_KEY_FIRST(KEY_ENTER):
|
||||
code = LV_EVENT_PRESSED;
|
||||
break;
|
||||
|
||||
case EVT_KEY_BREAK(KEY_ENTER):
|
||||
code = LV_EVENT_RELEASED;
|
||||
break;
|
||||
|
||||
case EVT_ROTARY_LEFT:
|
||||
if (lv_btnmatrix_get_selected_btn(lvobj) != 0) {
|
||||
code = LV_EVENT_KEY;
|
||||
c = LV_KEY_LEFT;
|
||||
}
|
||||
break;
|
||||
case EVT_ROTARY_RIGHT:
|
||||
if (lv_btnmatrix_get_selected_btn(lvobj) < btn_cnt - 1) {
|
||||
code = LV_EVENT_KEY;
|
||||
c = LV_KEY_RIGHT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((code == LV_EVENT_KEY) && c != 0) lv_event_send(lvobj, code, &c);
|
||||
else if (code != LV_EVENT_ALL) lv_event_send(lvobj, code, lv_indev_get_act());
|
||||
else FormField::onEvent(event);
|
||||
}
|
||||
|
||||
void ButtonMatrix::setFocus(uint8_t flag, Window* from)
|
||||
{
|
||||
if (lv_btnmatrix_get_selected_btn(lvobj) == LV_BTNMATRIX_BTN_NONE) {
|
||||
if (flag == SET_FOCUS_BACKWARD)
|
||||
lv_btnmatrix_set_selected_btn(lvobj, btn_cnt - 1);
|
||||
else
|
||||
lv_btnmatrix_set_selected_btn(lvobj, 0);
|
||||
}
|
||||
|
||||
FormField::setFocus(flag, from);
|
||||
lv_group_focus_obj(lvobj);
|
||||
FormField::onClicked();
|
||||
}
|
||||
|
||||
+1
-2
@@ -41,6 +41,5 @@ class ButtonMatrix : public FormField
|
||||
void setText(uint8_t btn_id, const char* txt);
|
||||
void update();
|
||||
|
||||
void onEvent(event_t event) override;
|
||||
void setFocus(uint8_t flag, Window* from) override;
|
||||
void onClicked() override;
|
||||
};
|
||||
|
||||
+2
-29
@@ -52,34 +52,7 @@ CheckBox::CheckBox(Window* parent, const rect_t& rect,
|
||||
LV_EVENT_VALUE_CHANGED, this);
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void CheckBox::onEvent(event_t event)
|
||||
void CheckBox::onClicked()
|
||||
{
|
||||
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString("CheckBox").c_str(), event);
|
||||
|
||||
if (enabled && event == EVT_KEY_BREAK(KEY_ENTER)) {
|
||||
onKeyPress();
|
||||
if (lv_obj_get_state(lvobj) & LV_STATE_CHECKED)
|
||||
lv_obj_clear_state(lvobj, LV_STATE_CHECKED);
|
||||
else
|
||||
lv_obj_add_state(lvobj, LV_STATE_CHECKED);
|
||||
|
||||
_setValue(lv_obj_get_state(lvobj) & LV_STATE_CHECKED);
|
||||
}
|
||||
else {
|
||||
FormField::onEvent(event);
|
||||
}
|
||||
// prevent FormField::onClicked()
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool CheckBox::onTouchEnd(coord_t x, coord_t y)
|
||||
{
|
||||
if (!hasFocus()) {
|
||||
setFocus(SET_FOCUS_DEFAULT);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+20
-40
@@ -22,52 +22,32 @@
|
||||
#include <utility>
|
||||
#include "form.h"
|
||||
|
||||
class CheckBox : public FormField {
|
||||
public:
|
||||
CheckBox(Window * parent, const rect_t & rect, std::function<uint8_t()> getValue, std::function<void(uint8_t)> setValue, WindowFlags flags = 0);
|
||||
class CheckBox : public FormField
|
||||
{
|
||||
public:
|
||||
CheckBox(Window* parent, const rect_t& rect,
|
||||
std::function<uint8_t()> getValue,
|
||||
std::function<void(uint8_t)> setValue, WindowFlags flags = 0);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "CheckBox";
|
||||
}
|
||||
std::string getName() const override { return "CheckBox"; }
|
||||
#endif
|
||||
|
||||
const char * getLabel() const
|
||||
{
|
||||
return label.c_str();
|
||||
}
|
||||
void onClicked() override;
|
||||
|
||||
void setLabel(std::string newLabel)
|
||||
{
|
||||
label = std::move(newLabel);
|
||||
}
|
||||
const char* getLabel() const { return label.c_str(); }
|
||||
void setLabel(std::string newLabel) { label = std::move(newLabel); }
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void onEvent(event_t event) override;
|
||||
#endif
|
||||
uint8_t getValue() const { return _getValue(); }
|
||||
void setValue(uint8_t value) { _setValue(value); }
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool onTouchEnd(coord_t x, coord_t y) override;
|
||||
#endif
|
||||
void setSetValueHandler(std::function<void(uint8_t)> handler)
|
||||
{
|
||||
_setValue = std::move(handler);
|
||||
}
|
||||
|
||||
uint8_t getValue() const
|
||||
{
|
||||
return _getValue();
|
||||
}
|
||||
|
||||
void setValue(uint8_t value)
|
||||
{
|
||||
_setValue(value);
|
||||
}
|
||||
|
||||
void setSetValueHandler(std::function<void(uint8_t)> handler)
|
||||
{
|
||||
_setValue = std::move(handler);
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string label;
|
||||
std::function<uint8_t()> _getValue;
|
||||
std::function<void(uint8_t)> _setValue;
|
||||
protected:
|
||||
std::string label;
|
||||
std::function<uint8_t()> _getValue;
|
||||
std::function<void(uint8_t)> _setValue;
|
||||
};
|
||||
|
||||
+3
-26
@@ -181,20 +181,11 @@ void Choice::setValues(const char * const values[])
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void Choice::onEvent(event_t event)
|
||||
void Choice::onClicked()
|
||||
{
|
||||
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
|
||||
|
||||
if (event == EVT_KEY_BREAK(KEY_ENTER)) {
|
||||
onKeyPress();
|
||||
openMenu();
|
||||
}
|
||||
else {
|
||||
FormField::onEvent(event);
|
||||
}
|
||||
onKeyPress();
|
||||
openMenu();
|
||||
}
|
||||
#endif
|
||||
|
||||
void Choice::openMenu()
|
||||
{
|
||||
@@ -247,17 +238,3 @@ void Choice::openMenu()
|
||||
setEditMode(false);
|
||||
});
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool Choice::onTouchEnd(coord_t, coord_t)
|
||||
{
|
||||
if (enabled) {
|
||||
if (!hasFocus()) {
|
||||
setFocus(SET_FOCUS_DEFAULT);
|
||||
}
|
||||
onKeyPress();
|
||||
openMenu();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
+1
-7
@@ -81,13 +81,7 @@ class Choice: public ChoiceBase {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void onEvent(event_t event) override;
|
||||
#endif
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool onTouchEnd(coord_t x, coord_t y) override;
|
||||
#endif
|
||||
void onClicked() override;
|
||||
|
||||
void setBeforeDisplayMenuHandler(std::function<void(Menu*)> handler)
|
||||
{
|
||||
|
||||
+9
-12
@@ -21,14 +21,16 @@
|
||||
#include "mainwindow.h"
|
||||
#include "theme.h"
|
||||
|
||||
static rect_t _get_form_rect(const rect_t& rect)
|
||||
{
|
||||
return {0, POPUP_HEADER_HEIGHT, rect.w,
|
||||
coord_t(rect.h - POPUP_HEADER_HEIGHT)};
|
||||
}
|
||||
|
||||
DialogWindowContent::DialogWindowContent(Dialog* parent, const rect_t& rect) :
|
||||
ModalWindowContent(parent, rect),
|
||||
form(this,
|
||||
{ 0, POPUP_HEADER_HEIGHT, rect.w,
|
||||
coord_t(rect.h - POPUP_HEADER_HEIGHT) },
|
||||
FORM_NO_BORDER | FORM_FORWARD_FOCUS)
|
||||
form(this, _get_form_rect(rect), FORM_NO_BORDER)
|
||||
{
|
||||
form.setFocus(SET_FOCUS_DEFAULT);
|
||||
}
|
||||
|
||||
void DialogWindowContent::deleteLater(bool detach, bool trash)
|
||||
@@ -58,12 +60,7 @@ Dialog::Dialog(Window* parent, std::string title, const rect_t& rect) :
|
||||
if (!title.empty()) content->setTitle(std::move(title));
|
||||
}
|
||||
|
||||
void Dialog::onEvent(event_t event)
|
||||
void Dialog::onCancel()
|
||||
{
|
||||
#if defined(HARDWARE_KEYS)
|
||||
if (event == EVT_KEY_LONG(KEY_EXIT) || event == EVT_KEY_BREAK(KEY_EXIT)) {
|
||||
killEvents(event);
|
||||
deleteLater();
|
||||
}
|
||||
#endif
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
+2
-1
@@ -48,6 +48,7 @@ class Dialog : public ModalWindow
|
||||
Dialog(Window* parent, std::string title, const rect_t& rect);
|
||||
|
||||
protected:
|
||||
void onEvent(event_t event) override;
|
||||
DialogWindowContent* content;
|
||||
|
||||
void onCancel() override;
|
||||
};
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "expansion_panel.h"
|
||||
|
||||
void ExpansionPanel::updateHeight(bool move)
|
||||
{
|
||||
coord_t newHeight = (isOpen ? header->height() + body->height() : header->height());
|
||||
if (move) {
|
||||
parent->moveWindowsTop(bottom(), newHeight - height());
|
||||
}
|
||||
setHeight(newHeight);
|
||||
}
|
||||
|
||||
void ExpansionPanel::setFocus(uint8_t flag, Window * from)
|
||||
{
|
||||
if (!enabled || isOpen)
|
||||
FormGroup::setFocus(flag, from);
|
||||
else
|
||||
header->setFocus(flag, from);
|
||||
}
|
||||
|
||||
ExpansionPanelHeader::ExpansionPanelHeader(ExpansionPanel * parent):
|
||||
FormGroup(parent, {0, 0, parent->width(), parent->height()}, FORWARD_SCROLL)
|
||||
{
|
||||
}
|
||||
|
||||
void ExpansionPanelHeader::onEvent(event_t event)
|
||||
{
|
||||
auto panel = static_cast<ExpansionPanel *>(parent);
|
||||
|
||||
if (event == EVT_KEY_BREAK(KEY_ENTER)) {
|
||||
panel->toggle();
|
||||
}
|
||||
else if (event == EVT_ROTARY_RIGHT && !panel->isOpen) {
|
||||
auto next = panel->getNextField();
|
||||
if (next)
|
||||
next->setFocus(SET_FOCUS_FORWARD, this);
|
||||
}
|
||||
else if (event == EVT_ROTARY_LEFT) {
|
||||
auto previous = panel->getPreviousField();
|
||||
if (previous) {
|
||||
previous->setFocus(SET_FOCUS_BACKWARD, this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
FormGroup::onEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool ExpansionPanelHeader::onTouchEnd(coord_t, coord_t)
|
||||
{
|
||||
if (enabled) {
|
||||
static_cast<ExpansionPanel *>(parent)->toggle();
|
||||
setFocus(SET_FOCUS_DEFAULT);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "form.h"
|
||||
|
||||
class ExpansionPanel;
|
||||
|
||||
class ExpansionPanelHeader: virtual public FormGroup
|
||||
{
|
||||
public:
|
||||
explicit ExpansionPanelHeader(ExpansionPanel * parent);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "ExpansionPanelHeader";
|
||||
}
|
||||
#endif
|
||||
|
||||
void onEvent(event_t event) override;
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool onTouchEnd(coord_t, coord_t) override;
|
||||
#endif
|
||||
};
|
||||
|
||||
class ExpansionPanel: public FormGroup
|
||||
{
|
||||
friend class ExpansionPanelHeader;
|
||||
|
||||
public:
|
||||
ExpansionPanel(Window * parent, const rect_t & rect):
|
||||
FormGroup(parent, rect, FORM_NO_BORDER | FORM_FORWARD_FOCUS | FORWARD_SCROLL)
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "ExpansionPanel";
|
||||
}
|
||||
#endif
|
||||
|
||||
void toggle()
|
||||
{
|
||||
open(!isOpen);
|
||||
}
|
||||
|
||||
virtual void open(bool state = true)
|
||||
{
|
||||
isOpen = state;
|
||||
updateHeight();
|
||||
}
|
||||
|
||||
void setCloseAllowed(bool value = true)
|
||||
{
|
||||
header->enable(value);
|
||||
}
|
||||
|
||||
void enable(bool value = true)
|
||||
{
|
||||
FormGroup::enable(value);
|
||||
header->enable(value);
|
||||
}
|
||||
|
||||
void disable()
|
||||
{
|
||||
open(false);
|
||||
enable(false);
|
||||
}
|
||||
|
||||
void updateHeight(bool move = true);
|
||||
|
||||
void setFocus(uint8_t flag = SET_FOCUS_DEFAULT, Window * from = nullptr) override;
|
||||
|
||||
FormGroup * body = nullptr;
|
||||
|
||||
protected:
|
||||
ExpansionPanelHeader * header = nullptr;
|
||||
bool isOpen = false;
|
||||
};
|
||||
+3
-24
@@ -120,7 +120,7 @@ bool FileChoice::openMenu()
|
||||
|
||||
menu->setCloseHandler([=]() {
|
||||
editMode = false;
|
||||
setFocus(SET_FOCUS_DEFAULT);
|
||||
// setFocus(SET_FOCUS_DEFAULT);
|
||||
});
|
||||
|
||||
return true;
|
||||
@@ -132,29 +132,8 @@ bool FileChoice::openMenu()
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void FileChoice::onEvent(event_t event)
|
||||
void FileChoice::onClicked()
|
||||
{
|
||||
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
|
||||
|
||||
if (event == EVT_KEY_BREAK(KEY_ENTER)) {
|
||||
if (openMenu()) {
|
||||
editMode = true;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
else {
|
||||
FormField::onEvent(event);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool FileChoice::onTouchEnd(coord_t, coord_t)
|
||||
{
|
||||
setFocus(SET_FOCUS_DEFAULT);
|
||||
setEditMode(true);
|
||||
onKeyPress();
|
||||
openMenu();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
+1
-7
@@ -35,13 +35,7 @@ public:
|
||||
std::string getName() const override { return "FileChoice"; }
|
||||
#endif
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void onEvent(event_t event) override;
|
||||
#endif
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool onTouchEnd(coord_t x, coord_t y) override;
|
||||
#endif
|
||||
void onClicked() override;
|
||||
|
||||
protected:
|
||||
std::string getLabelText() override;
|
||||
|
||||
+27
-210
@@ -21,71 +21,45 @@
|
||||
#include "bitmapbuffer.h"
|
||||
#include "libopenui_config.h"
|
||||
|
||||
#include "widgets/window_base.h"
|
||||
|
||||
FormField::FormField(Window* parent, const rect_t& rect,
|
||||
WindowFlags windowFlags, LcdFlags textFlags,
|
||||
LvglCreate objConstruct) :
|
||||
Window(parent, rect, windowFlags, textFlags, objConstruct)
|
||||
{
|
||||
if (!(windowFlags & NO_FOCUS) || (windowFlags & FORM_FORWARD_FOCUS)) {
|
||||
auto cont = dynamic_cast<FieldContainer*>(parent);
|
||||
if (cont) {
|
||||
cont->addField(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void FormField::onEvent(event_t event)
|
||||
void FormField::setEditMode(bool newEditMode)
|
||||
{
|
||||
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString("FormField").c_str(), event);
|
||||
editMode = newEditMode;
|
||||
|
||||
if (event == EVT_ROTARY_RIGHT/*EVT_KEY_BREAK(KEY_DOWN)*/) {
|
||||
if (next) {
|
||||
onKeyPress();
|
||||
next->setFocus(SET_FOCUS_FORWARD, this);
|
||||
}
|
||||
if (lvobj != nullptr) {
|
||||
lv_group_t* grp = (lv_group_t*)lv_obj_get_group(lvobj);
|
||||
if (grp != nullptr) lv_group_set_editing(grp, editMode);
|
||||
}
|
||||
else if (event == EVT_ROTARY_LEFT/*EVT_KEY_BREAK(KEY_UP)*/) {
|
||||
if (previous) {
|
||||
onKeyPress();
|
||||
previous->setFocus(SET_FOCUS_BACKWARD, this);
|
||||
}
|
||||
|
||||
if (editMode && lvobj != nullptr) {
|
||||
lv_obj_add_state(lvobj, LV_STATE_EDITED);
|
||||
} else if (lvobj != nullptr) {
|
||||
lv_obj_clear_state(lvobj, LV_STATE_EDITED);
|
||||
}
|
||||
else if (event == EVT_KEY_BREAK(KEY_ENTER)) {
|
||||
onKeyPress();
|
||||
setEditMode(!editMode);
|
||||
invalidate();
|
||||
}
|
||||
else if (event == EVT_KEY_BREAK(KEY_EXIT) && editMode) {
|
||||
onKeyPress();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void FormField::onClicked()
|
||||
{
|
||||
setEditMode(!editMode);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void FormField::onCancel()
|
||||
{
|
||||
if (isEditMode()) {
|
||||
setEditMode(false);
|
||||
invalidate();
|
||||
}
|
||||
else {
|
||||
Window::onEvent(event);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
extern lv_group_t* inputGroup;
|
||||
void FormField::setFocus(uint8_t flag, Window * from)
|
||||
{
|
||||
if (enabled && !lv_obj_has_flag(lvobj, LV_OBJ_FLAG_HIDDEN)) {
|
||||
Window::setFocus(flag, from);
|
||||
if(lvobj != nullptr) {
|
||||
lv_group_focus_obj(lvobj);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (flag == SET_FOCUS_BACKWARD) {
|
||||
if (previous) {
|
||||
previous->setFocus(flag, this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (next) {
|
||||
next->setFocus(flag, this);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Window::onCancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,35 +100,11 @@ void FormGroup::Line::addChild(Window* window)
|
||||
}
|
||||
}
|
||||
|
||||
void FormGroup::Line::addField(FormField *field)
|
||||
{
|
||||
group->addField(field);
|
||||
}
|
||||
|
||||
void FormGroup::Line::removeField(FormField *field)
|
||||
{
|
||||
auto form = static_cast<FormGroup*>(parent);
|
||||
form->removeField(field);
|
||||
}
|
||||
|
||||
FormGroup::FormGroup(Window* parent, const rect_t& rect,
|
||||
WindowFlags windowflags, LvglCreate objConstruct) :
|
||||
FormField(parent, rect, windowflags, 0, objConstruct)
|
||||
Window(parent, rect, windowflags, 0, objConstruct)
|
||||
{
|
||||
lv_obj_set_style_bg_opa(lvobj, LV_OPA_TRANSP, LV_PART_MAIN);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void FormGroup::clear()
|
||||
{
|
||||
Window::clear();
|
||||
first = nullptr;
|
||||
last = nullptr;
|
||||
if (previous && (windowFlags & FORM_FORWARD_FOCUS)) {
|
||||
previous->setNextField(this);
|
||||
}
|
||||
}
|
||||
|
||||
void FormGroup::setFlexLayout(lv_flex_flow_t flow, lv_coord_t padding)
|
||||
@@ -175,136 +125,3 @@ FormGroup::Line* FormGroup::newLine(FlexGridLayout* layout)
|
||||
auto lv_line = window_create(lvobj);
|
||||
return new Line(this, lv_line, layout);
|
||||
}
|
||||
|
||||
void FormGroup::removeField(FormField * field)
|
||||
{
|
||||
FormField* prev = field->getPreviousField();
|
||||
FormField* next = field->getNextField();
|
||||
|
||||
if (prev) { prev->setNextField(next); }
|
||||
if (next) { next->setPreviousField(prev); }
|
||||
|
||||
if (first == field) {
|
||||
if (prev && (prev != field)) first = prev;
|
||||
else if (next && (next != field)) first = next;
|
||||
else first = nullptr;
|
||||
}
|
||||
|
||||
if (last == field) {
|
||||
if (next && (next != field)) last = next;
|
||||
else if (prev && (prev != field)) last = prev;
|
||||
else last = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void FormGroup::addField(FormField * field)
|
||||
{
|
||||
if (field->getWindowFlags() & FORM_DETACHED)
|
||||
return;
|
||||
|
||||
if (last)
|
||||
link(last, field);
|
||||
last = field;
|
||||
if (!first)
|
||||
first = field;
|
||||
|
||||
if (WRAP_FORM_FIELDS_WITHIN_PAGE) {
|
||||
if (previous && (windowFlags & FORM_FORWARD_FOCUS)) {
|
||||
last->setNextField(this);
|
||||
link(previous, first);
|
||||
}
|
||||
else {
|
||||
link(last, first);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (windowFlags & FORM_FORWARD_FOCUS) {
|
||||
last->setNextField(this);
|
||||
if (previous)
|
||||
link(previous, first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FormGroup::setFocus(uint8_t flag, Window * from)
|
||||
{
|
||||
TRACE_WINDOWS("%s setFocus(%d)", getWindowDebugString("FormGroup").c_str(), flag);
|
||||
|
||||
if (windowFlags & FORM_FORWARD_FOCUS) {
|
||||
switch (flag) {
|
||||
case SET_FOCUS_BACKWARD:
|
||||
if (from && from->isChild(first)) {
|
||||
if (previous == this) {
|
||||
last->setFocus(SET_FOCUS_BACKWARD, this);
|
||||
}
|
||||
else if (previous) {
|
||||
previous->setFocus(SET_FOCUS_BACKWARD, this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (last) {
|
||||
last->setFocus(SET_FOCUS_BACKWARD, this);
|
||||
}
|
||||
else if (previous) {
|
||||
previous->setFocus(SET_FOCUS_BACKWARD, this);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SET_FOCUS_FIRST:
|
||||
clearFocus();
|
||||
// no break;
|
||||
|
||||
case SET_FOCUS_FORWARD:
|
||||
if (from && from->isChild(this)) {
|
||||
if (next == this) {
|
||||
if (first)
|
||||
first->setFocus(SET_FOCUS_FORWARD, this);
|
||||
}
|
||||
else if (next) {
|
||||
next->setFocus(SET_FOCUS_FORWARD, this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (first) {
|
||||
first->setFocus(SET_FOCUS_FORWARD, this);
|
||||
}
|
||||
else if (next) {
|
||||
next->setFocus(SET_FOCUS_FORWARD, this);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (from == previous) {
|
||||
if (first) {
|
||||
first->setFocus(SET_FOCUS_DEFAULT);
|
||||
}
|
||||
else {
|
||||
clearFocus();
|
||||
focusWindow = this;
|
||||
}
|
||||
}
|
||||
else if (next) {
|
||||
next->setFocus(SET_FOCUS_FORWARD);
|
||||
}
|
||||
else {
|
||||
clearFocus();
|
||||
focusWindow = this;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!(windowFlags & NO_FOCUS)) {
|
||||
FormField::setFocus(flag, from);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void FormGroup::onEvent(event_t event)
|
||||
{
|
||||
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString("FormGroup").c_str(), event);
|
||||
|
||||
FormField::onEvent(event);
|
||||
}
|
||||
#endif
|
||||
|
||||
+8
-76
@@ -36,9 +36,7 @@ class FormField : public Window
|
||||
|
||||
virtual void changeEnd(bool forceChanged = false)
|
||||
{
|
||||
if (changeHandler) {
|
||||
changeHandler();
|
||||
}
|
||||
if (changeHandler) { changeHandler(); }
|
||||
}
|
||||
|
||||
void setChangeHandler(std::function<void()> handler)
|
||||
@@ -51,33 +49,10 @@ class FormField : public Window
|
||||
backgroundHandler = std::move(handler);
|
||||
}
|
||||
|
||||
inline void setNextField(FormField *field) { next = field; }
|
||||
|
||||
inline void setPreviousField(FormField *field) { previous = field; }
|
||||
|
||||
inline FormField *getPreviousField() { return previous; }
|
||||
|
||||
inline FormField *getNextField() { return next; }
|
||||
|
||||
inline bool isEditMode() const { return editMode; }
|
||||
virtual void setEditMode(bool newEditMode);
|
||||
|
||||
virtual void setEditMode(bool newEditMode)
|
||||
{
|
||||
editMode = newEditMode;
|
||||
|
||||
// if (lvobj != nullptr) {
|
||||
// lv_group_t *grp = (lv_group_t *)lv_obj_get_group(lvobj);
|
||||
// if (grp != nullptr) lv_group_set_editing(grp, editMode);
|
||||
// }
|
||||
|
||||
if (editMode && lvobj != nullptr) {
|
||||
lv_obj_add_state(lvobj, LV_STATE_EDITED);
|
||||
} else if (lvobj != nullptr) {
|
||||
lv_obj_clear_state(lvobj, LV_STATE_EDITED);
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
|
||||
// TODO: replace with LVGL flags
|
||||
void enable(bool value = true)
|
||||
{
|
||||
enabled = value;
|
||||
@@ -87,45 +62,26 @@ class FormField : public Window
|
||||
bool isEnabled() const { return enabled; }
|
||||
void disable() { enable(false); }
|
||||
|
||||
void setFocus(uint8_t flag = SET_FOCUS_DEFAULT,
|
||||
Window *from = nullptr) override;
|
||||
|
||||
void onFocusLost() override
|
||||
{
|
||||
setEditMode(false);
|
||||
Window::onFocusLost();
|
||||
}
|
||||
|
||||
inline static void link(FormField *previous, FormField *next)
|
||||
{
|
||||
previous->setNextField(next);
|
||||
next->setPreviousField(previous);
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void onEvent(event_t event) override;
|
||||
#endif
|
||||
|
||||
void onClicked() override;
|
||||
void onCancel() override;
|
||||
|
||||
protected:
|
||||
FormField *next = nullptr;
|
||||
FormField *previous = nullptr;
|
||||
bool editMode = false;
|
||||
bool enabled = true;
|
||||
std::function<void()> changeHandler = nullptr;
|
||||
std::function<uint32_t(FormField *)> backgroundHandler = nullptr;
|
||||
};
|
||||
|
||||
class FieldContainer
|
||||
class FormGroup : public Window
|
||||
{
|
||||
public:
|
||||
virtual void addField(FormField *field) = 0;
|
||||
virtual void removeField(FormField *field) = 0;
|
||||
};
|
||||
|
||||
class FormGroup : public FormField, public FieldContainer
|
||||
{
|
||||
public:
|
||||
class Line : public Window, public FieldContainer
|
||||
class Line : public Window
|
||||
{
|
||||
FlexGridLayout* layout;
|
||||
FormGroup* group;
|
||||
@@ -138,8 +94,6 @@ class FormGroup : public FormField, public FieldContainer
|
||||
|
||||
protected:
|
||||
void addChild(Window* window) override;
|
||||
void addField(FormField *field) override;
|
||||
void removeField(FormField *field) override;
|
||||
};
|
||||
|
||||
FormGroup(Window *parent, const rect_t &rect, WindowFlags windowflags = 0,
|
||||
@@ -149,30 +103,8 @@ class FormGroup : public FormField, public FieldContainer
|
||||
std::string getName() const override { return "FormGroup"; }
|
||||
#endif
|
||||
|
||||
void clear();
|
||||
|
||||
void setFlexLayout(lv_flex_flow_t flow = LV_FLEX_FLOW_COLUMN, lv_coord_t padding = 0);
|
||||
Line* newLine(FlexGridLayout* layout = nullptr);
|
||||
|
||||
void setFocus(uint8_t flag = SET_FOCUS_DEFAULT,
|
||||
Window *from = nullptr) override;
|
||||
|
||||
void addField(FormField *field) override;
|
||||
void removeField(FormField *field) override;
|
||||
|
||||
void setFirstField(FormField *field) { first = field; }
|
||||
void setLastField(FormField *field) { last = field; }
|
||||
FormField *getFirstField() const { return first; }
|
||||
FormField *getLastField() const { return last; }
|
||||
|
||||
|
||||
protected:
|
||||
FormField *first = nullptr;
|
||||
FormField *last = nullptr;
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void onEvent(event_t event) override;
|
||||
#endif
|
||||
};
|
||||
|
||||
class FormWindow : public FormGroup
|
||||
|
||||
+57
-8
@@ -17,6 +17,8 @@
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
#include "keyboard_base.h"
|
||||
|
||||
#include "form.h"
|
||||
#include "mainwindow.h"
|
||||
|
||||
Keyboard * Keyboard::activeKeyboard = nullptr;
|
||||
@@ -24,28 +26,66 @@ Keyboard * Keyboard::activeKeyboard = nullptr;
|
||||
static void keyboard_event_cb(lv_event_t * e)
|
||||
{
|
||||
auto code = lv_event_get_code(e);
|
||||
Keyboard *kb = (Keyboard *) lv_event_get_user_data(e);
|
||||
if (code == LV_EVENT_READY) {
|
||||
pushEvent(EVT_VIRTUAL_KEY('\n'));
|
||||
kb->hide();
|
||||
Keyboard::hide();
|
||||
} else if (code == LV_EVENT_CANCEL) {
|
||||
Keyboard::hide();
|
||||
} else if (code == LV_EVENT_KEY) {
|
||||
int32_t c = *((int32_t *)lv_event_get_param(e));
|
||||
if (c == LV_KEY_ESC) {
|
||||
Keyboard::hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void field_focus_leave(lv_event_t* e)
|
||||
{
|
||||
Keyboard::hide();
|
||||
}
|
||||
|
||||
static void _assign_lv_group(lv_group_t* g)
|
||||
{
|
||||
// associate it with all input devices
|
||||
lv_indev_t* indev = lv_indev_get_next(NULL);
|
||||
while (indev) {
|
||||
lv_indev_set_group(indev, g);
|
||||
indev = lv_indev_get_next(indev);
|
||||
}
|
||||
}
|
||||
|
||||
Keyboard::Keyboard(coord_t height) :
|
||||
FormWindow(MainWindow::instance(), {0, LCD_H - height, LCD_W, height}, OPAQUE)
|
||||
Window(MainWindow::instance(), {0, LCD_H - height, LCD_W, height}, OPAQUE)
|
||||
{
|
||||
// set the background of the window and opacity to 100%
|
||||
lv_obj_set_parent(lvobj, lv_layer_top()); // the keyboard is always on top
|
||||
lv_obj_set_style_bg_color(lvobj, lv_color_make(0xE0, 0xE0, 0xE0), LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_opa(lvobj, LV_OPA_100, LV_PART_MAIN);
|
||||
|
||||
keyboard = lv_keyboard_create(this->getLvObj());
|
||||
// use a separate group for the keyboard
|
||||
group = lv_group_create();
|
||||
lv_group_set_editing(group, true);
|
||||
|
||||
auto old_g = lv_group_get_default();
|
||||
lv_group_set_default(group);
|
||||
|
||||
keyboard = lv_keyboard_create(lvobj);
|
||||
lv_group_set_default(old_g);
|
||||
|
||||
lv_obj_add_event_cb(keyboard, keyboard_event_cb, LV_EVENT_ALL, this);
|
||||
|
||||
lv_obj_set_pos(keyboard, 0, 0);
|
||||
lv_obj_set_size(keyboard, LCD_W, height);
|
||||
|
||||
// TODO: really needed ???
|
||||
lv_obj_clear_flag(keyboard, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
Keyboard::~Keyboard()
|
||||
{
|
||||
if (group) lv_group_del(group);
|
||||
}
|
||||
|
||||
void Keyboard::clearField()
|
||||
{
|
||||
TRACE("CLEAR FIELD");
|
||||
@@ -62,10 +102,16 @@ void Keyboard::clearField()
|
||||
}
|
||||
|
||||
if (field) {
|
||||
// restore field's group
|
||||
auto obj = field->getLvObj();
|
||||
lv_obj_remove_event_cb(obj, field_focus_leave);
|
||||
lv_group_t* g = (lv_group_t*)lv_obj_get_group(obj);
|
||||
if (g) _assign_lv_group(g);
|
||||
|
||||
field->setEditMode(false);
|
||||
field->changeEnd();
|
||||
field = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Keyboard::hide()
|
||||
@@ -81,7 +127,7 @@ bool Keyboard::attachKeyboard()
|
||||
{
|
||||
if (activeKeyboard) {
|
||||
if (activeKeyboard == this) return false;
|
||||
activeKeyboard->clearField();
|
||||
hide();
|
||||
}
|
||||
|
||||
activeKeyboard = this;
|
||||
@@ -113,8 +159,11 @@ void Keyboard::setField(FormField* newField)
|
||||
|
||||
invalidate();
|
||||
newField->setEditMode(true);
|
||||
lv_keyboard_set_textarea(keyboard, newField->getLvObj());
|
||||
|
||||
|
||||
lv_keyboard_set_textarea(keyboard, obj);
|
||||
lv_obj_add_event_cb(obj, field_focus_leave, LV_EVENT_DEFOCUSED, nullptr);
|
||||
_assign_lv_group(group);
|
||||
|
||||
field = newField;
|
||||
}
|
||||
}
|
||||
|
||||
+20
-15
@@ -19,24 +19,29 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "form.h"
|
||||
#include "window.h"
|
||||
|
||||
class Keyboard: public FormWindow
|
||||
class FormField;
|
||||
|
||||
class Keyboard : public Window
|
||||
{
|
||||
public:
|
||||
explicit Keyboard(coord_t height);
|
||||
void clearField();
|
||||
static void hide();
|
||||
public:
|
||||
explicit Keyboard(coord_t height);
|
||||
~Keyboard();
|
||||
|
||||
protected:
|
||||
static Keyboard * activeKeyboard;
|
||||
lv_obj_t * keyboard = nullptr;
|
||||
void clearField();
|
||||
static void hide();
|
||||
|
||||
FormField *field = nullptr;
|
||||
Window *fieldContainer = nullptr;
|
||||
lv_coord_t scroll_pos = 0;
|
||||
protected:
|
||||
static Keyboard *activeKeyboard;
|
||||
|
||||
void setField(FormField *newField);
|
||||
bool attachKeyboard();
|
||||
lv_group_t* group = nullptr;
|
||||
lv_obj_t* keyboard = nullptr;
|
||||
|
||||
FormField* field = nullptr;
|
||||
Window* fieldContainer = nullptr;
|
||||
lv_coord_t scroll_pos = 0;
|
||||
|
||||
void setField(FormField* newField);
|
||||
bool attachKeyboard();
|
||||
};
|
||||
|
||||
|
||||
+64
-50
@@ -18,64 +18,63 @@
|
||||
*/
|
||||
|
||||
#include "keyboard_number.h"
|
||||
#include "button.h"
|
||||
#include "numberedit.h"
|
||||
|
||||
constexpr coord_t KEYBOARD_HEIGHT = 90;
|
||||
NumberKeyboard * NumberKeyboard::_instance = nullptr;
|
||||
|
||||
static const char* number_kb_map[] = {
|
||||
"<<", "-", "+", ">>", "\n",
|
||||
"MIN", "DEF", "+/-", "MAX", ""
|
||||
};
|
||||
|
||||
#define LV_KB_BTN(width) LV_BTNMATRIX_CTRL_POPOVER | width
|
||||
#define LV_KB_CTRL(width) LV_KEYBOARD_CTRL_BTN_FLAGS | width
|
||||
|
||||
static const lv_btnmatrix_ctrl_t number_kb_ctrl_map[] = {
|
||||
LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_BTN(4),
|
||||
LV_KB_BTN(4), LV_KB_BTN(4), LV_KB_CTRL(4), LV_KB_BTN(4)
|
||||
};
|
||||
|
||||
static void on_key(lv_event_t* e)
|
||||
{
|
||||
lv_obj_t * obj = lv_event_get_target(e);
|
||||
NumberEdit* edit = (NumberEdit*)lv_event_get_user_data(e);
|
||||
if (!obj || !edit) return;
|
||||
|
||||
uint16_t btn_id = lv_btnmatrix_get_selected_btn(obj);
|
||||
if(btn_id == LV_BTNMATRIX_BTN_NONE) return;
|
||||
|
||||
const char * txt = lv_btnmatrix_get_btn_text(obj, lv_btnmatrix_get_selected_btn(obj));
|
||||
if(txt == NULL) return;
|
||||
|
||||
if (strcmp(txt, "<<") == 0) {
|
||||
edit->onEvent(EVT_VIRTUAL_KEY_BACKWARD);
|
||||
} else if (strcmp(txt, "-") == 0) {
|
||||
edit->onEvent(EVT_VIRTUAL_KEY_MINUS);
|
||||
} else if (strcmp(txt, "+") == 0) {
|
||||
edit->onEvent(EVT_VIRTUAL_KEY_PLUS);
|
||||
} else if (strcmp(txt, ">>") == 0) {
|
||||
edit->onEvent(EVT_VIRTUAL_KEY_FORWARD);
|
||||
} else if (strcmp(txt, "MIN") == 0) {
|
||||
edit->onEvent(EVT_VIRTUAL_KEY_MIN);
|
||||
} else if (strcmp(txt, "DEF") == 0) {
|
||||
edit->onEvent(EVT_VIRTUAL_KEY_DEFAULT);
|
||||
} else if (strcmp(txt, "MAX") == 0) {
|
||||
edit->onEvent(EVT_VIRTUAL_KEY_MAX);
|
||||
} else if (strcmp(txt, "+/-") == 0) {
|
||||
edit->onEvent(EVT_VIRTUAL_KEY_SIGN);
|
||||
}
|
||||
}
|
||||
|
||||
NumberKeyboard::NumberKeyboard() :
|
||||
Keyboard(KEYBOARD_HEIGHT)
|
||||
{
|
||||
// ToDo: for now we are still using the old keyboard
|
||||
lv_obj_add_flag(keyboard, LV_OBJ_FLAG_HIDDEN);
|
||||
// setup custom keyboard
|
||||
lv_keyboard_set_map(keyboard, LV_KEYBOARD_MODE_USER_1,
|
||||
number_kb_map, number_kb_ctrl_map);
|
||||
|
||||
new TextButton(this, {LCD_W / 2 - 115, 10, 50, 30}, "<<",
|
||||
[=]() -> uint8_t {
|
||||
pushEvent(EVT_VIRTUAL_KEY_BACKWARD);
|
||||
return 0;
|
||||
}, BUTTON_BACKGROUND | OPAQUE | NO_FOCUS);
|
||||
|
||||
new TextButton(this, {LCD_W / 2 - 55, 10, 50, 30}, "-",
|
||||
[=]() -> uint8_t {
|
||||
pushEvent(EVT_VIRTUAL_KEY_MINUS);
|
||||
return 0;
|
||||
}, BUTTON_BACKGROUND | OPAQUE | NO_FOCUS);
|
||||
|
||||
new TextButton(this, {LCD_W / 2 + 5, 10, 50, 30}, "+",
|
||||
[=]() -> uint8_t {
|
||||
pushEvent(EVT_VIRTUAL_KEY_PLUS);
|
||||
return 0;
|
||||
}, BUTTON_BACKGROUND | OPAQUE | NO_FOCUS);
|
||||
|
||||
new TextButton(this, {LCD_W / 2 + 65, 10, 50, 30}, ">>",
|
||||
[=]() -> uint8_t {
|
||||
pushEvent(EVT_VIRTUAL_KEY_FORWARD);
|
||||
return 0;
|
||||
}, BUTTON_BACKGROUND | OPAQUE | NO_FOCUS);
|
||||
|
||||
new TextButton(this, {LCD_W / 2 - 115, 50, 50, 30}, "MIN",
|
||||
[=]() -> uint8_t {
|
||||
pushEvent(EVT_VIRTUAL_KEY_MIN);
|
||||
return 0;
|
||||
}, BUTTON_BACKGROUND | OPAQUE | NO_FOCUS);
|
||||
|
||||
new TextButton(this, {LCD_W / 2 + 65, 50, 50, 30}, "MAX",
|
||||
[=]() -> uint8_t {
|
||||
pushEvent(EVT_VIRTUAL_KEY_MAX);
|
||||
return 0;
|
||||
}, BUTTON_BACKGROUND | OPAQUE | NO_FOCUS);
|
||||
|
||||
new TextButton(this, { LCD_W/2 - 55, 50, 50, 30 }, "DEF",
|
||||
[=]() -> uint8_t {
|
||||
pushEvent(EVT_VIRTUAL_KEY_DEFAULT);
|
||||
return 0;
|
||||
}, BUTTON_BACKGROUND | OPAQUE | NO_FOCUS);
|
||||
|
||||
new TextButton(this, { LCD_W/2 + 5, 50, 50, 30 }, "+/-",
|
||||
[=]() -> uint8_t {
|
||||
pushEvent(EVT_VIRTUAL_KEY_SIGN);
|
||||
return 0;
|
||||
}, BUTTON_BACKGROUND | OPAQUE | NO_FOCUS);
|
||||
lv_keyboard_set_mode(keyboard, LV_KEYBOARD_MODE_USER_1);
|
||||
}
|
||||
|
||||
NumberKeyboard::~NumberKeyboard()
|
||||
@@ -83,3 +82,18 @@ NumberKeyboard::~NumberKeyboard()
|
||||
_instance = nullptr;
|
||||
}
|
||||
|
||||
void NumberKeyboard::show(NumberEdit* field)
|
||||
{
|
||||
if (!_instance) _instance = new NumberKeyboard();
|
||||
|
||||
lv_obj_clear_flag(_instance->lvobj, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(_instance->keyboard, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
_instance->setField(field);
|
||||
|
||||
auto kb = _instance->keyboard;
|
||||
lv_keyboard_set_textarea(kb, nullptr);
|
||||
|
||||
lv_obj_remove_event_cb(kb, on_key);
|
||||
lv_obj_add_event_cb(kb, on_key, LV_EVENT_VALUE_CHANGED, field);
|
||||
}
|
||||
|
||||
+10
-27
@@ -21,37 +21,20 @@
|
||||
|
||||
#include "keyboard_base.h"
|
||||
|
||||
class NumberKeyboard : public Keyboard {
|
||||
public:
|
||||
NumberKeyboard();
|
||||
class NumberEdit;
|
||||
|
||||
~NumberKeyboard() override;
|
||||
class NumberKeyboard : public Keyboard
|
||||
{
|
||||
public:
|
||||
NumberKeyboard();
|
||||
~NumberKeyboard() override;
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "NumberKeyboard";
|
||||
}
|
||||
std::string getName() const override { return "NumberKeyboard"; }
|
||||
#endif
|
||||
|
||||
static void show(FormField * field)
|
||||
{
|
||||
if (!_instance)
|
||||
_instance = new NumberKeyboard();
|
||||
// else
|
||||
// lv_obj_clear_flag(_instance->keyboard, LV_OBJ_FLAG_HIDDEN);
|
||||
static void show(NumberEdit* field);
|
||||
|
||||
// lv_keyboard_set_mode(keyboard, LV_KEYBOARD_MODE_NUMBER);
|
||||
|
||||
lv_obj_clear_flag(_instance->lvobj, LV_OBJ_FLAG_HIDDEN);
|
||||
// lv_obj_clear_flag(_instance->keyboard, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_keyboard_set_mode(_instance->keyboard, LV_KEYBOARD_MODE_NUMBER);
|
||||
lv_obj_move_foreground(_instance->getLvObj());
|
||||
|
||||
_instance->setField(field);
|
||||
}
|
||||
|
||||
protected:
|
||||
static NumberKeyboard * _instance;
|
||||
protected:
|
||||
static NumberKeyboard* _instance;
|
||||
};
|
||||
|
||||
|
||||
@@ -39,3 +39,14 @@ void TextKeyboard::onEvent(event_t event)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
void TextKeyboard::show(FormField* field)
|
||||
{
|
||||
if (!_instance) _instance = new TextKeyboard();
|
||||
|
||||
lv_obj_clear_flag(_instance->lvobj, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(_instance->keyboard, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_keyboard_set_mode(_instance->keyboard, LV_KEYBOARD_MODE_TEXT_LOWER);
|
||||
|
||||
_instance->setField(field);
|
||||
}
|
||||
|
||||
+10
-24
@@ -36,36 +36,22 @@
|
||||
#define KEYBOARD_ENTER_WIDTH 80
|
||||
#define KEYBOARD_BITMAP_WIDTH 45
|
||||
|
||||
class TextKeyboard : public Keyboard {
|
||||
public:
|
||||
TextKeyboard();
|
||||
|
||||
~TextKeyboard() override;
|
||||
class TextKeyboard : public Keyboard
|
||||
{
|
||||
public:
|
||||
TextKeyboard();
|
||||
~TextKeyboard() override;
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "TextKeyboard";
|
||||
}
|
||||
std::string getName() const override { return "TextKeyboard"; }
|
||||
#endif
|
||||
|
||||
static void show(FormField * field)
|
||||
{
|
||||
if (!_instance)
|
||||
_instance = new TextKeyboard();
|
||||
static void show(FormField* field);
|
||||
|
||||
lv_obj_clear_flag(_instance->lvobj, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(_instance->keyboard, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_keyboard_set_mode(_instance->keyboard, LV_KEYBOARD_MODE_TEXT_LOWER);
|
||||
_instance->setField(field);
|
||||
}
|
||||
|
||||
protected:
|
||||
protected:
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void onEvent(event_t event) override;
|
||||
void onEvent(event_t event) override;
|
||||
#endif
|
||||
|
||||
static TextKeyboard * _instance;
|
||||
// const char * const * layout;
|
||||
static TextKeyboard* _instance;
|
||||
};
|
||||
|
||||
|
||||
+64
@@ -20,3 +20,67 @@
|
||||
#include "layer.h"
|
||||
|
||||
std::list<Layer> Layer::stack;
|
||||
|
||||
Layer::Layer(Window* w, lv_group_t* g) : window(w), group(g) {}
|
||||
Layer::~Layer() { lv_group_del(group); }
|
||||
|
||||
static void _assign_lv_group(lv_group_t* g)
|
||||
{
|
||||
lv_group_set_default(g);
|
||||
|
||||
// associate it with all input devices
|
||||
lv_indev_t* indev = lv_indev_get_next(NULL);
|
||||
while (indev) {
|
||||
lv_indev_set_group(indev, g);
|
||||
indev = lv_indev_get_next(indev);
|
||||
}
|
||||
}
|
||||
|
||||
void Layer::push(Window* w)
|
||||
{
|
||||
// create a new group
|
||||
auto g = lv_group_create();
|
||||
_assign_lv_group(g);
|
||||
|
||||
// and store
|
||||
stack.emplace_back(w, g);
|
||||
}
|
||||
|
||||
void Layer::pop(Window* w)
|
||||
{
|
||||
if (stack.empty()) return;
|
||||
|
||||
if (back() == w) {
|
||||
stack.pop_back();
|
||||
} else {
|
||||
for (auto layer = stack.crbegin(); layer != stack.crend(); layer++) {
|
||||
if (layer->window == w) {
|
||||
stack.erase(layer.base());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!stack.empty()) {
|
||||
lv_group_t* g = stack.back().group;
|
||||
_assign_lv_group(g);
|
||||
} else {
|
||||
lv_group_set_default(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
Window* Layer::back()
|
||||
{
|
||||
if (stack.empty()) return nullptr;
|
||||
return stack.back().window;
|
||||
}
|
||||
|
||||
Window* Layer::getFirstOpaque()
|
||||
{
|
||||
for (auto layer = stack.crbegin(); layer != stack.crend(); layer++) {
|
||||
auto w = layer->window;
|
||||
if (w && (w->getWindowFlags() & OPAQUE)) return w;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
+10
-58
@@ -20,69 +20,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "window.h"
|
||||
extern lv_obj_t * canvas;
|
||||
|
||||
class Layer
|
||||
{
|
||||
public:
|
||||
explicit Layer(Window * main):
|
||||
main(main)
|
||||
{
|
||||
}
|
||||
static std::list<Layer> stack;
|
||||
|
||||
Window * main;
|
||||
Window * focus = nullptr;
|
||||
Window* window;
|
||||
lv_group_t* group;
|
||||
|
||||
static std::list<Layer> stack;
|
||||
public:
|
||||
explicit Layer(Window* w, lv_group_t* g);
|
||||
~Layer();
|
||||
|
||||
static void push(Window * window)
|
||||
{
|
||||
static void push(Window* window);
|
||||
static void pop(Window* window);
|
||||
|
||||
if (!stack.empty()) {
|
||||
Layer & parentLayer = stack.back();
|
||||
parentLayer.focus = Window::getFocus();
|
||||
}
|
||||
|
||||
|
||||
stack.emplace_back(Layer(window));
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
TRACE_WINDOWS("New layer added for %s (%d layers)", window->getWindowDebugString().c_str(), stack.size());
|
||||
for (auto & layer: stack) {
|
||||
TRACE_WINDOWS(" - %s (focus=%s)", layer.main->getWindowDebugString().c_str(), layer.focus ? layer.focus->getWindowDebugString().c_str() : "---");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void pop(Window * window)
|
||||
{
|
||||
if (stack.back().main == window) {
|
||||
stack.pop_back();
|
||||
const auto & back = stack.back();
|
||||
if (back.focus) {
|
||||
back.focus->setFocus(SET_FOCUS_DEFAULT);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO it would be better to do it in reverse order
|
||||
for (auto it = stack.begin(); it != stack.end(); it++) {
|
||||
if (it->main == window) {
|
||||
stack.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
TRACE_WINDOWS("Layer removed for %s (%d layers)", window->getWindowDebugString().c_str(), stack.size());
|
||||
for (auto & layer: stack) {
|
||||
TRACE_WINDOWS(" - %s (focus=%s)", layer.main->getWindowDebugString().c_str(), layer.focus ? layer.focus->getWindowDebugString().c_str() : "---");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static Window* back()
|
||||
{
|
||||
return stack.back().main;
|
||||
}
|
||||
static Window* back();
|
||||
static Window* getFirstOpaque();
|
||||
};
|
||||
|
||||
+4
-15
@@ -36,7 +36,7 @@ MainWindow::MainWindow() :
|
||||
Window(nullptr, {0, 0, LCD_W, LCD_H}, OPAQUE),
|
||||
invalidatedRect(rect)
|
||||
{
|
||||
Layer::push(this);
|
||||
// Layer::push(this);
|
||||
}
|
||||
|
||||
void MainWindow::emptyTrash()
|
||||
@@ -98,21 +98,10 @@ void MainWindow::run(bool trash)
|
||||
{
|
||||
auto start = ticksNow();
|
||||
|
||||
// KLK: removed for now. This is now
|
||||
// called from lvgl event processing when
|
||||
// necessary
|
||||
auto layer = Layer::stack.rbegin();
|
||||
while (layer != Layer::stack.rend()) {
|
||||
if (layer->main && (layer->main->getWindowFlags() & OPAQUE)) {
|
||||
layer->main->checkEvents();
|
||||
break;
|
||||
}
|
||||
++layer;
|
||||
}
|
||||
auto opaque = Layer::getFirstOpaque();
|
||||
if (opaque) opaque->checkEvents();
|
||||
|
||||
if (trash) {
|
||||
emptyTrash();
|
||||
}
|
||||
if (trash) emptyTrash();
|
||||
|
||||
auto delta = ticksNow() - start;
|
||||
if (delta > 10 * SYSTEM_TICKS_1MS) {
|
||||
|
||||
+18
-49
@@ -60,6 +60,9 @@ MenuBody::MenuBody(Window * parent, const rect_t & rect):
|
||||
{
|
||||
setColumnCount(1);
|
||||
setColumnWidth(0, rect.w);
|
||||
|
||||
lv_group_t* g = (lv_group_t*)lv_obj_get_group(lvobj);
|
||||
if (g) { lv_group_set_editing(g, true); }
|
||||
}
|
||||
|
||||
void MenuBody::addLine(const std::string &text, std::function<void()> onPress,
|
||||
@@ -176,49 +179,11 @@ void MenuBody::selectNext(MENU_DIRECTION direction)
|
||||
}
|
||||
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void MenuBody::onEvent(event_t event)
|
||||
{
|
||||
// TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
|
||||
|
||||
// if (event == EVT_ROTARY_RIGHT) {
|
||||
// if (!lines.empty()) {
|
||||
// selectNext(DIRECTION_UP);
|
||||
// onKeyPress();
|
||||
// }
|
||||
// }
|
||||
// else if (event == EVT_ROTARY_LEFT) {
|
||||
// if (!lines.empty()) {
|
||||
// selectNext(DIRECTION_DOWN);
|
||||
// onKeyPress();
|
||||
// }
|
||||
// }
|
||||
// else if (event == EVT_KEY_BREAK(KEY_ENTER)) {
|
||||
// if (!lines.empty()) {
|
||||
// onKeyPress();
|
||||
// if (selectedIndex < 0) {
|
||||
// setIndex(0);
|
||||
// }
|
||||
// else {
|
||||
// Menu * menu = getParentMenu();
|
||||
// if (menu->multiple) {
|
||||
// lines[selectedIndex].onPress();
|
||||
// menu->invalidate();
|
||||
// }
|
||||
// else {
|
||||
// lines[selectedIndex].onPress();
|
||||
// menu->deleteLater();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
#if defined(HARDWARE_KEYS)
|
||||
if (event == EVT_KEY_BREAK(KEY_EXIT)) {
|
||||
onKeyPress();
|
||||
if (onCancel) {
|
||||
onCancel();
|
||||
}
|
||||
Window::onEvent(event);
|
||||
onCancel();
|
||||
}
|
||||
else {
|
||||
TableField::onEvent(event);
|
||||
@@ -226,12 +191,18 @@ void MenuBody::onEvent(event_t event)
|
||||
}
|
||||
#endif
|
||||
|
||||
void MenuBody::onCancel()
|
||||
{
|
||||
if(_onCancel) _onCancel();
|
||||
TableField::onCancel();
|
||||
}
|
||||
|
||||
MenuWindowContent::MenuWindowContent(Menu* parent) :
|
||||
ModalWindowContent(parent, {(LCD_W - MENUS_WIDTH) / 2,
|
||||
(LCD_H - MENUS_WIDTH) / 2, MENUS_WIDTH, 0}),
|
||||
body(this, {0, 0, width(), height()})
|
||||
{
|
||||
body.setFocus(SET_FOCUS_DEFAULT);
|
||||
// body.setFocus(SET_FOCUS_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(lvobj, LV_OPA_100, LV_PART_MAIN);
|
||||
}
|
||||
|
||||
@@ -305,19 +276,17 @@ void Menu::removeLines()
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void Menu::onEvent(event_t event)
|
||||
{
|
||||
#if defined(HARDWARE_KEYS)
|
||||
if (toolbar && (event == EVT_KEY_BREAK(KEY_PGDN) || event == EVT_KEY_LONG(KEY_PGDN) ||
|
||||
event == EVT_KEY_BREAK(KEY_PGUP))) {
|
||||
toolbar->onEvent(event);
|
||||
}
|
||||
else if (event == EVT_KEY_BREAK(KEY_EXIT)) {
|
||||
deleteLater();
|
||||
}
|
||||
else if (event == EVT_KEY_BREAK(KEY_ENTER) && !multiple) {
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Menu::onCancel()
|
||||
{
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
+8
-10
@@ -92,9 +92,8 @@ class MenuBody: public TableField
|
||||
return lines.size();
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void onEvent(event_t event) override;
|
||||
#endif
|
||||
void onCancel() override;
|
||||
|
||||
void addLine(const std::string &text, std::function<void()> onPress,
|
||||
std::function<bool()> isChecked);
|
||||
@@ -107,7 +106,7 @@ class MenuBody: public TableField
|
||||
|
||||
void setCancelHandler(std::function<void()> handler)
|
||||
{
|
||||
onCancel = std::move(handler);
|
||||
_onCancel = std::move(handler);
|
||||
}
|
||||
|
||||
coord_t getContentHeight();
|
||||
@@ -124,7 +123,7 @@ class MenuBody: public TableField
|
||||
|
||||
std::vector<MenuLine> lines;
|
||||
int selectedIndex = 0;
|
||||
std::function<void()> onCancel;
|
||||
std::function<void()> _onCancel;
|
||||
|
||||
inline Menu * getParentMenu();
|
||||
};
|
||||
@@ -175,10 +174,10 @@ class Menu: public ModalWindow
|
||||
waitHandler = std::move(handler);
|
||||
}
|
||||
|
||||
void setFocusBody(uint8_t flag = SET_FOCUS_DEFAULT)
|
||||
{
|
||||
content->body.setFocus(flag);
|
||||
}
|
||||
// void setFocusBody(uint8_t flag = SET_FOCUS_DEFAULT)
|
||||
// {
|
||||
// content->body.setFocus(flag);
|
||||
// }
|
||||
|
||||
void setToolbar(Window * window);
|
||||
|
||||
@@ -210,9 +209,8 @@ class Menu: public ModalWindow
|
||||
content->body.setIndex(index);
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void onEvent(event_t event) override;
|
||||
#endif
|
||||
void onCancel() override;
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
|
||||
+29
-33
@@ -28,11 +28,7 @@ int getFirstAvailable(int min, int max, std::function<bool(int)>isValueAvailable
|
||||
class MenuToolbarButton: public Button {
|
||||
public:
|
||||
MenuToolbarButton(FormGroup * window, const rect_t & rect, const char* picto):
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
Button(window, rect, nullptr),
|
||||
#else
|
||||
Button(window, rect, nullptr),
|
||||
#endif
|
||||
picto(picto)
|
||||
{
|
||||
}
|
||||
@@ -64,36 +60,36 @@ class MenuToolbar: public FormGroup {
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void onEvent(event_t event) override
|
||||
{
|
||||
if (event == EVT_KEY_BREAK(KEY_PGDN) || event == EVT_KEY_LONG(KEY_PGDN) || event == EVT_KEY_BREAK(KEY_PGUP)) {
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
if (current != children.end()) {
|
||||
static_cast<MenuToolbarButton *>(*current)->onTouchEnd(0,0);
|
||||
}
|
||||
#endif
|
||||
current = IS_KEY_LONG(event) || event == EVT_KEY_BREAK(KEY_PGUP) ?
|
||||
current == children.end() ?
|
||||
--current:
|
||||
current == children.begin() ?
|
||||
children.end() :
|
||||
--current :
|
||||
current == children.end() ?
|
||||
children.begin() :
|
||||
++current;
|
||||
// if (event == EVT_KEY_BREAK(KEY_PGDN) || event == EVT_KEY_LONG(KEY_PGDN) || event == EVT_KEY_BREAK(KEY_PGUP)) {
|
||||
// #if defined(HARDWARE_TOUCH)
|
||||
// if (current != children.end()) {
|
||||
// static_cast<MenuToolbarButton *>(*current)->onTouchEnd(0,0);
|
||||
// }
|
||||
// #endif
|
||||
// current = IS_KEY_LONG(event) || event == EVT_KEY_BREAK(KEY_PGUP) ?
|
||||
// current == children.end() ?
|
||||
// --current:
|
||||
// current == children.begin() ?
|
||||
// children.end() :
|
||||
// --current :
|
||||
// current == children.end() ?
|
||||
// children.begin() :
|
||||
// ++current;
|
||||
|
||||
if (IS_KEY_LONG(event))
|
||||
killEvents(event);
|
||||
// if (IS_KEY_LONG(event))
|
||||
// killEvents(event);
|
||||
|
||||
if (current != children.end()) {
|
||||
auto button = static_cast<MenuToolbarButton *>(*current);
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
button->onTouchEnd(0,0);
|
||||
#endif
|
||||
scrollTo(button);
|
||||
}
|
||||
else {
|
||||
lv_obj_scroll_to_y(lvobj, 0, LV_ANIM_OFF);
|
||||
}
|
||||
}
|
||||
// if (current != children.end()) {
|
||||
// auto button = static_cast<MenuToolbarButton *>(*current);
|
||||
// #if defined(HARDWARE_TOUCH)
|
||||
// button->onTouchEnd(0,0);
|
||||
// #endif
|
||||
// scrollTo(button);
|
||||
// }
|
||||
// else {
|
||||
// lv_obj_scroll_to_y(lvobj, 0, LV_ANIM_OFF);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -139,7 +135,7 @@ class MenuToolbar: public FormGroup {
|
||||
} else {
|
||||
choice->fillMenu(menu, val);
|
||||
}
|
||||
menu->setFocusBody();
|
||||
// menu->setFocusBody();
|
||||
|
||||
// set current for page key procesing
|
||||
current = std::find_if(children.begin(), children.end(), [button](Window *o) { return o == button; });
|
||||
|
||||
+10
-9
@@ -19,6 +19,7 @@
|
||||
|
||||
|
||||
#include "modal_window.h"
|
||||
#include "keyboard_base.h"
|
||||
#include "font.h"
|
||||
#include "layer.h"
|
||||
|
||||
@@ -26,30 +27,25 @@ ModalWindow::ModalWindow(Window * parent, bool closeWhenClickOutside):
|
||||
Window(parent->getFullScreenWindow(), {0, 0, LCD_W, LCD_H}),
|
||||
closeWhenClickOutside(closeWhenClickOutside)
|
||||
{
|
||||
Layer::push(this);
|
||||
lv_obj_set_style_bg_color(lvobj, lv_color_black(), LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_opa(lvobj, LV_OPA_50, LV_PART_MAIN);
|
||||
Layer::push(this);
|
||||
}
|
||||
|
||||
void ModalWindow::deleteLater(bool detach, bool trash)
|
||||
{
|
||||
if (_deleted)
|
||||
return;
|
||||
|
||||
Window::deleteLater(detach, trash);
|
||||
if (_deleted) return;
|
||||
Layer::pop(this);
|
||||
Window::deleteLater(detach, trash);
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool ModalWindow::onTouchEnd(coord_t x, coord_t y)
|
||||
void ModalWindow::onClicked()
|
||||
{
|
||||
if (closeWhenClickOutside) {
|
||||
onKeyPress();
|
||||
deleteLater();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
ModalWindowContent::ModalWindowContent(ModalWindow* parent,
|
||||
const rect_t& rect) :
|
||||
@@ -57,6 +53,11 @@ ModalWindowContent::ModalWindowContent(ModalWindow* parent,
|
||||
{
|
||||
}
|
||||
|
||||
void ModalWindowContent::onClicked()
|
||||
{
|
||||
Keyboard::hide();
|
||||
}
|
||||
|
||||
void ModalWindowContent::setTitle(const std::string& text)
|
||||
{
|
||||
if (!title) {
|
||||
|
||||
+22
-30
@@ -21,49 +21,41 @@
|
||||
|
||||
#include "window.h"
|
||||
|
||||
class ModalWindow: public Window
|
||||
class ModalWindow : public Window
|
||||
{
|
||||
public:
|
||||
explicit ModalWindow(Window * parent, bool closeWhenClickOutside = false);
|
||||
public:
|
||||
explicit ModalWindow(Window* parent, bool closeWhenClickOutside = false);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "ModalWindow";
|
||||
}
|
||||
std::string getName() const override { return "ModalWindow"; }
|
||||
#endif
|
||||
|
||||
void deleteLater(bool detach = true, bool trash = true) override; // NOLINT(google-default-arguments)
|
||||
void setCloseWhenClickOutside(bool value = true)
|
||||
{
|
||||
closeWhenClickOutside = value;
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool onTouchEnd(coord_t x, coord_t y) override;
|
||||
#endif
|
||||
void onClicked() override;
|
||||
void deleteLater(bool detach = true, bool trash = true) override;
|
||||
|
||||
void setCloseWhenClickOutside(bool value = true)
|
||||
{
|
||||
closeWhenClickOutside = value;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool closeWhenClickOutside;
|
||||
protected:
|
||||
bool closeWhenClickOutside;
|
||||
};
|
||||
|
||||
class ModalWindowContent: public Window
|
||||
class ModalWindowContent : public Window
|
||||
{
|
||||
public:
|
||||
explicit ModalWindowContent(ModalWindow * parent, const rect_t & rect);
|
||||
public:
|
||||
explicit ModalWindowContent(ModalWindow* parent, const rect_t& rect);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "ModalWindowContent";
|
||||
}
|
||||
std::string getName() const override { return "ModalWindowContent"; }
|
||||
#endif
|
||||
|
||||
void setTitle(const std::string& text);
|
||||
std::string getTitle() const;
|
||||
void setTitle(const std::string& text);
|
||||
std::string getTitle() const;
|
||||
|
||||
protected:
|
||||
lv_obj_t* title = nullptr;
|
||||
void onClicked() override;
|
||||
|
||||
protected:
|
||||
lv_obj_t* title = nullptr;
|
||||
};
|
||||
|
||||
|
||||
+14
-59
@@ -26,32 +26,18 @@
|
||||
|
||||
static void numberedit_cb(lv_event_t* e)
|
||||
{
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
if (code == LV_EVENT_DELETE) return;
|
||||
|
||||
NumberEdit* numEdit = (NumberEdit*)lv_event_get_user_data(e);
|
||||
if (!numEdit || numEdit->deleted()) return;
|
||||
|
||||
uint32_t key = lv_event_get_key(e);
|
||||
lv_obj_t* obj = numEdit->getLvObj();
|
||||
|
||||
if (obj != nullptr && lv_obj_is_editable(obj)) {
|
||||
lv_group_t* grp = (lv_group_t*)lv_obj_get_group(obj);
|
||||
if (grp && lv_group_get_focused(grp) == obj)
|
||||
numEdit->setEditMode(lv_group_get_editing(grp));
|
||||
|
||||
switch (key) {
|
||||
case LV_KEY_LEFT:
|
||||
// numEdit->onEvent(EVT_ROTARY_LEFT);
|
||||
break;
|
||||
case LV_KEY_RIGHT:
|
||||
// numEdit->onEvent(EVT_ROTARY_RIGHT);
|
||||
break;
|
||||
}
|
||||
switch (key) {
|
||||
case LV_KEY_LEFT:
|
||||
numEdit->onEvent(EVT_ROTARY_LEFT);
|
||||
break;
|
||||
case LV_KEY_RIGHT:
|
||||
numEdit->onEvent(EVT_ROTARY_RIGHT);
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: this looks highly forbidden!!!
|
||||
e->code = LV_EVENT_REFRESH;
|
||||
}
|
||||
|
||||
// create a new class for number edit so we can set the sytles differently if needed.
|
||||
@@ -133,14 +119,6 @@ void NumberEdit::onEvent(event_t event)
|
||||
}
|
||||
#endif
|
||||
|
||||
case EVT_KEY_FIRST(KEY_EXIT):
|
||||
#if defined(SOFTWARE_KEYBOARD)
|
||||
Keyboard::hide();
|
||||
return;
|
||||
#endif
|
||||
break;
|
||||
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
case EVT_VIRTUAL_KEY_PLUS:
|
||||
setValue(getValue() + getStep());
|
||||
@@ -180,35 +158,12 @@ void NumberEdit::onEvent(event_t event)
|
||||
FormField::onEvent(event);
|
||||
}
|
||||
|
||||
void NumberEdit::onFocusLost()
|
||||
void NumberEdit::onClicked()
|
||||
{
|
||||
#if defined(SOFTWARE_KEYBOARD)
|
||||
Keyboard::hide();
|
||||
#endif
|
||||
|
||||
FormField::onFocusLost();
|
||||
lv_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act());
|
||||
if(indev_type == LV_INDEV_TYPE_POINTER) {
|
||||
NumberKeyboard::show(this);
|
||||
} else {
|
||||
FormField::onClicked();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool NumberEdit::onTouchEnd(coord_t, coord_t)
|
||||
{
|
||||
if (!enabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hasFocus()) {
|
||||
setEditMode(true);
|
||||
}
|
||||
else {
|
||||
setFocus(SET_FOCUS_DEFAULT);
|
||||
}
|
||||
|
||||
#if defined(SOFTWARE_KEYBOARD)
|
||||
NumberKeyboard::show(this);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+17
-18
@@ -24,30 +24,29 @@
|
||||
|
||||
class NumberEdit : public BaseNumberEdit
|
||||
{
|
||||
public:
|
||||
NumberEdit(Window * parent, const rect_t & rect, int vmin, int vmax, std::function<int()> getValue, std::function<void(int)> setValue = nullptr, WindowFlags windowFlags = 0, LcdFlags textFlags = 0);
|
||||
public:
|
||||
NumberEdit(Window* parent, const rect_t& rect, int vmin, int vmax,
|
||||
std::function<int()> getValue,
|
||||
std::function<void(int)> setValue = nullptr,
|
||||
WindowFlags windowFlags = 0, LcdFlags textFlags = 0);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "NumberEdit(" + std::to_string(getValue()) + ")";
|
||||
}
|
||||
std::string getName() const override
|
||||
{
|
||||
return "NumberEdit(" + std::to_string(getValue()) + ")";
|
||||
}
|
||||
#endif
|
||||
|
||||
void setAvailableHandler(std::function<bool(int)> handler)
|
||||
{
|
||||
isValueAvailable = std::move(handler);
|
||||
}
|
||||
void setAvailableHandler(std::function<bool(int)> handler)
|
||||
{
|
||||
isValueAvailable = std::move(handler);
|
||||
}
|
||||
|
||||
void onEvent(event_t event) override;
|
||||
void onFocusLost() override;
|
||||
void onEvent(event_t event) override;
|
||||
void onClicked() override;
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool onTouchEnd(coord_t x, coord_t y) override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
std::function<bool(int)> isValueAvailable;
|
||||
protected:
|
||||
std::function<bool(int)> isValueAvailable;
|
||||
};
|
||||
|
||||
extern const lv_obj_class_t lv_numberedit_class;
|
||||
|
||||
+20
-13
@@ -24,14 +24,21 @@ void TableField::clicked(lv_event_t *e)
|
||||
lv_obj_t* target = lv_event_get_target(e);
|
||||
if (!target) return;
|
||||
|
||||
uint16_t row;
|
||||
uint16_t col;
|
||||
lv_table_get_selected_cell(target, &row, &col);
|
||||
|
||||
TableField* tf = (TableField*)lv_obj_get_user_data(target);
|
||||
if (!tf) return;
|
||||
|
||||
tf->onPress(row, col);
|
||||
lv_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act());
|
||||
if(indev_type == LV_INDEV_TYPE_ENCODER) {
|
||||
// Encoder send VALUE_CHANGED when selection changes
|
||||
tf->adjustScroll();
|
||||
} else {
|
||||
// Otherwise it's a click
|
||||
uint16_t row;
|
||||
uint16_t col;
|
||||
lv_table_get_selected_cell(target, &row, &col);
|
||||
|
||||
tf->onPress(row, col);
|
||||
}
|
||||
}
|
||||
|
||||
void TableField::draw_begin(lv_event_t* e)
|
||||
@@ -73,7 +80,7 @@ void TableField::draw_end(lv_event_t* e)
|
||||
}
|
||||
|
||||
TableField::TableField(Window* parent, const rect_t& rect, WindowFlags windowFlags) :
|
||||
FormField(parent, rect, windowFlags, 0, lv_table_create)
|
||||
Window(parent, rect, windowFlags, 0, lv_table_create)
|
||||
{
|
||||
lv_obj_add_event_cb(lvobj, TableField::clicked, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
lv_obj_add_event_cb(lvobj, TableField::draw_begin, LV_EVENT_DRAW_PART_BEGIN, nullptr);
|
||||
@@ -205,15 +212,15 @@ void TableField::onEvent(event_t event)
|
||||
onKeyPress();
|
||||
selectNext(-1);
|
||||
}
|
||||
else if (event == EVT_KEY_BREAK(KEY_ENTER)) {
|
||||
onKeyPress();
|
||||
// else if (event == EVT_KEY_BREAK(KEY_ENTER)) {
|
||||
// onKeyPress();
|
||||
|
||||
uint16_t row;
|
||||
uint16_t col;
|
||||
lv_table_get_selected_cell(lvobj, &row, &col);
|
||||
// uint16_t row;
|
||||
// uint16_t col;
|
||||
// lv_table_get_selected_cell(lvobj, &row, &col);
|
||||
|
||||
onPress(row, col);
|
||||
}
|
||||
// onPress(row, col);
|
||||
// }
|
||||
else {
|
||||
Window::onEvent(event);
|
||||
}
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
|
||||
#include "form.h"
|
||||
|
||||
class TableField : public FormField
|
||||
class TableField : public Window
|
||||
{
|
||||
public:
|
||||
TableField(Window* parent, const rect_t& rect,
|
||||
|
||||
+6
-31
@@ -55,7 +55,11 @@ TextEdit::TextEdit(Window *parent, const rect_t &rect, char *value,
|
||||
lv_obj_set_scrollbar_mode(lvobj, LV_SCROLLBAR_MODE_OFF);
|
||||
lv_textarea_set_password_mode(lvobj, false);
|
||||
lv_textarea_set_one_line(lvobj, true);
|
||||
lv_textarea_set_text(lvobj, value);
|
||||
|
||||
// value may not be null-terminated
|
||||
std::string txt(value, length);
|
||||
lv_textarea_set_text(lvobj, txt.c_str());
|
||||
|
||||
lv_textarea_set_placeholder_text(lvobj, "---");
|
||||
lv_textarea_set_max_length(lvobj, length);
|
||||
|
||||
@@ -145,16 +149,6 @@ void TextEdit::onEvent(event_t event)
|
||||
}
|
||||
break;
|
||||
|
||||
case EVT_KEY_BREAK(KEY_EXIT):
|
||||
changeEnd();
|
||||
FormField::onEvent(event);
|
||||
|
||||
#if defined(SOFTWARE_KEYBOARD)
|
||||
Keyboard::hide();
|
||||
#endif
|
||||
setFocus(SET_FOCUS_DEFAULT, this);
|
||||
break;
|
||||
|
||||
case EVT_KEY_LONG(KEY_ENTER):
|
||||
{
|
||||
killEvents(event);
|
||||
@@ -219,33 +213,14 @@ void TextEdit::onEvent(event_t event)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool TextEdit::onTouchEnd(coord_t x, coord_t y)
|
||||
void TextEdit::onClicked()
|
||||
{
|
||||
if (!isEnabled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!hasFocus()) {
|
||||
setFocus(SET_FOCUS_DEFAULT);
|
||||
}
|
||||
|
||||
cursorPos = lv_textarea_get_cursor_pos(lvobj);
|
||||
|
||||
#if defined(SOFTWARE_KEYBOARD)
|
||||
TextKeyboard::show(this);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void TextEdit::onFocusLost()
|
||||
{
|
||||
#if defined(SOFTWARE_KEYBOARD)
|
||||
TextKeyboard::hide();
|
||||
#endif
|
||||
|
||||
changeEnd();
|
||||
FormField::onFocusLost();
|
||||
}
|
||||
|
||||
+4
-3
@@ -47,10 +47,11 @@ class TextEdit : public FormField {
|
||||
}
|
||||
|
||||
void onEvent(event_t event) override;
|
||||
void onClicked() override;
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool onTouchEnd(coord_t x, coord_t y) override;
|
||||
#endif
|
||||
// #if defined(HARDWARE_TOUCH)
|
||||
// bool onTouchEnd(coord_t x, coord_t y) override;
|
||||
// #endif
|
||||
|
||||
void onFocusLost() override;
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "simple_btn.h"
|
||||
|
||||
#define MY_CLASS &simple_btn_class
|
||||
|
||||
const lv_obj_class_t simple_btn_class = {
|
||||
.width_def = LV_DPI_DEF,
|
||||
.height_def = LV_DPI_DEF,
|
||||
.group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE,
|
||||
.instance_size = sizeof(lv_btn_t),
|
||||
.base_class = &lv_btn_class,
|
||||
};
|
||||
|
||||
lv_obj_t* simple_btn_create(lv_obj_t* parent)
|
||||
{
|
||||
LV_LOG_INFO("begin");
|
||||
lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
|
||||
lv_obj_class_init_obj(obj);
|
||||
return obj;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef SIMPLE_BTN_H
|
||||
#define SIMPLE_BTN_H
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const lv_obj_class_t simple_btn_class;
|
||||
lv_obj_t* simple_btn_create(lv_obj_t* parent);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "window_base.h"
|
||||
|
||||
void window_event_cb(lv_event_t* e);
|
||||
|
||||
#define MY_CLASS &window_base_class
|
||||
|
||||
static void window_base_event(const lv_obj_class_t* class_p, lv_event_t* e);
|
||||
|
||||
const lv_obj_class_t window_base_class = {
|
||||
.base_class = &lv_obj_class,
|
||||
.event_cb = window_base_event,
|
||||
.width_def = LV_DPI_DEF,
|
||||
.height_def = LV_DPI_DEF,
|
||||
.editable = LV_OBJ_CLASS_EDITABLE_FALSE,
|
||||
.group_def = LV_OBJ_CLASS_GROUP_DEF_FALSE,
|
||||
.instance_size = sizeof(lv_obj_t)
|
||||
};
|
||||
|
||||
static void window_base_event(const lv_obj_class_t* class_p, lv_event_t* e)
|
||||
{
|
||||
/* Call the ancestor's event handler */
|
||||
lv_res_t res = lv_obj_event_base(MY_CLASS, e);
|
||||
if (res != LV_RES_OK) return;
|
||||
|
||||
window_event_cb(e);
|
||||
}
|
||||
|
||||
lv_obj_t* window_create(lv_obj_t* parent)
|
||||
{
|
||||
lv_obj_t* obj = lv_obj_class_create_obj(MY_CLASS, parent);
|
||||
lv_obj_class_init_obj(obj);
|
||||
return obj;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Source:
|
||||
* https://github.com/opentx/libopenui
|
||||
*
|
||||
* This file is a part of libopenui library.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef WINDOW_BASE_H
|
||||
#define WINDOW_BASE_H
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const lv_obj_class_t window_base_class;
|
||||
lv_obj_t* window_create(lv_obj_t* parent);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+45
-136
@@ -21,15 +21,17 @@
|
||||
#include "touch.h"
|
||||
#include "mainwindow.h"
|
||||
|
||||
Window * Window::focusWindow = nullptr;
|
||||
#include "widgets/window_base.h"
|
||||
|
||||
// Window * Window::focusWindow = nullptr;
|
||||
std::list<Window *> Window::trash;
|
||||
|
||||
extern lv_obj_t *virtual_kb;
|
||||
|
||||
static bool is_scrolling = false;
|
||||
static bool inhibit_focus = false;
|
||||
// static bool inhibit_focus = false;
|
||||
|
||||
static void window_event_cb(lv_event_t * e)
|
||||
extern "C" void window_event_cb(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t *target = lv_event_get_target(e);
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
@@ -87,11 +89,11 @@ static void window_event_cb(lv_event_t * e)
|
||||
return;
|
||||
}
|
||||
|
||||
// Exclude keyboard ?
|
||||
// if(lv_indev_get_type(click_source) == LV_INDEV_TYPE_KEYPAD ||
|
||||
// lv_indev_get_type(click_source) == LV_INDEV_TYPE_ENCODER) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
lv_area_t obj_coords;
|
||||
lv_obj_get_coords(target, &obj_coords);
|
||||
|
||||
@@ -122,7 +124,6 @@ static void window_event_cb(lv_event_t * e)
|
||||
}
|
||||
#endif
|
||||
else if (code == LV_EVENT_SCROLL) {
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
lv_coord_t scroll_y = lv_obj_get_scroll_y(target);
|
||||
lv_coord_t scroll_x = lv_obj_get_scroll_x(target);
|
||||
@@ -130,53 +131,15 @@ static void window_event_cb(lv_event_t * e)
|
||||
TRACE_WINDOWS("SCROLL[x=%d;y=%d] %s", scroll_x, scroll_y,
|
||||
window->getWindowDebugString().c_str());
|
||||
#endif
|
||||
|
||||
|
||||
} else if (code == LV_EVENT_FOCUSED) {
|
||||
if (inhibit_focus) return;
|
||||
|
||||
bool focused = ((Window *)target->user_data)->hasFocus();
|
||||
TRACE_WINDOWS("FOCUSED[%d] %s", focused,
|
||||
window->getWindowDebugString().c_str());
|
||||
|
||||
if (!focused) {
|
||||
SetFocusFlag flag = SET_FOCUS_DEFAULT;
|
||||
lv_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act());
|
||||
if(indev_type == LV_INDEV_TYPE_POINTER) {
|
||||
flag = SET_FOCUS_NO_SCROLL;
|
||||
}
|
||||
window->setFocus(flag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void window_base_event(const lv_obj_class_t* class_p, lv_event_t* e)
|
||||
{
|
||||
/*Call the ancestor's event handler*/
|
||||
lv_res_t res = lv_obj_event_base(&window_base_class, e);
|
||||
if(res != LV_RES_OK) return;
|
||||
|
||||
window_event_cb(e);
|
||||
}
|
||||
|
||||
const lv_obj_class_t window_base_class = {
|
||||
.base_class = &lv_obj_class,
|
||||
.constructor_cb = nullptr,
|
||||
.destructor_cb = nullptr,
|
||||
.user_data = nullptr,
|
||||
.event_cb = window_base_event,
|
||||
.width_def = LV_DPI_DEF,
|
||||
.height_def = LV_DPI_DEF,
|
||||
.editable = LV_OBJ_CLASS_EDITABLE_FALSE,
|
||||
.group_def = LV_OBJ_CLASS_GROUP_DEF_FALSE,
|
||||
.instance_size = sizeof(lv_obj_t)
|
||||
};
|
||||
|
||||
lv_obj_t* window_create(lv_obj_t* parent)
|
||||
{
|
||||
lv_obj_t * obj = lv_obj_class_create_obj(&window_base_class, parent);
|
||||
lv_obj_class_init_obj(obj);
|
||||
return obj;
|
||||
else if (code == LV_EVENT_CLICKED) {
|
||||
TRACE("CLICKED[%p]", window);
|
||||
window->onClicked();
|
||||
}
|
||||
else if (code == LV_EVENT_CANCEL) {
|
||||
TRACE("CANCEL[%p]", window);
|
||||
window->onCancel();
|
||||
}
|
||||
}
|
||||
|
||||
Window::Window(Window *parent, const rect_t &rect, WindowFlags windowFlags,
|
||||
@@ -189,7 +152,7 @@ Window::Window(Window *parent, const rect_t &rect, WindowFlags windowFlags,
|
||||
lv_obj_t* lv_parent = nullptr;
|
||||
if (parent) lv_parent = parent->lvobj;
|
||||
|
||||
if (objConstruct != nullptr) {
|
||||
if (objConstruct != nullptr && objConstruct != window_create) {
|
||||
lvobj = objConstruct(lv_parent);
|
||||
lv_obj_add_event_cb(lvobj, window_event_cb, LV_EVENT_ALL, nullptr);
|
||||
} else {
|
||||
@@ -254,9 +217,6 @@ Window::Window(Window *parent, lv_obj_t* lvobj)
|
||||
Window::~Window()
|
||||
{
|
||||
TRACE_WINDOWS("Destroy %p %s", this, getWindowDebugString().c_str());
|
||||
if (focusWindow == this) {
|
||||
focusWindow = nullptr;
|
||||
}
|
||||
|
||||
if (children.size() > 0) deleteChildren();
|
||||
|
||||
@@ -352,10 +312,6 @@ void Window::deleteLater(bool detach, bool trash)
|
||||
|
||||
_deleted = true;
|
||||
|
||||
if (static_cast<Window *>(focusWindow) == static_cast<Window *>(this)) {
|
||||
focusWindow = nullptr;
|
||||
}
|
||||
|
||||
if (detach)
|
||||
this->detach();
|
||||
else
|
||||
@@ -389,62 +345,17 @@ void Window::clear()
|
||||
void Window::deleteChildren()
|
||||
{
|
||||
// prevent LVGL refocus while mass-deleting
|
||||
inhibit_focus = true;
|
||||
// inhibit_focus = true;
|
||||
for (auto window: children) {
|
||||
window->deleteLater(false);
|
||||
}
|
||||
inhibit_focus = false;
|
||||
// inhibit_focus = false;
|
||||
children.clear();
|
||||
}
|
||||
|
||||
void Window::clearFocus()
|
||||
{
|
||||
if (focusWindow) {
|
||||
focusWindow->onFocusLost();
|
||||
focusWindow = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Window::setFocus(uint8_t flag, Window * from)
|
||||
{
|
||||
if (deleted())
|
||||
return;
|
||||
|
||||
TRACE_WINDOWS("%s setFocus()", getWindowDebugString().c_str());
|
||||
|
||||
if (focusWindow != this) {
|
||||
// synchronize lvgl focused state with libopenui
|
||||
if (lvobj != nullptr &&
|
||||
!lv_obj_has_state(lvobj, LV_STATE_FOCUSED | LV_STATE_FOCUS_KEY)) {
|
||||
lv_obj_add_state(lvobj, LV_STATE_FOCUSED | LV_STATE_FOCUS_KEY);
|
||||
if (focusWindow != nullptr) {
|
||||
lv_obj_clear_state(focusWindow->lvobj, LV_STATE_FOCUSED |
|
||||
LV_STATE_FOCUS_KEY |
|
||||
LV_STATE_EDITED);
|
||||
}
|
||||
}
|
||||
|
||||
// scroll before calling focusHandler so that the window can adjust the
|
||||
// scroll position if needed
|
||||
if (flag != SET_FOCUS_NO_SCROLL) {
|
||||
lv_obj_scroll_to_view_recursive(lvobj, LV_ANIM_OFF);
|
||||
}
|
||||
invalidate();
|
||||
|
||||
clearFocus();
|
||||
focusWindow = this;
|
||||
if (focusHandler) {
|
||||
focusHandler(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Window::scrollTo(Window * child)
|
||||
{
|
||||
}
|
||||
|
||||
void Window::scrollTo(const rect_t & rect)
|
||||
bool Window::hasFocus() const
|
||||
{
|
||||
return lvobj && lv_obj_has_state(lvobj, LV_STATE_FOCUS_KEY);
|
||||
}
|
||||
|
||||
bool Window::hasOpaqueRect(const rect_t & testRect) const
|
||||
@@ -579,14 +490,6 @@ void Window::checkEvents()
|
||||
}
|
||||
}
|
||||
|
||||
if (this == Window::focusWindow) {
|
||||
event_t event = getWindowEvent();
|
||||
// lvglPushEncoderEvent(event);
|
||||
if (event) {
|
||||
this->onEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
if (windowFlags & REFRESH_ALWAYS) {
|
||||
invalidate();
|
||||
}
|
||||
@@ -595,46 +498,52 @@ void Window::checkEvents()
|
||||
void Window::onEvent(event_t event)
|
||||
{
|
||||
TRACE_WINDOWS("%s received event 0x%X", Window::getWindowDebugString("Window").c_str(), event);
|
||||
if (parent) {
|
||||
parent->onEvent(event);
|
||||
}
|
||||
if (parent) { parent->onEvent(event); }
|
||||
}
|
||||
|
||||
void Window::onClicked()
|
||||
{
|
||||
if (parent && !(windowFlags & OPAQUE)) { parent->onClicked(); }
|
||||
}
|
||||
|
||||
void Window::onCancel()
|
||||
{
|
||||
if (parent) { parent->onCancel(); }
|
||||
}
|
||||
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool Window::onTouchStart(coord_t x, coord_t y)
|
||||
{
|
||||
if (parent)
|
||||
return parent->onTouchStart(x, y);
|
||||
if (parent && !(windowFlags & OPAQUE)) return parent->onTouchStart(x, y);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Window::onTouchEnd(coord_t x, coord_t y)
|
||||
{
|
||||
if (parent && !(windowFlags & OPAQUE))
|
||||
return parent->onTouchEnd(x, y);
|
||||
if (parent && !(windowFlags & OPAQUE)) return parent->onTouchEnd(x, y);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Window::onTouchSlide(coord_t x, coord_t y, coord_t startX, coord_t startY, coord_t slideX, coord_t slideY)
|
||||
{
|
||||
// TODO: this is not used anymore: REMOVE
|
||||
|
||||
// for (auto it = children.rbegin(); it != children.rend(); ++it) {
|
||||
// auto child = *it;
|
||||
// if (child->rect.contains(startX, startY)) {
|
||||
// if (child->onTouchSlide(x - child->rect.x, y - child->rect.y, startX - child->rect.x, startY - child->rect.y, slideX, slideY)) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
for (auto it = children.rbegin(); it != children.rend(); ++it) {
|
||||
auto child = *it;
|
||||
if (child->rect.contains(startX, startY)) {
|
||||
if (child->onTouchSlide(x - child->rect.x, y - child->rect.y, startX - child->rect.x, startY - child->rect.y, slideX, slideY)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// return false;
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Window::adjustInnerHeight()
|
||||
{
|
||||
}
|
||||
|
||||
coord_t Window::adjustHeight()
|
||||
{
|
||||
coord_t old = rect.h;
|
||||
|
||||
+17
-35
@@ -26,10 +26,14 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
|
||||
#include "bitmapbuffer.h"
|
||||
#include "libopenui_defines.h"
|
||||
#include "libopenui_helpers.h"
|
||||
#include "libopenui_config.h"
|
||||
|
||||
#include "widgets/window_base.h"
|
||||
|
||||
#include "LvglWrapper.h"
|
||||
|
||||
typedef uint32_t WindowFlags;
|
||||
@@ -51,19 +55,16 @@ constexpr WindowFlags PAINT_CHILDREN_FIRST = 1u << 6u;
|
||||
constexpr WindowFlags PUSH_FRONT = 1u << 7u;
|
||||
constexpr WindowFlags WINDOW_FLAGS_LAST = PUSH_FRONT;
|
||||
|
||||
enum SetFocusFlag
|
||||
{
|
||||
SET_FOCUS_DEFAULT = 0,
|
||||
SET_FOCUS_FORWARD = 1,
|
||||
SET_FOCUS_BACKWARD = 2,
|
||||
SET_FOCUS_FIRST = 3,
|
||||
SET_FOCUS_NO_SCROLL= 4
|
||||
};
|
||||
// enum SetFocusFlag
|
||||
// {
|
||||
// SET_FOCUS_DEFAULT = 0,
|
||||
// SET_FOCUS_FORWARD = 1,
|
||||
// SET_FOCUS_BACKWARD = 2,
|
||||
// SET_FOCUS_FIRST = 3,
|
||||
// SET_FOCUS_NO_SCROLL= 4
|
||||
// };
|
||||
|
||||
typedef lv_obj_t *(*LvglCreate)(lv_obj_t *);
|
||||
extern const lv_obj_class_t window_base_class;
|
||||
|
||||
lv_obj_t* window_create(lv_obj_t* parent);
|
||||
|
||||
class Window
|
||||
{
|
||||
@@ -110,23 +111,7 @@ class Window
|
||||
void clear();
|
||||
virtual void deleteLater(bool detach = true, bool trash = true);
|
||||
|
||||
bool hasFocus() const
|
||||
{
|
||||
return focusWindow == this;
|
||||
}
|
||||
|
||||
static Window * getFocus()
|
||||
{
|
||||
return focusWindow;
|
||||
}
|
||||
|
||||
void scrollTo(const rect_t & rect);
|
||||
|
||||
void scrollTo(Window * child);
|
||||
|
||||
static void clearFocus();
|
||||
|
||||
virtual void setFocus(uint8_t flag = SET_FOCUS_DEFAULT, Window * from = nullptr);
|
||||
bool hasFocus() const;
|
||||
|
||||
void setRect(rect_t value)
|
||||
{
|
||||
@@ -216,8 +201,8 @@ class Window
|
||||
}
|
||||
|
||||
virtual void onEvent(event_t event);
|
||||
|
||||
void adjustInnerHeight();
|
||||
virtual void onClicked();
|
||||
virtual void onCancel();
|
||||
|
||||
coord_t adjustHeight();
|
||||
|
||||
@@ -243,10 +228,8 @@ class Window
|
||||
return _deleted;
|
||||
}
|
||||
|
||||
virtual void paint(BitmapBuffer *)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void paint(BitmapBuffer *) {}
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
virtual bool onTouchStart(coord_t x, coord_t y);
|
||||
virtual bool onTouchEnd(coord_t x, coord_t y);
|
||||
@@ -255,7 +238,6 @@ class Window
|
||||
inline lv_obj_t *getLvObj() { return lvobj; }
|
||||
|
||||
protected:
|
||||
static Window* focusWindow;
|
||||
static std::list<Window*> trash;
|
||||
|
||||
rect_t rect;
|
||||
|
||||
+1
-1
Submodule radio/src/thirdparty/libopenui/thirdparty/lvgl updated: 2d557d7128...a7ec082387
Reference in New Issue
Block a user