// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #pragma once #include "SpinnerPolicies.hpp" #include namespace gui { template class GenericSpinner : public TextFixedSize { public: using Range = typename Policy::Range; using Type = typename Policy::Type; using OnValueChanged = std::function; explicit GenericSpinner(Range range, Boundaries boundaries = Boundaries::Continuous, Orientation orientation = Orientation::Vertical); [[nodiscard]] Type getCurrentValue() const noexcept; void setCurrentValue(Type val); void setRange(Range range); void setFocusEdges(RectangleEdge edges); bool onInput(const InputEvent &inputEvent) override; bool onFocus(bool state) override; [[nodiscard]] bool isAtMin() const; [[nodiscard]] bool isAtMax() const; OnValueChanged onValueChanged; private: void stepNext(); void stepPrevious(); bool isPreviousEvent(const InputEvent &inputEvent); bool isNextEvent(const InputEvent &inputEvent); void update(); void invoke(); Policy policy; RectangleEdge focusEdges = RectangleEdge::Bottom; Orientation orientation = Orientation::Vertical; }; template GenericSpinner::GenericSpinner(GenericSpinner::Range range, Boundaries boundaries, Orientation orientation) : policy{range, boundaries}, orientation(orientation) { setEditMode(EditMode::Browse); drawUnderline(false); update(); } template void GenericSpinner::setFocusEdges(RectangleEdge edges) { focusEdges = edges; } template void GenericSpinner::setRange(Range range) { policy.updateRange(range); update(); } template void GenericSpinner::setCurrentValue(const Type val) { policy.set(val); update(); } template typename GenericSpinner::Type GenericSpinner::getCurrentValue() const noexcept { return policy.get(); } template bool GenericSpinner::isPreviousEvent(const InputEvent &inputEvent) { return (orientation == Orientation::Vertical && inputEvent.is(KeyCode::KEY_DOWN)) || (orientation == Orientation::Horizontal && inputEvent.is(KeyCode::KEY_LEFT)); } template bool GenericSpinner::isNextEvent(const InputEvent &inputEvent) { return (orientation == Orientation::Vertical && inputEvent.is(KeyCode::KEY_UP)) || (orientation == Orientation::Horizontal && inputEvent.is(KeyCode::KEY_RIGHT)); } template bool GenericSpinner::onInput(const InputEvent &inputEvent) { if (inputEvent.isShortRelease()) { if (isPreviousEvent(inputEvent)) { stepPrevious(); return true; } else if (isNextEvent(inputEvent)) { stepNext(); return true; } } return false; } template bool GenericSpinner::onFocus(bool state) { if (focus) { setEdges(focusEdges); } else { setEdges(RectangleEdge::None); } showCursor(state); return true; } template void GenericSpinner::stepNext() { if (policy.next()) { update(); invoke(); } } template void GenericSpinner::stepPrevious() { if (policy.previous()) { update(); invoke(); } } template void GenericSpinner::update() { setText(policy.str()); } template void GenericSpinner::invoke() { if (onValueChanged) { onValueChanged(getCurrentValue()); } } template bool GenericSpinner::isAtMin() const { return policy.isAtMin(); } template bool GenericSpinner::isAtMax() const { return policy.isAtMax(); } } // namespace gui