Make UI Element the owner of the Unique pointers to other UI elements to allow for easier scope management of adding elements to one another

This commit is contained in:
Matthew Colvin 2023-10-11 10:50:56 -05:00
parent 58787f5bf0
commit 736029c89a
16 changed files with 87 additions and 166 deletions

View file

@ -24,12 +24,39 @@ UIElement::~UIElement() {
}
}
void UIElement::AddElement(UIElement *anUIElement) {
LvglResourceManger::GetInstance().AttemptNow([this, anUIElement] {
lv_obj_set_parent(anUIElement->mLvglSelf, mLvglSelf);
});
UIElement *UIElement::AddElement(UIElement::Ptr anUIElement) {
auto lock = LvglResourceManger::GetInstance().scopeLock();
lv_obj_set_parent(anUIElement->mLvglSelf, mLvglSelf);
mContainedElements.push_back(std::move(anUIElement));
return mContainedElements[mContainedElements.size() - 1].get();
}
UIElement::Ptr UIElement::RemoveElement(UIElement *anElementRef) {
auto ElemToRemoveIter =
std::find_if(mContainedElements.begin(), mContainedElements.end(),
[anElementRef](auto &anElement) {
return anElement.get() == anElementRef;
});
if (ElemToRemoveIter != mContainedElements.end()) {
auto widget = std::move(*ElemToRemoveIter);
mContainedElements.erase(ElemToRemoveIter);
return widget;
}
return nullptr;
}
bool UIElement::KeyEvent(KeyPressAbstract::KeyEvent aKeyEvent) {
if (OnKeyEvent(aKeyEvent)) {
return true;
}
for (auto &elem : mContainedElements) {
if (elem->KeyEvent(aKeyEvent)) {
return true;
}
}
return false;
};
bool UIElement::IsVisible() {
auto lock = LvglResourceManger::GetInstance().scopeLock();
return lv_obj_is_visible(mLvglSelf);
@ -220,6 +247,9 @@ void UIElement::Show() {
if (IsVisible()) {
return;
}
for (auto &elem : mContainedElements) {
elem->OnShow();
}
{
auto lock = LvglResourceManger::GetInstance().scopeLock();
lv_obj_clear_flag(mLvglSelf, LV_OBJ_FLAG_HIDDEN);
@ -231,6 +261,9 @@ void UIElement::Hide() {
if (!IsVisible()) {
return;
}
for (auto &elem : mContainedElements) {
elem->OnHide();
}
{
auto lock = LvglResourceManger::GetInstance().scopeLock();
lv_obj_add_flag(mLvglSelf, LV_OBJ_FLAG_HIDDEN);
@ -238,10 +271,6 @@ void UIElement::Hide() {
OnHide();
}
bool UIElement::KeyEvent(KeyPressAbstract::KeyEvent aKeyEvent) {
return OnKeyEvent(aKeyEvent);
}
//////////////////// Statics //////////////////////////
void UIElement::LvglEventHandler(lv_event_t *anEvent) {

View file

@ -6,12 +6,15 @@
#include <lvgl.h>
#include "KeyPressAbstract.hpp"
#include <vector>
namespace UI {
class UIElement {
public:
using Ptr = std::unique_ptr<UIElement>;
UIElement(lv_obj_t *aLvglSelf, const ID aId = ID());
virtual ~UIElement();
@ -61,7 +64,12 @@ public:
lv_style_selector_t aStyle = LV_PART_MAIN);
TextStyle GetTextStyle(lv_style_selector_t aStyle = LV_PART_MAIN);
virtual void AddElement(UIElement *anElement);
UIElement *AddElement(UIElement::Ptr anElement);
template <class UIElemTy> UIElemTy *AddElement(UIElement::Ptr aWidget);
UIElement::Ptr RemoveElement(UIElement *aUIElementRef);
size_t GetNumContainedElements() { return mContainedElements.size(); }
ID GetID() { return mId; };
@ -107,6 +115,9 @@ private:
lv_obj_t *mLvglSelf;
const ID mId;
uint32_t mLvglKeepAliveTime = 0;
/// @brief Elements that are currently in this element
std::vector<UIElement::Ptr> mContainedElements;
};
/**
@ -130,4 +141,9 @@ UIElemTy UIElement::GetElement(lv_obj_t *aLvglObject) {
return nullptr;
}
template <class UIElemTy>
UIElemTy *UIElement::AddElement(UIElement::Ptr anElement) {
return static_cast<UIElemTy *>(AddElement(std::move(anElement)));
}
} // namespace UI

View file

@ -1,55 +0,0 @@
#include "WidgetContainer.hpp"
using namespace UI;
WidgetContainer::WidgetContainer(lv_obj_t *aLvglSelf, ID aID)
: UIElement(aLvglSelf, aID) {}
UI::Widget::Base *WidgetContainer::AddWidget(Widget::Base::Ptr aWidget) {
AddElement(aWidget.get());
mWidgets.push_back(std::move(aWidget));
return mWidgets[mWidgets.size() - 1].get();
}
UI::Widget::Base::Ptr
WidgetContainer::RemoveWidget(Widget::Base *aWidgetRefrence) {
auto widgetToRemoveIter = std::find_if(
mWidgets.begin(), mWidgets.end(), [aWidgetRefrence](auto &aWidget) {
return aWidget.get() == aWidgetRefrence;
});
if (widgetToRemoveIter != mWidgets.end()) {
auto widget = std::move(*widgetToRemoveIter);
mWidgets.erase(widgetToRemoveIter);
return widget;
}
return nullptr;
}
bool WidgetContainer::KeyEvent(KeyPressAbstract::KeyEvent aKeyEvent) {
if (OnKeyEvent(aKeyEvent)) {
return true;
}
for (auto &widget : mWidgets) {
auto used = widget->KeyEvent(aKeyEvent);
if (used) {
return true;
}
}
return false;
};
void WidgetContainer::OnShow() {
for (auto &widget : mWidgets) {
if (widget->IsVisible()) {
widget->OnShow();
}
}
};
void WidgetContainer::OnHide() {
for (auto &widget : mWidgets) {
if (widget->IsVisible()) {
widget->OnHide();
}
}
};

View file

@ -1,38 +0,0 @@
#pragma once
#include "UIElement.hpp"
#include "WidgetBase.hpp"
namespace UI {
class WidgetContainer : public UIElement {
public:
WidgetContainer(lv_obj_t *aLvglSelf, ID aID);
template <class ElementTy> ElementTy *AddWidget(Widget::Base::Ptr aWidget);
Widget::Base *AddWidget(Widget::Base::Ptr aWidget);
Widget::Base::Ptr RemoveWidget(Widget::Base *aWidgetRefrence);
size_t GetNumWidgets() { return mWidgets.size(); }
protected:
/// @brief Forward To widgets that are visible
void OnShow() override;
/// @brief Forward To widgets that are visible
void OnHide() override;
/// @brief Pass Key Events to widgets until one is handled
/// TODO: consider an ability to have a selected widget be the first
/// one to get events.
bool KeyEvent(KeyPressAbstract::KeyEvent aKeyEvent) override;
private:
std::vector<Widget::Base::Ptr> mWidgets;
};
template <class ElementTy>
ElementTy *WidgetContainer::AddWidget(Widget::Base::Ptr aWidget) {
return static_cast<ElementTy *>(AddWidget(std::move(aWidget)));
}
} // namespace UI

View file

@ -6,7 +6,7 @@ using namespace UI::Page;
DisplaySettings::DisplaySettings(std::shared_ptr<DisplayAbstract> aDisplay)
: Base(UI::ID::Pages::DisplaySettings), mDisplay(aDisplay),
mBrightnessSlider(
AddWidget<Widget::Slider>(std::make_unique<Widget::Slider>(
AddElement<Widget::Slider>(std::make_unique<Widget::Slider>(
[this](auto aNewBrightness) {
mDisplay->setBrightness(aNewBrightness);
},

View file

@ -6,7 +6,7 @@ using namespace UI::Page;
Base::Base(ID aID)
: Base(lv_obj_create(Screen::BackgroundScreen::getLvInstance()), aID) {}
Base::Base(lv_obj_t *aLvglSelf, ID aID) : WidgetContainer(aLvglSelf, aID) {
Base::Base(lv_obj_t *aLvglSelf, ID aID) : UIElement(aLvglSelf, aID) {
SetHeight(lv_pct(100));
SetWidth(lv_pct(100));
SetPadding(Padding()); // Set Padding to default

View file

@ -1,6 +1,5 @@
#pragma once
#include "UIElement.hpp"
#include "WidgetContainer.hpp"
#include <string>
#include <vector>
@ -10,7 +9,7 @@ class PopUpScreen;
namespace UI::Page {
class Tab;
class TabView;
class Base : public WidgetContainer {
class Base : public UIElement {
// Classes that Own Pages
friend Tab; // Allow Tab to Forward all Key Events to its page
friend TabView; // Allow Tab view to call OnShow and OnHide Since it can show

View file

@ -19,7 +19,7 @@ SettingsPage::SettingsPage(std::shared_ptr<HardwareAbstract> aHardware)
button->SetHeight(lv_pct(10));
button->SetWidth(lv_pct(10));
mButton = AddWidget(std::move(button));
mButton = AddElement<Widget::Button>(std::move(button));
}
void SettingsPage::OnShow() {}
@ -41,7 +41,7 @@ void SettingsPage::AddSlider() {
fakeSlider->SetY(nextY + 10);
}
sliders.push_back(AddWidget(std::move(fakeSlider)));
sliders.push_back(AddElement(std::move(fakeSlider)));
}
bool SettingsPage::OnKeyEvent(KeyPressAbstract::KeyEvent aKeyEvent) {
@ -57,7 +57,7 @@ bool SettingsPage::OnKeyEvent(KeyPressAbstract::KeyEvent aKeyEvent) {
case id::Aux2:
if (aKeyEvent.mType == eventType::Release) {
if (sliders.size() > 0) {
auto widget = RemoveWidget(sliders[0]);
RemoveElement(sliders[0]);
sliders.erase(
sliders.begin()); // sliders is non owning so after removing delete
// it from non owning array

View file

@ -13,8 +13,9 @@ public:
protected:
void OnShow() override;
void OnHide() override{};
std::vector<Widget::Base *> sliders;
std::vector<UIElement *> sliders;
Widget::Base *mButton;
std::shared_ptr<HardwareAbstract> mHardware;
};

View file

@ -7,12 +7,9 @@ using namespace UI::Page;
Tab::Tab(lv_obj_t *aTab, ID aId) : Base(aTab, aId) {}
void Tab::GiveContent(Page::Base::Ptr aContent) {
AddElement(aContent.get());
mContent = std::move(aContent);
mContent = AddElement<Page::Base>(std::move(aContent));
}
Base::Ptr Tab::TakeContent() { return std::move(mContent); }
bool Tab::OnKeyEvent(KeyPressAbstract::KeyEvent aKeyEvent) {
return mContent->OnKeyEvent(aKeyEvent);
}

View file

@ -22,7 +22,7 @@ public:
void OnHide() override;
private:
Base::Ptr mContent;
Base *mContent;
};
class TabView : public Base {

View file

@ -5,33 +5,24 @@
using namespace UI::Screen;
HomeScreen::HomeScreen(std::shared_ptr<HardwareAbstract> aHardware)
: Base(UI::ID::Screens::Home), mHardware(aHardware),
mTabView(ID(ID::Pages::INVALID_PAGE_ID)) {
: Base(UI::ID::Screens::Home), mHardware(aHardware) {
SetBgColor(UI::Color::BLACK);
SetPushAnimation(LV_SCR_LOAD_ANIM_FADE_IN);
AddElement(&mTabView); // Adds Tabview to Homescreen
mTabView = AddElement<Page::TabView>(std::make_unique<Page::TabView>(
ID(ID::Pages::INVALID_PAGE_ID))); // Adds Tabview to Homescreen
// Adds pages to the Tab view
mTabView.AddTab(std::make_unique<Page::SettingsPage>(aHardware), "Settings");
mTabView.AddTab(std::make_unique<Page::SettingsPage>(aHardware), "Settings1");
mTabView->AddTab(std::make_unique<Page::SettingsPage>(aHardware), "Settings");
mTabView->AddTab(std::make_unique<Page::SettingsPage>(aHardware),
"Settings1");
}
void HomeScreen::SetBgColor(lv_color_t value, lv_style_selector_t selector) {
mTabView.SetBgColor(value, selector);
mTabView->SetBgColor(value, selector);
UI::UIElement::SetBgColor(value, selector);
}
bool HomeScreen::OnKeyEvent(KeyPressAbstract::KeyEvent aKeyEvent) {
return false;
};
void HomeScreen::OnShow() { mTabView.OnShow(); };
void HomeScreen::OnHide() { mTabView.OnHide(); };
bool HomeScreen::KeyEvent(KeyPressAbstract::KeyEvent aKeyEvent) {
if (OnKeyEvent(aKeyEvent)) {
return true;
}
return mTabView.KeyEvent(aKeyEvent);
};

View file

@ -13,15 +13,13 @@ public:
void SetBgColor(lv_color_t value,
lv_style_selector_t selector = LV_PART_MAIN) override;
bool KeyEvent(KeyPressAbstract::KeyEvent aKeyEvent) override;
protected:
void OnShow() override;
void OnHide() override;
void OnShow() override{};
void OnHide() override{};
bool OnKeyEvent(KeyPressAbstract::KeyEvent aKeyEvent) override;
private:
Page::TabView mTabView;
Page::TabView *mTabView;
std::shared_ptr<HardwareAbstract> mHardware = nullptr;
};

View file

@ -6,10 +6,15 @@ using namespace UI;
using namespace UI::Screen;
PopUpScreen::PopUpScreen(Page::Base::Ptr aPage)
: Screen::Base(UI::ID::Screens::PopUp), mContentPage(std::move(aPage)),
mExitButton(std::make_unique<Widget::Button>(
[this] { UI::Screen::Manager::getInstance().popScreen(this); })),
mTitle(std::make_unique<Widget::Label>(mContentPage->GetTitle())) {
: Screen::Base(UI::ID::Screens::PopUp) {
mContentPage = AddElement<Page::Base>(std::move(aPage));
mExitButton = AddElement<Widget::Button>(std::make_unique<Widget::Button>(
[this] { UI::Screen::Manager::getInstance().popScreen(this); }));
mTitle = AddElement<Widget::Label>(
std::make_unique<Widget::Label>(mContentPage->GetTitle()));
mExitButton->SetWidth(lv_pct(10));
mExitButton->SetHeight(mExitButton->GetWidth());
@ -18,28 +23,13 @@ PopUpScreen::PopUpScreen(Page::Base::Ptr aPage)
mTitle->SetWidth(mExitButton->GetX());
mTitle->SetHeight(mExitButton->GetHeight());
mTitle->AlignTo(mExitButton.get(), LV_ALIGN_OUT_LEFT_BOTTOM);
mTitle->AlignTo(mExitButton, LV_ALIGN_OUT_LEFT_BOTTOM);
mTitle->SetTextStyle(mTitle->GetTextStyle().Align(LV_TEXT_ALIGN_CENTER));
mContentPage->SetHeight(GetHeight() - mExitButton->GetBottom() - 5);
mContentPage->SetY(mExitButton->GetBottom() + 5);
AddElement(mContentPage.get());
AddElement(mExitButton.get());
AddElement(mTitle.get());
}
bool PopUpScreen::OnKeyEvent(KeyPressAbstract::KeyEvent aKeyEvent) {
return mContentPage->OnKeyEvent(aKeyEvent);
}
void PopUpScreen::OnShow() {
mContentPage->OnShow();
mExitButton->OnShow();
mTitle->OnShow();
};
void PopUpScreen::OnHide() {
mContentPage->OnHide();
mExitButton->OnHide();
mTitle->OnHide();
};

View file

@ -14,14 +14,10 @@ public:
bool OnKeyEvent(KeyPressAbstract::KeyEvent aKeyEvent) override;
protected:
void OnShow() override;
void OnHide() override;
private:
UI::Page::Base::Ptr mContentPage;
std::unique_ptr<Widget::Button> mExitButton;
std::unique_ptr<Widget::Label> mTitle;
UI::Page::Base *mContentPage = nullptr;
Widget::Button *mExitButton = nullptr;
Widget::Label *mTitle = nullptr;
};
} // namespace UI::Screen

View file

@ -5,8 +5,6 @@
namespace UI {
class WidgetContainer;
namespace Screen {
class PopUpScreen;
}
@ -16,7 +14,6 @@ namespace UI::Widget {
class Base : public UIElement {
// Classes that Own Widgets
friend class UI::WidgetContainer;
friend class UI::Screen::PopUpScreen;
public: