Convert Lvgl resource manager to recursive mutex to allow re locking in thread.

This helps with creation and getting values and should be safe since it still keeps lvgl on  one thread at a time.

Add OnLvglEvent to UIElement that allows foreasy place for UI Elements  to respond to LVGL events .

Add button  class that can react to being presssed via a  callback function.

Add GetBottom() api to allow easy grabbing of bottom Y coordinate.

use some new stuff in the settings  page to sort test it all out.
This commit is contained in:
MatthewColvin 2023-10-06 22:11:15 -05:00
parent a11b78c540
commit 235d8e043f
8 changed files with 63 additions and 7 deletions

View file

@ -14,5 +14,5 @@ BasicUI::BasicUI(std::shared_ptr<HardwareAbstract> aHardware)
}); });
Screen::Manager::getInstance().pushScreen( Screen::Manager::getInstance().pushScreen(
std::make_unique<Screen::HomeScreen>()); std::make_unique<Screen::HomeScreen>(aHardware));
} }

View file

@ -16,7 +16,7 @@ public:
return mInstance; return mInstance;
} }
[[nodiscard]] std::scoped_lock<std::mutex> scopeLock() { [[nodiscard]] std::scoped_lock<std::recursive_mutex> scopeLock() {
return std::scoped_lock(mLvglMutex); return std::scoped_lock(mLvglMutex);
} }
@ -45,5 +45,5 @@ protected:
} }
std::queue<std::function<void()>> mLvglTasks; std::queue<std::function<void()>> mLvglTasks;
std::mutex mLvglMutex; std::recursive_mutex mLvglMutex;
}; };

View file

@ -6,6 +6,10 @@ UIElement::UIElement(lv_obj_t *aLvglSelf, ID aId)
: mLvglSelf(aLvglSelf), mId(aId) { : mLvglSelf(aLvglSelf), mId(aId) {
auto lock = LvglResourceManger::GetInstance().scopeLock(); auto lock = LvglResourceManger::GetInstance().scopeLock();
mLvglSelf->user_data = this; mLvglSelf->user_data = this;
// Register Handler so that all object are able to override OnLvglEvent to
// handle events easilyOnLvEvent
lv_obj_add_event_cb(mLvglSelf, UIElement::LvglEventHandler, LV_EVENT_ALL,
this);
} }
UIElement::~UIElement() { UIElement::~UIElement() {
@ -68,6 +72,8 @@ lv_coord_t UIElement::GetX() {
return lv_obj_get_x(mLvglSelf); return lv_obj_get_x(mLvglSelf);
} }
lv_coord_t UIElement::GetBottom() { return GetY() + GetHeight(); };
void UIElement::AlignTo(UIElement *anElementToAlignTo, lv_align_t anAlignment, void UIElement::AlignTo(UIElement *anElementToAlignTo, lv_align_t anAlignment,
lv_coord_t aXoffset, lv_coord_t aYOffset) { lv_coord_t aXoffset, lv_coord_t aYOffset) {
LvglResourceManger::GetInstance().AttemptNow([=] { LvglResourceManger::GetInstance().AttemptNow([=] {
@ -114,4 +120,11 @@ bool UIElement::KeyEvent(KeyPressAbstract::KeyEvent aKeyEvent) {
return OnKeyEvent(aKeyEvent); return OnKeyEvent(aKeyEvent);
} }
//////////////////// Statics //////////////////////////
void UIElement::LvglEventHandler(lv_event_t *anEvent) {
auto lock = LvglResourceManger::GetInstance().scopeLock();
reinterpret_cast<UIElement *>(anEvent->user_data)->OnLvglEvent(anEvent);
}
} // namespace UI } // namespace UI

View file

@ -30,9 +30,10 @@ public:
lv_coord_t GetY(); lv_coord_t GetY();
lv_coord_t GetX(); lv_coord_t GetX();
lv_coord_t GetBottom();
void AlignTo(UIElement *anElementToAlignWith,lv_align_t anAlignment, void AlignTo(UIElement *anElementToAlignWith, lv_align_t anAlignment,
lv_coord_t aXoffset = 0, lv_coord_t aYOffset = 0); lv_coord_t aXoffset = 0, lv_coord_t aYOffset = 0);
virtual void AddElement(UIElement *anElement); virtual void AddElement(UIElement *anElement);
@ -54,6 +55,9 @@ protected:
/// @brief Override in child class to run something after element is hidden /// @brief Override in child class to run something after element is hidden
virtual void OnHide() = 0; virtual void OnHide() = 0;
// Override in object to handle LVGL events for that object
virtual void OnLvglEvent(lv_event_t *anEvent){};
/// @brief Set KeyEvent to the UI element to see if it wants to handle it /// @brief Set KeyEvent to the UI element to see if it wants to handle it
virtual bool KeyEvent(KeyPressAbstract::KeyEvent aKeyEvent); virtual bool KeyEvent(KeyPressAbstract::KeyEvent aKeyEvent);
@ -63,6 +67,8 @@ protected:
virtual bool OnKeyEvent(KeyPressAbstract::KeyEvent aKeyEvent) = 0; virtual bool OnKeyEvent(KeyPressAbstract::KeyEvent aKeyEvent) = 0;
private: private:
static void LvglEventHandler(lv_event_t *anEvent);
lv_obj_t *mLvglSelf; lv_obj_t *mLvglSelf;
const ID mId; const ID mId;
}; };

View file

@ -1,11 +1,18 @@
#include "SettingsPage.hpp" #include "SettingsPage.hpp"
#include "BackgroundScreen.hpp" #include "BackgroundScreen.hpp"
#include "Button.hpp"
using namespace UI::Page; using namespace UI::Page;
SettingsPage::SettingsPage(std::shared_ptr<HardwareAbstract> aHardware) SettingsPage::SettingsPage(std::shared_ptr<HardwareAbstract> aHardware)
: Base(ID::Pages::Settings), mHardware(aHardware) { : Base(ID::Pages::Settings), mHardware(aHardware) {
SetBgColor(lv_color_make(255, 0, 0)); SetBgColor(lv_color_make(255, 0, 0));
auto button = std::make_unique<UI::Widget::Button>([this] { AddSlider(); });
button->SetY(0);
button->SetHeight(lv_pct(10));
button->SetWidth(lv_pct(10));
mButton = AddWidget(std::move(button));
} }
void SettingsPage::OnShow() {} void SettingsPage::OnShow() {}
@ -16,7 +23,7 @@ void SettingsPage::AddSlider() {
fakeSlider->SetHeight(lv_pct(10)); fakeSlider->SetHeight(lv_pct(10));
fakeSlider->SetWidth(GetWidth()); fakeSlider->SetWidth(GetWidth());
if (sliders.empty()) { if (sliders.empty()) {
fakeSlider->SetY(0); fakeSlider->SetY(mButton->GetBottom());
} else { } else {
auto nextY = sliders.back()->GetY() + sliders.back()->GetHeight(); auto nextY = sliders.back()->GetY() + sliders.back()->GetHeight();
fakeSlider->SetY(nextY + 10); fakeSlider->SetY(nextY + 10);
@ -50,7 +57,7 @@ bool SettingsPage::OnKeyEvent(KeyPressAbstract::KeyEvent aKeyEvent) {
case id::Aux4: case id::Aux4:
break; break;
default: default:
used = false; used = Page::Base::OnKeyEvent(aKeyEvent);
break; break;
} }
return used; return used;

View file

@ -14,6 +14,7 @@ protected:
void OnShow() override; void OnShow() override;
std::vector<Widget::Base *> sliders; std::vector<Widget::Base *> sliders;
Widget::Base *mButton;
std::shared_ptr<HardwareAbstract> mHardware; std::shared_ptr<HardwareAbstract> mHardware;
}; };
} // namespace UI::Page } // namespace UI::Page

View file

@ -0,0 +1,14 @@
#include "Button.hpp"
#include "BackgroundScreen.hpp"
using namespace UI::Widget;
Button::Button(std::function<void()> aOnPressHandler)
: Base(lv_btn_create(UI::Screen::BackgroundScreen::getLvInstance())),
mOnPress(aOnPressHandler) {}
void Button::OnLvglEvent(lv_event_t *anEvent) {
if (anEvent->code == LV_EVENT_PRESSED) {
mOnPress();
}
};

View file

@ -0,0 +1,15 @@
#pragma once
#include "WidgetBase.hpp"
namespace UI::Widget {
class Button : public Base {
public:
Button(std::function<void()> aOnPressHandler);
void OnLvglEvent(lv_event_t *anEvent) override;
private:
std::function<void()> mOnPress;
};
} // namespace UI::Widget