OLD | NEW |
| (Empty) |
1 | |
2 /* | |
3 * Copyright 2011 Google Inc. | |
4 * | |
5 * Use of this source code is governed by a BSD-style license that can be | |
6 * found in the LICENSE file. | |
7 */ | |
8 #include "SkStackViewLayout.h" | |
9 | |
10 SkStackViewLayout::SkStackViewLayout() | |
11 { | |
12 fMargin.set(0, 0, 0, 0); | |
13 fSpacer = 0; | |
14 fOrient = kHorizontal_Orient; | |
15 fPack = kStart_Pack; | |
16 fAlign = kStart_Align; | |
17 fRound = false; | |
18 } | |
19 | |
20 void SkStackViewLayout::setOrient(Orient ori) | |
21 { | |
22 SkASSERT((unsigned)ori < kOrientCount); | |
23 fOrient = SkToU8(ori); | |
24 } | |
25 | |
26 void SkStackViewLayout::getMargin(SkRect* margin) const | |
27 { | |
28 if (margin) | |
29 *margin = fMargin; | |
30 } | |
31 | |
32 void SkStackViewLayout::setMargin(const SkRect& margin) | |
33 { | |
34 fMargin = margin; | |
35 } | |
36 | |
37 void SkStackViewLayout::setSpacer(SkScalar spacer) | |
38 { | |
39 fSpacer = spacer; | |
40 } | |
41 | |
42 void SkStackViewLayout::setPack(Pack pack) | |
43 { | |
44 SkASSERT((unsigned)pack < kPackCount); | |
45 fPack = SkToU8(pack); | |
46 } | |
47 | |
48 void SkStackViewLayout::setAlign(Align align) | |
49 { | |
50 SkASSERT((unsigned)align < kAlignCount); | |
51 fAlign = SkToU8(align); | |
52 } | |
53 | |
54 void SkStackViewLayout::setRound(bool r) | |
55 { | |
56 fRound = SkToU8(r); | |
57 } | |
58 | |
59 //////////////////////////////////////////////////////////////////////////////// | |
60 | |
61 typedef SkScalar (*AlignProc)(SkScalar childLimit, SkScalar parentLimit); | |
62 typedef SkScalar (SkView::*GetSizeProc)() const; | |
63 typedef void (SkView::*SetLocProc)(SkScalar coord); | |
64 typedef void (SkView::*SetSizeProc)(SkScalar coord); | |
65 | |
66 static SkScalar left_align_proc(SkScalar childLimit, SkScalar parentLimit) { ret
urn 0; } | |
67 static SkScalar center_align_proc(SkScalar childLimit, SkScalar parentLimit) { r
eturn SkScalarHalf(parentLimit - childLimit); } | |
68 static SkScalar right_align_proc(SkScalar childLimit, SkScalar parentLimit) { re
turn parentLimit - childLimit; } | |
69 static SkScalar fill_align_proc(SkScalar childLimit, SkScalar parentLimit) { ret
urn 0; } | |
70 | |
71 /* Measure the main-dimension for all the children. If a child is marked flex
in that direction | |
72 ignore its current value but increment the counter for flexChildren | |
73 */ | |
74 static SkScalar compute_children_limit(SkView* parent, GetSizeProc sizeProc, int
* count, | |
75 uint32_t flexMask, int* flexCount) | |
76 { | |
77 SkView::B2FIter iter(parent); | |
78 SkView* child; | |
79 SkScalar limit = 0; | |
80 int n = 0, flex = 0; | |
81 | |
82 while ((child = iter.next()) != nullptr) | |
83 { | |
84 n += 1; | |
85 if (child->getFlags() & flexMask) | |
86 flex += 1; | |
87 else | |
88 limit += (child->*sizeProc)(); | |
89 } | |
90 if (count) | |
91 *count = n; | |
92 if (flexCount) | |
93 *flexCount = flex; | |
94 return limit; | |
95 } | |
96 | |
97 void SkStackViewLayout::onLayoutChildren(SkView* parent) | |
98 { | |
99 static AlignProc gAlignProcs[] = { | |
100 left_align_proc, | |
101 center_align_proc, | |
102 right_align_proc, | |
103 fill_align_proc | |
104 }; | |
105 | |
106 SkScalar startM, endM, crossStartM, crossLimit; | |
107 GetSizeProc mainGetSizeP, crossGetSizeP; | |
108 SetLocProc mainLocP, crossLocP; | |
109 SetSizeProc mainSetSizeP, crossSetSizeP; | |
110 SkView::Flag_Mask flexMask; | |
111 | |
112 if (fOrient == kHorizontal_Orient) | |
113 { | |
114 startM = fMargin.fLeft; | |
115 endM = fMargin.fRight; | |
116 crossStartM = fMargin.fTop; | |
117 crossLimit = -fMargin.fTop - fMargin.fBottom; | |
118 | |
119 mainGetSizeP = &SkView::width; | |
120 crossGetSizeP = &SkView::height; | |
121 mainLocP = &SkView::setLocX; | |
122 crossLocP = &SkView::setLocY; | |
123 | |
124 mainSetSizeP = &SkView::setWidth; | |
125 crossSetSizeP = &SkView::setHeight; | |
126 | |
127 flexMask = SkView::kFlexH_Mask; | |
128 } | |
129 else | |
130 { | |
131 startM = fMargin.fTop; | |
132 endM = fMargin.fBottom; | |
133 crossStartM = fMargin.fLeft; | |
134 crossLimit = -fMargin.fLeft - fMargin.fRight; | |
135 | |
136 mainGetSizeP = &SkView::height; | |
137 crossGetSizeP = &SkView::width; | |
138 mainLocP = &SkView::setLocY; | |
139 crossLocP = &SkView::setLocX; | |
140 | |
141 mainSetSizeP = &SkView::setHeight; | |
142 crossSetSizeP = &SkView::setWidth; | |
143 | |
144 flexMask = SkView::kFlexV_Mask; | |
145 } | |
146 crossLimit += (parent->*crossGetSizeP)(); | |
147 if (fAlign != kStretch_Align) | |
148 crossSetSizeP = nullptr; | |
149 | |
150 int childCount, flexCount; | |
151 SkScalar childLimit = compute_children_limit(parent, mainGetSizeP, &child
Count, flexMask, &flexCount); | |
152 | |
153 if (childCount == 0) | |
154 return; | |
155 | |
156 childLimit += (childCount - 1) * fSpacer; | |
157 | |
158 SkScalar parentLimit = (parent->*mainGetSizeP)() - startM - endM; | |
159 SkScalar pos = startM + gAlignProcs[fPack](childLimit, parentLimit); | |
160 SkScalar flexAmount = 0; | |
161 SkView::B2FIter iter(parent); | |
162 SkView* child; | |
163 | |
164 if (flexCount > 0 && parentLimit > childLimit) | |
165 flexAmount = (parentLimit - childLimit) / flexCount; | |
166 | |
167 while ((child = iter.next()) != nullptr) | |
168 { | |
169 if (fRound) | |
170 pos = SkScalarRoundToScalar(pos); | |
171 (child->*mainLocP)(pos); | |
172 SkScalar crossLoc = crossStartM + gAlignProcs[fAlign]((child->*crossGetS
izeP)(), crossLimit); | |
173 if (fRound) | |
174 crossLoc = SkScalarRoundToScalar(crossLoc); | |
175 (child->*crossLocP)(crossLoc); | |
176 | |
177 if (crossSetSizeP) | |
178 (child->*crossSetSizeP)(crossLimit); | |
179 if (child->getFlags() & flexMask) | |
180 (child->*mainSetSizeP)(flexAmount); | |
181 pos += (child->*mainGetSizeP)() + fSpacer; | |
182 } | |
183 } | |
184 | |
185 ////////////////////////////////////////////////////////////////////////////////
////// | |
186 | |
187 #ifdef SK_DEBUG | |
188 static void assert_no_attr(const SkDOM& dom, const SkDOM::Node* node, const
char attr[]) | |
189 { | |
190 const char* value = dom.findAttr(node, attr); | |
191 if (value) | |
192 SkDebugf("unknown attribute %s=\"%s\"\n", attr, value); | |
193 } | |
194 #else | |
195 #define assert_no_attr(dom, node, attr) | |
196 #endif | |
197 | |
198 void SkStackViewLayout::onInflate(const SkDOM& dom, const SkDOM::Node* node) | |
199 { | |
200 int index; | |
201 SkScalar value[4]; | |
202 | |
203 if ((index = dom.findList(node, "orient", "horizontal,vertical")) >= 0) | |
204 this->setOrient((Orient)index); | |
205 else { | |
206 assert_no_attr(dom, node, "orient"); | |
207 } | |
208 | |
209 if (dom.findScalars(node, "margin", value, 4)) | |
210 { | |
211 SkRect margin; | |
212 margin.set(value[0], value[1], value[2], value[3]); | |
213 this->setMargin(margin); | |
214 } | |
215 else { | |
216 assert_no_attr(dom, node, "margin"); | |
217 } | |
218 | |
219 if (dom.findScalar(node, "spacer", value)) | |
220 this->setSpacer(value[0]); | |
221 else { | |
222 assert_no_attr(dom, node, "spacer"); | |
223 } | |
224 | |
225 if ((index = dom.findList(node, "pack", "start,center,end")) >= 0) | |
226 this->setPack((Pack)index); | |
227 else { | |
228 assert_no_attr(dom, node, "pack"); | |
229 } | |
230 | |
231 if ((index = dom.findList(node, "align", "start,center,end,stretch")) >= 0) | |
232 this->setAlign((Align)index); | |
233 else { | |
234 assert_no_attr(dom, node, "align"); | |
235 } | |
236 } | |
237 | |
238 ////////////////////////////////////////////////////////////////////////////////
/////////// | |
239 | |
240 SkFillViewLayout::SkFillViewLayout() | |
241 { | |
242 fMargin.setEmpty(); | |
243 } | |
244 | |
245 void SkFillViewLayout::getMargin(SkRect* r) const | |
246 { | |
247 if (r) | |
248 *r = fMargin; | |
249 } | |
250 | |
251 void SkFillViewLayout::setMargin(const SkRect& margin) | |
252 { | |
253 fMargin = margin; | |
254 } | |
255 | |
256 void SkFillViewLayout::onLayoutChildren(SkView* parent) | |
257 { | |
258 SkView::B2FIter iter(parent); | |
259 SkView* child; | |
260 | |
261 while ((child = iter.next()) != nullptr) | |
262 { | |
263 child->setLoc(fMargin.fLeft, fMargin.fTop); | |
264 child->setSize( parent->width() - fMargin.fRight - fMargin.fLeft, | |
265 parent->height() - fMargin.fBottom - fMargin.fTop); | |
266 } | |
267 } | |
268 | |
269 void SkFillViewLayout::onInflate(const SkDOM& dom, const SkDOM::Node* node) | |
270 { | |
271 this->INHERITED::onInflate(dom, node); | |
272 (void)dom.findScalars(node, "margin", (SkScalar*)&fMargin, 4); | |
273 } | |
OLD | NEW |