| 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 |