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:
parent
58787f5bf0
commit
736029c89a
16 changed files with 87 additions and 166 deletions
|
@ -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) {
|
||||
|
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
};
|
|
@ -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
|
|
@ -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);
|
||||
},
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ public:
|
|||
void OnHide() override;
|
||||
|
||||
private:
|
||||
Base::Ptr mContent;
|
||||
Base *mContent;
|
||||
};
|
||||
|
||||
class TabView : public Base {
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
};
|
|
@ -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
|
|
@ -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:
|
||||
|
|
Loading…
Add table
Reference in a new issue