Flow.hx 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  1. package h2d;
  2. enum FlowAlign {
  3. Top;
  4. Left;
  5. Right;
  6. Middle;
  7. Bottom;
  8. }
  9. @:allow(h2d.Flow)
  10. class FlowProperties {
  11. var elt : Object;
  12. public var paddingLeft = 0;
  13. public var paddingTop = 0;
  14. public var paddingRight = 0;
  15. public var paddingBottom = 0;
  16. public var isAbsolute(default,set) = false;
  17. public var horizontalAlign : Null<FlowAlign>;
  18. public var verticalAlign : Null<FlowAlign>;
  19. public var offsetX = 0;
  20. public var offsetY = 0;
  21. public var minWidth : Null<Int>;
  22. public var minHeight : Null<Int>;
  23. public var calculatedWidth(default,null) : Int = 0;
  24. public var calculatedHeight(default,null) : Int = 0;
  25. public var isBreak(default,null) : Bool;
  26. /**
  27. If our flow have a maximum size, it will constraint the children by using .constraintSize()
  28. **/
  29. public var constraint = true;
  30. public function new(elt) {
  31. this.elt = elt;
  32. }
  33. public inline function align(vertical, horizontal) {
  34. this.verticalAlign = vertical;
  35. this.horizontalAlign = horizontal;
  36. }
  37. function set_isAbsolute(a) {
  38. if( a ) @:privateAccess elt.constraintSize( -1, -1); // remove constraint
  39. return isAbsolute = a;
  40. }
  41. }
  42. class Flow extends Object {
  43. var tmpBounds = new h2d.col.Bounds();
  44. /**
  45. If some sub element gets resized, you need to set reflow to true in order to force
  46. the reflow of elements. You can also directly call reflow() which will immediately
  47. update all elements positions.
  48. If a reflow is needed, reflow() will be called before rendering the flow.
  49. Each change in one of the flow properties or addition/removal of elements will set needReflow to true.
  50. **/
  51. public var needReflow(default, set) : Bool = true;
  52. /**
  53. Horizontal alignment of elements inside the flow.
  54. **/
  55. public var horizontalAlign(default, set) : Null<FlowAlign>;
  56. /**
  57. Vertical alignment of elements inside the flow.
  58. **/
  59. public var verticalAlign(default,set) : Null<FlowAlign>;
  60. public var minWidth(default, set) : Null<Int>;
  61. public var minHeight(default, set) : Null<Int>;
  62. public var maxWidth(default, set) : Null<Int>;
  63. public var maxHeight(default, set) : Null<Int>;
  64. public var lineHeight(default, set) : Null<Int>;
  65. public var colWidth(default, set) : Null<Int>;
  66. /**
  67. Enabling overflow will treat maxWidth/maxHeight and lineHeight/colWidth constraints as absolute : bigger elements will overflow instead of expanding the limit.
  68. **/
  69. public var overflow(default, set) : Bool = false;
  70. /**
  71. Will set all padding values at the same time.
  72. **/
  73. public var padding(never, set) : Int;
  74. public var paddingHorizontal(never, set) : Int;
  75. public var paddingVertical(never, set) : Int;
  76. public var paddingLeft(default, set) : Int = 0;
  77. public var paddingRight(default, set) : Int = 0;
  78. public var paddingTop(default, set) : Int = 0;
  79. public var paddingBottom(default, set) : Int = 0;
  80. /**
  81. The horizontal space between two flowed elements.
  82. **/
  83. public var horizontalSpacing(default, set) : Int = 0;
  84. /**
  85. The vertical space between two flowed elements.
  86. **/
  87. public var verticalSpacing(default, set) : Int = 0;
  88. /**
  89. Set enableInteractive to true to create an h2d.Interactive accessible through
  90. the interactive field which will automatically cover the whole Flow area.
  91. **/
  92. public var enableInteractive(default, set) : Bool;
  93. /**
  94. See enableInteractive.
  95. **/
  96. public var interactive(default, null) : h2d.Interactive;
  97. /**
  98. Setting a background tile will create a ScaleGrid background which uses the borderWidth/Height values for its borders.
  99. It will automatically resize when the reflow is done to cover the whole Flow area.
  100. **/
  101. public var backgroundTile(default, set) : h2d.Tile;
  102. public var borderWidth(default, set) : Int = 0;
  103. public var borderHeight(default, set) : Int = 0;
  104. /**
  105. Calculate the client width, which is the innner size of the flow without the borders and padding.
  106. **/
  107. public var innerWidth(get, never) : Int;
  108. /**
  109. Calculate the client height, which is the innner size of the flow without the borders and padding.
  110. **/
  111. public var innerHeight(get, never) : Int;
  112. /**
  113. Flow total width (inlcudes borders and paddings)
  114. **/
  115. public var outerWidth(get, never) : Int;
  116. /**
  117. Flow total height (inlcudes borders and paddings)
  118. **/
  119. public var outerHeight(get, never) : Int;
  120. /**
  121. By default, elements will be flowed horizontaly, then in several lines if maxWidth is reached.
  122. You can instead flow them vertically, then to next column is maxHeight is reached by setting the isVertical flag to true.
  123. **/
  124. public var isVertical(default, set) : Bool;
  125. /**
  126. When isInline is set to false, the flow size will be reported based on its bounds instead of its calculated size.
  127. See getSize() documentation.
  128. **/
  129. public var isInline = true;
  130. /**
  131. When set to true, the debug will display red box around the flow, green box for the client space and blue boxes for each element.
  132. **/
  133. public var debug(default, set) : Bool;
  134. /**
  135. When set to true, uses specified lineHeight/colWidth instead of maxWidth/maxHeight for alignment.
  136. **/
  137. public var multiline(default,set) : Bool = false;
  138. var background : h2d.ScaleGrid;
  139. var debugGraphics : h2d.Graphics;
  140. var properties : Array<FlowProperties> = [];
  141. var calculatedWidth : Float = 0.;
  142. var calculatedHeight : Float = 0.;
  143. var constraintWidth : Float = -1;
  144. var constraintHeight : Float = -1;
  145. var realMaxWidth : Float = -1;
  146. var realMaxHeight : Float = -1;
  147. public function new(?parent) {
  148. super(parent);
  149. }
  150. /**
  151. Get the per-element properties. Returns null if the element is not currently part of the flow.
  152. **/
  153. public function getProperties( e : h2d.Object ) {
  154. needReflow = true; // properties might be changed
  155. return properties[getChildIndex(e)];
  156. }
  157. function set_isVertical(v) {
  158. if( isVertical == v )
  159. return v;
  160. needReflow = true;
  161. return isVertical = v;
  162. }
  163. function set_horizontalAlign(v) {
  164. if( horizontalAlign == v )
  165. return v;
  166. needReflow = true;
  167. return horizontalAlign = v;
  168. }
  169. function set_debug(v) {
  170. if( debug == v )
  171. return v;
  172. needReflow = true;
  173. if( v ) {
  174. debugGraphics = new h2d.Graphics(this);
  175. getProperties(debugGraphics).isAbsolute = true;
  176. } else {
  177. debugGraphics.remove();
  178. debugGraphics = null;
  179. }
  180. return debug = v;
  181. }
  182. function set_verticalAlign(v) {
  183. if( verticalAlign == v )
  184. return v;
  185. needReflow = true;
  186. return verticalAlign = v;
  187. }
  188. function set_overflow(v) {
  189. if( overflow == v )
  190. return v;
  191. needReflow = true;
  192. return overflow = v;
  193. }
  194. function set_multiline(v) {
  195. if( multiline == v )
  196. return v;
  197. needReflow = true;
  198. return multiline = v;
  199. }
  200. function set_needReflow(v) {
  201. if( needReflow == v )
  202. return v;
  203. if( v )
  204. onContentChanged();
  205. return needReflow = v;
  206. }
  207. function set_lineHeight(v) {
  208. if( lineHeight == v )
  209. return v;
  210. needReflow = true;
  211. return lineHeight = v;
  212. }
  213. function set_colWidth(v) {
  214. if( colWidth == v )
  215. return v;
  216. needReflow = true;
  217. return colWidth = v;
  218. }
  219. function set_padding(v) {
  220. paddingLeft = v;
  221. paddingTop = v;
  222. paddingRight = v;
  223. paddingBottom = v;
  224. return v;
  225. }
  226. inline function set_paddingHorizontal(v) {
  227. paddingLeft = v;
  228. paddingRight = v;
  229. return v;
  230. }
  231. inline function set_paddingVertical(v) {
  232. paddingTop = v;
  233. paddingBottom = v;
  234. return v;
  235. }
  236. function get_outerWidth() {
  237. if( needReflow ) reflow();
  238. return Math.ceil(calculatedWidth);
  239. }
  240. function get_outerHeight() {
  241. if( needReflow ) reflow();
  242. return Math.ceil(calculatedHeight);
  243. }
  244. function get_innerWidth() {
  245. if( needReflow ) reflow();
  246. return Math.ceil(calculatedWidth) - (paddingLeft + paddingRight + borderWidth * 2);
  247. }
  248. function get_innerHeight() {
  249. if( needReflow ) reflow();
  250. return Math.ceil(calculatedHeight) - (paddingTop + paddingBottom + borderHeight * 2);
  251. }
  252. function set_paddingLeft(v) {
  253. if( paddingLeft == v ) return v;
  254. needReflow = true;
  255. return paddingLeft = v;
  256. }
  257. function set_paddingRight(v) {
  258. if( paddingRight == v ) return v;
  259. needReflow = true;
  260. return paddingRight = v;
  261. }
  262. function set_paddingTop(v) {
  263. if( paddingTop == v ) return v;
  264. needReflow = true;
  265. return paddingTop = v;
  266. }
  267. function set_paddingBottom(v) {
  268. if( paddingBottom == v ) return v;
  269. needReflow = true;
  270. return paddingBottom = v;
  271. }
  272. override function constraintSize( width, height ) {
  273. constraintWidth = width;
  274. constraintHeight = height;
  275. updateConstraint();
  276. }
  277. override function contentChanged( s : Object ) {
  278. while( s.parent != this )
  279. s = s.parent;
  280. if( getProperties(s).isAbsolute )
  281. return;
  282. needReflow = true;
  283. onContentChanged();
  284. }
  285. /**
  286. Adds some spacing by either increasing the padding of the latest
  287. non absolute element or the padding of the flow if no element was found.
  288. The padding affected depends on the isVertical property.
  289. **/
  290. public function addSpacing( v : Int ) {
  291. var last = properties.length - 1;
  292. while( last >= 0 && properties[last].isAbsolute )
  293. last--;
  294. if( isVertical ) {
  295. if( last >= 0 )
  296. properties[last].paddingBottom += v;
  297. else
  298. paddingTop += v;
  299. } else {
  300. if( last >= 0 )
  301. properties[last].paddingRight += v;
  302. else
  303. paddingLeft += v;
  304. }
  305. }
  306. override function getBoundsRec( relativeTo, out, forSize ) {
  307. if( needReflow ) reflow();
  308. if( forSize ) {
  309. if( !isInline )
  310. super.getBoundsRec(relativeTo, out, true);
  311. if( calculatedWidth != 0 )
  312. addBounds(relativeTo, out, 0, 0, calculatedWidth, calculatedHeight);
  313. } else
  314. super.getBoundsRec(relativeTo, out, forSize);
  315. }
  316. override function setParentContainer(c) {
  317. parentContainer = c;
  318. // break propogation
  319. }
  320. override function addChildAt( s, pos ) {
  321. if( background != null ) pos++;
  322. var fp = getProperties(s);
  323. super.addChildAt(s, pos);
  324. if( fp == null ) fp = new FlowProperties(s) else properties.remove(fp);
  325. properties.insert(pos, fp);
  326. needReflow = true;
  327. s.setParentContainer(this);
  328. }
  329. override public function removeChild(s:Object) {
  330. var index = getChildIndex(s);
  331. super.removeChild(s);
  332. if( index >= 0 ) {
  333. needReflow = true;
  334. properties.splice(index, 1);
  335. s.constraintSize( -1, -1); // remove constraint
  336. }
  337. if( s != null ) {
  338. if( s == background )
  339. backgroundTile = null;
  340. if( s == interactive )
  341. enableInteractive = false;
  342. }
  343. }
  344. override function sync(ctx:RenderContext) {
  345. if( needReflow ) reflow();
  346. super.sync(ctx);
  347. }
  348. function set_maxWidth(w) {
  349. if( maxWidth == w )
  350. return w;
  351. maxWidth = w;
  352. updateConstraint();
  353. return w;
  354. }
  355. function set_maxHeight(h) {
  356. if( maxHeight == h )
  357. return h;
  358. maxHeight = h;
  359. updateConstraint();
  360. return h;
  361. }
  362. function updateConstraint() {
  363. var oldW = realMaxWidth, oldH = realMaxHeight;
  364. realMaxWidth = if( maxWidth == null ) constraintWidth else if( constraintWidth < 0 ) maxWidth else hxd.Math.min(maxWidth, constraintWidth);
  365. realMaxHeight = if( maxHeight == null ) constraintHeight else if( constraintHeight < 0 ) maxHeight else hxd.Math.min(maxHeight, constraintHeight);
  366. if( realMaxWidth != oldW || realMaxHeight != oldH )
  367. needReflow = true;
  368. }
  369. function set_minWidth(w) {
  370. if( minWidth == w )
  371. return w;
  372. needReflow = true;
  373. return minWidth = w;
  374. }
  375. function set_minHeight(h) {
  376. if( minHeight == h )
  377. return h;
  378. needReflow = true;
  379. return minHeight = h;
  380. }
  381. function set_horizontalSpacing(s) {
  382. if( horizontalSpacing == s )
  383. return s;
  384. needReflow = true;
  385. return horizontalSpacing = s;
  386. }
  387. function set_verticalSpacing(s) {
  388. if( verticalSpacing == s )
  389. return s;
  390. needReflow = true;
  391. return verticalSpacing = s;
  392. }
  393. function set_enableInteractive(b) {
  394. if( enableInteractive == b )
  395. return b;
  396. if( b ) {
  397. if( interactive == null ) {
  398. interactive = new h2d.Interactive(0, 0, this);
  399. interactive.cursor = Default;
  400. properties[properties.length - 1].isAbsolute = true;
  401. if( !needReflow ) {
  402. interactive.width = calculatedWidth;
  403. interactive.height = calculatedHeight;
  404. }
  405. }
  406. } else {
  407. if( interactive != null ) {
  408. interactive.remove();
  409. interactive = null;
  410. }
  411. }
  412. return enableInteractive = b;
  413. }
  414. function set_backgroundTile(t) {
  415. if( backgroundTile == t )
  416. return t;
  417. if( t != null ) {
  418. if( background == null ) {
  419. var background = new h2d.ScaleGrid(t, borderWidth, borderHeight);
  420. addChildAt(background, 0);
  421. properties[0].isAbsolute = true;
  422. this.background = background;
  423. if( !needReflow ) {
  424. background.width = Math.ceil(calculatedWidth);
  425. background.height = Math.ceil(calculatedHeight);
  426. }
  427. }
  428. background.tile = t;
  429. } else {
  430. if( background != null ) {
  431. background.remove();
  432. background = null;
  433. }
  434. }
  435. return backgroundTile = t;
  436. }
  437. function set_borderWidth(v) {
  438. if( borderWidth == v )
  439. return v;
  440. if( background != null ) background.borderWidth = v;
  441. needReflow = true;
  442. return borderWidth = v;
  443. }
  444. function set_borderHeight(v) {
  445. if( borderHeight == v )
  446. return v;
  447. if( background != null ) background.borderHeight = v;
  448. needReflow = true;
  449. return borderHeight = v;
  450. }
  451. /**
  452. Call to force all flowed elements position to be updated.
  453. See needReflow for more informations.
  454. **/
  455. public function reflow() {
  456. onBeforeReflow();
  457. var isConstraintWidth = realMaxWidth >= 0;
  458. var isConstraintHeight = realMaxHeight >= 0;
  459. // outter size
  460. var maxTotWidth = realMaxWidth < 0 ? 100000000 : Math.floor(realMaxWidth);
  461. var maxTotHeight = realMaxHeight < 0 ? 100000000 : Math.floor(realMaxHeight);
  462. // inner size
  463. var maxWidth = maxTotWidth - (paddingLeft + paddingRight + borderWidth * 2);
  464. var maxHeight = maxTotHeight - (paddingTop + paddingBottom + borderHeight * 2);
  465. var cw, ch;
  466. if( !isVertical ) {
  467. var halign = horizontalAlign == null ? Left : horizontalAlign;
  468. var valign = verticalAlign == null ? Bottom : verticalAlign;
  469. var startX = paddingLeft + borderWidth;
  470. var x = startX;
  471. var y = paddingTop + borderHeight;
  472. cw = x;
  473. var maxLineHeight = 0;
  474. var minLineHeight = this.lineHeight != null ? lineHeight : (this.minHeight != null && !multiline) ? (this.minHeight - (paddingTop + paddingBottom + borderHeight * 2)) : 0;
  475. var lastIndex = 0;
  476. inline function alignLine( maxIndex ) {
  477. if( maxLineHeight < minLineHeight )
  478. maxLineHeight = minLineHeight;
  479. else if( overflow && minLineHeight != 0 )
  480. maxLineHeight = minLineHeight;
  481. for( i in lastIndex...maxIndex ) {
  482. var p = properties[i];
  483. if( p.isAbsolute ) continue;
  484. var c = children[i];
  485. if( !c.visible ) continue;
  486. var a = p.verticalAlign != null ? p.verticalAlign : valign;
  487. c.y = y + p.offsetY + p.paddingTop;
  488. switch( a ) {
  489. case Bottom:
  490. c.y += maxLineHeight - Std.int(p.calculatedHeight);
  491. case Middle:
  492. c.y += Std.int((maxLineHeight - p.calculatedHeight) * 0.5);
  493. default:
  494. }
  495. }
  496. lastIndex = maxIndex;
  497. }
  498. for( i in 0...children.length ) {
  499. var p = properties[i];
  500. if( p.isAbsolute ) continue;
  501. var c = children[i];
  502. if( !c.visible ) continue;
  503. c.constraintSize(
  504. isConstraintWidth && p.constraint ? (maxWidth - (p.paddingLeft + p.paddingRight)) / Math.abs(c.scaleX) : -1,
  505. isConstraintHeight && p.constraint ? (maxHeight - (p.paddingTop + p.paddingBottom)) / Math.abs(c.scaleX) : -1
  506. );
  507. var b = c.getSize(tmpBounds);
  508. var br = false;
  509. p.calculatedWidth = Math.ceil(b.xMax) + p.paddingLeft + p.paddingRight;
  510. p.calculatedHeight = Math.ceil(b.yMax) + p.paddingTop + p.paddingBottom;
  511. if( p.minWidth != null && p.calculatedWidth < p.minWidth ) p.calculatedWidth = p.minWidth;
  512. if( p.minHeight != null && p.calculatedHeight < p.minHeight ) p.calculatedHeight = p.minHeight;
  513. if( multiline && x + p.calculatedWidth > maxWidth && x > startX ) {
  514. br = true;
  515. alignLine(i);
  516. y += maxLineHeight + verticalSpacing;
  517. maxLineHeight = 0;
  518. x = startX;
  519. }
  520. p.isBreak = br;
  521. x += p.calculatedWidth;
  522. if( x > cw ) cw = x;
  523. x += horizontalSpacing;
  524. if( p.calculatedHeight > maxLineHeight ) maxLineHeight = p.calculatedHeight;
  525. }
  526. alignLine(children.length);
  527. cw += paddingRight + borderWidth;
  528. ch = y + maxLineHeight + paddingBottom + borderHeight;
  529. // horizontal align
  530. if( minWidth != null && cw < minWidth ) cw = minWidth;
  531. var endX = cw - (paddingRight + borderWidth);
  532. var xmin = startX, xmax = endX;
  533. var midSpace = 0;
  534. for( i in 0...children.length ) {
  535. var p = properties[i];
  536. if( p.isAbsolute || !children[i].visible ) continue;
  537. if( p.isBreak ) {
  538. xmin = startX;
  539. xmax = endX;
  540. midSpace = 0;
  541. }
  542. var px;
  543. var align = p.horizontalAlign == null ? halign : p.horizontalAlign;
  544. switch( align ) {
  545. case Right:
  546. if( midSpace != 0 ) {
  547. xmin += midSpace;
  548. midSpace = 0;
  549. }
  550. xmax -= p.calculatedWidth;
  551. px = xmax;
  552. xmax -= horizontalSpacing;
  553. case Middle:
  554. if( midSpace == 0 ) {
  555. var remSize = p.calculatedWidth;
  556. for( j in i + 1...children.length ) {
  557. var p = properties[j];
  558. if( p.isAbsolute || !children[j].visible ) continue;
  559. if( p.isBreak ) break;
  560. remSize += horizontalSpacing + p.calculatedWidth;
  561. }
  562. midSpace = Std.int(((xmax - xmin) - remSize) * 0.5);
  563. xmin += midSpace;
  564. }
  565. px = xmin;
  566. xmin += p.calculatedWidth + horizontalSpacing;
  567. default:
  568. if( midSpace != 0 ) {
  569. xmin += midSpace;
  570. midSpace = 0;
  571. }
  572. px = xmin;
  573. xmin += p.calculatedWidth + horizontalSpacing;
  574. }
  575. children[i].x = px + p.offsetX + p.paddingLeft;
  576. }
  577. } else {
  578. var halign = horizontalAlign == null ? Left : horizontalAlign;
  579. var valign = verticalAlign == null ? Top : verticalAlign;
  580. var startY = paddingTop + borderHeight;
  581. var y = startY;
  582. var x = paddingLeft + borderWidth;
  583. ch = y;
  584. var maxColWidth = 0;
  585. var minColWidth = this.colWidth != null ? colWidth : (this.minWidth != null && !multiline) ? (this.minWidth - (paddingLeft + paddingRight + borderWidth * 2)) : 0;
  586. var lastIndex = 0;
  587. inline function alignLine( maxIndex ) {
  588. if( maxColWidth < minColWidth )
  589. maxColWidth = minColWidth;
  590. else if( overflow && minColWidth != 0 )
  591. maxColWidth = minColWidth;
  592. for( i in lastIndex...maxIndex ) {
  593. var p = properties[i];
  594. if( p.isAbsolute ) continue;
  595. var c = children[i];
  596. if( !c.visible ) continue;
  597. var a = p.horizontalAlign != null ? p.horizontalAlign : halign;
  598. c.x = x + p.offsetX + p.paddingLeft;
  599. switch( a ) {
  600. case Right:
  601. c.x += maxColWidth - p.calculatedWidth;
  602. case Middle:
  603. c.x += Std.int((maxColWidth - p.calculatedWidth) * 0.5);
  604. default:
  605. }
  606. }
  607. lastIndex = maxIndex;
  608. }
  609. for( i in 0...children.length ) {
  610. var p = properties[i];
  611. if( p.isAbsolute ) continue;
  612. var c = children[i];
  613. if( !c.visible ) continue;
  614. c.constraintSize(
  615. isConstraintWidth && p.constraint ? (maxWidth - (p.paddingLeft + p.paddingRight)) / Math.abs(c.scaleX) : -1,
  616. isConstraintHeight && p.constraint ? (maxHeight - (p.paddingTop + p.paddingBottom)) / Math.abs(c.scaleY) : -1
  617. );
  618. var b = c.getSize(tmpBounds);
  619. var br = false;
  620. p.calculatedWidth = Math.ceil(b.xMax) + p.paddingLeft + p.paddingRight;
  621. p.calculatedHeight = Math.ceil(b.yMax) + p.paddingTop + p.paddingBottom;
  622. if( p.minWidth != null && p.calculatedWidth < p.minWidth ) p.calculatedWidth = p.minWidth;
  623. if( p.minHeight != null && p.calculatedHeight < p.minHeight ) p.calculatedHeight = p.minHeight;
  624. if( multiline && y + p.calculatedHeight > maxHeight && y > startY ) {
  625. br = true;
  626. alignLine(i);
  627. x += maxColWidth + horizontalSpacing;
  628. maxColWidth = 0;
  629. y = startY;
  630. }
  631. p.isBreak = br;
  632. c.y = y + p.offsetY + p.paddingTop;
  633. y += p.calculatedHeight;
  634. if( y > ch ) ch = y;
  635. y += verticalSpacing;
  636. if( p.calculatedWidth > maxColWidth ) maxColWidth = p.calculatedWidth;
  637. }
  638. alignLine(children.length);
  639. ch += paddingBottom + borderHeight;
  640. cw = x + maxColWidth + paddingRight + borderWidth;
  641. // vertical align
  642. if( minHeight != null && ch < minHeight ) ch = minHeight;
  643. var endY : Int = ch - (paddingBottom + borderHeight);
  644. var ymin = startY, ymax = endY;
  645. var midSpace = 0;
  646. for( i in 0...children.length ) {
  647. var p = properties[i];
  648. if( p.isAbsolute || !children[i].visible ) continue;
  649. if( p.isBreak ) {
  650. ymin = startY;
  651. ymax = endY;
  652. midSpace = 0;
  653. }
  654. var py;
  655. var align = p.verticalAlign == null ? valign : p.verticalAlign;
  656. switch( align ) {
  657. case Bottom:
  658. if( midSpace != 0 ) {
  659. ymin += midSpace;
  660. midSpace = 0;
  661. }
  662. ymax -= p.calculatedHeight;
  663. py = ymax;
  664. ymax -= verticalSpacing;
  665. case Middle:
  666. if( midSpace == 0 ) {
  667. var remSize = p.calculatedHeight;
  668. for( j in i + 1...children.length ) {
  669. var p = properties[j];
  670. if( p.isAbsolute || !children[j].visible ) continue;
  671. if( p.isBreak ) break;
  672. remSize += verticalSpacing + p.calculatedHeight;
  673. }
  674. midSpace = Std.int(((ymax - ymin) - remSize) * 0.5);
  675. ymin += midSpace;
  676. }
  677. py = ymin;
  678. ymin += p.calculatedHeight + verticalSpacing;
  679. default:
  680. if( midSpace != 0 ) {
  681. ymin += midSpace;
  682. midSpace = 0;
  683. }
  684. py = ymin;
  685. ymin += p.calculatedHeight + verticalSpacing;
  686. }
  687. children[i].y = py + p.offsetY + p.paddingTop;
  688. }
  689. }
  690. if( minWidth != null && cw < minWidth ) cw = minWidth;
  691. if( minHeight != null && ch < minHeight ) ch = minHeight;
  692. if( overflow ) {
  693. if( isConstraintWidth && cw > maxTotWidth ) cw = maxTotWidth;
  694. if( isConstraintHeight && ch > maxTotHeight ) ch = maxTotHeight;
  695. }
  696. if( interactive != null ) {
  697. interactive.width = cw;
  698. interactive.height = ch;
  699. }
  700. if( background != null ) {
  701. background.width = Math.ceil(cw);
  702. background.height = Math.ceil(ch);
  703. }
  704. calculatedWidth = cw;
  705. calculatedHeight = ch;
  706. needReflow = false;
  707. if( debug ) {
  708. debugGraphics.clear();
  709. if( debugGraphics != children[children.length - 1] ) {
  710. addChild(debugGraphics); // always on-top
  711. needReflow = false;
  712. }
  713. if( paddingLeft != 0 || paddingRight != 0 || paddingTop != 0 || paddingBottom != 0 || borderWidth != 0 || borderHeight != 0 ) {
  714. debugGraphics.lineStyle(1, 0x00FF00);
  715. debugGraphics.drawRect(paddingLeft + borderWidth, paddingTop + borderHeight, innerWidth, innerHeight);
  716. }
  717. debugGraphics.lineStyle(1, 0x0080FF);
  718. for( i in 0...children.length ) {
  719. var p = properties[i];
  720. var c = children[i];
  721. if( p.isAbsolute || !c.visible ) continue;
  722. debugGraphics.drawRect(c.x, c.y, p.calculatedWidth, p.calculatedHeight);
  723. }
  724. debugGraphics.lineStyle(1, 0xFF0000);
  725. debugGraphics.drawRect(0, 0, cw, ch);
  726. }
  727. onAfterReflow();
  728. }
  729. /**
  730. Called before each reflow() is done.
  731. **/
  732. public dynamic function onBeforeReflow() {
  733. }
  734. /**
  735. Called after each time a reflow() was done.
  736. **/
  737. public dynamic function onAfterReflow() {
  738. }
  739. }