~aleteoryx/muditaos

ref: 25250fc9c8730d958eb4b7417bac2be0686a6eaf muditaos/module-apps/apps-common/widgets/spinners/ItemSpinner.hpp -rw-r--r-- 4.6 KiB
25250fc9 — Tomasz Rybarski [BH-1314] Home Screen Layouts Selectable 4 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// 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 "SpinnerPolicies.hpp"
#include <Item.hpp>

namespace gui
{
    template <typename Policy> class ItemSpinner : public Item
    {
      public:
        using Range = typename Policy::Range;
        using Type  = typename Policy::Type;

        using OnValueChanged = std::function<void(const Type &&)>;

        explicit ItemSpinner(Item *parent,
                             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;
        [[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;
        gui::Item *currentLayout = nullptr;
    };

    template <typename ValuePolicy>
    ItemSpinner<ValuePolicy>::ItemSpinner(Item *parent,
                                          ItemSpinner::Range range,
                                          Boundaries boundaries,
                                          Orientation orientation)
        : Item(), policy{range, boundaries}, orientation(orientation)
    {
        this->parent = parent;
        if (parent != nullptr) {
            parent->addWidget(this);
        }
    }

    template <typename ValuePolicy> void ItemSpinner<ValuePolicy>::setFocusEdges(RectangleEdge edges)
    {
        focusEdges = edges;
    }

    template <typename Policy> void ItemSpinner<Policy>::setRange(Range range)
    {
        policy.updateRange(range);
        update();
    }

    template <typename ValuePolicy> void ItemSpinner<ValuePolicy>::setCurrentValue(const Type val)
    {
        policy.set(val);
        update();
    }

    template <typename Policy> typename ItemSpinner<Policy>::Type ItemSpinner<Policy>::getCurrentValue() const noexcept
    {
        return policy.get();
    }

    template <typename ValuePolicy> bool ItemSpinner<ValuePolicy>::isPreviousEvent(const InputEvent &inputEvent)
    {
        return (orientation == Orientation::Vertical && inputEvent.is(KeyCode::KEY_DOWN)) ||
               (orientation == Orientation::Horizontal && inputEvent.is(KeyCode::KEY_LEFT));
    }

    template <typename ValuePolicy> bool ItemSpinner<ValuePolicy>::isNextEvent(const InputEvent &inputEvent)
    {
        return (orientation == Orientation::Vertical && inputEvent.is(KeyCode::KEY_UP)) ||
               (orientation == Orientation::Horizontal && inputEvent.is(KeyCode::KEY_RIGHT));
    }

    template <typename ValuePolicy> bool ItemSpinner<ValuePolicy>::onInput(const InputEvent &inputEvent)
    {
        if (inputEvent.isShortRelease()) {
            if (isPreviousEvent(inputEvent)) {
                stepPrevious();
                return true;
            }
            else if (isNextEvent(inputEvent)) {
                stepNext();
                return true;
            }
        }
        return false;
    }

    template <typename Policy> void ItemSpinner<Policy>::stepNext()
    {
        if (policy.next()) {
            update();
            invoke();
        }
    }

    template <typename Policy> void ItemSpinner<Policy>::stepPrevious()
    {
        if (policy.previous()) {
            update();
            invoke();
        }
    }

    template <typename Policy> void ItemSpinner<Policy>::update()
    {
        if (currentLayout) {
            this->removeWidget(currentLayout);
        }
        currentLayout = policy.get();
        this->addWidget(currentLayout);
        informContentChanged();
    }
    template <typename Policy> void ItemSpinner<Policy>::invoke()
    {
        if (onValueChanged) {
            onValueChanged(getCurrentValue());
        }
    }
    template <typename Policy> bool ItemSpinner<Policy>::isAtMin() const
    {
        return policy.isAtMin();
    }
    template <typename Policy> bool ItemSpinner<Policy>::isAtMax() const
    {
        return policy.isAtMax();
    }
} // namespace gui