From 810a8dc1c3863f4bc6da00aac0f429a8d208705a Mon Sep 17 00:00:00 2001 From: Przemyslaw Brudny Date: Tue, 25 Jan 2022 15:14:53 +0100 Subject: [PATCH] [EGD-7792] Meditation timer interval widget replacement Meditation timer interval widget replacement. --- .../models/NewEditAlarmModel.cpp | 4 +- .../widgets/AlarmClockStyle.hpp | 10 +- .../widgets/AlarmOptionsItem.cpp | 23 +-- .../widgets/AlarmOptionsItem.hpp | 10 +- .../application-call/data/CallAppStyle.hpp | 4 +- .../application-call/windows/NumberWindow.cpp | 2 +- .../application-meditation/data/Style.hpp | 27 --- .../widgets/IntervalBox.cpp | 166 ++++++------------ .../widgets/IntervalBox.hpp | 48 +---- .../windows/MeditationWindow.cpp | 4 +- module-apps/apps-common/CMakeLists.txt | 1 + .../apps-common/widgets/TextSpinnerBox.cpp | 10 +- .../widgets/TextSpinnerBoxWithLabel.cpp | 46 +++++ .../widgets/TextSpinnerBoxWithLabel.hpp | 37 ++++ .../widgets/spinners/GenericSpinner.hpp | 7 +- .../widgets/spinners/SpinnerPolicies.hpp | 11 +- 16 files changed, 183 insertions(+), 227 deletions(-) create mode 100644 module-apps/apps-common/widgets/TextSpinnerBoxWithLabel.cpp create mode 100644 module-apps/apps-common/widgets/TextSpinnerBoxWithLabel.hpp diff --git a/module-apps/application-alarm-clock/models/NewEditAlarmModel.cpp b/module-apps/application-alarm-clock/models/NewEditAlarmModel.cpp index 6bd28cdb8..1369c07a8 100644 --- a/module-apps/application-alarm-clock/models/NewEditAlarmModel.cpp +++ b/module-apps/application-alarm-clock/models/NewEditAlarmModel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "NewEditAlarmModel.hpp" @@ -30,7 +30,7 @@ namespace app::alarmClock unsigned int NewEditAlarmModel::getMinimalItemSpaceRequired() const { - return style::alarmClock::window::item::options::h; + return style::text_spinner_label::h; } void NewEditAlarmModel::requestRecords(uint32_t offset, uint32_t limit) diff --git a/module-apps/application-alarm-clock/widgets/AlarmClockStyle.hpp b/module-apps/application-alarm-clock/widgets/AlarmClockStyle.hpp index 0f4a40a02..a8756f364 100644 --- a/module-apps/application-alarm-clock/widgets/AlarmClockStyle.hpp +++ b/module-apps/application-alarm-clock/widgets/AlarmClockStyle.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #pragma once @@ -40,14 +40,6 @@ namespace style::alarmClock inline constexpr auto marginBot = 20; inline constexpr auto separator = 30; } // namespace time - - namespace options - { - inline constexpr auto spinner_h = 40; - inline constexpr auto label_h = 27; - inline constexpr auto h = spinner_h + label_h; - } // namespace options - } // namespace item } // namespace window diff --git a/module-apps/application-alarm-clock/widgets/AlarmOptionsItem.cpp b/module-apps/application-alarm-clock/widgets/AlarmOptionsItem.cpp index e5e9f88be..9879830ef 100644 --- a/module-apps/application-alarm-clock/widgets/AlarmOptionsItem.cpp +++ b/module-apps/application-alarm-clock/widgets/AlarmOptionsItem.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "AlarmOptionsItem.hpp" @@ -11,27 +11,12 @@ namespace gui { AlarmOptionsItem::AlarmOptionsItem(const std::string &description, const std::vector &options) { - setMinimumSize(style::listview::item_width_with_without_scroll, style::alarmClock::window::item::options::h); + setMinimumSize(style::listview::item_width_with_without_scroll, style::text_spinner_label::h); setEdges(RectangleEdge::None); setMargins(gui::Margins(style::widgets::leftMargin, style::margins::large, 0, 0)); - vBox = new gui::VBox(this, 0, 0, 0, 0); - vBox->setEdges(gui::RectangleEdge::None); - vBox->activeItem = false; - - descriptionLabel = new gui::Label(vBox, 0, 0, 0, 0); - descriptionLabel->setMinimumSize(style::window::default_body_width, - style::alarmClock::window::item::options::label_h); - descriptionLabel->setEdges(gui::RectangleEdge::None); - descriptionLabel->setAlignment(Alignment(gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Top)); - descriptionLabel->setFont(style::window::font::small); - descriptionLabel->activeItem = false; - descriptionLabel->setText(description); - - optionSpinner = new gui::TextSpinnerBox(vBox, options, Boundaries::Continuous); - optionSpinner->setMinimumSize(style::window::default_body_width, - style::alarmClock::window::item::options::spinner_h); + optionSpinner = new gui::TextSpinnerBoxWithLabel(this, description, options, Boundaries::Continuous); focusChangedCallback = [&](gui::Item &item) { setFocusItem(focus ? optionSpinner : nullptr); @@ -41,7 +26,7 @@ namespace gui inputCallback = [&](Item &item, const InputEvent &event) { return optionSpinner->onInput(event); }; dimensionChangedCallback = [&](gui::Item &, const BoundingBox &newDim) -> bool { - vBox->setArea({0, 0, newDim.w, newDim.h}); + optionSpinner->setArea({0, 0, newDim.w, newDim.h}); return true; }; } diff --git a/module-apps/application-alarm-clock/widgets/AlarmOptionsItem.hpp b/module-apps/application-alarm-clock/widgets/AlarmOptionsItem.hpp index e37edbfa2..ef9d4bd16 100644 --- a/module-apps/application-alarm-clock/widgets/AlarmOptionsItem.hpp +++ b/module-apps/application-alarm-clock/widgets/AlarmOptionsItem.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #pragma once @@ -7,7 +7,7 @@ #include #include -#include +#include namespace gui { @@ -17,11 +17,7 @@ namespace gui explicit AlarmOptionsItem(const std::string &description, const std::vector &options = {}); protected: - gui::TextSpinnerBox *optionSpinner = nullptr; - - private: - gui::VBox *vBox = nullptr; - gui::Label *descriptionLabel = nullptr; + gui::TextSpinnerBoxWithLabel *optionSpinner = nullptr; }; } /* namespace gui */ diff --git a/module-apps/application-call/data/CallAppStyle.hpp b/module-apps/application-call/data/CallAppStyle.hpp index 3d339f91a..c1f645a8a 100644 --- a/module-apps/application-call/data/CallAppStyle.hpp +++ b/module-apps/application-call/data/CallAppStyle.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #pragma once @@ -43,7 +43,7 @@ namespace callAppStyle inline constexpr auto x = 60U; inline constexpr auto y = 254U; inline constexpr auto w = style::window_width - 2 * x; - inline constexpr auto h = 20U; + inline constexpr auto h = 40U; } // namespace numberDescriptionLabel namespace icon diff --git a/module-apps/application-call/windows/NumberWindow.cpp b/module-apps/application-call/windows/NumberWindow.cpp index 214dbf991..e5ed067d2 100644 --- a/module-apps/application-call/windows/NumberWindow.cpp +++ b/module-apps/application-call/windows/NumberWindow.cpp @@ -68,7 +68,7 @@ namespace gui numberDescriptionLabel::h); numberDescriptionLabel->setFont(style::window::font::mediumlight); numberDescriptionLabel->setAlignment( - gui::Alignment{gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center}); + gui::Alignment{gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Top}); numberDescriptionLabel->setEdges(RectangleEdge::None); } diff --git a/module-apps/application-meditation/data/Style.hpp b/module-apps/application-meditation/data/Style.hpp index 5824a4043..489b83f9b 100644 --- a/module-apps/application-meditation/data/Style.hpp +++ b/module-apps/application-meditation/data/Style.hpp @@ -50,33 +50,6 @@ namespace style::meditation constexpr auto X = style::window::default_left_margin; constexpr auto Y = style::meditation::timer::Y + 2 * style::meditation::timer::Radius + VerticalWidgetGap; constexpr auto Width = style::window::default_body_width; - constexpr auto Height = 60; - - namespace topLabel - { - constexpr auto X = 0; - constexpr auto Y = 0; - constexpr auto Width = intervalBox::Width; - constexpr auto Height = intervalBox::Height / 2; - } // namespace topLabel - - namespace bottomLabel - { - constexpr auto X = 0; - constexpr auto Y = topLabel::Y + topLabel::Height; - constexpr auto Width = intervalBox::Width; - constexpr auto Height = intervalBox::Height / 2; - } // namespace bottomLabel - - namespace arrow - { - constexpr auto Y = 10; - constexpr auto Width = 15; - constexpr auto Height = intervalBox::Height / 2; - constexpr auto LeftX = 0; - constexpr auto RightX = intervalBox::Width - arrow::Width; - } // namespace arrow - } // namespace intervalBox namespace itemList diff --git a/module-apps/application-meditation/widgets/IntervalBox.cpp b/module-apps/application-meditation/widgets/IntervalBox.cpp index eb7f22a56..daea9180c 100644 --- a/module-apps/application-meditation/widgets/IntervalBox.cpp +++ b/module-apps/application-meditation/widgets/IntervalBox.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "IntervalBox.hpp" @@ -20,7 +20,7 @@ namespace } // namespace IntervalBox::IntervalBox(Item *parent, uint32_t x, uint32_t y, uint32_t w, uint32_t h, TimerProperty *timerSetter) - : BoxLayout(parent, x, y, w, h), timerSetter(timerSetter) + : HBox(parent, x, y, w, h), timerSetter(timerSetter) { assert(timerSetter); build(); @@ -28,136 +28,74 @@ IntervalBox::IntervalBox(Item *parent, uint32_t x, uint32_t y, uint32_t w, uint3 void IntervalBox::build() { - namespace boxStyle = style::meditation::intervalBox; + chimeSpinner = new gui::TextSpinnerBoxWithLabel( + this, utils::translate("app_meditation_interval_chime"), {}, Boundaries::Continuous); + chimeSpinner->setMinimumSize(widgetArea.w, widgetArea.h); + updateIntervals(); - auto topLabel = new Label(this, - boxStyle::topLabel::X, - boxStyle::topLabel::Y, - boxStyle::topLabel::Width, - boxStyle::topLabel::Height, - utils::translate("app_meditation_interval_chime")); - topLabel->setAlignment(Alignment(Alignment::Horizontal::Left, Alignment::Vertical::Bottom)); - topLabel->setFont(style::window::font::small); - topLabel->setEdges(RectangleEdge::None); + resizeItems(); - bottomLabel = new Label(this, - boxStyle::bottomLabel::X, - boxStyle::bottomLabel::Y, - boxStyle::bottomLabel::Width, - boxStyle::bottomLabel::Height); - bottomLabel->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Center)); - bottomLabel->setFont(style::window::font::small); - bottomLabel->setEdges(RectangleEdge::Bottom); - bottomLabel->setPenWidth(style::window::default_border_rect_no_focus); - - leftSwitchArrow = new gui::Image(bottomLabel, - boxStyle::arrow::LeftX, - boxStyle::arrow::Y, - boxStyle::arrow::Width, - boxStyle::arrow::Height, - "arrow_left_20px_W_M"); - rightSwitchArrow = new gui::Image(bottomLabel, - boxStyle::arrow::RightX, - boxStyle::arrow::Y, - boxStyle::arrow::Width, - boxStyle::arrow::Height, - "arrow_right_20px_W_M"); - - updateIntervals(ChimeIntervalList::Direction::Next); - leftSwitchArrow->setVisible(false); - rightSwitchArrow->setVisible(false); -} - -bool IntervalBox::onFocus(bool state) -{ - if (state) { - rescaleIntervals(); - bottomLabel->setPenWidth(style::window::default_border_focus_w); - bottomLabel->setFont(style::window::font::smallbold); - } - else { - bottomLabel->setPenWidth(style::window::default_border_rect_no_focus); - bottomLabel->setFont(style::window::font::small); - } - auto currentMeditationTime = timerSetter->getTime(); - leftSwitchArrow->setVisible(state && - chimeIntervals.hasNext(ChimeIntervalList::Direction::Previous, currentMeditationTime)); - rightSwitchArrow->setVisible(state && - chimeIntervals.hasNext(ChimeIntervalList::Direction::Next, currentMeditationTime)); - return true; -} - -bool IntervalBox::onInput(const InputEvent &inputEvent) -{ - if (inputEvent.isShortRelease()) { - if (inputEvent.is(KeyCode::KEY_LEFT)) { - updateIntervals(ChimeIntervalList::Direction::Previous); - return true; + focusChangedCallback = [&](gui::Item &item) { + if (focus) { + updateIntervals(); } - else if (inputEvent.is(KeyCode::KEY_RIGHT)) { - updateIntervals(ChimeIntervalList::Direction::Next); - return true; + setFocusItem(focus ? chimeSpinner : nullptr); + return true; + }; +} + +void IntervalBox::updateIntervals() +{ + auto setTime = timerSetter->getTime(); + + std::vector chimeOptions; + for (auto chime : chimeIntervals) { + if (chime < setTime) { + chimeOptions.push_back(intervalToString(chime)); + } + else { + break; } } - return false; -} -void IntervalBox::updateIntervals(ChimeIntervalList::Direction direction) -{ - auto currentMeditationTime = timerSetter->getTime(); - if (!chimeIntervals.moveToNext(direction, currentMeditationTime)) { - return; - } - intervalValue = chimeIntervals.getCurrent(); - bottomLabel->setText(ChimeIntervalList::toPrintableInterval(intervalValue)); + auto currentInterval = chimeSpinner->getCurrentValue(); + chimeSpinner->setData(chimeOptions); - leftSwitchArrow->setVisible(chimeIntervals.hasNext(ChimeIntervalList::Direction::Previous, currentMeditationTime)); - rightSwitchArrow->setVisible(chimeIntervals.hasNext(ChimeIntervalList::Direction::Next, currentMeditationTime)); -} - -void IntervalBox::rescaleIntervals() -{ - while (intervalValue >= timerSetter->getTime() && intervalValue != minutes{0}) { - updateIntervals(ChimeIntervalList::Direction::Previous); + if (stringToInterval(currentInterval) < setTime) { + chimeSpinner->setCurrentValue(currentInterval); } } -IntervalBox::ChimeIntervalList::ChimeIntervalList() : intervals(::chimeIntervals), current(intervals.begin()) -{} - -bool IntervalBox::ChimeIntervalList::moveToNext(Direction direction, std::chrono::minutes meditationTime) noexcept +std::chrono::seconds IntervalBox::getIntervalValue() noexcept { - if (!hasNext(direction, meditationTime)) { - return false; - } - if (direction == Direction::Next) { - current++; + if (stringToInterval(chimeSpinner->getCurrentValue()) < timerSetter->getTime()) { + return std::chrono::seconds{stringToInterval(chimeSpinner->getCurrentValue())}; } else { - current--; + return std::chrono::seconds{0}; } - return true; } -bool IntervalBox::ChimeIntervalList::hasNext(Direction direction, std::chrono::minutes meditationTime) const noexcept +std::string IntervalBox::intervalToString(std::chrono::minutes time) { - if (direction == Direction::Previous) { - return current != intervals.begin(); - } - auto result = std::next(current) != intervals.end(); - if (result) { - result = *std::next(current) < meditationTime; - } - return result; -} - -std::string IntervalBox::ChimeIntervalList::toPrintableInterval(std::chrono::minutes value) -{ - if (value.count() == 0) { + if (time.count() == 0) { return utils::translate("app_meditation_interval_none"); } const std::string toReplace = "%0"; - std::string temp = utils::translate("app_meditation_interval_every_x_minutes"); - temp.replace(temp.find(toReplace), toReplace.size(), std::to_string(static_cast(value.count()))); - return temp; + std::string description = utils::translate("app_meditation_interval_every_x_minutes"); + description.replace(description.find(toReplace), toReplace.size(), std::to_string(static_cast(time.count()))); + return description; +} + +std::chrono::minutes IntervalBox::stringToInterval(const std::string &description) +{ + if (description == utils::translate("app_meditation_interval_none")) { + return std::chrono::minutes(0); + } + + auto number = description; + number.erase(std::remove_if(number.begin(), number.end(), [](char c) { return !isdigit(c, std::locale()); }), + number.end()); + + return std::chrono::minutes(std::atoi(number.c_str())); } diff --git a/module-apps/application-meditation/widgets/IntervalBox.hpp b/module-apps/application-meditation/widgets/IntervalBox.hpp index 702daa117..b8ccffd01 100644 --- a/module-apps/application-meditation/widgets/IntervalBox.hpp +++ b/module-apps/application-meditation/widgets/IntervalBox.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -14,52 +15,21 @@ namespace gui { class TimerProperty; - class IntervalBox : public BoxLayout + class IntervalBox : public HBox { - class ChimeIntervalList - { - std::vector intervals; - std::vector::const_iterator current; - - public: - enum class Direction - { - Next, - Previous - }; - - ChimeIntervalList(); - - [[nodiscard]] std::chrono::minutes getCurrent() const noexcept - { - return *current; - } - - bool moveToNext(Direction dir, std::chrono::minutes meditationTime) noexcept; - [[nodiscard]] bool hasNext(Direction dir, std::chrono::minutes meditationTime) const noexcept; - - [[nodiscard]] static std::string toPrintableInterval(std::chrono::minutes time); - } chimeIntervals; - - TimerProperty *timerSetter = nullptr; - Label *bottomLabel = nullptr; - Image *leftSwitchArrow = nullptr; - Image *rightSwitchArrow = nullptr; - - std::chrono::minutes intervalValue{0}; + TimerProperty *timerSetter = nullptr; + TextSpinnerBoxWithLabel *chimeSpinner = nullptr; void build(); - void updateIntervals(ChimeIntervalList::Direction dir); + void updateIntervals(); + [[nodiscard]] std::string intervalToString(std::chrono::minutes time); + [[nodiscard]] std::chrono::minutes stringToInterval(const std::string &description); + void rescaleIntervals(); public: IntervalBox(Item *parent, uint32_t x, uint32_t y, uint32_t w, uint32_t h, TimerProperty *timerSetter); - bool onFocus(bool isFocused) final; - bool onInput(const InputEvent &inputEvent) final; - [[nodiscard]] std::chrono::seconds getIntervalValue() const noexcept - { - return std::chrono::seconds{intervalValue}; - } + [[nodiscard]] std::chrono::seconds getIntervalValue() noexcept; }; } // namespace gui diff --git a/module-apps/application-meditation/windows/MeditationWindow.cpp b/module-apps/application-meditation/windows/MeditationWindow.cpp index e22c37fba..f1f9a51ea 100644 --- a/module-apps/application-meditation/windows/MeditationWindow.cpp +++ b/module-apps/application-meditation/windows/MeditationWindow.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "ApplicationMeditation.hpp" @@ -51,7 +51,7 @@ namespace gui style::meditation::intervalBox::X, style::meditation::intervalBox::Y, style::meditation::intervalBox::Width, - style::meditation::intervalBox::Height, + style::text_spinner_label::h, timeSetter); intervalBox->setEdges(RectangleEdge::None); diff --git a/module-apps/apps-common/CMakeLists.txt b/module-apps/apps-common/CMakeLists.txt index 1b073bef9..b373c20dd 100644 --- a/module-apps/apps-common/CMakeLists.txt +++ b/module-apps/apps-common/CMakeLists.txt @@ -51,6 +51,7 @@ target_sources(apps-common widgets/ModesBox.cpp widgets/SpinBox.cpp widgets/TextSpinnerBox.cpp + widgets/TextSpinnerBoxWithLabel.cpp widgets/TextWithIconsWidget.cpp widgets/TimeSetSpinner.cpp widgets/AlarmSetSpinner.cpp diff --git a/module-apps/apps-common/widgets/TextSpinnerBox.cpp b/module-apps/apps-common/widgets/TextSpinnerBox.cpp index 9d8a816de..124bb3b42 100644 --- a/module-apps/apps-common/widgets/TextSpinnerBox.cpp +++ b/module-apps/apps-common/widgets/TextSpinnerBox.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "TextSpinnerBox.hpp" @@ -27,12 +27,18 @@ namespace gui inputCallback = [&](Item &item, const InputEvent &event) { return spinner->onInput(event); }; focusChangedCallback = [&](gui::Item &item) { - if (focus) { + if (focus && !spinner->isSingle()) { leftArrow->setVisible(true); rightArrow->setVisible(true); spinner->setFont(style::window::font::mediumbold); setPenWidth(style::window::default_border_focus_w); } + else if (focus && spinner->isSingle()) { + leftArrow->setVisible(false); + rightArrow->setVisible(false); + spinner->setFont(style::window::font::mediumbold); + setPenWidth(style::window::default_border_focus_w); + } else { leftArrow->setVisible(false); rightArrow->setVisible(false); diff --git a/module-apps/apps-common/widgets/TextSpinnerBoxWithLabel.cpp b/module-apps/apps-common/widgets/TextSpinnerBoxWithLabel.cpp new file mode 100644 index 000000000..27c077021 --- /dev/null +++ b/module-apps/apps-common/widgets/TextSpinnerBoxWithLabel.cpp @@ -0,0 +1,46 @@ +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "TextSpinnerBoxWithLabel.hpp" + +namespace gui +{ + TextSpinnerBoxWithLabel::TextSpinnerBoxWithLabel(Item *parent, + const std::string &description, + const std::vector &data, + Boundaries boundaries) + : VBox(parent) + { + setEdges(RectangleEdge::None); + descriptionLabel = new gui::Label(this, 0, 0, 0, 0); + descriptionLabel->setMinimumSize(style::window::default_body_width, style::text_spinner_label::label_h); + descriptionLabel->setEdges(gui::RectangleEdge::None); + descriptionLabel->setAlignment(Alignment(gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Top)); + descriptionLabel->setFont(style::window::font::small); + descriptionLabel->activeItem = false; + descriptionLabel->setText(description); + + optionSpinner = new gui::TextSpinnerBox(this, data, boundaries); + optionSpinner->setMinimumSize(style::window::default_body_width, style::text_spinner_label::spinner_h); + + focusChangedCallback = [&](gui::Item &item) { + setFocusItem(focus ? optionSpinner : nullptr); + return true; + }; + } + + void TextSpinnerBoxWithLabel::setData(const std::vector &data) + { + optionSpinner->setData(data); + } + + UTF8 TextSpinnerBoxWithLabel::getCurrentValue() const noexcept + { + return optionSpinner->getCurrentValue(); + } + + void TextSpinnerBoxWithLabel::setCurrentValue(UTF8 val) + { + optionSpinner->setCurrentValue(val); + } +} // namespace gui diff --git a/module-apps/apps-common/widgets/TextSpinnerBoxWithLabel.hpp b/module-apps/apps-common/widgets/TextSpinnerBoxWithLabel.hpp new file mode 100644 index 000000000..f279dc6fa --- /dev/null +++ b/module-apps/apps-common/widgets/TextSpinnerBoxWithLabel.hpp @@ -0,0 +1,37 @@ +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#pragma once + +#include +#include +#include + +namespace style::text_spinner_label +{ + inline constexpr auto spinner_h = 40; + inline constexpr auto label_h = 27; + inline constexpr auto h = spinner_h + label_h; +} // namespace style::text_spinner_label + +namespace gui +{ + class TextSpinnerBoxWithLabel : public VBox + { + public: + TextSpinnerBoxWithLabel(Item *parent, + const std::string &description, + const std::vector &data, + Boundaries boundaries); + + void setData(const std::vector &data); + [[nodiscard]] UTF8 getCurrentValue() const noexcept; + void setCurrentValue(UTF8 val); + + protected: + gui::TextSpinnerBox *optionSpinner = nullptr; + + private: + gui::Label *descriptionLabel = nullptr; + }; +} // namespace gui diff --git a/module-apps/apps-common/widgets/spinners/GenericSpinner.hpp b/module-apps/apps-common/widgets/spinners/GenericSpinner.hpp index 91ba98dbd..c346f875b 100644 --- a/module-apps/apps-common/widgets/spinners/GenericSpinner.hpp +++ b/module-apps/apps-common/widgets/spinners/GenericSpinner.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #pragma once @@ -27,6 +27,7 @@ namespace gui void setFocusEdges(RectangleEdge edges); bool onInput(const InputEvent &inputEvent) override; bool onFocus(bool state) override; + [[nodiscard]] bool isSingle() const; [[nodiscard]] bool isAtMin() const; [[nodiscard]] bool isAtMax() const; @@ -144,6 +145,10 @@ namespace gui onValueChanged(getCurrentValue()); } } + template bool GenericSpinner::isSingle() const + { + return policy.isSingle(); + } template bool GenericSpinner::isAtMin() const { return policy.isAtMin(); diff --git a/module-apps/apps-common/widgets/spinners/SpinnerPolicies.hpp b/module-apps/apps-common/widgets/spinners/SpinnerPolicies.hpp index e696c247a..58a2cc08a 100644 --- a/module-apps/apps-common/widgets/spinners/SpinnerPolicies.hpp +++ b/module-apps/apps-common/widgets/spinners/SpinnerPolicies.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #pragma once @@ -85,6 +85,10 @@ namespace gui } } + [[nodiscard]] bool isSingle() const + { + return range.size() == 1; + } [[nodiscard]] bool isAtMin() const { return pos == 0; @@ -291,7 +295,10 @@ namespace gui pos = 0; } } - + [[nodiscard]] bool isSingle() const + { + return range.size() == 1; + } [[nodiscard]] bool isAtMin() const { return pos == 0;