Replaced focus handling with LVGL groups

This commit is contained in:
Raphael Coeffic
2022-06-11 15:13:11 +02:00
committed by Raphael Coeffic
parent 866bc46d4d
commit 25715ed648
44 changed files with 746 additions and 1352 deletions
+3 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
};
-76
View File
@@ -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
-99
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
};
+11
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+38
View File
@@ -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;
}
+36
View File
@@ -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
View File
@@ -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
View File
@@ -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;
Submodule radio/src/thirdparty/libopenui/thirdparty/lvgl updated: 2d557d7128...a7ec082387