1 | // Aseprite UI Library |
2 | // Copyright (C) 2018-2022 Igara Studio S.A. |
3 | // Copyright (C) 2001-2017 David Capello |
4 | // |
5 | // This file is released under the terms of the MIT license. |
6 | // Read LICENSE.txt for more information. |
7 | |
8 | #ifdef HAVE_CONFIG_H |
9 | #include "config.h" |
10 | #endif |
11 | |
12 | #include "gfx/size.h" |
13 | #include "ui/box.h" |
14 | #include "ui/message.h" |
15 | #include "ui/resize_event.h" |
16 | #include "ui/size_hint_event.h" |
17 | #include "ui/theme.h" |
18 | |
19 | #include <algorithm> |
20 | |
21 | namespace ui { |
22 | |
23 | using namespace gfx; |
24 | |
25 | Box::Box(int align) |
26 | : Widget(kBoxWidget) |
27 | { |
28 | enableFlags(IGNORE_MOUSE); |
29 | setAlign(align); |
30 | initTheme(); |
31 | } |
32 | |
33 | void Box::onSizeHint(SizeHintEvent& ev) |
34 | { |
35 | #define ADD_CHILD_SIZE(w, h) { \ |
36 | if (align() & HOMOGENEOUS) \ |
37 | prefSize.w = std::max(prefSize.w, childSize.w); \ |
38 | else \ |
39 | prefSize.w += childSize.w; \ |
40 | prefSize.h = std::max(prefSize.h, childSize.h); \ |
41 | } |
42 | |
43 | #define FINAL_ADJUSTMENT(w) { \ |
44 | if (align() & HOMOGENEOUS) \ |
45 | prefSize.w *= visibleChildren; \ |
46 | prefSize.w += childSpacing() * (visibleChildren-1); \ |
47 | } |
48 | |
49 | int visibleChildren = 0; |
50 | for (auto child : children()) { |
51 | if (!child->hasFlags(HIDDEN)) |
52 | ++visibleChildren; |
53 | } |
54 | |
55 | Size prefSize(0, 0); |
56 | for (auto child : children()) { |
57 | if (child->hasFlags(HIDDEN)) |
58 | continue; |
59 | |
60 | Size childSize = child->sizeHint(); |
61 | if (align() & HORIZONTAL) { |
62 | ADD_CHILD_SIZE(w, h); |
63 | } |
64 | else { |
65 | ADD_CHILD_SIZE(h, w); |
66 | } |
67 | } |
68 | |
69 | if (visibleChildren > 0) { |
70 | if (align() & HORIZONTAL) { |
71 | FINAL_ADJUSTMENT(w); |
72 | } |
73 | else { |
74 | FINAL_ADJUSTMENT(h); |
75 | } |
76 | } |
77 | |
78 | prefSize.w += border().width(); |
79 | prefSize.h += border().height(); |
80 | |
81 | ev.setSizeHint(prefSize); |
82 | } |
83 | |
84 | void Box::onResize(ResizeEvent& ev) |
85 | { |
86 | #define LAYOUT_CHILDREN(x, y, w, h) { \ |
87 | availExtraSize = availSize.w - prefSize.w; \ |
88 | availSize.w -= childSpacing() * (visibleChildren-1); \ |
89 | if (align() & HOMOGENEOUS) \ |
90 | homogeneousSize = availSize.w / visibleChildren; \ |
91 | \ |
92 | Rect defChildPos(childrenBounds()); \ |
93 | int i = 0, j = 0; \ |
94 | for (auto child : children()) { \ |
95 | if (child->hasFlags(HIDDEN)) \ |
96 | continue; \ |
97 | \ |
98 | int size = 0; \ |
99 | \ |
100 | if (align() & HOMOGENEOUS) { \ |
101 | if (i < visibleChildren-1) \ |
102 | size = homogeneousSize; \ |
103 | else \ |
104 | size = availSize.w; \ |
105 | } \ |
106 | else { \ |
107 | size = child->sizeHint().w; \ |
108 | \ |
109 | if (child->isExpansive()) { \ |
110 | int = (availExtraSize / (expansiveChildren-j)); \ |
111 | size += extraSize; \ |
112 | availExtraSize -= extraSize; \ |
113 | if (++j == expansiveChildren) \ |
114 | size += availExtraSize; \ |
115 | } \ |
116 | } \ |
117 | \ |
118 | Rect childPos = defChildPos; \ |
119 | childPos.w = size = std::clamp(size, child->minSize().w, child->maxSize().w); \ |
120 | childPos.h = std::clamp(childPos.h, child->minSize().h, child->maxSize().h); \ |
121 | child->setBounds(childPos); \ |
122 | \ |
123 | defChildPos.x += size + childSpacing(); \ |
124 | availSize.w -= size; \ |
125 | ++i; \ |
126 | } \ |
127 | } |
128 | |
129 | setBoundsQuietly(ev.bounds()); |
130 | |
131 | int visibleChildren = 0; |
132 | int expansiveChildren = 0; |
133 | for (auto child : children()) { |
134 | if (!child->hasFlags(HIDDEN)) { |
135 | ++visibleChildren; |
136 | if (child->isExpansive()) |
137 | ++expansiveChildren; |
138 | } |
139 | } |
140 | |
141 | if (visibleChildren > 0) { |
142 | Size prefSize(sizeHint()); |
143 | Size availSize(childrenBounds().size()); |
144 | int homogeneousSize = 0; |
145 | int = 0; |
146 | |
147 | prefSize.w -= border().width(); |
148 | prefSize.h -= border().height(); |
149 | |
150 | if (align() & HORIZONTAL) { |
151 | LAYOUT_CHILDREN(x, y, w, h); |
152 | } |
153 | else { |
154 | LAYOUT_CHILDREN(y, x, h, w); |
155 | } |
156 | } |
157 | } |
158 | |
159 | } // namespace ui |
160 | |