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