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