~aleteoryx/muditaos

muditaos/module-gui/gui/widgets/BoxLayout.hpp -rw-r--r-- 6.5 KiB
a405cad6Aleteoryx trim readme 6 days 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
151
152
153
154
155
156
157
158
159
160
161
162
163
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

#pragma once

#include <cstdint>

#include "Layout.hpp"
#include "Rect.hpp"
#include <Alignment.hpp>
#include "LayoutSizeStore.hpp"
#include <log/log.hpp>

namespace gui
{

    class BoxLayout : public Rect, Layout
    {
      protected:
        struct BoxElement
        {
            BoxElement(Item *item) : item{item}, noUpdate{false} {};
            Item *item;
            bool noUpdate;
        };

        template <Axis axis>
        Length sizeUsed(Item *box, Area area = Area::Min)
        {
            Length sum = 0;

            std::for_each(box->children.begin(), box->children.end(), [&](auto &child) {
                sum += child->visible ? child->area(area).size(axis) + child->getMargins().getSumInAxis(axis) : 0;
            });
            return sum;
        };

        template <Axis axis>
        Length sizeUsedWithoutElem(Item *box, Item *elem, Area area = Area::Min)
        {
            Length sum = 0;

            std::for_each(box->children.begin(), box->children.end(), [&](auto &child) {
                if (child != elem) {
                    sum += child->visible ? child->area(area).size(axis) + child->getMargins().getSumInAxis(axis) : 0;
                }
            });
            return sum;
        };

        template <Axis axis>
        Length sizeLeft(Item *box, Area area = Area::Min)
        {
            return (sizeUsed<axis>(box, area) >= box->getSize(axis)) ? 0
                                                                     : box->getSize(axis) - sizeUsed<axis>(box, area);
        };

        template <Axis axis>
        Length sizeLeftWithoutElem(Item *box, Item *elem, Area area = Area::Min)
        {
            return (sizeUsedWithoutElem<axis>(box, elem, area) >= box->getSize(axis))
                       ? 0
                       : box->getSize(axis) - sizeUsedWithoutElem<axis>(box, elem, area);
        };

        template <Axis axis>
        void resizeItems();
        template <Axis axis>
        [[nodiscard]] Position getAxisAlignmentValue(Position calcPos, Length calcSize, Item *el);

        std::list<Item *> outOfDrawAreaItems;
        void addToOutOfDrawAreaList(Item *item);
        void addFromOutOfDrawAreaList();
        virtual void resizeItems();
        bool reverseOrder = false;

        template <Axis axis>
        [[nodiscard]] Length calculateElemResize(Item *el, Length &toSplit);
        template <Axis axis>
        [[nodiscard]] Length calculateElemAxisSize(Item *el, Length calculatedResize, Length &toSplit);
        template <Axis axis>
        [[nodiscard]] Length calculateElemOrtAxisSize(Item *el);
        template <Axis axis>
        [[nodiscard]] Position calculateElemAxisPosition(Item *el,
                                                         Length axisItemSize,
                                                         Position &startingPosition,
                                                         Position &leftPosition);
        template <Axis axis>
        [[nodiscard]] Position calculateElemOrtAxisPosition(Item *el, Length orthogonalItemSize);

        Item *getLastVisibleElement();

        /// get next navigation item including `from` item, ecludes not visible items and not acvite items
        std::list<Item *>::iterator nextNavigationItem(std::list<Item *>::iterator from);

      public:
        BoxLayout();
        BoxLayout(Item *parent, const uint32_t &x, const uint32_t &y, const uint32_t &w, const uint32_t &h);
        bool onInput(const InputEvent &inputEvent) override;
        virtual bool onFocus(bool state) override;
        virtual ~BoxLayout() = default;

        // virtual methods from Item
        void setAlignment(const Alignment &value) override;
        void addWidget(gui::Item *item) override;
        bool removeWidget(Item *item) override;
        bool erase(Item *item) override;
        void erase() override;
        [[nodiscard]] bool empty() const noexcept;
        /// add item if it will fit in box, return true on success
        /// axis sets direction to define space left in container
        template <Axis axis>
        void addWidget(Item *item);
        /// set navigation from last to fist element in box
        virtual void setNavigation();
        std::list<Item *>::iterator getNavigationFocusedItem();
        [[nodiscard]] unsigned int getFocusItemIndex() const;
        [[nodiscard]] unsigned int getVisibleChildrenCount();
        /// If requested causes box to change its structure parent may need to do some actions via this callback.
        std::function<void()> parentOnRequestedResizeCallback = nullptr;
        void setVisible(bool value) override;
        /// set visible but from previous scope... (page, element etc)
        void setVisible(bool value, bool previous);
        void setReverseOrder(bool value);
        [[nodiscard]] bool getReverseOrder();
        /// callback for situaton when we reached top/bottom/left/right of box
        /// if we want to do sth special (i.e. request new items)
        std::function<bool(const InputEvent &inputEvent)> borderCallback = nullptr;
        /// set focus on specified box element
        bool setFocusOnElement(unsigned int elementNumber);
        void setFocusOnLastElement();
        template <Axis axis>
        Size handleRequestResize(const Item *, Length request_w, Length request_h);
        bool onDimensionChanged(const BoundingBox &oldDim, const BoundingBox &newDim) override;
        void handleContentChanged() override;
        /// Get primary sizes used in axis dominant layouts
        Length getPrimarySizeLeft();
        Length getPrimarySize();
    };

    class HBox : public BoxLayout
    {
      public:
        void resizeItems() override;
        HBox();
        HBox(Item *parent, const uint32_t &x = 0, const uint32_t &y = 0, const uint32_t &w = 0, const uint32_t &h = 0);
        virtual ~HBox() = default;
        virtual void addWidget(Item *item) override;
        Size handleRequestResize(const Item *, Length request_w, Length request_h) override;
    };

    class VBox : public BoxLayout
    {
      public:
        void resizeItems() override;
        VBox();
        VBox(Item *parent, const uint32_t &x = 0, const uint32_t &y = 0, const uint32_t &w = 0, const uint32_t &h = 0);
        virtual ~VBox() = default;
        virtual void addWidget(Item *item) override;
        Size handleRequestResize(const Item *, Length request_w, Length request_h) override;
    };

} /* namespace gui */