// 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 namespace gui { template class ItemSpinner : public Item { public: using range = typename Container::range; using value_type = typename Container::value_type; using OnValueChanged = std::function; explicit ItemSpinner(Item *parent, range range, Boundaries boundaries = Boundaries::Continuous, Orientation orientation = Orientation::Vertical); [[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 ItemSpinner::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 void ItemSpinner::setFocusEdges(RectangleEdge edges) { focusEdges = edges; } template void ItemSpinner::setRange(range range) { container.updateRange(range); update(); } template void ItemSpinner::setCurrentValue(const value_type val) { container.set(val); update(); } template typename ItemSpinner::value_type ItemSpinner::getCurrentValue() const noexcept { return container.get(); } template bool ItemSpinner::isPreviousEvent(const InputEvent &inputEvent) { return (orientation == Orientation::Vertical && inputEvent.is(KeyCode::KEY_DOWN)) || (orientation == Orientation::Horizontal && inputEvent.is(KeyCode::KEY_LEFT)); } template bool ItemSpinner::isNextEvent(const InputEvent &inputEvent) { return (orientation == Orientation::Vertical && inputEvent.is(KeyCode::KEY_UP)) || (orientation == Orientation::Horizontal && inputEvent.is(KeyCode::KEY_RIGHT)); } template bool ItemSpinner::onInput(const InputEvent &inputEvent) { if (inputEvent.isShortRelease()) { if (isPreviousEvent(inputEvent)) { stepPrevious(); return true; } else if (isNextEvent(inputEvent)) { stepNext(); return true; } } return false; } template void ItemSpinner::stepNext() { if (container.next()) { update(); invoke(); } } template void ItemSpinner::stepPrevious() { if (container.previous()) { update(); invoke(); } } template void ItemSpinner::update() { if (currentLayout != nullptr) { this->removeWidget(currentLayout); } currentLayout = container.get(); this->addWidget(currentLayout); informContentChanged(); } template void ItemSpinner::invoke() { if (onValueChanged) { onValueChanged(getCurrentValue()); } } template bool ItemSpinner::isAtMin() const { return container.is_min(); } template bool ItemSpinner::isAtMax() const { return container.is_max(); } } // namespace gui