• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SkStackViewLayout()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 
setOrient(Orient ori)20 void SkStackViewLayout::setOrient(Orient ori)
21 {
22 	SkASSERT((unsigned)ori < kOrientCount);
23 	fOrient = SkToU8(ori);
24 }
25 
getMargin(SkRect * margin) const26 void SkStackViewLayout::getMargin(SkRect* margin) const
27 {
28 	if (margin)
29 		*margin = fMargin;
30 }
31 
setMargin(const SkRect & margin)32 void SkStackViewLayout::setMargin(const SkRect& margin)
33 {
34 	fMargin = margin;
35 }
36 
setSpacer(SkScalar spacer)37 void SkStackViewLayout::setSpacer(SkScalar spacer)
38 {
39 	fSpacer = spacer;
40 }
41 
setPack(Pack pack)42 void SkStackViewLayout::setPack(Pack pack)
43 {
44 	SkASSERT((unsigned)pack < kPackCount);
45 	fPack = SkToU8(pack);
46 }
47 
setAlign(Align align)48 void SkStackViewLayout::setAlign(Align align)
49 {
50 	SkASSERT((unsigned)align < kAlignCount);
51 	fAlign = SkToU8(align);
52 }
53 
setRound(bool r)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 
left_align_proc(SkScalar childLimit,SkScalar parentLimit)66 static SkScalar left_align_proc(SkScalar childLimit, SkScalar parentLimit) { return 0; }
center_align_proc(SkScalar childLimit,SkScalar parentLimit)67 static SkScalar center_align_proc(SkScalar childLimit, SkScalar parentLimit) { return SkScalarHalf(parentLimit - childLimit); }
right_align_proc(SkScalar childLimit,SkScalar parentLimit)68 static SkScalar right_align_proc(SkScalar childLimit, SkScalar parentLimit) { return parentLimit - childLimit; }
fill_align_proc(SkScalar childLimit,SkScalar parentLimit)69 static SkScalar fill_align_proc(SkScalar childLimit, SkScalar parentLimit) { return 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 */
compute_children_limit(SkView * parent,GetSizeProc sizeProc,int * count,uint32_t flexMask,int * flexCount)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()) != NULL)
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 
onLayoutChildren(SkView * parent)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 = NULL;
149 
150 	int			childCount, flexCount;
151 	SkScalar	childLimit = compute_children_limit(parent, mainGetSizeP, &childCount, 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()) != NULL)
168 	{
169 		if (fRound)
170 			pos = SkIntToScalar(SkScalarRound(pos));
171 		(child->*mainLocP)(pos);
172 		SkScalar crossLoc = crossStartM + gAlignProcs[fAlign]((child->*crossGetSizeP)(), crossLimit);
173 		if (fRound)
174 			crossLoc = SkIntToScalar(SkScalarRound(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
assert_no_attr(const SkDOM & dom,const SkDOM::Node * node,const char attr[])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 
onInflate(const SkDOM & dom,const SkDOM::Node * node)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 
SkFillViewLayout()240 SkFillViewLayout::SkFillViewLayout()
241 {
242 	fMargin.setEmpty();
243 }
244 
getMargin(SkRect * r) const245 void SkFillViewLayout::getMargin(SkRect* r) const
246 {
247 	if (r)
248 		*r = fMargin;
249 }
250 
setMargin(const SkRect & margin)251 void SkFillViewLayout::setMargin(const SkRect& margin)
252 {
253 	fMargin = margin;
254 }
255 
onLayoutChildren(SkView * parent)256 void SkFillViewLayout::onLayoutChildren(SkView* parent)
257 {
258 	SkView::B2FIter	iter(parent);
259 	SkView*			child;
260 
261 	while ((child = iter.next()) != NULL)
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 
onInflate(const SkDOM & dom,const SkDOM::Node * node)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 }
274 
275