aboutsummaryrefslogtreecommitdiff
path: root/CruUI/ui/layout_base.h
blob: 25a6774cd5424d0f6c8bb9f6acc0aa1c5459aa62 (plain)
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
#pragma once

#include "system_headers.h"
#include <unordered_set>

#include "base.h"
#include "ui_base.h"

namespace cru
{
    namespace ui
    {
        class Control;


        enum class MeasureMode
        {
            Exactly,
            Content,
            Stretch
        };

        struct MeasureLength final
        {
            constexpr static MeasureLength Exactly(const float length)
            {
                return MeasureLength(MeasureMode::Exactly, length);
            }

            constexpr static MeasureLength Content()
            {
                return MeasureLength(MeasureMode::Content, 0);
            }

            constexpr static MeasureLength Stretch()
            {
                return MeasureLength(MeasureMode::Stretch, 0);
            }

            constexpr MeasureLength() = default;

            constexpr explicit MeasureLength(const MeasureMode mode, const float length)
                : length(length), mode(mode)
            {

            }

            constexpr bool Validate() const
            {
                if (mode == MeasureMode::Exactly && length < 0.0)
                {
#ifdef CRU_DEBUG
                    ::OutputDebugStringW(L"MeasureLength validation error: mode is Exactly but length is less than 0.\n");
#endif
                    return false;
                }
                return true;
            }

            float length = 0.0;
            MeasureMode mode = MeasureMode::Content;
        };

        struct BasicLayoutParams
        {
            BasicLayoutParams() = default;
            BasicLayoutParams(const BasicLayoutParams&) = default;
            BasicLayoutParams(BasicLayoutParams&&) = default;
            BasicLayoutParams& operator = (const BasicLayoutParams&) = default;
            BasicLayoutParams& operator = (BasicLayoutParams&&) = default;
            virtual ~BasicLayoutParams() = default;

            bool Validate() const
            {
                if (!width.Validate())
                {
#ifdef CRU_DEBUG
                    ::OutputDebugStringW(L"Width(MeasureLength) is not valid.");
#endif
                    return false;
                }
                if (!height.Validate())
                {
#ifdef CRU_DEBUG
                    ::OutputDebugStringW(L"Height(MeasureLength) is not valid.");
#endif
                    return false;
                }
                return true;
            }

            MeasureLength width;
            MeasureLength height;
        };


        class LayoutManager : public Object
        {
        public:
            static LayoutManager* GetInstance();

        public:
            LayoutManager() = default;
            LayoutManager(const LayoutManager& other) = delete;
            LayoutManager(LayoutManager&& other) = delete;
            LayoutManager& operator=(const LayoutManager& other) = delete;
            LayoutManager& operator=(LayoutManager&& other) = delete;
            ~LayoutManager() override = default;

            //Mark position cache of the control and its descendants invalid,
            //(which is saved as an auto-managed list internal)
            //and send a message to refresh them.
            void InvalidateControlPositionCache(Control* control);

            //Refresh position cache of the control and its descendants whose cache
            //has been marked as invalid.
            void RefreshInvalidControlPositionCache();

            //Refresh position cache of the control and its descendants immediately.
            static void RefreshControlPositionCache(Control* control);

        private:
            static void RefreshControlPositionCacheInternal(Control* control, const Point& parent_lefttop_absolute);

        private:
            std::unordered_set<Control*> cache_invalid_controls_;
        };
    }
}