mirror of
https://github.com/mudita/MuditaOS.git
synced 2026-05-19 14:15:02 -04:00
Disable libphonenumber initialization since it is not used in Harmony but takes around 1.4MB of memory Add heap allocation statistics
186 lines
5.4 KiB
C++
186 lines
5.4 KiB
C++
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
|
|
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
|
|
|
|
#pragma once
|
|
|
|
#include <Item.hpp>
|
|
#include <InputEvent.hpp>
|
|
|
|
namespace gui
|
|
{
|
|
template <typename Container>
|
|
class ItemSpinner : public Item
|
|
{
|
|
public:
|
|
using range = typename Container::range;
|
|
using value_type = typename Container::value_type;
|
|
|
|
using OnValueChanged = std::function<void(const value_type &&)>;
|
|
|
|
explicit ItemSpinner(Item *parent,
|
|
range range,
|
|
Boundaries boundaries = Boundaries::Continuous,
|
|
Orientation orientation = Orientation::Vertical);
|
|
~ItemSpinner();
|
|
|
|
[[nodiscard]] value_type getCurrentValue() const noexcept;
|
|
void setCurrentValue(value_type val);
|
|
void setRange(range range);
|
|
|
|
void setFocusEdges(RectangleEdge edges);
|
|
bool onInput(const InputEvent &inputEvent) override;
|
|
[[nodiscard]] bool isAtMin() const;
|
|
[[nodiscard]] bool isAtMax() const;
|
|
|
|
OnValueChanged onValueChanged;
|
|
|
|
private:
|
|
inline typename Container::Boundaries convert_boundaries(gui::Boundaries boundaries)
|
|
{
|
|
switch (boundaries) {
|
|
case gui::Boundaries::Fixed:
|
|
return Container::Boundaries::Fixed;
|
|
case gui::Boundaries::Continuous:
|
|
return Container::Boundaries::Continuous;
|
|
}
|
|
return Container::Boundaries::Fixed;
|
|
}
|
|
void stepNext();
|
|
void stepPrevious();
|
|
bool isPreviousEvent(const InputEvent &inputEvent);
|
|
bool isNextEvent(const InputEvent &inputEvent);
|
|
void update();
|
|
void invoke();
|
|
|
|
Container container;
|
|
RectangleEdge focusEdges = RectangleEdge::Bottom;
|
|
Orientation orientation = Orientation::Vertical;
|
|
gui::Item *currentLayout = nullptr;
|
|
};
|
|
|
|
template <typename Container>
|
|
ItemSpinner<Container>::ItemSpinner(Item *parent,
|
|
ItemSpinner::range range,
|
|
Boundaries boundaries,
|
|
Orientation orientation)
|
|
: Item(), container{range, convert_boundaries(boundaries)}, orientation(orientation)
|
|
{
|
|
this->parent = parent;
|
|
if (parent != nullptr) {
|
|
parent->addWidget(this);
|
|
}
|
|
}
|
|
|
|
template <typename Container>
|
|
ItemSpinner<Container>::~ItemSpinner()
|
|
{
|
|
for (Item *layout : container) {
|
|
if (layout != currentLayout) {
|
|
delete layout;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename Container>
|
|
void ItemSpinner<Container>::setFocusEdges(RectangleEdge edges)
|
|
{
|
|
focusEdges = edges;
|
|
}
|
|
|
|
template <typename Container>
|
|
void ItemSpinner<Container>::setRange(range range)
|
|
{
|
|
container.updateRange(range);
|
|
update();
|
|
}
|
|
|
|
template <typename Container>
|
|
void ItemSpinner<Container>::setCurrentValue(const value_type val)
|
|
{
|
|
container.set(val);
|
|
update();
|
|
}
|
|
|
|
template <typename Container>
|
|
typename ItemSpinner<Container>::value_type ItemSpinner<Container>::getCurrentValue() const noexcept
|
|
{
|
|
return container.get();
|
|
}
|
|
|
|
template <typename Container>
|
|
bool ItemSpinner<Container>::isPreviousEvent(const InputEvent &inputEvent)
|
|
{
|
|
return (orientation == Orientation::Vertical && inputEvent.is(KeyCode::KEY_DOWN)) ||
|
|
(orientation == Orientation::Horizontal && inputEvent.is(KeyCode::KEY_LEFT));
|
|
}
|
|
|
|
template <typename Container>
|
|
bool ItemSpinner<Container>::isNextEvent(const InputEvent &inputEvent)
|
|
{
|
|
return (orientation == Orientation::Vertical && inputEvent.is(KeyCode::KEY_UP)) ||
|
|
(orientation == Orientation::Horizontal && inputEvent.is(KeyCode::KEY_RIGHT));
|
|
}
|
|
|
|
template <typename Container>
|
|
bool ItemSpinner<Container>::onInput(const InputEvent &inputEvent)
|
|
{
|
|
if (inputEvent.isShortRelease()) {
|
|
if (isPreviousEvent(inputEvent)) {
|
|
stepPrevious();
|
|
return true;
|
|
}
|
|
else if (isNextEvent(inputEvent)) {
|
|
stepNext();
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
template <typename Container>
|
|
void ItemSpinner<Container>::stepNext()
|
|
{
|
|
if (container.next()) {
|
|
update();
|
|
invoke();
|
|
}
|
|
}
|
|
|
|
template <typename Container>
|
|
void ItemSpinner<Container>::stepPrevious()
|
|
{
|
|
if (container.previous()) {
|
|
update();
|
|
invoke();
|
|
}
|
|
}
|
|
|
|
template <typename Container>
|
|
void ItemSpinner<Container>::update()
|
|
{
|
|
if (currentLayout != nullptr) {
|
|
this->removeWidget(currentLayout);
|
|
}
|
|
currentLayout = container.get();
|
|
this->addWidget(currentLayout);
|
|
informContentChanged();
|
|
}
|
|
template <typename Container>
|
|
void ItemSpinner<Container>::invoke()
|
|
{
|
|
if (onValueChanged) {
|
|
onValueChanged(getCurrentValue());
|
|
}
|
|
}
|
|
template <typename Container>
|
|
bool ItemSpinner<Container>::isAtMin() const
|
|
{
|
|
return container.is_min();
|
|
}
|
|
template <typename Container>
|
|
bool ItemSpinner<Container>::isAtMax() const
|
|
{
|
|
return container.is_max();
|
|
}
|
|
} // namespace gui
|