├── .travis.yml ├── LICENSE.md ├── README.md ├── documentation ├── ImportAll.hx └── compile.hxml ├── haxedoc.xml ├── haxelib.json ├── layout ├── Layout.hx ├── LayoutGroup.hx ├── LayoutItem.hx └── LayoutType.hx ├── skylark └── layout │ ├── Layout.hx │ ├── LayoutGroup.hx │ ├── LayoutItem.hx │ └── LayoutType.hx └── tests ├── .gitignore ├── .munit ├── test.hxml └── test ├── BasicLayoutTest.hx └── GroupTest.hx /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c++ 2 | 3 | before_install: 4 | - export DISPLAY=:99.0 5 | - sh -e /etc/init.d/xvfb start 6 | - /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x32 -extension GLX 7 | - export AUDIODEV=null 8 | - sudo add-apt-repository ppa:eyecreate/haxe -y 9 | - sudo apt-get update 10 | 11 | install: 12 | - sudo apt-get install haxe -y --force-yes 13 | - sudo apt-get install g++-multilib gcc-multilib 14 | - sudo apt-get install mesa-common-dev libgl1-mesa-dev libglu1-mesa-dev -y 15 | - mkdir ~/haxelib 16 | - haxelib setup ~/haxelib 17 | - haxelib install hxcpp 18 | - haxelib install mcover 19 | - git clone https://github.com/jgranick/MassiveUnit ~/munit --depth 1 20 | - haxelib dev munit ~/munit/src 21 | - haxelib dev layout $(pwd) 22 | - cd ~/munit/tool 23 | - haxe build.hxml 24 | 25 | before_script: 26 | - cd $TRAVIS_BUILD_DIR/tests 27 | - haxelib run munit gen 28 | 29 | script: 30 | - haxelib run munit test -as3 -norun 31 | - haxelib run munit test -browser phantomjs 32 | - haxelib run munit test -neko 33 | - haxelib run munit test -cpp 34 | 35 | notifications: 36 | slack: openfl:sBwVO0kgB7EuWLYzZzUezVIz 37 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | License 2 | ======= 3 | 4 | The MIT License (MIT) 5 | 6 | Copyright (c) 2009-2015 Joshua Granick 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE.md) [![Haxelib Version](https://img.shields.io/github/tag/openfl/layout.svg?style=flat&label=haxelib)](http://lib.haxe.org/p/layout) 2 | 3 | Layout 4 | ===== 5 | 6 | Layout is an easy-to-use library for handling fluid layout. 7 | 8 | 9 | Installation 10 | ============ 11 | 12 | You can easily install Layout using haxelib: 13 | 14 | haxelib install layout 15 | 16 | To add it to a Lime or OpenFL project, add this to your project file: 17 | 18 | 19 | 20 | 21 | Development Builds 22 | ================== 23 | 24 | Clone the Layout repository: 25 | 26 | git clone https://github.com/openfl/layout 27 | 28 | Tell haxelib where your development copy of Layout is installed: 29 | 30 | haxelib dev layout layout 31 | 32 | To return to release builds: 33 | 34 | haxelib dev layout 35 | -------------------------------------------------------------------------------- /documentation/ImportAll.hx: -------------------------------------------------------------------------------- 1 | package; 2 | 3 | import skylark.layout.LayoutGroup; 4 | import skylark.layout.LayoutItem; 5 | import skylark.layout.LayoutManager; 6 | import skylark.layout.LayoutType; -------------------------------------------------------------------------------- /documentation/compile.hxml: -------------------------------------------------------------------------------- 1 | -swf all.swf 2 | --no-output 3 | -xml ../haxedoc.xml 4 | -cp ../ 5 | ImportAll -------------------------------------------------------------------------------- /haxelib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "layout", 3 | "url": "http://github.com/openfl/layout", 4 | "license": "MIT", 5 | "tags": ["cpp", "flash", "neko", "js"], 6 | "description": "Flexible system for fluid resizing layouts", 7 | "version": "1.2.1", 8 | "releasenote": "Fixed possible stack overflow", 9 | "contributors": [ "singmajesty" ], 10 | "dependencies": {} 11 | } 12 | -------------------------------------------------------------------------------- /layout/Layout.hx: -------------------------------------------------------------------------------- 1 | package layout; 2 | 3 | 4 | typedef Layout = skylark.layout.Layout; -------------------------------------------------------------------------------- /layout/LayoutGroup.hx: -------------------------------------------------------------------------------- 1 | package layout; 2 | 3 | 4 | typedef LayoutGroup = skylark.layout.LayoutGroup; -------------------------------------------------------------------------------- /layout/LayoutItem.hx: -------------------------------------------------------------------------------- 1 | package layout; 2 | 3 | 4 | typedef LayoutItem = skylark.layout.LayoutItem; -------------------------------------------------------------------------------- /layout/LayoutType.hx: -------------------------------------------------------------------------------- 1 | package layout; 2 | 3 | 4 | typedef LayoutType = skylark.layout.LayoutType; -------------------------------------------------------------------------------- /skylark/layout/Layout.hx: -------------------------------------------------------------------------------- 1 | package skylark.layout; 2 | 3 | 4 | #if (flash || openfl || nme) 5 | import flash.events.Event; 6 | import flash.events.EventDispatcher; 7 | #end 8 | 9 | @:access(skylark.layout.LayoutGroup) 10 | 11 | 12 | class Layout #if (flash || openfl || nme) extends EventDispatcher #end { 13 | 14 | 15 | public var clampHeight (get, set):Bool; 16 | public var clampWidth (get, set):Bool; 17 | public var height (get, null):Float; 18 | public var initHeight (default, null):Float; 19 | public var initWidth (get, null):Float; 20 | public var minHeight (get, set):Float; 21 | public var minWidth (get, set):Float; 22 | public var pixelScale (get, set):Float; 23 | public var width (get, null):Float; 24 | 25 | private var items:LayoutGroup; 26 | 27 | private var _initHeight:Float; 28 | private var _initWidth:Float; 29 | 30 | 31 | public function new (initWidth:Float = 0, initHeight:Float = 0) { 32 | 33 | #if (flash || openfl || nme) 34 | super (); 35 | #end 36 | 37 | _initWidth = initWidth; 38 | _initHeight = initHeight; 39 | 40 | initialize (); 41 | 42 | } 43 | 44 | 45 | public function addItem (item:LayoutItem, autoConfigureVertical:Bool = true, autoConfigureHorizontal:Bool = true):Void { 46 | 47 | items.addItem (item, autoConfigureVertical, autoConfigureHorizontal, false); 48 | 49 | } 50 | 51 | 52 | private function initialize ():Void { 53 | 54 | items = new LayoutGroup (LayoutType.NONE, LayoutType.NONE, false); 55 | items.resize (_initWidth, _initHeight); 56 | 57 | } 58 | 59 | 60 | public function layoutItems ():Void { 61 | 62 | items.layoutItemGroup (); 63 | 64 | } 65 | 66 | 67 | public function resize (width:Float, height:Float):Void { 68 | 69 | if (_initWidth == 0 && _initHeight == 0) { 70 | 71 | if (items.width == 0 && items.height == 0) { 72 | 73 | items.refreshSize (); 74 | 75 | } 76 | 77 | _initWidth = items.width; 78 | _initHeight = items.height; 79 | 80 | items.setInitSize (_initWidth, _initHeight); 81 | items.configureItems (); 82 | 83 | } 84 | 85 | var cacheWidth = items.width; 86 | var cacheHeight = items.height; 87 | 88 | items.resize (width, height); 89 | 90 | if (items.width != cacheWidth || items.height != cacheHeight) { 91 | 92 | #if (flash || openfl || nme) 93 | dispatchEvent (new Event (Event.RESIZE)); 94 | #end 95 | 96 | } 97 | 98 | } 99 | 100 | 101 | public function setMinSize (minWidth:Float = 0, minHeight:Float = 0):Void { 102 | 103 | items.minWidth = minWidth; 104 | items.minHeight = minHeight; 105 | 106 | } 107 | 108 | 109 | 110 | 111 | // Get & Set Methods 112 | 113 | 114 | 115 | 116 | private function get_clampHeight ():Bool { 117 | 118 | return items.clampHeight; 119 | 120 | } 121 | 122 | 123 | private function set_clampHeight (value:Bool):Bool { 124 | 125 | return items.clampHeight = value; 126 | 127 | } 128 | 129 | 130 | private function get_clampWidth ():Bool { 131 | 132 | return items.clampWidth; 133 | 134 | } 135 | 136 | 137 | private function set_clampWidth (value:Bool):Bool { 138 | 139 | return items.clampWidth = value; 140 | 141 | } 142 | 143 | 144 | private function get_height ():Float { 145 | 146 | return items.height; 147 | 148 | } 149 | 150 | 151 | private function get_initHeight ():Float { 152 | 153 | return items.initHeight; 154 | 155 | } 156 | 157 | 158 | private function get_initWidth ():Float { 159 | 160 | return items.initWidth; 161 | 162 | } 163 | 164 | 165 | private function get_minHeight ():Float { 166 | 167 | return items.minHeight; 168 | 169 | } 170 | 171 | 172 | private function set_minHeight (value:Float):Float { 173 | 174 | return items.minHeight = value; 175 | 176 | } 177 | 178 | 179 | private function get_minWidth ():Float { 180 | 181 | return items.minWidth; 182 | 183 | } 184 | 185 | 186 | private function set_minWidth (value:Float):Float { 187 | 188 | return items.minWidth = value; 189 | 190 | } 191 | 192 | 193 | private function get_pixelScale ():Float { 194 | 195 | return items.pixelScale; 196 | 197 | } 198 | 199 | 200 | private function set_pixelScale (value:Float):Float { 201 | 202 | return items.pixelScale = value; 203 | 204 | } 205 | 206 | 207 | private function get_width ():Float { 208 | 209 | return items.width; 210 | 211 | } 212 | 213 | 214 | } -------------------------------------------------------------------------------- /skylark/layout/LayoutGroup.hx: -------------------------------------------------------------------------------- 1 | package skylark.layout; 2 | 3 | 4 | class LayoutGroup extends LayoutItem { 5 | 6 | 7 | public var clampHeight:Bool; 8 | public var clampWidth:Bool; 9 | public var height (get, set):Float; 10 | public var initHeight (default, null):Float; 11 | public var initScale (default, null):Float; 12 | public var initWidth (default, null):Float; 13 | public var items:Array; 14 | public var pixelScale (get, set):Float; 15 | public var width (get, set):Float; 16 | public var x (get, set):Float; 17 | public var y (get, set):Float; 18 | 19 | private var itemConfigureHorizontal:Array ; 20 | private var itemConfigureVertical:Array ; 21 | private var loop:Bool; 22 | 23 | private var _height:Float; 24 | private var _pixelScale:Float; 25 | private var _width:Float; 26 | private var _x:Float; 27 | private var _y:Float; 28 | 29 | 30 | public function new (verticalLayout:LayoutType = null, horizontalLayout:LayoutType = null, rigidVertical:Bool = true, rigidHorizontal:Bool = true) { 31 | 32 | if (verticalLayout == null) { 33 | 34 | verticalLayout = LayoutType.NONE; 35 | 36 | } 37 | 38 | if (horizontalLayout == null) { 39 | 40 | horizontalLayout = LayoutType.NONE; 41 | 42 | } 43 | 44 | super (this, verticalLayout, horizontalLayout, rigidVertical, rigidHorizontal); 45 | 46 | _x = 0; 47 | _y = 0; 48 | _width = 0; 49 | _height = 0; 50 | _pixelScale = 0; 51 | 52 | resize (0, 0); 53 | 54 | } 55 | 56 | 57 | public function addItem (item:LayoutItem, autoConfigureVertical:Bool = true, autoConfigureHorizontal:Bool = true, updateSize:Bool = true):Void { 58 | 59 | if (initWidth != 0 && initHeight != 0) { 60 | 61 | configureItem (item, autoConfigureVertical, autoConfigureHorizontal); 62 | 63 | } 64 | 65 | items.push (item); 66 | itemConfigureVertical.push (autoConfigureVertical); 67 | itemConfigureHorizontal.push (autoConfigureHorizontal); 68 | 69 | if (updateSize) { 70 | 71 | refreshSize (); 72 | 73 | if (initWidth != 0 && initHeight != 0) { 74 | 75 | configureItems (); 76 | 77 | } 78 | 79 | } 80 | 81 | } 82 | 83 | 84 | private function configureItem (item:LayoutItem, autoConfigureVertical:Bool, autoConfigureHorizontal:Bool):Void { 85 | 86 | item.configureItems (); 87 | 88 | if (autoConfigureVertical) { 89 | 90 | switch (item.verticalLayout) { 91 | 92 | case LayoutType.BOTTOM: 93 | 94 | item.marginBottom = initHeight - item.objectY - item.objectHeight - _y; 95 | 96 | case LayoutType.CENTER: 97 | 98 | var verticalOffset = item.objectY - (initHeight / 2 - item.objectHeight / 2) - _y; 99 | 100 | if (verticalOffset > 0) { 101 | 102 | item.marginTop = verticalOffset; 103 | 104 | } else { 105 | 106 | item.marginBottom = Math.abs (verticalOffset); 107 | 108 | } 109 | 110 | case LayoutType.STRETCH: 111 | 112 | item.marginTop = item.objectY - _y; 113 | item.marginBottom = initHeight - item.objectY - item.objectHeight - _y; 114 | 115 | if (item.rigidVertical && item.minHeight == null) { 116 | 117 | item.minHeight = item.objectHeight; 118 | 119 | } 120 | 121 | case LayoutType.TOP: 122 | 123 | item.marginTop = item.objectY - _y; 124 | 125 | default: 126 | 127 | } 128 | 129 | } 130 | 131 | if (autoConfigureHorizontal) { 132 | 133 | switch (item.horizontalLayout) { 134 | 135 | case LayoutType.CENTER: 136 | 137 | var horizontalOffset = item.objectX - (initWidth / 2 - item.objectWidth / 2) - _x; 138 | 139 | if (horizontalOffset > 0) { 140 | 141 | item.marginLeft = horizontalOffset; 142 | 143 | } else { 144 | 145 | item.marginRight = Math.abs (horizontalOffset); 146 | 147 | } 148 | 149 | case LayoutType.LEFT: 150 | 151 | item.marginLeft = item.objectX - _x; 152 | 153 | case LayoutType.RIGHT: 154 | 155 | item.marginRight = initWidth - item.objectX - item.objectWidth - _x; 156 | 157 | case LayoutType.STRETCH: 158 | 159 | item.marginLeft = item.objectX - _x; 160 | item.marginRight = initWidth - item.objectX - item.objectWidth - _x; 161 | 162 | if (item.rigidHorizontal && item.minWidth == null) { 163 | 164 | item.minWidth = item.objectWidth; 165 | 166 | } 167 | 168 | default: 169 | 170 | } 171 | 172 | } 173 | 174 | } 175 | 176 | 177 | private override function configureItems ():Void { 178 | 179 | for (i in 0...items.length) { 180 | 181 | configureItem (items[i], itemConfigureVertical[i], itemConfigureHorizontal[i]); 182 | 183 | } 184 | 185 | } 186 | 187 | 188 | private override function initialize ():Void { 189 | 190 | items = new Array (); 191 | itemConfigureHorizontal = new Array (); 192 | itemConfigureVertical = new Array (); 193 | 194 | super.initialize (); 195 | 196 | } 197 | 198 | 199 | private function layoutItemGroup ():Void { 200 | 201 | var minWidth = ifDefined (minWidth, 0); 202 | var minHeight = ifDefined (minHeight, 0); 203 | 204 | var minObjectHeight, minObjectWidth; 205 | 206 | for (item in items) { 207 | 208 | item.layoutItem (this); 209 | 210 | if (item.rigidVertical) { 211 | 212 | minObjectHeight = item.marginTop + item.marginBottom; 213 | 214 | if (item.minHeight != null) { 215 | 216 | minObjectHeight += item.minHeight; 217 | 218 | } else { 219 | 220 | minObjectHeight += item.objectHeight; 221 | 222 | } 223 | 224 | if (minHeight < minObjectHeight) { 225 | 226 | minHeight = minObjectHeight; 227 | 228 | } 229 | 230 | } 231 | 232 | if (item.rigidHorizontal) { 233 | 234 | minObjectWidth = item.marginLeft + item.marginRight; 235 | 236 | if (item.minWidth != null) { 237 | 238 | minObjectWidth += item.minWidth; 239 | 240 | } else { 241 | 242 | minObjectWidth += item.objectWidth; 243 | 244 | } 245 | 246 | if (minWidth < minObjectWidth) { 247 | 248 | minWidth = minObjectWidth; 249 | 250 | } 251 | 252 | } 253 | 254 | } 255 | 256 | var newWidth = width; 257 | var newHeight = height; 258 | 259 | if (newWidth < minWidth) { 260 | 261 | newWidth = minWidth; 262 | 263 | } 264 | 265 | if (newHeight < minHeight) { 266 | 267 | newHeight = minHeight; 268 | 269 | } 270 | 271 | if (clampWidth && newWidth > initWidth) { 272 | 273 | newWidth = initWidth; 274 | 275 | } 276 | 277 | if (clampHeight && newHeight > initHeight) { 278 | 279 | newHeight = initHeight; 280 | 281 | } 282 | 283 | if (newWidth != width || newHeight != height) { 284 | 285 | if (!loop) { 286 | 287 | loop = true; 288 | resize (newWidth, newHeight); 289 | loop = false; 290 | 291 | } 292 | 293 | } 294 | 295 | } 296 | 297 | 298 | private override function refreshSize ():Void { 299 | 300 | if (items.length > 0) { 301 | 302 | var beginningX = Math.POSITIVE_INFINITY; 303 | var beginningY = Math.POSITIVE_INFINITY; 304 | var endX = Math.NEGATIVE_INFINITY; 305 | var endY = Math.NEGATIVE_INFINITY; 306 | 307 | for (item in items) { 308 | 309 | item.refreshSize (); 310 | 311 | if (item.verticalLayout != LayoutType.NONE) { 312 | 313 | if (item.objectY < beginningY) { 314 | 315 | beginningY = item.objectY; 316 | 317 | } 318 | 319 | if (item.objectY + item.objectHeight > endY) { 320 | 321 | endY = item.objectY + item.objectHeight; 322 | 323 | } 324 | 325 | } 326 | 327 | if (item.horizontalLayout != LayoutType.NONE) { 328 | 329 | if (item.objectX < beginningX) { 330 | 331 | beginningX = item.objectX; 332 | 333 | } 334 | 335 | if (item.objectX + item.objectWidth > endX) { 336 | 337 | endX = item.objectX + item.objectWidth; 338 | 339 | } 340 | 341 | } 342 | 343 | } 344 | 345 | if (beginningX != Math.POSITIVE_INFINITY && endX != Math.NEGATIVE_INFINITY) { 346 | 347 | _x = beginningX; 348 | _width = initWidth = endX - beginningX; 349 | 350 | } 351 | 352 | if (beginningY != Math.POSITIVE_INFINITY && endY != Math.NEGATIVE_INFINITY) { 353 | 354 | _y = beginningY; 355 | _height = initHeight = endY - beginningY; 356 | 357 | } 358 | 359 | } 360 | 361 | } 362 | 363 | 364 | public function resize (width:Float, height:Float):Void { 365 | 366 | _width = width; 367 | _height = height; 368 | 369 | if (items.length > 0) { 370 | 371 | layoutItemGroup (); 372 | 373 | } else { 374 | 375 | initWidth = width; 376 | initHeight = height; 377 | 378 | } 379 | 380 | } 381 | 382 | 383 | public function scale (scale:Float):Void { 384 | 385 | _pixelScale = scale; 386 | 387 | if (items.length > 0) { 388 | 389 | layoutItemGroup (); 390 | 391 | } else { 392 | 393 | initScale = _pixelScale; 394 | 395 | } 396 | 397 | } 398 | 399 | 400 | public function setInitSize (width:Float, height:Float):Void { 401 | 402 | initWidth = width; 403 | initHeight = height; 404 | 405 | } 406 | 407 | 408 | 409 | 410 | // Get & Set Methods 411 | 412 | 413 | 414 | 415 | private function get_height ():Float { 416 | 417 | return _height; 418 | 419 | } 420 | 421 | 422 | private function set_height (value:Float):Float { 423 | 424 | resize (_width, value); 425 | 426 | return _height; 427 | 428 | } 429 | 430 | 431 | private function get_pixelScale ():Float { 432 | 433 | return _pixelScale; 434 | 435 | } 436 | 437 | 438 | private function set_pixelScale (value:Float):Float { 439 | 440 | scale (value); 441 | 442 | return _pixelScale; 443 | 444 | } 445 | 446 | 447 | private function get_width ():Float { 448 | 449 | return _width; 450 | 451 | } 452 | 453 | 454 | private function set_width (value:Float):Float { 455 | 456 | resize (value, _height); 457 | 458 | return _width; 459 | 460 | } 461 | 462 | 463 | private function get_x ():Float { 464 | 465 | return _x; 466 | 467 | } 468 | 469 | 470 | private function set_x (value:Float):Float { 471 | 472 | _x = value; 473 | 474 | layoutItemGroup (); 475 | 476 | return _x; 477 | 478 | } 479 | 480 | 481 | private function get_y ():Float { 482 | 483 | return _y; 484 | 485 | } 486 | 487 | 488 | private function set_y (value:Float):Float { 489 | 490 | _y = value; 491 | 492 | layoutItemGroup (); 493 | 494 | return _y; 495 | 496 | } 497 | 498 | 499 | } -------------------------------------------------------------------------------- /skylark/layout/LayoutItem.hx: -------------------------------------------------------------------------------- 1 | package skylark.layout; 2 | 3 | 4 | class LayoutItem { 5 | 6 | 7 | public var horizontalLayout:LayoutType; 8 | public var marginLeft:Float; 9 | public var marginRight:Float; 10 | public var marginTop:Float; 11 | public var marginBottom:Float; 12 | public var minHeight:Null; 13 | public var minWidth:Null; 14 | public var object:Dynamic; 15 | public var rigidHorizontal:Bool; 16 | public var rigidVertical:Bool; 17 | public var verticalLayout:LayoutType; 18 | 19 | private var objectHeight (get, set):Float; 20 | private var objectScaleX (get, set):Float; 21 | private var objectScaleY (get, set):Float; 22 | private var objectWidth (get, set):Float; 23 | private var objectX (get, set):Float; 24 | private var objectY (get, set):Float; 25 | 26 | 27 | public function new (object:Dynamic, verticalLayout:LayoutType = null, horizontalLayout:LayoutType = null, rigidVertical:Bool = true, rigidHorizontal:Bool = true) { 28 | 29 | if (verticalLayout == null) { 30 | 31 | verticalLayout = LayoutType.TOP; 32 | 33 | } 34 | 35 | if (horizontalLayout == null) { 36 | 37 | horizontalLayout = LayoutType.LEFT; 38 | 39 | } 40 | 41 | this.object = object; 42 | this.verticalLayout = verticalLayout; 43 | this.horizontalLayout = horizontalLayout; 44 | this.rigidVertical = rigidVertical; 45 | this.rigidHorizontal = rigidHorizontal; 46 | 47 | initialize (); 48 | 49 | } 50 | 51 | 52 | private function configureItems ():Void { 53 | 54 | 55 | 56 | } 57 | 58 | 59 | private inline function getField (target:Dynamic, propertyName:String):Dynamic { 60 | 61 | #if (haxe_209 || haxe3) 62 | 63 | var value = null; 64 | 65 | if (Reflect.hasField (target, propertyName)) { 66 | 67 | #if flash 68 | value = untyped target[propertyName]; 69 | #else 70 | value = Reflect.field (target, propertyName); 71 | #end 72 | 73 | } else { 74 | 75 | value = Reflect.getProperty (target, propertyName); 76 | 77 | } 78 | 79 | return value; 80 | 81 | #else 82 | 83 | return Reflect.field (target, propertyName); 84 | 85 | #end 86 | 87 | } 88 | 89 | 90 | private function ifDefined (value:T, defaultValue:T):T { 91 | 92 | if (value != null) { 93 | 94 | if (!Std.is (value, String) || (Std.is (value, String) && value != cast "")) { 95 | 96 | return value; 97 | 98 | } 99 | 100 | } 101 | 102 | return defaultValue; 103 | 104 | } 105 | 106 | 107 | private function initialize ():Void { 108 | 109 | setMargins (); 110 | 111 | } 112 | 113 | 114 | private function layoutItem (layoutGroup:LayoutGroup):Void { 115 | 116 | switch (verticalLayout) { 117 | 118 | case BOTTOM: 119 | 120 | objectY = layoutGroup.height - objectHeight - marginBottom; 121 | 122 | case CENTER: 123 | 124 | objectY = layoutGroup.height / 2 - objectHeight / 2 + marginTop - marginBottom; 125 | 126 | case STRETCH: 127 | 128 | objectY = marginTop; 129 | 130 | var stretchHeight = layoutGroup.height - marginTop - marginBottom; 131 | 132 | if (stretchHeight < 0) { 133 | 134 | stretchHeight = 0; 135 | 136 | } 137 | 138 | if (rigidVertical && minHeight != null && stretchHeight < minHeight) { 139 | 140 | objectHeight = minHeight; 141 | 142 | } else { 143 | 144 | objectHeight = stretchHeight; 145 | 146 | } 147 | 148 | case TOP: 149 | 150 | objectY = marginTop; 151 | 152 | default: 153 | 154 | } 155 | 156 | switch (horizontalLayout) { 157 | 158 | case CENTER: 159 | 160 | objectX = layoutGroup.width / 2 - objectWidth / 2 + marginLeft - marginRight; 161 | 162 | case LEFT: 163 | 164 | objectX = marginLeft; 165 | 166 | case RIGHT: 167 | 168 | objectX = layoutGroup.width - objectWidth - marginRight; 169 | 170 | case STRETCH: 171 | 172 | objectX = marginLeft; 173 | 174 | var stretchWidth = layoutGroup.width - marginLeft - marginRight; 175 | 176 | if (stretchWidth < 0) { 177 | 178 | stretchWidth = 0; 179 | 180 | } 181 | 182 | if (rigidHorizontal && minWidth != null && stretchWidth < minWidth) { 183 | 184 | objectWidth = minWidth; 185 | 186 | } else { 187 | 188 | objectWidth = stretchWidth; 189 | 190 | } 191 | 192 | default: 193 | 194 | } 195 | 196 | objectX += layoutGroup.x; 197 | objectY += layoutGroup.y; 198 | 199 | } 200 | 201 | 202 | private function refreshSize ():Void { 203 | 204 | 205 | 206 | } 207 | 208 | 209 | private inline function setField (target:Dynamic, propertyName:String, value:Dynamic):Void { 210 | 211 | if (Reflect.hasField (target, propertyName)) { 212 | 213 | #if flash 214 | untyped target[propertyName] = value; 215 | #else 216 | Reflect.setField (target, propertyName, value); 217 | #end 218 | 219 | } else { 220 | 221 | #if (haxe_209 || haxe3) 222 | Reflect.setProperty (target, propertyName, value); 223 | #end 224 | 225 | } 226 | 227 | } 228 | 229 | 230 | public function setMargins (marginTop:Float = 0, marginRight:Float = 0, marginBottom:Float = 0, marginLeft:Float = 0):Void { 231 | 232 | this.marginTop = marginTop; 233 | this.marginRight = marginRight; 234 | this.marginBottom = marginBottom; 235 | this.marginLeft = marginLeft; 236 | 237 | } 238 | 239 | 240 | public function setMinSize (minWidth:Float = 0, minHeight:Float = 0):Void { 241 | 242 | this.minWidth = minWidth; 243 | this.minHeight = minHeight; 244 | 245 | } 246 | 247 | 248 | 249 | 250 | // Get & Set Methods 251 | 252 | 253 | 254 | 255 | private #if (!neko && !js) inline #end function get_objectHeight ():Float { 256 | 257 | return getField (object, "height"); 258 | 259 | } 260 | 261 | 262 | private #if (!neko && !js) inline #end function set_objectHeight (value:Float):Float { 263 | 264 | setField (object, "height", value); 265 | return value; 266 | 267 | } 268 | 269 | 270 | private #if (!neko && !js) inline #end function get_objectScaleX ():Float { 271 | 272 | return getField (object, "scaleX"); 273 | 274 | } 275 | 276 | 277 | private #if (!neko && !js) inline #end function set_objectScaleX (value:Float):Float { 278 | 279 | setField (object, "scaleX", value); 280 | return value; 281 | 282 | } 283 | 284 | 285 | private #if (!neko && !js) inline #end function get_objectScaleY ():Float { 286 | 287 | return getField (object, "scaleY"); 288 | 289 | } 290 | 291 | 292 | private #if (!neko && !js) inline #end function set_objectScaleY (value:Float):Float { 293 | 294 | setField (object, "scaleY", value); 295 | return value; 296 | 297 | } 298 | 299 | 300 | private #if (!neko && !js) inline #end function get_objectWidth ():Float { 301 | 302 | return getField (object, "width"); 303 | 304 | } 305 | 306 | 307 | private #if (!neko && !js) inline #end function set_objectWidth (value:Float):Float { 308 | 309 | setField (object, "width", value); 310 | return value; 311 | 312 | } 313 | 314 | 315 | private #if (!neko && !js) inline #end function get_objectX ():Float { 316 | 317 | return getField (object, "x"); 318 | 319 | } 320 | 321 | 322 | private #if (!neko && !js) inline #end function set_objectX (value:Float):Float { 323 | 324 | setField (object, "x", value); 325 | return value; 326 | 327 | } 328 | 329 | 330 | private #if (!neko && !js) inline #end function get_objectY ():Float { 331 | 332 | return getField (object, "y"); 333 | 334 | } 335 | 336 | 337 | private #if (!neko && !js) inline #end function set_objectY (value:Float):Float { 338 | 339 | setField (object, "y", value); 340 | return value; 341 | 342 | } 343 | 344 | 345 | } -------------------------------------------------------------------------------- /skylark/layout/LayoutType.hx: -------------------------------------------------------------------------------- 1 | package skylark.layout; 2 | 3 | 4 | enum LayoutType { 5 | 6 | BOTTOM; 7 | CENTER; 8 | LEFT; 9 | NONE; 10 | RIGHT; 11 | STRETCH; 12 | TOP; 13 | 14 | } -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | report 3 | src 4 | test/ExampleTest.hx 5 | test/TestMain.hx 6 | test/TestSuite.hx 7 | -------------------------------------------------------------------------------- /tests/.munit: -------------------------------------------------------------------------------- 1 | version=2.1.0 2 | src=test 3 | bin=build 4 | report=report 5 | hxml=test.hxml 6 | classPaths=src 7 | -------------------------------------------------------------------------------- /tests/test.hxml: -------------------------------------------------------------------------------- 1 | ## Flash 9+ 2 | -main TestMain 3 | -lib munit 4 | -lib hamcrest 5 | -lib layout 6 | -cp src 7 | 8 | -cp test 9 | -swf-version 11 10 | -swf build/as3_test.swf 11 | 12 | --next 13 | 14 | ## JavaScript 15 | -main TestMain 16 | -lib munit 17 | -lib hamcrest 18 | -lib layout 19 | -cp src 20 | 21 | -cp test 22 | -js build/js_test.js 23 | 24 | --next 25 | 26 | ## Neko 27 | -main TestMain 28 | -lib munit 29 | -lib hamcrest 30 | -lib layout 31 | -cp src 32 | 33 | -cp test 34 | -neko build/neko_test.n 35 | 36 | --next 37 | 38 | ## CPP 39 | -main TestMain 40 | -lib munit 41 | -lib hamcrest 42 | -lib layout 43 | -cp src 44 | 45 | -cp test 46 | #-D HXCPP_M64 47 | -cpp build/cpp_test 48 | 49 | 50 | -------------------------------------------------------------------------------- /tests/test/BasicLayoutTest.hx: -------------------------------------------------------------------------------- 1 | package; 2 | 3 | 4 | import skylark.layout.Layout; 5 | import skylark.layout.LayoutItem; 6 | import skylark.layout.LayoutType; 7 | import massive.munit.Assert; 8 | 9 | 10 | class BasicLayoutTest { 11 | 12 | 13 | public static var background:DisplayObject; 14 | public static var logo:DisplayObject; 15 | public static var sidebar:DisplayObject; 16 | public static var footer:DisplayObject; 17 | 18 | private static var layoutHeight = 200; 19 | private static var layoutWidth = 200; 20 | 21 | 22 | @Before public function setup ():Void { 23 | 24 | background = new DisplayObject (); 25 | background.x = 0; 26 | background.y = 0; 27 | background.width = layoutWidth; 28 | background.height = layoutHeight; 29 | 30 | logo = new DisplayObject (); 31 | logo.x = 10; 32 | logo.y = 10; 33 | logo.width = 40; 34 | logo.height = 25; 35 | 36 | sidebar = new DisplayObject (); 37 | sidebar.x = layoutWidth - 60; 38 | sidebar.y = 0; 39 | sidebar.width = 60; 40 | sidebar.height = layoutHeight - 40; 41 | 42 | footer = new DisplayObject (); 43 | footer.x = 0; 44 | footer.y = layoutHeight - 40; 45 | footer.width = layoutWidth; 46 | footer.height = 40; 47 | 48 | } 49 | 50 | 51 | @Test public function testStandard ():Void { 52 | 53 | // Set an exact layout size 54 | 55 | var layout = new Layout (layoutWidth, layoutHeight); 56 | 57 | layout.addItem (new LayoutItem (background, STRETCH, STRETCH)); 58 | layout.addItem (new LayoutItem (logo, TOP, LEFT)); 59 | layout.addItem (new LayoutItem (sidebar, STRETCH, RIGHT)); 60 | layout.addItem (new LayoutItem (footer, BOTTOM, STRETCH)); 61 | 62 | var sizesHeight = [ 200, 240, 1370, 1200, 100, 220, 10 ]; 63 | var sizesWidth = [ 200, 300, 1200, 1500, 220, 100, 10 ]; 64 | 65 | for (i in 0...sizesWidth.length) { 66 | 67 | var width = sizesWidth[i]; 68 | var height = sizesHeight[i]; 69 | 70 | layout.resize (width, height); 71 | 72 | // Items are rigid horizontal/vertical by default, so the layout should not allow smaller sizes than 200 x 200 (background size) 73 | 74 | if (width < layoutWidth) width = layoutWidth; 75 | if (height < layoutHeight) height = layoutHeight; 76 | 77 | Assert.areEqual (0, background.x); 78 | Assert.areEqual (0, background.y); 79 | Assert.areEqual (width, background.width); 80 | Assert.areEqual (height, background.height); 81 | 82 | Assert.areEqual (10, logo.x); 83 | Assert.areEqual (10, logo.y); 84 | Assert.areEqual (40, logo.width); 85 | Assert.areEqual (25, logo.height); 86 | 87 | Assert.areEqual (width - 60, sidebar.x); 88 | Assert.areEqual (0, sidebar.y); 89 | Assert.areEqual (60, sidebar.width); 90 | Assert.areEqual (height - 40, sidebar.height); 91 | 92 | Assert.areEqual (0, footer.x); 93 | Assert.areEqual (height - 40, footer.y); 94 | Assert.areEqual (width, footer.width); 95 | Assert.areEqual (40, footer.height); 96 | 97 | 98 | } 99 | 100 | } 101 | 102 | 103 | @Test public function testStandardNoInitSize ():Void { 104 | 105 | // Get the init layout size automatically (based on the size of the objects added before resizing) 106 | 107 | var layout = new Layout (); 108 | 109 | layout.addItem (new LayoutItem (background, STRETCH, STRETCH)); 110 | layout.addItem (new LayoutItem (logo, TOP, LEFT)); 111 | layout.addItem (new LayoutItem (sidebar, STRETCH, RIGHT)); 112 | layout.addItem (new LayoutItem (footer, BOTTOM, STRETCH)); 113 | 114 | var sizesHeight = [ 200, 240, 1370, 1200, 100, 220, 10 ]; 115 | var sizesWidth = [ 200, 300, 1200, 1500, 220, 100, 10 ]; 116 | 117 | for (i in 0...sizesWidth.length) { 118 | 119 | var width = sizesWidth[i]; 120 | var height = sizesHeight[i]; 121 | 122 | layout.resize (width, height); 123 | 124 | // Items are rigid horizontal/vertical by default, so the layout should not allow smaller sizes than 200 x 200 (background size) 125 | 126 | if (width < layoutWidth) width = layoutWidth; 127 | if (height < layoutHeight) height = layoutHeight; 128 | 129 | Assert.areEqual (0, background.x); 130 | Assert.areEqual (0, background.y); 131 | Assert.areEqual (width, background.width); 132 | Assert.areEqual (height, background.height); 133 | 134 | Assert.areEqual (10, logo.x); 135 | Assert.areEqual (10, logo.y); 136 | Assert.areEqual (40, logo.width); 137 | Assert.areEqual (25, logo.height); 138 | 139 | Assert.areEqual (width - 60, sidebar.x); 140 | Assert.areEqual (0, sidebar.y); 141 | Assert.areEqual (60, sidebar.width); 142 | Assert.areEqual (height - 40, sidebar.height); 143 | 144 | Assert.areEqual (0, footer.x); 145 | Assert.areEqual (height - 40, footer.y); 146 | Assert.areEqual (width, footer.width); 147 | Assert.areEqual (40, footer.height); 148 | 149 | 150 | } 151 | 152 | } 153 | 154 | 155 | private inline function testLayout (verticalType:LayoutType, horizontalType:LayoutType, ?pos:haxe.PosInfos) { 156 | 157 | var layout = new Layout (layoutWidth, layoutHeight); 158 | 159 | layout.addItem (new LayoutItem (background, verticalType, horizontalType)); 160 | layout.addItem (new LayoutItem (logo, verticalType, horizontalType)); 161 | layout.addItem (new LayoutItem (sidebar, verticalType, horizontalType)); 162 | layout.addItem (new LayoutItem (footer, verticalType, horizontalType)); 163 | 164 | testLayoutSize (layout, verticalType, horizontalType, 200, 200, pos); 165 | testLayoutSize (layout, verticalType, horizontalType, 300, 240, pos); 166 | testLayoutSize (layout, verticalType, horizontalType, 1200, 1370, pos); 167 | testLayoutSize (layout, verticalType, horizontalType, 1500, 1200, pos); 168 | testLayoutSize (layout, verticalType, horizontalType, 220, 1200, pos); 169 | testLayoutSize (layout, verticalType, horizontalType, 100, 220, pos); 170 | testLayoutSize (layout, verticalType, horizontalType, 220, 100, pos); 171 | testLayoutSize (layout, verticalType, horizontalType, 10, 10, pos); 172 | 173 | setup (); 174 | 175 | var layout = new Layout (); 176 | 177 | layout.addItem (new LayoutItem (background, verticalType, horizontalType)); 178 | layout.addItem (new LayoutItem (logo, verticalType, horizontalType)); 179 | layout.addItem (new LayoutItem (sidebar, verticalType, horizontalType)); 180 | layout.addItem (new LayoutItem (footer, verticalType, horizontalType)); 181 | 182 | testLayoutSize (layout, verticalType, horizontalType, 200, 200, pos); 183 | testLayoutSize (layout, verticalType, horizontalType, 300, 240, pos); 184 | testLayoutSize (layout, verticalType, horizontalType, 1200, 1370, pos); 185 | testLayoutSize (layout, verticalType, horizontalType, 1500, 1200, pos); 186 | testLayoutSize (layout, verticalType, horizontalType, 220, 1200, pos); 187 | testLayoutSize (layout, verticalType, horizontalType, 100, 220, pos); 188 | testLayoutSize (layout, verticalType, horizontalType, 220, 100, pos); 189 | testLayoutSize (layout, verticalType, horizontalType, 10, 10, pos); 190 | 191 | } 192 | 193 | 194 | private inline function testLayoutSize (layout:Layout, verticalType:LayoutType, horizontalType:LayoutType, width:Float, height:Float, ?pos:haxe.PosInfos) { 195 | 196 | layout.resize (width, height); 197 | 198 | if (width < layoutWidth) width = layoutWidth; 199 | if (height < layoutHeight) height = layoutHeight; 200 | 201 | var scaleWidth = (horizontalType == STRETCH) ? width : layoutWidth; 202 | var scaleHeight = (verticalType == STRETCH) ? height : layoutHeight; 203 | 204 | var offsetY = switch (verticalType) { 205 | 206 | case CENTER: (height / 2) - (layoutHeight / 2); 207 | case BOTTOM: height - layoutHeight; 208 | default: 0; 209 | 210 | } 211 | 212 | var offsetX = switch (horizontalType) { 213 | 214 | case CENTER: (width / 2) - (layoutWidth / 2); 215 | case RIGHT: width - layoutWidth; 216 | default: 0; 217 | 218 | } 219 | 220 | Assert.areEqual (offsetX, background.x, pos); 221 | Assert.areEqual (offsetY, background.y, pos); 222 | Assert.areEqual (scaleWidth, background.width, pos); 223 | Assert.areEqual (scaleHeight, background.height, pos); 224 | 225 | Assert.areEqual (offsetX + 10, logo.x, pos); 226 | Assert.areEqual (offsetY + 10, logo.y, pos); 227 | Assert.areEqual (scaleWidth - layoutWidth + 40, logo.width, pos); 228 | Assert.areEqual (scaleHeight - layoutHeight + 25, logo.height, pos); 229 | 230 | Assert.areEqual (offsetX + layoutWidth - 60, sidebar.x, pos); 231 | Assert.areEqual (offsetY, sidebar.y, pos); 232 | Assert.areEqual (scaleWidth - layoutWidth + 60, sidebar.width, pos); 233 | Assert.areEqual (scaleHeight - 40, sidebar.height, pos); 234 | 235 | Assert.areEqual (offsetX, footer.x, pos); 236 | Assert.areEqual (offsetY + layoutHeight - 40, footer.y, pos); 237 | Assert.areEqual (scaleWidth, footer.width, pos); 238 | Assert.areEqual (scaleHeight - layoutHeight + 40, footer.height, pos); 239 | 240 | //Assert.areEqual (offsetX, background.x); 241 | //Assert.areEqual (offsetY, background.y); 242 | //Assert.areEqual (scaleWidth, background.width); 243 | //Assert.areEqual (scaleHeight, background.height); 244 | // 245 | //Assert.areEqual (offsetX + 10, logo.x); 246 | //Assert.areEqual (offsetY + 10, logo.y); 247 | //Assert.areEqual (scaleWidth - layoutWidth + 40, logo.width); 248 | //Assert.areEqual (scaleHeight - layoutHeight + 25, logo.height); 249 | // 250 | //Assert.areEqual (offsetX + layoutWidth - 60, sidebar.x); 251 | //Assert.areEqual (offsetY, sidebar.y); 252 | //Assert.areEqual (scaleWidth - layoutWidth + 60, sidebar.width); 253 | //Assert.areEqual (scaleHeight - 40, sidebar.height); 254 | // 255 | //Assert.areEqual (offsetX, footer.x); 256 | //Assert.areEqual (offsetY + layoutHeight - 40, footer.y); 257 | //Assert.areEqual (scaleWidth, footer.width); 258 | //Assert.areEqual (scaleHeight - layoutHeight + 40, footer.height); 259 | 260 | } 261 | 262 | 263 | @Test public function testTopLeft ():Void { 264 | 265 | testLayout (TOP, LEFT); 266 | 267 | } 268 | 269 | 270 | @Test public function testTopCenter ():Void { 271 | 272 | testLayout (TOP, CENTER); 273 | 274 | } 275 | 276 | 277 | @Test public function testTopRight ():Void { 278 | 279 | testLayout (TOP, RIGHT); 280 | 281 | } 282 | 283 | 284 | @Test public function testCenterLeft ():Void { 285 | 286 | testLayout (CENTER, LEFT); 287 | 288 | } 289 | 290 | 291 | @Test public function testCenterCenter ():Void { 292 | 293 | testLayout (CENTER, CENTER); 294 | 295 | } 296 | 297 | 298 | @Test public function testCenterRight ():Void { 299 | 300 | testLayout (CENTER, RIGHT); 301 | 302 | } 303 | 304 | 305 | @Test public function testBottomLeft ():Void { 306 | 307 | testLayout (BOTTOM, LEFT); 308 | 309 | } 310 | 311 | 312 | @Test public function testBottomCenter ():Void { 313 | 314 | testLayout (BOTTOM, CENTER); 315 | 316 | } 317 | 318 | 319 | @Test public function testBottomRight ():Void { 320 | 321 | testLayout (BOTTOM, RIGHT); 322 | 323 | } 324 | 325 | 326 | @Test public function testStretchLeft ():Void { 327 | 328 | testLayout (STRETCH, LEFT); 329 | 330 | } 331 | 332 | 333 | @Test public function testStretchCenter ():Void { 334 | 335 | testLayout (STRETCH, CENTER); 336 | 337 | } 338 | 339 | 340 | @Test public function testStretchRight ():Void { 341 | 342 | testLayout (STRETCH, RIGHT); 343 | 344 | } 345 | 346 | 347 | @Test public function testStretchStretch ():Void { 348 | 349 | testLayout (STRETCH, STRETCH); 350 | 351 | } 352 | 353 | 354 | @Test public function testTopStretch ():Void { 355 | 356 | testLayout (TOP, STRETCH); 357 | 358 | } 359 | 360 | 361 | @Test public function testCenterStretch ():Void { 362 | 363 | testLayout (CENTER, STRETCH); 364 | 365 | } 366 | 367 | 368 | @Test public function testBottomStretch ():Void { 369 | 370 | testLayout (BOTTOM, STRETCH); 371 | 372 | } 373 | 374 | 375 | @Test public function testNoneLeft ():Void { 376 | 377 | testLayout (NONE, LEFT); 378 | 379 | } 380 | 381 | 382 | @Test public function testNoneCenter ():Void { 383 | 384 | testLayout (NONE, CENTER); 385 | 386 | } 387 | 388 | 389 | @Test public function testNoneRight ():Void { 390 | 391 | testLayout (NONE, RIGHT); 392 | 393 | } 394 | 395 | 396 | @Test public function testNoneStretch ():Void { 397 | 398 | testLayout (NONE, STRETCH); 399 | 400 | } 401 | 402 | 403 | @Test public function testNoneNone ():Void { 404 | 405 | testLayout (NONE, NONE); 406 | 407 | } 408 | 409 | 410 | @Test public function testStretchNone ():Void { 411 | 412 | testLayout (STRETCH, NONE); 413 | 414 | } 415 | 416 | 417 | @Test public function testTopNone ():Void { 418 | 419 | testLayout (TOP, NONE); 420 | 421 | } 422 | 423 | 424 | @Test public function testCenterNone ():Void { 425 | 426 | testLayout (CENTER, NONE); 427 | 428 | } 429 | 430 | 431 | @Test public function testBottomNone ():Void { 432 | 433 | testLayout (BOTTOM, NONE); 434 | 435 | } 436 | 437 | 438 | } 439 | 440 | 441 | private class DisplayObject { 442 | 443 | 444 | public var x:Float; 445 | public var y:Float; 446 | public var width:Float; 447 | public var height:Float; 448 | 449 | 450 | public function new () { 451 | 452 | 453 | 454 | } 455 | 456 | 457 | } -------------------------------------------------------------------------------- /tests/test/GroupTest.hx: -------------------------------------------------------------------------------- 1 | package; 2 | 3 | 4 | import skylark.layout.Layout; 5 | import skylark.layout.LayoutGroup; 6 | import skylark.layout.LayoutItem; 7 | import skylark.layout.LayoutType; 8 | import massive.munit.Assert; 9 | 10 | @:access(skylark.layout) 11 | 12 | 13 | class GroupTest { 14 | 15 | 16 | public static var background:DisplayObject; 17 | public static var logo:DisplayObject; 18 | public static var sidebar:DisplayObject; 19 | public static var footer:DisplayObject; 20 | 21 | private static var layoutHeight = 200; 22 | private static var layoutWidth = 200; 23 | 24 | 25 | @Before public function setup ():Void { 26 | 27 | background = new DisplayObject (); 28 | background.x = 0; 29 | background.y = 0; 30 | background.width = layoutWidth; 31 | background.height = layoutHeight; 32 | 33 | logo = new DisplayObject (); 34 | logo.x = 10; 35 | logo.y = 10; 36 | logo.width = 40; 37 | logo.height = 25; 38 | 39 | sidebar = new DisplayObject (); 40 | sidebar.x = layoutWidth - 60; 41 | sidebar.y = 0; 42 | sidebar.width = 60; 43 | sidebar.height = layoutHeight - 40; 44 | 45 | footer = new DisplayObject (); 46 | footer.x = 0; 47 | footer.y = layoutHeight - 40; 48 | footer.width = layoutWidth; 49 | footer.height = 40; 50 | 51 | } 52 | 53 | 54 | private inline function testLayout (verticalType:LayoutType, horizontalType:LayoutType, ?pos:haxe.PosInfos) { 55 | 56 | var layout = new Layout (layoutWidth, layoutHeight); 57 | var layoutGroup = new LayoutGroup (STRETCH, STRETCH); 58 | 59 | layoutGroup.width = layoutWidth; 60 | layoutGroup.height = layoutHeight; 61 | 62 | layoutGroup.addItem (new LayoutItem (background, verticalType, horizontalType)); 63 | layoutGroup.addItem (new LayoutItem (logo, verticalType, horizontalType)); 64 | layoutGroup.addItem (new LayoutItem (sidebar, verticalType, horizontalType)); 65 | layoutGroup.addItem (new LayoutItem (footer, verticalType, horizontalType)); 66 | 67 | layout.addItem (layoutGroup); 68 | 69 | testLayoutSize (layout, verticalType, horizontalType, 200, 200, pos); 70 | testLayoutSize (layout, verticalType, horizontalType, 300, 240, pos); 71 | testLayoutSize (layout, verticalType, horizontalType, 1200, 1370, pos); 72 | testLayoutSize (layout, verticalType, horizontalType, 1500, 1200, pos); 73 | testLayoutSize (layout, verticalType, horizontalType, 220, 1200, pos); 74 | testLayoutSize (layout, verticalType, horizontalType, 100, 220, pos); 75 | testLayoutSize (layout, verticalType, horizontalType, 220, 100, pos); 76 | testLayoutSize (layout, verticalType, horizontalType, 10, 10, pos); 77 | 78 | setup (); 79 | 80 | var layout = new Layout (); 81 | var layoutGroup = new LayoutGroup (STRETCH, STRETCH); 82 | 83 | layoutGroup.addItem (new LayoutItem (background, verticalType, horizontalType)); 84 | layoutGroup.addItem (new LayoutItem (logo, verticalType, horizontalType)); 85 | layoutGroup.addItem (new LayoutItem (sidebar, verticalType, horizontalType)); 86 | layoutGroup.addItem (new LayoutItem (footer, verticalType, horizontalType)); 87 | 88 | layout.addItem (layoutGroup); 89 | 90 | testLayoutSize (layout, verticalType, horizontalType, 200, 200, pos); 91 | testLayoutSize (layout, verticalType, horizontalType, 300, 240, pos); 92 | testLayoutSize (layout, verticalType, horizontalType, 1200, 1370, pos); 93 | testLayoutSize (layout, verticalType, horizontalType, 1500, 1200, pos); 94 | testLayoutSize (layout, verticalType, horizontalType, 220, 1200, pos); 95 | testLayoutSize (layout, verticalType, horizontalType, 100, 220, pos); 96 | testLayoutSize (layout, verticalType, horizontalType, 220, 100, pos); 97 | testLayoutSize (layout, verticalType, horizontalType, 10, 10, pos); 98 | 99 | } 100 | 101 | 102 | private inline function testLayoutSize (layout:Layout, verticalType:LayoutType, horizontalType:LayoutType, width:Float, height:Float, ?pos:haxe.PosInfos) { 103 | 104 | layout.resize (width, height); 105 | 106 | if (width < layoutWidth) width = layoutWidth; 107 | if (height < layoutHeight) height = layoutHeight; 108 | 109 | var scaleWidth = (horizontalType == STRETCH) ? width : layoutWidth; 110 | var scaleHeight = (verticalType == STRETCH) ? height : layoutHeight; 111 | 112 | var offsetY = switch (verticalType) { 113 | 114 | case CENTER: (height / 2) - (layoutHeight / 2); 115 | case BOTTOM: height - layoutHeight; 116 | default: 0; 117 | 118 | } 119 | 120 | var offsetX = switch (horizontalType) { 121 | 122 | case CENTER: (width / 2) - (layoutWidth / 2); 123 | case RIGHT: width - layoutWidth; 124 | default: 0; 125 | 126 | } 127 | 128 | //Assert.areEqual (offsetX, background.x, pos); 129 | //Assert.areEqual (offsetY, background.y, pos); 130 | //Assert.areEqual (scaleWidth, background.width, pos); 131 | //Assert.areEqual (scaleHeight, background.height, pos); 132 | // 133 | //Assert.areEqual (offsetX + 10, logo.x, pos); 134 | //Assert.areEqual (offsetY + 10, logo.y, pos); 135 | //Assert.areEqual (scaleWidth - layoutWidth + 40, logo.width, pos); 136 | //Assert.areEqual (scaleHeight - layoutHeight + 25, logo.height, pos); 137 | // 138 | //Assert.areEqual (offsetX + layoutWidth - 60, sidebar.x, pos); 139 | //Assert.areEqual (offsetY, sidebar.y, pos); 140 | //Assert.areEqual (scaleWidth - layoutWidth + 60, sidebar.width, pos); 141 | //Assert.areEqual (scaleHeight - 40, sidebar.height, pos); 142 | // 143 | //Assert.areEqual (offsetX, footer.x, pos); 144 | //Assert.areEqual (offsetY + layoutHeight - 40, footer.y, pos); 145 | //Assert.areEqual (scaleWidth, footer.width, pos); 146 | //Assert.areEqual (scaleHeight - layoutHeight + 40, footer.height, pos); 147 | 148 | Assert.areEqual (offsetX, background.x); 149 | Assert.areEqual (offsetY, background.y); 150 | Assert.areEqual (scaleWidth, background.width); 151 | Assert.areEqual (scaleHeight, background.height); 152 | 153 | Assert.areEqual (offsetX + 10, logo.x); 154 | Assert.areEqual (offsetY + 10, logo.y); 155 | Assert.areEqual (scaleWidth - layoutWidth + 40, logo.width); 156 | Assert.areEqual (scaleHeight - layoutHeight + 25, logo.height); 157 | 158 | Assert.areEqual (offsetX + layoutWidth - 60, sidebar.x); 159 | Assert.areEqual (offsetY, sidebar.y); 160 | Assert.areEqual (scaleWidth - layoutWidth + 60, sidebar.width); 161 | Assert.areEqual (scaleHeight - 40, sidebar.height); 162 | 163 | Assert.areEqual (offsetX, footer.x); 164 | Assert.areEqual (offsetY + layoutHeight - 40, footer.y); 165 | Assert.areEqual (scaleWidth, footer.width); 166 | Assert.areEqual (scaleHeight - layoutHeight + 40, footer.height); 167 | 168 | } 169 | 170 | 171 | @Test public function testTopLeft ():Void { 172 | 173 | testLayout (TOP, LEFT); 174 | 175 | } 176 | 177 | 178 | @Test public function testTopCenter ():Void { 179 | 180 | testLayout (TOP, CENTER); 181 | 182 | } 183 | 184 | 185 | @Test public function testTopRight ():Void { 186 | 187 | testLayout (TOP, RIGHT); 188 | 189 | } 190 | 191 | 192 | @Test public function testCenterLeft ():Void { 193 | 194 | testLayout (CENTER, LEFT); 195 | 196 | } 197 | 198 | 199 | @Test public function testCenterCenter ():Void { 200 | 201 | testLayout (CENTER, CENTER); 202 | 203 | } 204 | 205 | 206 | @Test public function testCenterRight ():Void { 207 | 208 | testLayout (CENTER, RIGHT); 209 | 210 | } 211 | 212 | 213 | @Test public function testBottomLeft ():Void { 214 | 215 | testLayout (BOTTOM, LEFT); 216 | 217 | } 218 | 219 | 220 | @Test public function testBottomCenter ():Void { 221 | 222 | testLayout (BOTTOM, CENTER); 223 | 224 | } 225 | 226 | 227 | @Test public function testBottomRight ():Void { 228 | 229 | testLayout (BOTTOM, RIGHT); 230 | 231 | } 232 | 233 | 234 | @Test public function testStretchLeft ():Void { 235 | 236 | testLayout (STRETCH, LEFT); 237 | 238 | } 239 | 240 | 241 | @Test public function testStretchCenter ():Void { 242 | 243 | testLayout (STRETCH, CENTER); 244 | 245 | } 246 | 247 | 248 | @Test public function testStretchRight ():Void { 249 | 250 | testLayout (STRETCH, RIGHT); 251 | 252 | } 253 | 254 | 255 | @Test public function testStretchStretch ():Void { 256 | 257 | testLayout (STRETCH, STRETCH); 258 | 259 | } 260 | 261 | 262 | @Test public function testTopStretch ():Void { 263 | 264 | testLayout (TOP, STRETCH); 265 | 266 | } 267 | 268 | 269 | @Test public function testCenterStretch ():Void { 270 | 271 | testLayout (CENTER, STRETCH); 272 | 273 | } 274 | 275 | 276 | @Test public function testBottomStretch ():Void { 277 | 278 | testLayout (BOTTOM, STRETCH); 279 | 280 | } 281 | 282 | 283 | @Test public function testNoneLeft ():Void { 284 | 285 | testLayout (NONE, LEFT); 286 | 287 | } 288 | 289 | 290 | @Test public function testNoneCenter ():Void { 291 | 292 | testLayout (NONE, CENTER); 293 | 294 | } 295 | 296 | 297 | @Test public function testNoneRight ():Void { 298 | 299 | testLayout (NONE, RIGHT); 300 | 301 | } 302 | 303 | 304 | @Test public function testNoneStretch ():Void { 305 | 306 | testLayout (NONE, STRETCH); 307 | 308 | } 309 | 310 | 311 | @Test public function testNoneNone ():Void { 312 | 313 | testLayout (NONE, NONE); 314 | 315 | } 316 | 317 | 318 | @Test public function testStretchNone ():Void { 319 | 320 | testLayout (STRETCH, NONE); 321 | 322 | } 323 | 324 | 325 | @Test public function testTopNone ():Void { 326 | 327 | testLayout (TOP, NONE); 328 | 329 | } 330 | 331 | 332 | @Test public function testCenterNone ():Void { 333 | 334 | testLayout (CENTER, NONE); 335 | 336 | } 337 | 338 | 339 | @Test public function testBottomNone ():Void { 340 | 341 | testLayout (BOTTOM, NONE); 342 | 343 | } 344 | 345 | 346 | } 347 | 348 | 349 | private class DisplayObject { 350 | 351 | 352 | public var x:Float; 353 | public var y:Float; 354 | public var width:Float; 355 | public var height:Float; 356 | 357 | 358 | public function new () { 359 | 360 | 361 | 362 | } 363 | 364 | 365 | } --------------------------------------------------------------------------------