Home | History | Annotate | Download | only in views
      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) { return 0; }
     67 static SkScalar center_align_proc(SkScalar childLimit, SkScalar parentLimit) { return SkScalarHalf(parentLimit - childLimit); }
     68 static SkScalar right_align_proc(SkScalar childLimit, SkScalar parentLimit) { return parentLimit - childLimit; }
     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 */
     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 
     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
    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()) != 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 
    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