├── .gitignore ├── LICENSE ├── PATENTS ├── README.md ├── absolute_position_test.go ├── align_content_test.go ├── align_items_test.go ├── align_self_test.go ├── aspect_ratio_test.go ├── baseline_func_test.go ├── border_test.go ├── compute_margin_test.go ├── compute_padding_test.go ├── default_values_test.go ├── dimension_test.go ├── dirty_marking_test.go ├── display_test.go ├── edge_test.go ├── enums.go ├── flex_direction_test.go ├── flex_test.go ├── flex_wrap_test.go ├── had_overflow_test.go ├── issue5_test.go ├── justify_content_test.go ├── margin_test.go ├── math.go ├── math_test.go ├── measure_cache_test.go ├── measure_mode_test.go ├── measure_test.go ├── min_max_dimension_test.go ├── node_child_test.go ├── padding_test.go ├── percentage_test.go ├── print.go ├── relayout_test.go ├── rounding_function_test.go ├── rounding_measure_func_test.go ├── rounding_test.go ├── size_overflow_test.go ├── style_test.go ├── yoga.go ├── yoga_h.go └── yoga_props.go /.gitignore: -------------------------------------------------------------------------------- 1 | debug 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD License 2 | 3 | For yoga software 4 | 5 | Copyright (c) 2014-present, Facebook, Inc. All rights reserved. 6 | Copyright (c) 2017-present, Krzysztof Kowalczyk. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without modification, 9 | are permitted provided that the following conditions are met: 10 | 11 | * Redistributions of source code must retain the above copyright notice, this 12 | list of conditions and the following disclaimer. 13 | 14 | * Redistributions in binary form must reproduce the above copyright notice, 15 | this list of conditions and the following disclaimer in the documentation 16 | and/or other materials provided with the distribution. 17 | 18 | * Neither the name Facebook nor the names of its contributors may be used to 19 | endorse or promote products derived from this software without specific 20 | prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 23 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 26 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 29 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /PATENTS: -------------------------------------------------------------------------------- 1 | Additional Grant of Patent Rights Version 2 2 | 3 | "Software" means the yoga software distributed by Facebook, Inc. 4 | 5 | Facebook, Inc. (“Facebook”) hereby grants to each recipient of the Software 6 | (“you”) a perpetual, worldwide, royalty-free, non-exclusive, irrevocable 7 | (subject to the termination provision below) license under any Necessary 8 | Claims, to make, have made, use, sell, offer to sell, import, and otherwise 9 | transfer the Software. For avoidance of doubt, no license is granted under 10 | Facebook's rights in any patent claims that are infringed by (i) modifications 11 | to the Software made by you or any third party or (ii) the Software in 12 | combination with any software or other technology. 13 | 14 | The license granted hereunder will terminate, automatically and without notice, 15 | if you (or any of your subsidiaries, corporate affiliates or agents) initiate 16 | directly or indirectly, or take a direct financial interest in, any Patent 17 | Assertion: (i) against Facebook or any of its subsidiaries or corporate 18 | affiliates, (ii) against any party if such Patent Assertion arises in whole or 19 | in part from any software, technology, product or service of Facebook or any of 20 | its subsidiaries or corporate affiliates, or (iii) against any party relating 21 | to the Software. Notwithstanding the foregoing, if Facebook or any of its 22 | subsidiaries or corporate affiliates files a lawsuit alleging patent 23 | infringement against you in the first instance, and you respond by filing a 24 | patent infringement counterclaim in that lawsuit against that party that is 25 | unrelated to the Software, the license granted hereunder will not terminate 26 | under section (i) of this paragraph due to such counterclaim. 27 | 28 | A "Necessary Claim" is a claim of a patent owned by Facebook that is 29 | necessarily infringed by the Software standing alone. 30 | 31 | A "Patent Assertion" is any lawsuit or other action alleging direct, indirect, 32 | or contributory infringement or inducement to infringe any patent, including a 33 | cross-claim or counterclaim. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flex - CSS flexbox layout implementation in Go 2 | 3 | Go implementation of [flexbox CSS](https://www.w3.org/TR/css-flexbox-1/) layout algorithm. 4 | 5 | A pure Go port of [Facebook's Yoga](https://github.com/facebook/yoga). 6 | 7 | ## How to use 8 | 9 | Read [tutorial](https://blog.kowalczyk.info/article/9/tutorial-on-using-github.comkjkflex-go-package.html) or look at `_test.go` files. 10 | 11 | ## Status 12 | 13 | The port is finished. The code works and passess all Yoga tests. 14 | 15 | The API is awkward by Go standards but it's the best I could do given that I want to stay close to C version. 16 | 17 | Logic is currently synced up to https://github.com/facebook/yoga/commit/f45059e1e696727c1282742b89d2c8bf06345254 18 | 19 | ## How the port was made 20 | 21 | You can read a [detailed story](https://blog.kowalczyk.info/article/wN9R/experience-porting-4.5k-loc-of-c-to-go-facebooks-css-flexbox-implementation-yoga.html). 22 | 23 | In short: 24 | 25 | * manually ported [C code](https://github.com/facebook/yoga/tree/master/yoga) to Go, line-by-line 26 | * manually ported [tests](https://github.com/facebook/yoga/tree/master/tests) to Go 27 | * tweak the API from C style to be more Go like. The structure and logic still is very close to C code (this makes porting future C changes easy) 28 | -------------------------------------------------------------------------------- /align_self_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import "testing" 4 | 5 | func TestAlign_self_center(t *testing.T) { 6 | config := NewConfig() 7 | 8 | root := NewNodeWithConfig(config) 9 | root.StyleSetWidth(100) 10 | root.StyleSetHeight(100) 11 | 12 | rootChild0 := NewNodeWithConfig(config) 13 | rootChild0.StyleSetAlignSelf(AlignCenter) 14 | rootChild0.StyleSetWidth(10) 15 | rootChild0.StyleSetHeight(10) 16 | root.InsertChild(rootChild0, 0) 17 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 18 | 19 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 20 | assertFloatEqual(t, 0, root.LayoutGetTop()) 21 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 22 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 23 | 24 | assertFloatEqual(t, 45, rootChild0.LayoutGetLeft()) 25 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 26 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 27 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 28 | 29 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 30 | 31 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 32 | assertFloatEqual(t, 0, root.LayoutGetTop()) 33 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 34 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 35 | 36 | assertFloatEqual(t, 45, rootChild0.LayoutGetLeft()) 37 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 38 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 39 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 40 | } 41 | 42 | func TestAlign_self_flex_end(t *testing.T) { 43 | config := NewConfig() 44 | 45 | root := NewNodeWithConfig(config) 46 | root.StyleSetWidth(100) 47 | root.StyleSetHeight(100) 48 | 49 | rootChild0 := NewNodeWithConfig(config) 50 | rootChild0.StyleSetAlignSelf(AlignFlexEnd) 51 | rootChild0.StyleSetWidth(10) 52 | rootChild0.StyleSetHeight(10) 53 | root.InsertChild(rootChild0, 0) 54 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 55 | 56 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 57 | assertFloatEqual(t, 0, root.LayoutGetTop()) 58 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 59 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 60 | 61 | assertFloatEqual(t, 90, rootChild0.LayoutGetLeft()) 62 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 63 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 64 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 65 | 66 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 67 | 68 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 69 | assertFloatEqual(t, 0, root.LayoutGetTop()) 70 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 71 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 72 | 73 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 74 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 75 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 76 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 77 | } 78 | 79 | func TestAlign_self_flex_start(t *testing.T) { 80 | config := NewConfig() 81 | 82 | root := NewNodeWithConfig(config) 83 | root.StyleSetWidth(100) 84 | root.StyleSetHeight(100) 85 | 86 | rootChild0 := NewNodeWithConfig(config) 87 | rootChild0.StyleSetAlignSelf(AlignFlexStart) 88 | rootChild0.StyleSetWidth(10) 89 | rootChild0.StyleSetHeight(10) 90 | root.InsertChild(rootChild0, 0) 91 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 92 | 93 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 94 | assertFloatEqual(t, 0, root.LayoutGetTop()) 95 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 96 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 97 | 98 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 99 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 100 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 101 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 102 | 103 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 104 | 105 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 106 | assertFloatEqual(t, 0, root.LayoutGetTop()) 107 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 108 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 109 | 110 | assertFloatEqual(t, 90, rootChild0.LayoutGetLeft()) 111 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 112 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 113 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 114 | } 115 | 116 | func TestAlign_self_flex_end_override_flex_start(t *testing.T) { 117 | config := NewConfig() 118 | 119 | root := NewNodeWithConfig(config) 120 | root.StyleSetAlignItems(AlignFlexStart) 121 | root.StyleSetWidth(100) 122 | root.StyleSetHeight(100) 123 | 124 | rootChild0 := NewNodeWithConfig(config) 125 | rootChild0.StyleSetAlignSelf(AlignFlexEnd) 126 | rootChild0.StyleSetWidth(10) 127 | rootChild0.StyleSetHeight(10) 128 | root.InsertChild(rootChild0, 0) 129 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 130 | 131 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 132 | assertFloatEqual(t, 0, root.LayoutGetTop()) 133 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 134 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 135 | 136 | assertFloatEqual(t, 90, rootChild0.LayoutGetLeft()) 137 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 138 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 139 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 140 | 141 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 142 | 143 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 144 | assertFloatEqual(t, 0, root.LayoutGetTop()) 145 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 146 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 147 | 148 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 149 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 150 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 151 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 152 | } 153 | 154 | func TestAlign_self_baseline(t *testing.T) { 155 | config := NewConfig() 156 | 157 | root := NewNodeWithConfig(config) 158 | root.StyleSetFlexDirection(FlexDirectionRow) 159 | root.StyleSetWidth(100) 160 | root.StyleSetHeight(100) 161 | 162 | rootChild0 := NewNodeWithConfig(config) 163 | rootChild0.StyleSetAlignSelf(AlignBaseline) 164 | rootChild0.StyleSetWidth(50) 165 | rootChild0.StyleSetHeight(50) 166 | root.InsertChild(rootChild0, 0) 167 | 168 | rootChild1 := NewNodeWithConfig(config) 169 | rootChild1.StyleSetAlignSelf(AlignBaseline) 170 | rootChild1.StyleSetWidth(50) 171 | rootChild1.StyleSetHeight(20) 172 | root.InsertChild(rootChild1, 1) 173 | 174 | rootChild1child0 := NewNodeWithConfig(config) 175 | rootChild1child0.StyleSetWidth(50) 176 | rootChild1child0.StyleSetHeight(10) 177 | rootChild1.InsertChild(rootChild1child0, 0) 178 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 179 | 180 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 181 | assertFloatEqual(t, 0, root.LayoutGetTop()) 182 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 183 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 184 | 185 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 186 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 187 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 188 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 189 | 190 | assertFloatEqual(t, 50, rootChild1.LayoutGetLeft()) 191 | assertFloatEqual(t, 40, rootChild1.LayoutGetTop()) 192 | assertFloatEqual(t, 50, rootChild1.LayoutGetWidth()) 193 | assertFloatEqual(t, 20, rootChild1.LayoutGetHeight()) 194 | 195 | assertFloatEqual(t, 0, rootChild1child0.LayoutGetLeft()) 196 | assertFloatEqual(t, 0, rootChild1child0.LayoutGetTop()) 197 | assertFloatEqual(t, 50, rootChild1child0.LayoutGetWidth()) 198 | assertFloatEqual(t, 10, rootChild1child0.LayoutGetHeight()) 199 | 200 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 201 | 202 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 203 | assertFloatEqual(t, 0, root.LayoutGetTop()) 204 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 205 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 206 | 207 | assertFloatEqual(t, 50, rootChild0.LayoutGetLeft()) 208 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 209 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 210 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 211 | 212 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 213 | assertFloatEqual(t, 40, rootChild1.LayoutGetTop()) 214 | assertFloatEqual(t, 50, rootChild1.LayoutGetWidth()) 215 | assertFloatEqual(t, 20, rootChild1.LayoutGetHeight()) 216 | 217 | assertFloatEqual(t, 0, rootChild1child0.LayoutGetLeft()) 218 | assertFloatEqual(t, 0, rootChild1child0.LayoutGetTop()) 219 | assertFloatEqual(t, 50, rootChild1child0.LayoutGetWidth()) 220 | assertFloatEqual(t, 10, rootChild1child0.LayoutGetHeight()) 221 | } 222 | -------------------------------------------------------------------------------- /aspect_ratio_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import "testing" 4 | 5 | func _measure(node *Node, width float32, widthMode MeasureMode, 6 | height float32, heightMode MeasureMode) Size { 7 | 8 | if widthMode != MeasureModeExactly { 9 | width = 50 10 | } 11 | if heightMode != MeasureModeExactly { 12 | height = 50 13 | } 14 | return Size{ 15 | Width: width, 16 | Height: height, 17 | } 18 | } 19 | 20 | func TestAspect_ratio_cross_defined(t *testing.T) { 21 | root := NewNode() 22 | root.StyleSetAlignItems(AlignFlexStart) 23 | root.StyleSetWidth(100) 24 | root.StyleSetHeight(100) 25 | 26 | rootChild0 := NewNode() 27 | rootChild0.StyleSetWidth(50) 28 | rootChild0.StyleSetAspectRatio(1) 29 | root.InsertChild(rootChild0, 0) 30 | 31 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 32 | 33 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 34 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 35 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 36 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 37 | } 38 | 39 | func TestAspect_ratio_main_defined(t *testing.T) { 40 | root := NewNode() 41 | root.StyleSetAlignItems(AlignFlexStart) 42 | root.StyleSetWidth(100) 43 | root.StyleSetHeight(100) 44 | 45 | rootChild0 := NewNode() 46 | rootChild0.StyleSetHeight(50) 47 | rootChild0.StyleSetAspectRatio(1) 48 | root.InsertChild(rootChild0, 0) 49 | 50 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 51 | 52 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 53 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 54 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 55 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 56 | } 57 | 58 | func TestAspect_ratio_both_dimensions_defined_row(t *testing.T) { 59 | root := NewNode() 60 | root.StyleSetFlexDirection(FlexDirectionRow) 61 | root.StyleSetAlignItems(AlignFlexStart) 62 | root.StyleSetWidth(100) 63 | root.StyleSetHeight(100) 64 | 65 | rootChild0 := NewNode() 66 | rootChild0.StyleSetWidth(100) 67 | rootChild0.StyleSetHeight(50) 68 | rootChild0.StyleSetAspectRatio(1) 69 | root.InsertChild(rootChild0, 0) 70 | 71 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 72 | 73 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 74 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 75 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 76 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 77 | } 78 | 79 | func TestAspect_ratio_both_dimensions_defined_column(t *testing.T) { 80 | root := NewNode() 81 | root.StyleSetAlignItems(AlignFlexStart) 82 | root.StyleSetWidth(100) 83 | root.StyleSetHeight(100) 84 | 85 | rootChild0 := NewNode() 86 | rootChild0.StyleSetWidth(100) 87 | rootChild0.StyleSetHeight(50) 88 | rootChild0.StyleSetAspectRatio(1) 89 | root.InsertChild(rootChild0, 0) 90 | 91 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 92 | 93 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 94 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 95 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 96 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 97 | } 98 | 99 | func TestAspect_ratio_align_stretch(t *testing.T) { 100 | root := NewNode() 101 | root.StyleSetWidth(100) 102 | root.StyleSetHeight(100) 103 | 104 | rootChild0 := NewNode() 105 | rootChild0.StyleSetAspectRatio(1) 106 | root.InsertChild(rootChild0, 0) 107 | 108 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 109 | 110 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 111 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 112 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 113 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 114 | } 115 | 116 | func TestAspect_ratio_flex_grow(t *testing.T) { 117 | root := NewNode() 118 | root.StyleSetAlignItems(AlignFlexStart) 119 | root.StyleSetWidth(100) 120 | root.StyleSetHeight(100) 121 | 122 | rootChild0 := NewNode() 123 | rootChild0.StyleSetHeight(50) 124 | rootChild0.StyleSetFlexGrow(1) 125 | rootChild0.StyleSetAspectRatio(1) 126 | root.InsertChild(rootChild0, 0) 127 | 128 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 129 | 130 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 131 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 132 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 133 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 134 | } 135 | 136 | func TestAspect_ratio_flex_shrink(t *testing.T) { 137 | root := NewNode() 138 | root.StyleSetAlignItems(AlignFlexStart) 139 | root.StyleSetWidth(100) 140 | root.StyleSetHeight(100) 141 | 142 | rootChild0 := NewNode() 143 | rootChild0.StyleSetHeight(150) 144 | rootChild0.StyleSetFlexShrink(1) 145 | rootChild0.StyleSetAspectRatio(1) 146 | root.InsertChild(rootChild0, 0) 147 | 148 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 149 | 150 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 151 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 152 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 153 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 154 | } 155 | 156 | func TestAspect_ratio_basis(t *testing.T) { 157 | root := NewNode() 158 | root.StyleSetAlignItems(AlignFlexStart) 159 | root.StyleSetWidth(100) 160 | root.StyleSetHeight(100) 161 | 162 | rootChild0 := NewNode() 163 | rootChild0.StyleSetFlexBasis(50) 164 | rootChild0.StyleSetAspectRatio(1) 165 | root.InsertChild(rootChild0, 0) 166 | 167 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 168 | 169 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 170 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 171 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 172 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 173 | } 174 | 175 | func TestAspect_ratio_absolute_layout_width_defined(t *testing.T) { 176 | root := NewNode() 177 | root.StyleSetWidth(100) 178 | root.StyleSetHeight(100) 179 | 180 | rootChild0 := NewNode() 181 | rootChild0.StyleSetPositionType(PositionTypeAbsolute) 182 | rootChild0.StyleSetPosition(EdgeLeft, 0) 183 | rootChild0.StyleSetPosition(EdgeTop, 0) 184 | rootChild0.StyleSetWidth(50) 185 | rootChild0.StyleSetAspectRatio(1) 186 | root.InsertChild(rootChild0, 0) 187 | 188 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 189 | 190 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 191 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 192 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 193 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 194 | } 195 | 196 | func TestAspect_ratio_absolute_layout_height_defined(t *testing.T) { 197 | root := NewNode() 198 | root.StyleSetWidth(100) 199 | root.StyleSetHeight(100) 200 | 201 | rootChild0 := NewNode() 202 | rootChild0.StyleSetPositionType(PositionTypeAbsolute) 203 | rootChild0.StyleSetPosition(EdgeLeft, 0) 204 | rootChild0.StyleSetPosition(EdgeTop, 0) 205 | rootChild0.StyleSetHeight(50) 206 | rootChild0.StyleSetAspectRatio(1) 207 | root.InsertChild(rootChild0, 0) 208 | 209 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 210 | 211 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 212 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 213 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 214 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 215 | } 216 | 217 | func TestAspect_ratio_with_max_cross_defined(t *testing.T) { 218 | root := NewNode() 219 | root.StyleSetAlignItems(AlignFlexStart) 220 | root.StyleSetWidth(100) 221 | root.StyleSetHeight(100) 222 | 223 | rootChild0 := NewNode() 224 | rootChild0.StyleSetHeight(50) 225 | rootChild0.StyleSetMaxWidth(40) 226 | rootChild0.StyleSetAspectRatio(1) 227 | root.InsertChild(rootChild0, 0) 228 | 229 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 230 | 231 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 232 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 233 | assertFloatEqual(t, 40, rootChild0.LayoutGetWidth()) 234 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 235 | } 236 | 237 | func TestAspect_ratio_with_max_main_defined(t *testing.T) { 238 | root := NewNode() 239 | root.StyleSetAlignItems(AlignFlexStart) 240 | root.StyleSetWidth(100) 241 | root.StyleSetHeight(100) 242 | 243 | rootChild0 := NewNode() 244 | rootChild0.StyleSetWidth(50) 245 | rootChild0.StyleSetMaxHeight(40) 246 | rootChild0.StyleSetAspectRatio(1) 247 | root.InsertChild(rootChild0, 0) 248 | 249 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 250 | 251 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 252 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 253 | assertFloatEqual(t, 40, rootChild0.LayoutGetWidth()) 254 | assertFloatEqual(t, 40, rootChild0.LayoutGetHeight()) 255 | } 256 | 257 | func TestAspect_ratio_with_min_cross_defined(t *testing.T) { 258 | root := NewNode() 259 | root.StyleSetAlignItems(AlignFlexStart) 260 | root.StyleSetWidth(100) 261 | root.StyleSetHeight(100) 262 | 263 | rootChild0 := NewNode() 264 | rootChild0.StyleSetHeight(30) 265 | rootChild0.StyleSetMinWidth(40) 266 | rootChild0.StyleSetAspectRatio(1) 267 | root.InsertChild(rootChild0, 0) 268 | 269 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 270 | 271 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 272 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 273 | assertFloatEqual(t, 40, rootChild0.LayoutGetWidth()) 274 | assertFloatEqual(t, 30, rootChild0.LayoutGetHeight()) 275 | } 276 | 277 | func TestAspect_ratio_with_min_main_defined(t *testing.T) { 278 | root := NewNode() 279 | root.StyleSetAlignItems(AlignFlexStart) 280 | root.StyleSetWidth(100) 281 | root.StyleSetHeight(100) 282 | 283 | rootChild0 := NewNode() 284 | rootChild0.StyleSetWidth(30) 285 | rootChild0.StyleSetMinHeight(40) 286 | rootChild0.StyleSetAspectRatio(1) 287 | root.InsertChild(rootChild0, 0) 288 | 289 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 290 | 291 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 292 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 293 | assertFloatEqual(t, 40, rootChild0.LayoutGetWidth()) 294 | assertFloatEqual(t, 40, rootChild0.LayoutGetHeight()) 295 | } 296 | 297 | func TestAspect_ratio_double_cross(t *testing.T) { 298 | root := NewNode() 299 | root.StyleSetAlignItems(AlignFlexStart) 300 | root.StyleSetWidth(100) 301 | root.StyleSetHeight(100) 302 | 303 | rootChild0 := NewNode() 304 | rootChild0.StyleSetHeight(50) 305 | rootChild0.StyleSetAspectRatio(2) 306 | root.InsertChild(rootChild0, 0) 307 | 308 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 309 | 310 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 311 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 312 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 313 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 314 | } 315 | 316 | func TestAspect_ratio_half_cross(t *testing.T) { 317 | root := NewNode() 318 | root.StyleSetAlignItems(AlignFlexStart) 319 | root.StyleSetWidth(100) 320 | root.StyleSetHeight(100) 321 | 322 | rootChild0 := NewNode() 323 | rootChild0.StyleSetHeight(100) 324 | rootChild0.StyleSetAspectRatio(0.5) 325 | root.InsertChild(rootChild0, 0) 326 | 327 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 328 | 329 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 330 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 331 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 332 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 333 | } 334 | 335 | func TestAspect_ratio_double_main(t *testing.T) { 336 | root := NewNode() 337 | root.StyleSetAlignItems(AlignFlexStart) 338 | root.StyleSetWidth(100) 339 | root.StyleSetHeight(100) 340 | 341 | rootChild0 := NewNode() 342 | rootChild0.StyleSetWidth(50) 343 | rootChild0.StyleSetAspectRatio(0.5) 344 | root.InsertChild(rootChild0, 0) 345 | 346 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 347 | 348 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 349 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 350 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 351 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 352 | } 353 | 354 | func TestAspect_ratio_half_main(t *testing.T) { 355 | root := NewNode() 356 | root.StyleSetAlignItems(AlignFlexStart) 357 | root.StyleSetWidth(100) 358 | root.StyleSetHeight(100) 359 | 360 | rootChild0 := NewNode() 361 | rootChild0.StyleSetWidth(100) 362 | rootChild0.StyleSetAspectRatio(2) 363 | root.InsertChild(rootChild0, 0) 364 | 365 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 366 | 367 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 368 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 369 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 370 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 371 | } 372 | 373 | func TestAspect_ratio_with_measure_func(t *testing.T) { 374 | root := NewNode() 375 | root.StyleSetAlignItems(AlignFlexStart) 376 | root.StyleSetWidth(100) 377 | root.StyleSetHeight(100) 378 | 379 | rootChild0 := NewNode() 380 | rootChild0.SetMeasureFunc(_measure) 381 | rootChild0.StyleSetAspectRatio(1) 382 | root.InsertChild(rootChild0, 0) 383 | 384 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 385 | 386 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 387 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 388 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 389 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 390 | } 391 | 392 | func TestAspect_ratio_width_height_flex_grow_row(t *testing.T) { 393 | root := NewNode() 394 | root.StyleSetFlexDirection(FlexDirectionRow) 395 | root.StyleSetAlignItems(AlignFlexStart) 396 | root.StyleSetWidth(100) 397 | root.StyleSetHeight(200) 398 | 399 | rootChild0 := NewNode() 400 | rootChild0.StyleSetWidth(50) 401 | rootChild0.StyleSetHeight(50) 402 | rootChild0.StyleSetFlexGrow(1) 403 | rootChild0.StyleSetAspectRatio(1) 404 | root.InsertChild(rootChild0, 0) 405 | 406 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 407 | 408 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 409 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 410 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 411 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 412 | } 413 | 414 | func TestAspect_ratio_width_height_flex_grow_column(t *testing.T) { 415 | root := NewNode() 416 | root.StyleSetAlignItems(AlignFlexStart) 417 | root.StyleSetWidth(200) 418 | root.StyleSetHeight(100) 419 | 420 | rootChild0 := NewNode() 421 | rootChild0.StyleSetWidth(50) 422 | rootChild0.StyleSetHeight(50) 423 | rootChild0.StyleSetFlexGrow(1) 424 | rootChild0.StyleSetAspectRatio(1) 425 | root.InsertChild(rootChild0, 0) 426 | 427 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 428 | 429 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 430 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 431 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 432 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 433 | } 434 | 435 | func TestAspect_ratio_height_as_flex_basis(t *testing.T) { 436 | root := NewNode() 437 | root.StyleSetAlignItems(AlignFlexStart) 438 | root.StyleSetFlexDirection(FlexDirectionRow) 439 | root.StyleSetWidth(200) 440 | root.StyleSetHeight(200) 441 | 442 | rootChild0 := NewNode() 443 | rootChild0.StyleSetHeight(50) 444 | rootChild0.StyleSetFlexGrow(1) 445 | rootChild0.StyleSetAspectRatio(1) 446 | root.InsertChild(rootChild0, 0) 447 | 448 | rootChild1 := NewNode() 449 | rootChild1.StyleSetHeight(100) 450 | rootChild1.StyleSetFlexGrow(1) 451 | rootChild1.StyleSetAspectRatio(1) 452 | root.InsertChild(rootChild1, 1) 453 | 454 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 455 | 456 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 457 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 458 | assertFloatEqual(t, 75, rootChild0.LayoutGetWidth()) 459 | assertFloatEqual(t, 75, rootChild0.LayoutGetHeight()) 460 | 461 | assertFloatEqual(t, 75, rootChild1.LayoutGetLeft()) 462 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 463 | assertFloatEqual(t, 125, rootChild1.LayoutGetWidth()) 464 | assertFloatEqual(t, 125, rootChild1.LayoutGetHeight()) 465 | } 466 | 467 | func TestAspect_ratio_width_as_flex_basis(t *testing.T) { 468 | root := NewNode() 469 | root.StyleSetAlignItems(AlignFlexStart) 470 | root.StyleSetWidth(200) 471 | root.StyleSetHeight(200) 472 | 473 | rootChild0 := NewNode() 474 | rootChild0.StyleSetWidth(50) 475 | rootChild0.StyleSetFlexGrow(1) 476 | rootChild0.StyleSetAspectRatio(1) 477 | root.InsertChild(rootChild0, 0) 478 | 479 | rootChild1 := NewNode() 480 | rootChild1.StyleSetWidth(100) 481 | rootChild1.StyleSetFlexGrow(1) 482 | rootChild1.StyleSetAspectRatio(1) 483 | root.InsertChild(rootChild1, 1) 484 | 485 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 486 | 487 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 488 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 489 | assertFloatEqual(t, 75, rootChild0.LayoutGetWidth()) 490 | assertFloatEqual(t, 75, rootChild0.LayoutGetHeight()) 491 | 492 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 493 | assertFloatEqual(t, 75, rootChild1.LayoutGetTop()) 494 | assertFloatEqual(t, 125, rootChild1.LayoutGetWidth()) 495 | assertFloatEqual(t, 125, rootChild1.LayoutGetHeight()) 496 | } 497 | 498 | func TestAspect_ratio_overrides_flex_grow_row(t *testing.T) { 499 | root := NewNode() 500 | root.StyleSetAlignItems(AlignFlexStart) 501 | root.StyleSetFlexDirection(FlexDirectionRow) 502 | root.StyleSetWidth(100) 503 | root.StyleSetHeight(100) 504 | 505 | rootChild0 := NewNode() 506 | rootChild0.StyleSetWidth(50) 507 | rootChild0.StyleSetFlexGrow(1) 508 | rootChild0.StyleSetAspectRatio(0.5) 509 | root.InsertChild(rootChild0, 0) 510 | 511 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 512 | 513 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 514 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 515 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 516 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 517 | } 518 | 519 | func TestAspect_ratio_overrides_flex_grow_column(t *testing.T) { 520 | root := NewNode() 521 | root.StyleSetAlignItems(AlignFlexStart) 522 | root.StyleSetWidth(100) 523 | root.StyleSetHeight(100) 524 | 525 | rootChild0 := NewNode() 526 | rootChild0.StyleSetHeight(50) 527 | rootChild0.StyleSetFlexGrow(1) 528 | rootChild0.StyleSetAspectRatio(2) 529 | root.InsertChild(rootChild0, 0) 530 | 531 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 532 | 533 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 534 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 535 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 536 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 537 | } 538 | 539 | func TestAspect_ratio_left_right_absolute(t *testing.T) { 540 | root := NewNode() 541 | root.StyleSetWidth(100) 542 | root.StyleSetHeight(100) 543 | 544 | rootChild0 := NewNode() 545 | rootChild0.StyleSetPositionType(PositionTypeAbsolute) 546 | rootChild0.StyleSetPosition(EdgeLeft, 10) 547 | rootChild0.StyleSetPosition(EdgeTop, 10) 548 | rootChild0.StyleSetPosition(EdgeRight, 10) 549 | rootChild0.StyleSetAspectRatio(1) 550 | root.InsertChild(rootChild0, 0) 551 | 552 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 553 | 554 | assertFloatEqual(t, 10, rootChild0.LayoutGetLeft()) 555 | assertFloatEqual(t, 10, rootChild0.LayoutGetTop()) 556 | assertFloatEqual(t, 80, rootChild0.LayoutGetWidth()) 557 | assertFloatEqual(t, 80, rootChild0.LayoutGetHeight()) 558 | } 559 | 560 | func TestAspect_ratio_top_bottom_absolute(t *testing.T) { 561 | root := NewNode() 562 | root.StyleSetWidth(100) 563 | root.StyleSetHeight(100) 564 | 565 | rootChild0 := NewNode() 566 | rootChild0.StyleSetPositionType(PositionTypeAbsolute) 567 | rootChild0.StyleSetPosition(EdgeLeft, 10) 568 | rootChild0.StyleSetPosition(EdgeTop, 10) 569 | rootChild0.StyleSetPosition(EdgeBottom, 10) 570 | rootChild0.StyleSetAspectRatio(1) 571 | root.InsertChild(rootChild0, 0) 572 | 573 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 574 | 575 | assertFloatEqual(t, 10, rootChild0.LayoutGetLeft()) 576 | assertFloatEqual(t, 10, rootChild0.LayoutGetTop()) 577 | assertFloatEqual(t, 80, rootChild0.LayoutGetWidth()) 578 | assertFloatEqual(t, 80, rootChild0.LayoutGetHeight()) 579 | } 580 | 581 | func TestAspect_ratio_width_overrides_align_stretch_row(t *testing.T) { 582 | root := NewNode() 583 | root.StyleSetFlexDirection(FlexDirectionRow) 584 | root.StyleSetWidth(100) 585 | root.StyleSetHeight(100) 586 | 587 | rootChild0 := NewNode() 588 | rootChild0.StyleSetWidth(50) 589 | rootChild0.StyleSetAspectRatio(1) 590 | root.InsertChild(rootChild0, 0) 591 | 592 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 593 | 594 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 595 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 596 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 597 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 598 | } 599 | 600 | func TestAspect_ratio_height_overrides_align_stretch_column(t *testing.T) { 601 | root := NewNode() 602 | root.StyleSetWidth(100) 603 | root.StyleSetHeight(100) 604 | 605 | rootChild0 := NewNode() 606 | rootChild0.StyleSetHeight(50) 607 | rootChild0.StyleSetAspectRatio(1) 608 | root.InsertChild(rootChild0, 0) 609 | 610 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 611 | 612 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 613 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 614 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 615 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 616 | } 617 | 618 | func TestAspect_ratio_allow_child_overflow_parent_size(t *testing.T) { 619 | root := NewNode() 620 | root.StyleSetAlignItems(AlignFlexStart) 621 | root.StyleSetWidth(100) 622 | 623 | rootChild0 := NewNode() 624 | rootChild0.StyleSetHeight(50) 625 | rootChild0.StyleSetAspectRatio(4) 626 | root.InsertChild(rootChild0, 0) 627 | 628 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 629 | 630 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 631 | assertFloatEqual(t, 50, root.LayoutGetHeight()) 632 | 633 | assertFloatEqual(t, 200, rootChild0.LayoutGetWidth()) 634 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 635 | } 636 | 637 | func TestAspect_ratio_defined_main_with_margin(t *testing.T) { 638 | root := NewNode() 639 | root.StyleSetAlignItems(AlignCenter) 640 | root.StyleSetJustifyContent(JustifyCenter) 641 | root.StyleSetWidth(100) 642 | root.StyleSetHeight(100) 643 | 644 | rootChild0 := NewNode() 645 | rootChild0.StyleSetHeight(50) 646 | rootChild0.StyleSetAspectRatio(1) 647 | rootChild0.StyleSetMargin(EdgeLeft, 10) 648 | rootChild0.StyleSetMargin(EdgeRight, 10) 649 | root.InsertChild(rootChild0, 0) 650 | 651 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 652 | 653 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 654 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 655 | 656 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 657 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 658 | } 659 | 660 | func TestAspect_ratio_defined_cross_with_margin(t *testing.T) { 661 | root := NewNode() 662 | root.StyleSetAlignItems(AlignCenter) 663 | root.StyleSetJustifyContent(JustifyCenter) 664 | root.StyleSetWidth(100) 665 | root.StyleSetHeight(100) 666 | 667 | rootChild0 := NewNode() 668 | rootChild0.StyleSetWidth(50) 669 | rootChild0.StyleSetAspectRatio(1) 670 | rootChild0.StyleSetMargin(EdgeLeft, 10) 671 | rootChild0.StyleSetMargin(EdgeRight, 10) 672 | root.InsertChild(rootChild0, 0) 673 | 674 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 675 | 676 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 677 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 678 | 679 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 680 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 681 | } 682 | -------------------------------------------------------------------------------- /baseline_func_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import "testing" 4 | 5 | func baselineFunc(node *Node, width float32, height float32) float32 { 6 | baseline := node.Context.(float32) 7 | return baseline 8 | } 9 | 10 | func TestAlign_baseline_customer_func(t *testing.T) { 11 | root := NewNode() 12 | root.StyleSetFlexDirection(FlexDirectionRow) 13 | root.StyleSetAlignItems(AlignBaseline) 14 | root.StyleSetWidth(100) 15 | root.StyleSetHeight(100) 16 | 17 | rootChild0 := NewNode() 18 | rootChild0.StyleSetWidth(50) 19 | rootChild0.StyleSetHeight(50) 20 | root.InsertChild(rootChild0, 0) 21 | 22 | rootChild1 := NewNode() 23 | rootChild1.StyleSetWidth(50) 24 | rootChild1.StyleSetHeight(20) 25 | root.InsertChild(rootChild1, 1) 26 | 27 | var baselineValue float32 = 10 28 | rootChild1child0 := NewNode() 29 | rootChild1child0.Context = baselineValue 30 | rootChild1child0.StyleSetWidth(50) 31 | rootChild1child0.Baseline = baselineFunc 32 | rootChild1child0.StyleSetHeight(20) 33 | rootChild1.InsertChild(rootChild1child0, 0) 34 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 35 | 36 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 37 | assertFloatEqual(t, 0, root.LayoutGetTop()) 38 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 39 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 40 | 41 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 42 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 43 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 44 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 45 | 46 | assertFloatEqual(t, 50, rootChild1.LayoutGetLeft()) 47 | assertFloatEqual(t, 40, rootChild1.LayoutGetTop()) 48 | assertFloatEqual(t, 50, rootChild1.LayoutGetWidth()) 49 | assertFloatEqual(t, 20, rootChild1.LayoutGetHeight()) 50 | 51 | assertFloatEqual(t, 0, rootChild1child0.LayoutGetLeft()) 52 | assertFloatEqual(t, 0, rootChild1child0.LayoutGetTop()) 53 | assertFloatEqual(t, 50, rootChild1child0.LayoutGetWidth()) 54 | assertFloatEqual(t, 20, rootChild1child0.LayoutGetHeight()) 55 | } 56 | -------------------------------------------------------------------------------- /border_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import "testing" 4 | 5 | func TestBorder_no_size(t *testing.T) { 6 | config := NewConfig() 7 | 8 | root := NewNodeWithConfig(config) 9 | root.StyleSetBorder(EdgeLeft, 10) 10 | root.StyleSetBorder(EdgeTop, 10) 11 | root.StyleSetBorder(EdgeRight, 10) 12 | root.StyleSetBorder(EdgeBottom, 10) 13 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 14 | 15 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 16 | assertFloatEqual(t, 0, root.LayoutGetTop()) 17 | assertFloatEqual(t, 20, root.LayoutGetWidth()) 18 | assertFloatEqual(t, 20, root.LayoutGetHeight()) 19 | 20 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 21 | 22 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 23 | assertFloatEqual(t, 0, root.LayoutGetTop()) 24 | assertFloatEqual(t, 20, root.LayoutGetWidth()) 25 | assertFloatEqual(t, 20, root.LayoutGetHeight()) 26 | } 27 | 28 | func TestBorder_container_match_child(t *testing.T) { 29 | config := NewConfig() 30 | 31 | root := NewNodeWithConfig(config) 32 | root.StyleSetBorder(EdgeLeft, 10) 33 | root.StyleSetBorder(EdgeTop, 10) 34 | root.StyleSetBorder(EdgeRight, 10) 35 | root.StyleSetBorder(EdgeBottom, 10) 36 | 37 | rootChild0 := NewNodeWithConfig(config) 38 | rootChild0.StyleSetWidth(10) 39 | rootChild0.StyleSetHeight(10) 40 | root.InsertChild(rootChild0, 0) 41 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 42 | 43 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 44 | assertFloatEqual(t, 0, root.LayoutGetTop()) 45 | assertFloatEqual(t, 30, root.LayoutGetWidth()) 46 | assertFloatEqual(t, 30, root.LayoutGetHeight()) 47 | 48 | assertFloatEqual(t, 10, rootChild0.LayoutGetLeft()) 49 | assertFloatEqual(t, 10, rootChild0.LayoutGetTop()) 50 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 51 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 52 | 53 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 54 | 55 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 56 | assertFloatEqual(t, 0, root.LayoutGetTop()) 57 | assertFloatEqual(t, 30, root.LayoutGetWidth()) 58 | assertFloatEqual(t, 30, root.LayoutGetHeight()) 59 | 60 | assertFloatEqual(t, 10, rootChild0.LayoutGetLeft()) 61 | assertFloatEqual(t, 10, rootChild0.LayoutGetTop()) 62 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 63 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 64 | } 65 | 66 | func TestBorder_flex_child(t *testing.T) { 67 | config := NewConfig() 68 | 69 | root := NewNodeWithConfig(config) 70 | root.StyleSetBorder(EdgeLeft, 10) 71 | root.StyleSetBorder(EdgeTop, 10) 72 | root.StyleSetBorder(EdgeRight, 10) 73 | root.StyleSetBorder(EdgeBottom, 10) 74 | root.StyleSetWidth(100) 75 | root.StyleSetHeight(100) 76 | 77 | rootChild0 := NewNodeWithConfig(config) 78 | rootChild0.StyleSetFlexGrow(1) 79 | rootChild0.StyleSetWidth(10) 80 | root.InsertChild(rootChild0, 0) 81 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 82 | 83 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 84 | assertFloatEqual(t, 0, root.LayoutGetTop()) 85 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 86 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 87 | 88 | assertFloatEqual(t, 10, rootChild0.LayoutGetLeft()) 89 | assertFloatEqual(t, 10, rootChild0.LayoutGetTop()) 90 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 91 | assertFloatEqual(t, 80, rootChild0.LayoutGetHeight()) 92 | 93 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 94 | 95 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 96 | assertFloatEqual(t, 0, root.LayoutGetTop()) 97 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 98 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 99 | 100 | assertFloatEqual(t, 80, rootChild0.LayoutGetLeft()) 101 | assertFloatEqual(t, 10, rootChild0.LayoutGetTop()) 102 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 103 | assertFloatEqual(t, 80, rootChild0.LayoutGetHeight()) 104 | } 105 | 106 | func TestBorder_stretch_child(t *testing.T) { 107 | config := NewConfig() 108 | 109 | root := NewNodeWithConfig(config) 110 | root.StyleSetBorder(EdgeLeft, 10) 111 | root.StyleSetBorder(EdgeTop, 10) 112 | root.StyleSetBorder(EdgeRight, 10) 113 | root.StyleSetBorder(EdgeBottom, 10) 114 | root.StyleSetWidth(100) 115 | root.StyleSetHeight(100) 116 | 117 | rootChild0 := NewNodeWithConfig(config) 118 | rootChild0.StyleSetHeight(10) 119 | root.InsertChild(rootChild0, 0) 120 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 121 | 122 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 123 | assertFloatEqual(t, 0, root.LayoutGetTop()) 124 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 125 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 126 | 127 | assertFloatEqual(t, 10, rootChild0.LayoutGetLeft()) 128 | assertFloatEqual(t, 10, rootChild0.LayoutGetTop()) 129 | assertFloatEqual(t, 80, rootChild0.LayoutGetWidth()) 130 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 131 | 132 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 133 | 134 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 135 | assertFloatEqual(t, 0, root.LayoutGetTop()) 136 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 137 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 138 | 139 | assertFloatEqual(t, 10, rootChild0.LayoutGetLeft()) 140 | assertFloatEqual(t, 10, rootChild0.LayoutGetTop()) 141 | assertFloatEqual(t, 80, rootChild0.LayoutGetWidth()) 142 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 143 | } 144 | 145 | func TestBorder_center_child(t *testing.T) { 146 | config := NewConfig() 147 | 148 | root := NewNodeWithConfig(config) 149 | root.StyleSetJustifyContent(JustifyCenter) 150 | root.StyleSetAlignItems(AlignCenter) 151 | root.StyleSetBorder(EdgeStart, 10) 152 | root.StyleSetBorder(EdgeEnd, 20) 153 | root.StyleSetBorder(EdgeBottom, 20) 154 | root.StyleSetWidth(100) 155 | root.StyleSetHeight(100) 156 | 157 | rootChild0 := NewNodeWithConfig(config) 158 | rootChild0.StyleSetWidth(10) 159 | rootChild0.StyleSetHeight(10) 160 | root.InsertChild(rootChild0, 0) 161 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 162 | 163 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 164 | assertFloatEqual(t, 0, root.LayoutGetTop()) 165 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 166 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 167 | 168 | assertFloatEqual(t, 40, rootChild0.LayoutGetLeft()) 169 | assertFloatEqual(t, 35, rootChild0.LayoutGetTop()) 170 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 171 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 172 | 173 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 174 | 175 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 176 | assertFloatEqual(t, 0, root.LayoutGetTop()) 177 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 178 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 179 | 180 | assertFloatEqual(t, 50, rootChild0.LayoutGetLeft()) 181 | assertFloatEqual(t, 35, rootChild0.LayoutGetTop()) 182 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 183 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 184 | } 185 | -------------------------------------------------------------------------------- /compute_margin_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import "testing" 4 | 5 | func TestComputed_layout_margin(t *testing.T) { 6 | root := NewNode() 7 | root.StyleSetWidth(100) 8 | root.StyleSetHeight(100) 9 | root.StyleSetMarginPercent(EdgeStart, 10) 10 | 11 | CalculateLayout(root, 100, 100, DirectionLTR) 12 | 13 | assertFloatEqual(t, 10, root.LayoutGetMargin(EdgeLeft)) 14 | assertFloatEqual(t, 0, root.LayoutGetMargin(EdgeRight)) 15 | 16 | CalculateLayout(root, 100, 100, DirectionRTL) 17 | 18 | assertFloatEqual(t, 0, root.LayoutGetMargin(EdgeLeft)) 19 | assertFloatEqual(t, 10, root.LayoutGetMargin(EdgeRight)) 20 | } 21 | -------------------------------------------------------------------------------- /compute_padding_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import "testing" 4 | 5 | func TestComputed_layout_padding(t *testing.T) { 6 | root := NewNode() 7 | root.StyleSetWidth(100) 8 | root.StyleSetHeight(100) 9 | root.StyleSetPaddingPercent(EdgeStart, 10) 10 | 11 | CalculateLayout(root, 100, 100, DirectionLTR) 12 | 13 | assertFloatEqual(t, 10, root.LayoutGetPadding(EdgeLeft)) 14 | assertFloatEqual(t, 0, root.LayoutGetPadding(EdgeRight)) 15 | 16 | CalculateLayout(root, 100, 100, DirectionRTL) 17 | 18 | assertFloatEqual(t, 0, root.LayoutGetPadding(EdgeLeft)) 19 | assertFloatEqual(t, 10, root.LayoutGetPadding(EdgeRight)) 20 | } 21 | -------------------------------------------------------------------------------- /default_values_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestAssert_default_values(t *testing.T) { 10 | root := NewNode() 11 | 12 | assert.Equal(t, 0, len(root.Children)) 13 | var nilNode *Node 14 | assert.Equal(t, nilNode, root.GetChild(1)) 15 | assert.Equal(t, nilNode, root.GetChild(0)) 16 | 17 | assert.Equal(t, DirectionInherit, root.Style.Direction) 18 | assert.Equal(t, FlexDirectionColumn, root.Style.FlexDirection) 19 | assert.Equal(t, JustifyFlexStart, root.Style.JustifyContent) 20 | assert.Equal(t, AlignFlexStart, root.Style.AlignContent) 21 | assert.Equal(t, AlignStretch, root.Style.AlignItems) 22 | assert.Equal(t, AlignAuto, root.Style.AlignSelf) 23 | assert.Equal(t, PositionTypeRelative, root.Style.PositionType) 24 | assert.Equal(t, WrapNoWrap, root.Style.FlexWrap) 25 | assert.Equal(t, OverflowVisible, root.Style.Overflow) 26 | assertFloatEqual(t, 0, root.StyleGetFlexGrow()) 27 | assertFloatEqual(t, 0, root.StyleGetFlexShrink()) 28 | assert.Equal(t, root.Style.FlexBasis.Unit, UnitAuto) 29 | 30 | assert.Equal(t, root.StyleGetPosition(EdgeLeft).Unit, UnitUndefined) 31 | assert.Equal(t, root.StyleGetPosition(EdgeTop).Unit, UnitUndefined) 32 | assert.Equal(t, root.StyleGetPosition(EdgeRight).Unit, UnitUndefined) 33 | assert.Equal(t, root.StyleGetPosition(EdgeBottom).Unit, UnitUndefined) 34 | assert.Equal(t, root.StyleGetPosition(EdgeStart).Unit, UnitUndefined) 35 | assert.Equal(t, root.StyleGetPosition(EdgeEnd).Unit, UnitUndefined) 36 | 37 | assert.Equal(t, root.StyleGetMargin(EdgeLeft).Unit, UnitUndefined) 38 | assert.Equal(t, root.StyleGetMargin(EdgeTop).Unit, UnitUndefined) 39 | assert.Equal(t, root.StyleGetMargin(EdgeRight).Unit, UnitUndefined) 40 | assert.Equal(t, root.StyleGetMargin(EdgeBottom).Unit, UnitUndefined) 41 | assert.Equal(t, root.StyleGetMargin(EdgeStart).Unit, UnitUndefined) 42 | assert.Equal(t, root.StyleGetMargin(EdgeEnd).Unit, UnitUndefined) 43 | 44 | assert.Equal(t, root.StyleGetPadding(EdgeLeft).Unit, UnitUndefined) 45 | assert.Equal(t, root.StyleGetPadding(EdgeTop).Unit, UnitUndefined) 46 | assert.Equal(t, root.StyleGetPadding(EdgeRight).Unit, UnitUndefined) 47 | assert.Equal(t, root.StyleGetPadding(EdgeBottom).Unit, UnitUndefined) 48 | assert.Equal(t, root.StyleGetPadding(EdgeStart).Unit, UnitUndefined) 49 | assert.Equal(t, root.StyleGetPadding(EdgeEnd).Unit, UnitUndefined) 50 | 51 | assert.True(t, FloatIsUndefined(root.StyleGetBorder(EdgeLeft))) 52 | assert.True(t, FloatIsUndefined(root.StyleGetBorder(EdgeTop))) 53 | assert.True(t, FloatIsUndefined(root.StyleGetBorder(EdgeRight))) 54 | assert.True(t, FloatIsUndefined(root.StyleGetBorder(EdgeBottom))) 55 | assert.True(t, FloatIsUndefined(root.StyleGetBorder(EdgeStart))) 56 | assert.True(t, FloatIsUndefined(root.StyleGetBorder(EdgeEnd))) 57 | 58 | assert.Equal(t, root.StyleGetWidth().Unit, UnitAuto) 59 | assert.Equal(t, root.StyleGetHeight().Unit, UnitAuto) 60 | assert.Equal(t, root.StyleGetMinWidth().Unit, UnitUndefined) 61 | assert.Equal(t, root.StyleGetMinHeight().Unit, UnitUndefined) 62 | assert.Equal(t, root.StyleGetMaxWidth().Unit, UnitUndefined) 63 | assert.Equal(t, root.StyleGetMaxHeight().Unit, UnitUndefined) 64 | 65 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 66 | assertFloatEqual(t, 0, root.LayoutGetTop()) 67 | assertFloatEqual(t, 0, root.LayoutGetRight()) 68 | assertFloatEqual(t, 0, root.LayoutGetBottom()) 69 | 70 | assertFloatEqual(t, 0, root.LayoutGetMargin(EdgeLeft)) 71 | assertFloatEqual(t, 0, root.LayoutGetMargin(EdgeTop)) 72 | assertFloatEqual(t, 0, root.LayoutGetMargin(EdgeRight)) 73 | assertFloatEqual(t, 0, root.LayoutGetMargin(EdgeBottom)) 74 | 75 | assertFloatEqual(t, 0, root.LayoutGetPadding(EdgeLeft)) 76 | assertFloatEqual(t, 0, root.LayoutGetPadding(EdgeTop)) 77 | assertFloatEqual(t, 0, root.LayoutGetPadding(EdgeRight)) 78 | assertFloatEqual(t, 0, root.LayoutGetPadding(EdgeBottom)) 79 | 80 | assertFloatEqual(t, 0, root.LayoutGetBorder(EdgeLeft)) 81 | assertFloatEqual(t, 0, root.LayoutGetBorder(EdgeTop)) 82 | assertFloatEqual(t, 0, root.LayoutGetBorder(EdgeRight)) 83 | assertFloatEqual(t, 0, root.LayoutGetBorder(EdgeBottom)) 84 | 85 | assert.True(t, FloatIsUndefined(root.LayoutGetWidth())) 86 | assert.True(t, FloatIsUndefined(root.LayoutGetHeight())) 87 | assert.Equal(t, DirectionInherit, root.Layout.Direction) 88 | 89 | } 90 | 91 | func TestAssert_webdefault_values(t *testing.T) { 92 | config := NewConfig() 93 | config.UseWebDefaults = true 94 | root := NewNodeWithConfig(config) 95 | 96 | assert.Equal(t, FlexDirectionRow, root.Style.FlexDirection) 97 | assert.Equal(t, AlignStretch, root.Style.AlignContent) 98 | assertFloatEqual(t, 1, root.StyleGetFlexShrink()) 99 | 100 | } 101 | 102 | func TestAssert_webdefault_values_reset(t *testing.T) { 103 | config := NewConfig() 104 | config.UseWebDefaults = true 105 | root := NewNodeWithConfig(config) 106 | root.Reset() 107 | 108 | assert.Equal(t, FlexDirectionRow, root.Style.FlexDirection) 109 | assert.Equal(t, AlignStretch, root.Style.AlignContent) 110 | assertFloatEqual(t, 1, root.StyleGetFlexShrink()) 111 | 112 | } 113 | -------------------------------------------------------------------------------- /dimension_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import "testing" 4 | 5 | func TestWrap_child(t *testing.T) { 6 | config := NewConfig() 7 | root := NewNodeWithConfig(config) 8 | 9 | rootChild0 := NewNodeWithConfig(config) 10 | rootChild0.StyleSetWidth(100) 11 | rootChild0.StyleSetHeight(100) 12 | root.InsertChild(rootChild0, 0) 13 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 14 | 15 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 16 | assertFloatEqual(t, 0, root.LayoutGetTop()) 17 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 18 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 19 | 20 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 21 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 22 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 23 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 24 | 25 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 26 | 27 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 28 | assertFloatEqual(t, 0, root.LayoutGetTop()) 29 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 30 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 31 | 32 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 33 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 34 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 35 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 36 | } 37 | 38 | func TestWrap_grandchild(t *testing.T) { 39 | config := NewConfig() 40 | 41 | root := NewNodeWithConfig(config) 42 | 43 | rootChild0 := NewNodeWithConfig(config) 44 | root.InsertChild(rootChild0, 0) 45 | 46 | rootChild0Child0 := NewNodeWithConfig(config) 47 | rootChild0Child0.StyleSetWidth(100) 48 | rootChild0Child0.StyleSetHeight(100) 49 | rootChild0.InsertChild(rootChild0Child0, 0) 50 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 51 | 52 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 53 | assertFloatEqual(t, 0, root.LayoutGetTop()) 54 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 55 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 56 | 57 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 58 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 59 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 60 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 61 | 62 | assertFloatEqual(t, 0, rootChild0Child0.LayoutGetLeft()) 63 | assertFloatEqual(t, 0, rootChild0Child0.LayoutGetTop()) 64 | assertFloatEqual(t, 100, rootChild0Child0.LayoutGetWidth()) 65 | assertFloatEqual(t, 100, rootChild0Child0.LayoutGetHeight()) 66 | 67 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 68 | 69 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 70 | assertFloatEqual(t, 0, root.LayoutGetTop()) 71 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 72 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 73 | 74 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 75 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 76 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 77 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 78 | 79 | assertFloatEqual(t, 0, rootChild0Child0.LayoutGetLeft()) 80 | assertFloatEqual(t, 0, rootChild0Child0.LayoutGetTop()) 81 | assertFloatEqual(t, 100, rootChild0Child0.LayoutGetWidth()) 82 | assertFloatEqual(t, 100, rootChild0Child0.LayoutGetHeight()) 83 | } 84 | -------------------------------------------------------------------------------- /dirty_marking_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestDirty_propagation(t *testing.T) { 10 | root := NewNode() 11 | root.StyleSetAlignItems(AlignFlexStart) 12 | root.StyleSetWidth(100) 13 | root.StyleSetHeight(100) 14 | 15 | rootChild0 := NewNode() 16 | rootChild0.StyleSetWidth(50) 17 | rootChild0.StyleSetHeight(20) 18 | root.InsertChild(rootChild0, 0) 19 | 20 | rootChild1 := NewNode() 21 | rootChild1.StyleSetWidth(50) 22 | rootChild1.StyleSetHeight(20) 23 | root.InsertChild(rootChild1, 1) 24 | 25 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 26 | 27 | rootChild0.StyleSetWidth(20) 28 | 29 | assert.True(t, rootChild0.IsDirty) 30 | assert.False(t, rootChild1.IsDirty) 31 | assert.True(t, root.IsDirty) 32 | 33 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 34 | 35 | assert.False(t, rootChild0.IsDirty) 36 | assert.False(t, rootChild1.IsDirty) 37 | assert.False(t, root.IsDirty) 38 | 39 | } 40 | 41 | func TestDirty_propagation_only_if_prop_changed(t *testing.T) { 42 | root := NewNode() 43 | root.StyleSetAlignItems(AlignFlexStart) 44 | root.StyleSetWidth(100) 45 | root.StyleSetHeight(100) 46 | 47 | rootChild0 := NewNode() 48 | rootChild0.StyleSetWidth(50) 49 | rootChild0.StyleSetHeight(20) 50 | root.InsertChild(rootChild0, 0) 51 | 52 | rootChild1 := NewNode() 53 | rootChild1.StyleSetWidth(50) 54 | rootChild1.StyleSetHeight(20) 55 | root.InsertChild(rootChild1, 1) 56 | 57 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 58 | 59 | rootChild0.StyleSetWidth(50) 60 | 61 | assert.False(t, rootChild0.IsDirty) 62 | assert.False(t, rootChild1.IsDirty) 63 | assert.False(t, root.IsDirty) 64 | 65 | } 66 | 67 | func TestDirty_mark_all_children_as_dirty_when_display_changes(t *testing.T) { 68 | root := NewNode() 69 | root.StyleSetFlexDirection(FlexDirectionRow) 70 | root.StyleSetHeight(100) 71 | 72 | child0 := NewNode() 73 | child0.StyleSetFlexGrow(1) 74 | child1 := NewNode() 75 | child1.StyleSetFlexGrow(1) 76 | 77 | child1Child0 := NewNode() 78 | child1Child0Child0 := NewNode() 79 | child1Child0Child0.StyleSetWidth(8) 80 | child1Child0Child0.StyleSetHeight(16) 81 | 82 | child1Child0.InsertChild(child1Child0Child0, 0) 83 | 84 | child1.InsertChild(child1Child0, 0) 85 | root.InsertChild(child0, 0) 86 | root.InsertChild(child1, 0) 87 | 88 | child0.StyleSetDisplay(DisplayFlex) 89 | child1.StyleSetDisplay(DisplayNone) 90 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 91 | assertFloatEqual(t, 0, child1Child0Child0.LayoutGetWidth()) 92 | assertFloatEqual(t, 0, child1Child0Child0.LayoutGetHeight()) 93 | 94 | child0.StyleSetDisplay(DisplayNone) 95 | child1.StyleSetDisplay(DisplayFlex) 96 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 97 | assertFloatEqual(t, 8, child1Child0Child0.LayoutGetWidth()) 98 | assertFloatEqual(t, 16, child1Child0Child0.LayoutGetHeight()) 99 | 100 | child0.StyleSetDisplay(DisplayFlex) 101 | child1.StyleSetDisplay(DisplayNone) 102 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 103 | assertFloatEqual(t, 0, child1Child0Child0.LayoutGetWidth()) 104 | assertFloatEqual(t, 0, child1Child0Child0.LayoutGetHeight()) 105 | 106 | child0.StyleSetDisplay(DisplayNone) 107 | child1.StyleSetDisplay(DisplayFlex) 108 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 109 | assertFloatEqual(t, 8, child1Child0Child0.LayoutGetWidth()) 110 | assertFloatEqual(t, 16, child1Child0Child0.LayoutGetHeight()) 111 | } 112 | 113 | func TestDirty_node_only_if_children_are_actually_removed(t *testing.T) { 114 | root := NewNode() 115 | root.StyleSetAlignItems(AlignFlexStart) 116 | root.StyleSetWidth(50) 117 | root.StyleSetHeight(50) 118 | 119 | child0 := NewNode() 120 | child0.StyleSetWidth(50) 121 | child0.StyleSetHeight(25) 122 | root.InsertChild(child0, 0) 123 | 124 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 125 | 126 | child1 := NewNode() 127 | root.RemoveChild(child1) 128 | assert.False(t, root.IsDirty) 129 | 130 | root.RemoveChild(child0) 131 | assert.True(t, root.IsDirty) 132 | } 133 | -------------------------------------------------------------------------------- /display_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import "testing" 4 | 5 | func TestDisplay_none(t *testing.T) { 6 | config := NewConfig() 7 | 8 | root := NewNodeWithConfig(config) 9 | root.StyleSetFlexDirection(FlexDirectionRow) 10 | root.StyleSetWidth(100) 11 | root.StyleSetHeight(100) 12 | 13 | rootChild0 := NewNodeWithConfig(config) 14 | rootChild0.StyleSetFlexGrow(1) 15 | root.InsertChild(rootChild0, 0) 16 | 17 | rootChild1 := NewNodeWithConfig(config) 18 | rootChild1.StyleSetFlexGrow(1) 19 | rootChild1.StyleSetDisplay(DisplayNone) 20 | root.InsertChild(rootChild1, 1) 21 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 22 | 23 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 24 | assertFloatEqual(t, 0, root.LayoutGetTop()) 25 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 26 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 27 | 28 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 29 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 30 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 31 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 32 | 33 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 34 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 35 | assertFloatEqual(t, 0, rootChild1.LayoutGetWidth()) 36 | assertFloatEqual(t, 0, rootChild1.LayoutGetHeight()) 37 | 38 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 39 | 40 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 41 | assertFloatEqual(t, 0, root.LayoutGetTop()) 42 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 43 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 44 | 45 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 46 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 47 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 48 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 49 | 50 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 51 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 52 | assertFloatEqual(t, 0, rootChild1.LayoutGetWidth()) 53 | assertFloatEqual(t, 0, rootChild1.LayoutGetHeight()) 54 | } 55 | 56 | func TestDisplay_none_fixed_size(t *testing.T) { 57 | config := NewConfig() 58 | 59 | root := NewNodeWithConfig(config) 60 | root.StyleSetFlexDirection(FlexDirectionRow) 61 | root.StyleSetWidth(100) 62 | root.StyleSetHeight(100) 63 | 64 | rootChild0 := NewNodeWithConfig(config) 65 | rootChild0.StyleSetFlexGrow(1) 66 | root.InsertChild(rootChild0, 0) 67 | 68 | rootChild1 := NewNodeWithConfig(config) 69 | rootChild1.StyleSetWidth(20) 70 | rootChild1.StyleSetHeight(20) 71 | rootChild1.StyleSetDisplay(DisplayNone) 72 | root.InsertChild(rootChild1, 1) 73 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 74 | 75 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 76 | assertFloatEqual(t, 0, root.LayoutGetTop()) 77 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 78 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 79 | 80 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 81 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 82 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 83 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 84 | 85 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 86 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 87 | assertFloatEqual(t, 0, rootChild1.LayoutGetWidth()) 88 | assertFloatEqual(t, 0, rootChild1.LayoutGetHeight()) 89 | 90 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 91 | 92 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 93 | assertFloatEqual(t, 0, root.LayoutGetTop()) 94 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 95 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 96 | 97 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 98 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 99 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 100 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 101 | 102 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 103 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 104 | assertFloatEqual(t, 0, rootChild1.LayoutGetWidth()) 105 | assertFloatEqual(t, 0, rootChild1.LayoutGetHeight()) 106 | } 107 | 108 | func TestDisplay_none_with_margin(t *testing.T) { 109 | config := NewConfig() 110 | 111 | root := NewNodeWithConfig(config) 112 | root.StyleSetFlexDirection(FlexDirectionRow) 113 | root.StyleSetWidth(100) 114 | root.StyleSetHeight(100) 115 | 116 | rootChild0 := NewNodeWithConfig(config) 117 | rootChild0.StyleSetMargin(EdgeLeft, 10) 118 | rootChild0.StyleSetMargin(EdgeTop, 10) 119 | rootChild0.StyleSetMargin(EdgeRight, 10) 120 | rootChild0.StyleSetMargin(EdgeBottom, 10) 121 | rootChild0.StyleSetWidth(20) 122 | rootChild0.StyleSetHeight(20) 123 | rootChild0.StyleSetDisplay(DisplayNone) 124 | root.InsertChild(rootChild0, 0) 125 | 126 | rootChild1 := NewNodeWithConfig(config) 127 | rootChild1.StyleSetFlexGrow(1) 128 | root.InsertChild(rootChild1, 1) 129 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 130 | 131 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 132 | assertFloatEqual(t, 0, root.LayoutGetTop()) 133 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 134 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 135 | 136 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 137 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 138 | assertFloatEqual(t, 0, rootChild0.LayoutGetWidth()) 139 | assertFloatEqual(t, 0, rootChild0.LayoutGetHeight()) 140 | 141 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 142 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 143 | assertFloatEqual(t, 100, rootChild1.LayoutGetWidth()) 144 | assertFloatEqual(t, 100, rootChild1.LayoutGetHeight()) 145 | 146 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 147 | 148 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 149 | assertFloatEqual(t, 0, root.LayoutGetTop()) 150 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 151 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 152 | 153 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 154 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 155 | assertFloatEqual(t, 0, rootChild0.LayoutGetWidth()) 156 | assertFloatEqual(t, 0, rootChild0.LayoutGetHeight()) 157 | 158 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 159 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 160 | assertFloatEqual(t, 100, rootChild1.LayoutGetWidth()) 161 | assertFloatEqual(t, 100, rootChild1.LayoutGetHeight()) 162 | } 163 | 164 | func TestDisplay_none_with_child(t *testing.T) { 165 | config := NewConfig() 166 | 167 | root := NewNodeWithConfig(config) 168 | root.StyleSetFlexDirection(FlexDirectionRow) 169 | root.StyleSetWidth(100) 170 | root.StyleSetHeight(100) 171 | 172 | rootChild0 := NewNodeWithConfig(config) 173 | rootChild0.StyleSetFlexGrow(1) 174 | rootChild0.StyleSetFlexShrink(1) 175 | rootChild0.StyleSetFlexBasisPercent(0) 176 | root.InsertChild(rootChild0, 0) 177 | 178 | rootChild1 := NewNodeWithConfig(config) 179 | rootChild1.StyleSetFlexGrow(1) 180 | rootChild1.StyleSetFlexShrink(1) 181 | rootChild1.StyleSetFlexBasisPercent(0) 182 | rootChild1.StyleSetDisplay(DisplayNone) 183 | root.InsertChild(rootChild1, 1) 184 | 185 | rootChild1child0 := NewNodeWithConfig(config) 186 | rootChild1child0.StyleSetFlexGrow(1) 187 | rootChild1child0.StyleSetFlexShrink(1) 188 | rootChild1child0.StyleSetFlexBasisPercent(0) 189 | rootChild1child0.StyleSetWidth(20) 190 | rootChild1child0.StyleSetMinWidth(0) 191 | rootChild1child0.StyleSetMinHeight(0) 192 | rootChild1.InsertChild(rootChild1child0, 0) 193 | 194 | rootChild2 := NewNodeWithConfig(config) 195 | rootChild2.StyleSetFlexGrow(1) 196 | rootChild2.StyleSetFlexShrink(1) 197 | rootChild2.StyleSetFlexBasisPercent(0) 198 | root.InsertChild(rootChild2, 2) 199 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 200 | 201 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 202 | assertFloatEqual(t, 0, root.LayoutGetTop()) 203 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 204 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 205 | 206 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 207 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 208 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 209 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 210 | 211 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 212 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 213 | assertFloatEqual(t, 0, rootChild1.LayoutGetWidth()) 214 | assertFloatEqual(t, 0, rootChild1.LayoutGetHeight()) 215 | 216 | assertFloatEqual(t, 0, rootChild1child0.LayoutGetLeft()) 217 | assertFloatEqual(t, 0, rootChild1child0.LayoutGetTop()) 218 | assertFloatEqual(t, 0, rootChild1child0.LayoutGetWidth()) 219 | assertFloatEqual(t, 0, rootChild1child0.LayoutGetHeight()) 220 | 221 | assertFloatEqual(t, 50, rootChild2.LayoutGetLeft()) 222 | assertFloatEqual(t, 0, rootChild2.LayoutGetTop()) 223 | assertFloatEqual(t, 50, rootChild2.LayoutGetWidth()) 224 | assertFloatEqual(t, 100, rootChild2.LayoutGetHeight()) 225 | 226 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 227 | 228 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 229 | assertFloatEqual(t, 0, root.LayoutGetTop()) 230 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 231 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 232 | 233 | assertFloatEqual(t, 50, rootChild0.LayoutGetLeft()) 234 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 235 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 236 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 237 | 238 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 239 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 240 | assertFloatEqual(t, 0, rootChild1.LayoutGetWidth()) 241 | assertFloatEqual(t, 0, rootChild1.LayoutGetHeight()) 242 | 243 | assertFloatEqual(t, 0, rootChild1child0.LayoutGetLeft()) 244 | assertFloatEqual(t, 0, rootChild1child0.LayoutGetTop()) 245 | assertFloatEqual(t, 0, rootChild1child0.LayoutGetWidth()) 246 | assertFloatEqual(t, 0, rootChild1child0.LayoutGetHeight()) 247 | 248 | assertFloatEqual(t, 0, rootChild2.LayoutGetLeft()) 249 | assertFloatEqual(t, 0, rootChild2.LayoutGetTop()) 250 | assertFloatEqual(t, 50, rootChild2.LayoutGetWidth()) 251 | assertFloatEqual(t, 100, rootChild2.LayoutGetHeight()) 252 | } 253 | 254 | func TestDisplay_none_with_position(t *testing.T) { 255 | config := NewConfig() 256 | 257 | root := NewNodeWithConfig(config) 258 | root.StyleSetFlexDirection(FlexDirectionRow) 259 | root.StyleSetWidth(100) 260 | root.StyleSetHeight(100) 261 | 262 | rootChild0 := NewNodeWithConfig(config) 263 | rootChild0.StyleSetFlexGrow(1) 264 | root.InsertChild(rootChild0, 0) 265 | 266 | rootChild1 := NewNodeWithConfig(config) 267 | rootChild1.StyleSetFlexGrow(1) 268 | rootChild1.StyleSetPosition(EdgeTop, 10) 269 | rootChild1.StyleSetDisplay(DisplayNone) 270 | root.InsertChild(rootChild1, 1) 271 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 272 | 273 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 274 | assertFloatEqual(t, 0, root.LayoutGetTop()) 275 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 276 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 277 | 278 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 279 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 280 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 281 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 282 | 283 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 284 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 285 | assertFloatEqual(t, 0, rootChild1.LayoutGetWidth()) 286 | assertFloatEqual(t, 0, rootChild1.LayoutGetHeight()) 287 | 288 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 289 | 290 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 291 | assertFloatEqual(t, 0, root.LayoutGetTop()) 292 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 293 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 294 | 295 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 296 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 297 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 298 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 299 | 300 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 301 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 302 | assertFloatEqual(t, 0, rootChild1.LayoutGetWidth()) 303 | assertFloatEqual(t, 0, rootChild1.LayoutGetHeight()) 304 | } 305 | -------------------------------------------------------------------------------- /edge_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import "testing" 4 | 5 | func TestStart_overrides(t *testing.T) { 6 | root := NewNode() 7 | root.StyleSetFlexDirection(FlexDirectionRow) 8 | root.StyleSetWidth(100) 9 | root.StyleSetHeight(100) 10 | 11 | rootChild0 := NewNode() 12 | rootChild0.StyleSetFlexGrow(1) 13 | rootChild0.StyleSetMargin(EdgeStart, 10) 14 | rootChild0.StyleSetMargin(EdgeLeft, 20) 15 | rootChild0.StyleSetMargin(EdgeRight, 20) 16 | root.InsertChild(rootChild0, 0) 17 | 18 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 19 | assertFloatEqual(t, 10, rootChild0.LayoutGetLeft()) 20 | assertFloatEqual(t, 20, rootChild0.LayoutGetRight()) 21 | 22 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 23 | assertFloatEqual(t, 20, rootChild0.LayoutGetLeft()) 24 | assertFloatEqual(t, 10, rootChild0.LayoutGetRight()) 25 | } 26 | 27 | func TestEnd_overrides(t *testing.T) { 28 | root := NewNode() 29 | root.StyleSetFlexDirection(FlexDirectionRow) 30 | root.StyleSetWidth(100) 31 | root.StyleSetHeight(100) 32 | 33 | rootChild0 := NewNode() 34 | rootChild0.StyleSetFlexGrow(1) 35 | rootChild0.StyleSetMargin(EdgeEnd, 10) 36 | rootChild0.StyleSetMargin(EdgeLeft, 20) 37 | rootChild0.StyleSetMargin(EdgeRight, 20) 38 | root.InsertChild(rootChild0, 0) 39 | 40 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 41 | assertFloatEqual(t, 20, rootChild0.LayoutGetLeft()) 42 | assertFloatEqual(t, 10, rootChild0.LayoutGetRight()) 43 | 44 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 45 | assertFloatEqual(t, 10, rootChild0.LayoutGetLeft()) 46 | assertFloatEqual(t, 20, rootChild0.LayoutGetRight()) 47 | } 48 | 49 | func TestHorizontal_overridden(t *testing.T) { 50 | root := NewNode() 51 | root.StyleSetFlexDirection(FlexDirectionRow) 52 | root.StyleSetWidth(100) 53 | root.StyleSetHeight(100) 54 | 55 | rootChild0 := NewNode() 56 | rootChild0.StyleSetFlexGrow(1) 57 | rootChild0.StyleSetMargin(EdgeHorizontal, 10) 58 | rootChild0.StyleSetMargin(EdgeLeft, 20) 59 | root.InsertChild(rootChild0, 0) 60 | 61 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 62 | assertFloatEqual(t, 20, rootChild0.LayoutGetLeft()) 63 | assertFloatEqual(t, 10, rootChild0.LayoutGetRight()) 64 | } 65 | 66 | func TestVertical_overridden(t *testing.T) { 67 | root := NewNode() 68 | root.StyleSetFlexDirection(FlexDirectionColumn) 69 | root.StyleSetWidth(100) 70 | root.StyleSetHeight(100) 71 | 72 | rootChild0 := NewNode() 73 | rootChild0.StyleSetFlexGrow(1) 74 | rootChild0.StyleSetMargin(EdgeVertical, 10) 75 | rootChild0.StyleSetMargin(EdgeTop, 20) 76 | root.InsertChild(rootChild0, 0) 77 | 78 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 79 | assertFloatEqual(t, 20, rootChild0.LayoutGetTop()) 80 | assertFloatEqual(t, 10, rootChild0.LayoutGetBottom()) 81 | } 82 | 83 | func TestHorizontal_overrides_all(t *testing.T) { 84 | root := NewNode() 85 | root.StyleSetFlexDirection(FlexDirectionColumn) 86 | root.StyleSetWidth(100) 87 | root.StyleSetHeight(100) 88 | 89 | rootChild0 := NewNode() 90 | rootChild0.StyleSetFlexGrow(1) 91 | rootChild0.StyleSetMargin(EdgeHorizontal, 10) 92 | rootChild0.StyleSetMargin(EdgeAll, 20) 93 | root.InsertChild(rootChild0, 0) 94 | 95 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 96 | assertFloatEqual(t, 10, rootChild0.LayoutGetLeft()) 97 | assertFloatEqual(t, 20, rootChild0.LayoutGetTop()) 98 | assertFloatEqual(t, 10, rootChild0.LayoutGetRight()) 99 | assertFloatEqual(t, 20, rootChild0.LayoutGetBottom()) 100 | } 101 | 102 | func TestVertical_overrides_all(t *testing.T) { 103 | root := NewNode() 104 | root.StyleSetFlexDirection(FlexDirectionColumn) 105 | root.StyleSetWidth(100) 106 | root.StyleSetHeight(100) 107 | 108 | rootChild0 := NewNode() 109 | rootChild0.StyleSetFlexGrow(1) 110 | rootChild0.StyleSetMargin(EdgeVertical, 10) 111 | rootChild0.StyleSetMargin(EdgeAll, 20) 112 | root.InsertChild(rootChild0, 0) 113 | 114 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 115 | assertFloatEqual(t, 20, rootChild0.LayoutGetLeft()) 116 | assertFloatEqual(t, 10, rootChild0.LayoutGetTop()) 117 | assertFloatEqual(t, 20, rootChild0.LayoutGetRight()) 118 | assertFloatEqual(t, 10, rootChild0.LayoutGetBottom()) 119 | } 120 | 121 | func TestAll_overridden(t *testing.T) { 122 | root := NewNode() 123 | root.StyleSetFlexDirection(FlexDirectionColumn) 124 | root.StyleSetWidth(100) 125 | root.StyleSetHeight(100) 126 | 127 | rootChild0 := NewNode() 128 | rootChild0.StyleSetFlexGrow(1) 129 | rootChild0.StyleSetMargin(EdgeLeft, 10) 130 | rootChild0.StyleSetMargin(EdgeTop, 10) 131 | rootChild0.StyleSetMargin(EdgeRight, 10) 132 | rootChild0.StyleSetMargin(EdgeBottom, 10) 133 | rootChild0.StyleSetMargin(EdgeAll, 20) 134 | root.InsertChild(rootChild0, 0) 135 | 136 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 137 | assertFloatEqual(t, 10, rootChild0.LayoutGetLeft()) 138 | assertFloatEqual(t, 10, rootChild0.LayoutGetTop()) 139 | assertFloatEqual(t, 10, rootChild0.LayoutGetRight()) 140 | assertFloatEqual(t, 10, rootChild0.LayoutGetBottom()) 141 | } 142 | -------------------------------------------------------------------------------- /enums.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | // port of YGEnums.h 4 | 5 | // Align describes align flex attribute 6 | type Align int 7 | 8 | const ( 9 | // AlignAuto is "auto" 10 | AlignAuto Align = iota 11 | // AlignFlexStart is "flex-start" 12 | AlignFlexStart 13 | // AlignCenter if "center" 14 | AlignCenter 15 | // AlignFlexEnd is "flex-end" 16 | AlignFlexEnd 17 | // AlignStretch is "strech" 18 | AlignStretch 19 | // AlignBaseline is "baseline" 20 | AlignBaseline 21 | // AlignSpaceBetween is "space-between" 22 | AlignSpaceBetween 23 | // AlignSpaceAround is "space-around" 24 | AlignSpaceAround 25 | ) 26 | 27 | // Dimension represents dimention 28 | type Dimension int 29 | 30 | const ( 31 | // DimensionWidth is width 32 | DimensionWidth Dimension = iota 33 | // DimensionHeight is height 34 | DimensionHeight 35 | ) 36 | 37 | // Direction represents right-to-left or left-to-right direction 38 | type Direction int 39 | 40 | const ( 41 | // DirectionInherit is "inherit" 42 | DirectionInherit Direction = iota 43 | // DirectionLTR is "ltr" 44 | DirectionLTR 45 | // DirectionRTL is "rtl" 46 | DirectionRTL 47 | ) 48 | 49 | // Display is "display" property 50 | type Display int 51 | 52 | const ( 53 | // DisplayFlex is "flex" 54 | DisplayFlex Display = iota 55 | // DisplayNone is "none" 56 | DisplayNone 57 | ) 58 | 59 | // Edge represents an edge 60 | type Edge int 61 | 62 | const ( 63 | // EdgeLeft is left edge 64 | EdgeLeft Edge = iota 65 | // EdgeTop is top edge 66 | EdgeTop 67 | // EdgeRight is right edge 68 | EdgeRight 69 | // EdgeBottom is bottom edge 70 | EdgeBottom 71 | // EdgeStart is start edge 72 | EdgeStart 73 | // EdgeEnd is end edge 74 | EdgeEnd 75 | // EdgeHorizontal is horizontal edge 76 | EdgeHorizontal 77 | // EdgeVertical is vertical edge 78 | EdgeVertical 79 | // EdgeAll is all edge 80 | EdgeAll 81 | ) 82 | 83 | const ( 84 | // EdgeCount is count of edges 85 | EdgeCount = 9 86 | ) 87 | 88 | // ExperimentalFeature defines experimental features 89 | type ExperimentalFeature int 90 | 91 | const ( 92 | // ExperimentalFeatureWebFlexBasis is web flex basis 93 | ExperimentalFeatureWebFlexBasis ExperimentalFeature = iota 94 | ) 95 | 96 | const ( 97 | experimentalFeatureCount = 1 98 | ) 99 | 100 | // FlexDirection describes "flex-direction" property 101 | type FlexDirection int 102 | 103 | const ( 104 | // FlexDirectionColumn is "column" 105 | FlexDirectionColumn FlexDirection = iota 106 | // FlexDirectionColumnReverse is "column-reverse" 107 | FlexDirectionColumnReverse 108 | // FlexDirectionRow is "row" 109 | FlexDirectionRow 110 | // FlexDirectionRowReverse is "row-reverse" 111 | FlexDirectionRowReverse 112 | ) 113 | 114 | // Justify is "justify" property 115 | type Justify int 116 | 117 | const ( 118 | // JustifyFlexStart is "flex-start" 119 | JustifyFlexStart Justify = iota 120 | // JustifyCenter is "center" 121 | JustifyCenter 122 | // JustifyFlexEnd is "flex-end" 123 | JustifyFlexEnd 124 | // JustifySpaceBetween is "space-between" 125 | JustifySpaceBetween 126 | // JustifySpaceAround is "space-around" 127 | JustifySpaceAround 128 | ) 129 | 130 | // LogLevel represents log level 131 | type LogLevel int 132 | 133 | const ( 134 | LogLevelError LogLevel = iota 135 | LogLevelWarn 136 | LogLevelInfo 137 | LogLevelDebug 138 | LogLevelVerbose 139 | LogLevelFatal 140 | ) 141 | 142 | // MeasureMode defines measurement mode 143 | type MeasureMode int 144 | 145 | const ( 146 | // MeasureModeUndefined is undefined 147 | MeasureModeUndefined MeasureMode = iota 148 | // MeasureModeExactly is exactly 149 | MeasureModeExactly 150 | // MeasureModeAtMost is at-most 151 | MeasureModeAtMost 152 | ) 153 | 154 | const ( 155 | measureModeCount = 3 156 | ) 157 | 158 | // NodeType defines node type 159 | type NodeType int 160 | 161 | const ( 162 | // NodeTypeDefault is default node 163 | NodeTypeDefault NodeType = iota 164 | // NodeTypeText is text node 165 | NodeTypeText 166 | ) 167 | 168 | // Overflow describes "overflow" property 169 | type Overflow int 170 | 171 | const ( 172 | // OverflowVisible is "visible" 173 | OverflowVisible Overflow = iota 174 | // OverflowHidden is "hidden" 175 | OverflowHidden 176 | // OverflowScroll is "scroll" 177 | OverflowScroll 178 | ) 179 | 180 | // PositionType is "position" property 181 | type PositionType int 182 | 183 | const ( 184 | // PositionTypeRelative is "relative" 185 | PositionTypeRelative PositionType = iota 186 | // PositionTypeAbsolute is "absolute" 187 | PositionTypeAbsolute 188 | ) 189 | 190 | type PrintOptions int 191 | 192 | const ( 193 | PrintOptionsLayout PrintOptions = 1 << iota 194 | PrintOptionsStyle 195 | PrintOptionsChildren 196 | ) 197 | 198 | // Unit is "unit" property 199 | type Unit int 200 | 201 | const ( 202 | // UnitUndefined is "undefined" 203 | UnitUndefined Unit = iota 204 | // UnitPoint is "point" 205 | UnitPoint 206 | // UnitPercent is "percent" 207 | UnitPercent 208 | // UnitAuto is "auto" 209 | UnitAuto 210 | ) 211 | 212 | // Wrap is "wrap" property 213 | type Wrap int 214 | 215 | const ( 216 | // WrapNoWrap is "no-wrap" 217 | WrapNoWrap Wrap = iota 218 | // WrapWrap is "wrap" 219 | WrapWrap 220 | // WrapWrapReverse is "reverse" 221 | WrapWrapReverse 222 | ) 223 | 224 | // AlignToString returns string version of Align enum 225 | func AlignToString(value Align) string { 226 | switch value { 227 | case AlignAuto: 228 | return "auto" 229 | case AlignFlexStart: 230 | return "flex-start" 231 | case AlignCenter: 232 | return "center" 233 | case AlignFlexEnd: 234 | return "flex-end" 235 | case AlignStretch: 236 | return "stretch" 237 | case AlignBaseline: 238 | return "baseline" 239 | case AlignSpaceBetween: 240 | return "space-between" 241 | case AlignSpaceAround: 242 | return "space-around" 243 | } 244 | return "unknown" 245 | } 246 | 247 | // DimensionToString returns string version of Dimension enum 248 | func DimensionToString(value Dimension) string { 249 | switch value { 250 | case DimensionWidth: 251 | return "width" 252 | case DimensionHeight: 253 | return "height" 254 | } 255 | return "unknown" 256 | } 257 | 258 | // DirectionToString returns string version of Direction enum 259 | func DirectionToString(value Direction) string { 260 | switch value { 261 | case DirectionInherit: 262 | return "inherit" 263 | case DirectionLTR: 264 | return "ltr" 265 | case DirectionRTL: 266 | return "rtl" 267 | } 268 | return "unknown" 269 | } 270 | 271 | // DisplayToString returns string version of Display enum 272 | func DisplayToString(value Display) string { 273 | switch value { 274 | case DisplayFlex: 275 | return "flex" 276 | case DisplayNone: 277 | return "none" 278 | } 279 | return "unknown" 280 | } 281 | 282 | // EdgeToString returns string version of Edge enum 283 | func EdgeToString(value Edge) string { 284 | switch value { 285 | case EdgeLeft: 286 | return "left" 287 | case EdgeTop: 288 | return "top" 289 | case EdgeRight: 290 | return "right" 291 | case EdgeBottom: 292 | return "bottom" 293 | case EdgeStart: 294 | return "start" 295 | case EdgeEnd: 296 | return "end" 297 | case EdgeHorizontal: 298 | return "horizontal" 299 | case EdgeVertical: 300 | return "vertical" 301 | case EdgeAll: 302 | return "all" 303 | } 304 | return "unknown" 305 | } 306 | 307 | // ExperimentalFeatureToString returns string version of ExperimentalFeature enum 308 | func ExperimentalFeatureToString(value ExperimentalFeature) string { 309 | switch value { 310 | case ExperimentalFeatureWebFlexBasis: 311 | return "web-flex-basis" 312 | } 313 | return "unknown" 314 | } 315 | 316 | // FlexDirectionToString returns string version of FlexDirection enum 317 | func FlexDirectionToString(value FlexDirection) string { 318 | switch value { 319 | case FlexDirectionColumn: 320 | return "column" 321 | case FlexDirectionColumnReverse: 322 | return "column-reverse" 323 | case FlexDirectionRow: 324 | return "row" 325 | case FlexDirectionRowReverse: 326 | return "row-reverse" 327 | } 328 | return "unknown" 329 | } 330 | 331 | // JustifyToString returns string version of Justify enum 332 | func JustifyToString(value Justify) string { 333 | switch value { 334 | case JustifyFlexStart: 335 | return "flex-start" 336 | case JustifyCenter: 337 | return "center" 338 | case JustifyFlexEnd: 339 | return "flex-end" 340 | case JustifySpaceBetween: 341 | return "space-between" 342 | case JustifySpaceAround: 343 | return "space-around" 344 | } 345 | return "unknown" 346 | } 347 | 348 | // LogLevelToString returns string version of LogLevel enum 349 | func LogLevelToString(value LogLevel) string { 350 | switch value { 351 | case LogLevelError: 352 | return "error" 353 | case LogLevelWarn: 354 | return "warn" 355 | case LogLevelInfo: 356 | return "info" 357 | case LogLevelDebug: 358 | return "debug" 359 | case LogLevelVerbose: 360 | return "verbose" 361 | case LogLevelFatal: 362 | return "fatal" 363 | } 364 | return "unknown" 365 | } 366 | 367 | // MeasureModeToString returns string version of MeasureMode enum 368 | func MeasureModeToString(value MeasureMode) string { 369 | switch value { 370 | case MeasureModeUndefined: 371 | return "undefined" 372 | case MeasureModeExactly: 373 | return "exactly" 374 | case MeasureModeAtMost: 375 | return "at-most" 376 | } 377 | return "unknown" 378 | } 379 | 380 | // NodeTypeToString returns string version of NodeType enum 381 | func NodeTypeToString(value NodeType) string { 382 | switch value { 383 | case NodeTypeDefault: 384 | return "default" 385 | case NodeTypeText: 386 | return "text" 387 | } 388 | return "unknown" 389 | } 390 | 391 | // OverflowToString returns string version of Overflow enum 392 | func OverflowToString(value Overflow) string { 393 | switch value { 394 | case OverflowVisible: 395 | return "visible" 396 | case OverflowHidden: 397 | return "hidden" 398 | case OverflowScroll: 399 | return "scroll" 400 | } 401 | return "unknown" 402 | } 403 | 404 | // PositionTypeToString returns string version of PositionType enum 405 | func PositionTypeToString(value PositionType) string { 406 | switch value { 407 | case PositionTypeRelative: 408 | return "relative" 409 | case PositionTypeAbsolute: 410 | return "absolute" 411 | } 412 | return "unknown" 413 | } 414 | 415 | // PrintOptionsToString returns string version of PrintOptions enum 416 | func PrintOptionsToString(value PrintOptions) string { 417 | switch value { 418 | case PrintOptionsLayout: 419 | return "layout" 420 | case PrintOptionsStyle: 421 | return "style" 422 | case PrintOptionsChildren: 423 | return "children" 424 | } 425 | return "unknown" 426 | } 427 | 428 | // UnitToString returns string version of Unit enum 429 | func UnitToString(value Unit) string { 430 | switch value { 431 | case UnitUndefined: 432 | return "undefined" 433 | case UnitPoint: 434 | return "point" 435 | case UnitPercent: 436 | return "percent" 437 | case UnitAuto: 438 | return "auto" 439 | } 440 | return "unknown" 441 | } 442 | 443 | // WrapToString returns string version of Wrap enum 444 | func WrapToString(value Wrap) string { 445 | switch value { 446 | case WrapNoWrap: 447 | return "no-wrap" 448 | case WrapWrap: 449 | return "wrap" 450 | case WrapWrapReverse: 451 | return "wrap-reverse" 452 | } 453 | return "unknown" 454 | } 455 | -------------------------------------------------------------------------------- /flex_direction_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import "testing" 4 | 5 | func TestFlex_direction_column_no_height(t *testing.T) { 6 | config := NewConfig() 7 | root := NewNodeWithConfig(config) 8 | root.StyleSetWidth(100) 9 | 10 | rootChild0 := NewNodeWithConfig(config) 11 | rootChild0.StyleSetHeight(10) 12 | root.InsertChild(rootChild0, 0) 13 | 14 | rootChild1 := NewNodeWithConfig(config) 15 | rootChild1.StyleSetHeight(10) 16 | root.InsertChild(rootChild1, 1) 17 | 18 | rootChild2 := NewNodeWithConfig(config) 19 | rootChild2.StyleSetHeight(10) 20 | root.InsertChild(rootChild2, 2) 21 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 22 | 23 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 24 | assertFloatEqual(t, 0, root.LayoutGetTop()) 25 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 26 | assertFloatEqual(t, 30, root.LayoutGetHeight()) 27 | 28 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 29 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 30 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 31 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 32 | 33 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 34 | assertFloatEqual(t, 10, rootChild1.LayoutGetTop()) 35 | assertFloatEqual(t, 100, rootChild1.LayoutGetWidth()) 36 | assertFloatEqual(t, 10, rootChild1.LayoutGetHeight()) 37 | 38 | assertFloatEqual(t, 0, rootChild2.LayoutGetLeft()) 39 | assertFloatEqual(t, 20, rootChild2.LayoutGetTop()) 40 | assertFloatEqual(t, 100, rootChild2.LayoutGetWidth()) 41 | assertFloatEqual(t, 10, rootChild2.LayoutGetHeight()) 42 | 43 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 44 | 45 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 46 | assertFloatEqual(t, 0, root.LayoutGetTop()) 47 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 48 | assertFloatEqual(t, 30, root.LayoutGetHeight()) 49 | 50 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 51 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 52 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 53 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 54 | 55 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 56 | assertFloatEqual(t, 10, rootChild1.LayoutGetTop()) 57 | assertFloatEqual(t, 100, rootChild1.LayoutGetWidth()) 58 | assertFloatEqual(t, 10, rootChild1.LayoutGetHeight()) 59 | 60 | assertFloatEqual(t, 0, rootChild2.LayoutGetLeft()) 61 | assertFloatEqual(t, 20, rootChild2.LayoutGetTop()) 62 | assertFloatEqual(t, 100, rootChild2.LayoutGetWidth()) 63 | assertFloatEqual(t, 10, rootChild2.LayoutGetHeight()) 64 | } 65 | 66 | func TestFlex_direction_row_no_width(t *testing.T) { 67 | config := NewConfig() 68 | 69 | root := NewNodeWithConfig(config) 70 | root.StyleSetFlexDirection(FlexDirectionRow) 71 | root.StyleSetHeight(100) 72 | 73 | rootChild0 := NewNodeWithConfig(config) 74 | rootChild0.StyleSetWidth(10) 75 | root.InsertChild(rootChild0, 0) 76 | 77 | rootChild1 := NewNodeWithConfig(config) 78 | rootChild1.StyleSetWidth(10) 79 | root.InsertChild(rootChild1, 1) 80 | 81 | rootChild2 := NewNodeWithConfig(config) 82 | rootChild2.StyleSetWidth(10) 83 | root.InsertChild(rootChild2, 2) 84 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 85 | 86 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 87 | assertFloatEqual(t, 0, root.LayoutGetTop()) 88 | assertFloatEqual(t, 30, root.LayoutGetWidth()) 89 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 90 | 91 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 92 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 93 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 94 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 95 | 96 | assertFloatEqual(t, 10, rootChild1.LayoutGetLeft()) 97 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 98 | assertFloatEqual(t, 10, rootChild1.LayoutGetWidth()) 99 | assertFloatEqual(t, 100, rootChild1.LayoutGetHeight()) 100 | 101 | assertFloatEqual(t, 20, rootChild2.LayoutGetLeft()) 102 | assertFloatEqual(t, 0, rootChild2.LayoutGetTop()) 103 | assertFloatEqual(t, 10, rootChild2.LayoutGetWidth()) 104 | assertFloatEqual(t, 100, rootChild2.LayoutGetHeight()) 105 | 106 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 107 | 108 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 109 | assertFloatEqual(t, 0, root.LayoutGetTop()) 110 | assertFloatEqual(t, 30, root.LayoutGetWidth()) 111 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 112 | 113 | assertFloatEqual(t, 20, rootChild0.LayoutGetLeft()) 114 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 115 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 116 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 117 | 118 | assertFloatEqual(t, 10, rootChild1.LayoutGetLeft()) 119 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 120 | assertFloatEqual(t, 10, rootChild1.LayoutGetWidth()) 121 | assertFloatEqual(t, 100, rootChild1.LayoutGetHeight()) 122 | 123 | assertFloatEqual(t, 0, rootChild2.LayoutGetLeft()) 124 | assertFloatEqual(t, 0, rootChild2.LayoutGetTop()) 125 | assertFloatEqual(t, 10, rootChild2.LayoutGetWidth()) 126 | assertFloatEqual(t, 100, rootChild2.LayoutGetHeight()) 127 | } 128 | 129 | func TestFlex_direction_column(t *testing.T) { 130 | config := NewConfig() 131 | 132 | root := NewNodeWithConfig(config) 133 | root.StyleSetWidth(100) 134 | root.StyleSetHeight(100) 135 | 136 | rootChild0 := NewNodeWithConfig(config) 137 | rootChild0.StyleSetHeight(10) 138 | root.InsertChild(rootChild0, 0) 139 | 140 | rootChild1 := NewNodeWithConfig(config) 141 | rootChild1.StyleSetHeight(10) 142 | root.InsertChild(rootChild1, 1) 143 | 144 | rootChild2 := NewNodeWithConfig(config) 145 | rootChild2.StyleSetHeight(10) 146 | root.InsertChild(rootChild2, 2) 147 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 148 | 149 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 150 | assertFloatEqual(t, 0, root.LayoutGetTop()) 151 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 152 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 153 | 154 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 155 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 156 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 157 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 158 | 159 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 160 | assertFloatEqual(t, 10, rootChild1.LayoutGetTop()) 161 | assertFloatEqual(t, 100, rootChild1.LayoutGetWidth()) 162 | assertFloatEqual(t, 10, rootChild1.LayoutGetHeight()) 163 | 164 | assertFloatEqual(t, 0, rootChild2.LayoutGetLeft()) 165 | assertFloatEqual(t, 20, rootChild2.LayoutGetTop()) 166 | assertFloatEqual(t, 100, rootChild2.LayoutGetWidth()) 167 | assertFloatEqual(t, 10, rootChild2.LayoutGetHeight()) 168 | 169 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 170 | 171 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 172 | assertFloatEqual(t, 0, root.LayoutGetTop()) 173 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 174 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 175 | 176 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 177 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 178 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 179 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 180 | 181 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 182 | assertFloatEqual(t, 10, rootChild1.LayoutGetTop()) 183 | assertFloatEqual(t, 100, rootChild1.LayoutGetWidth()) 184 | assertFloatEqual(t, 10, rootChild1.LayoutGetHeight()) 185 | 186 | assertFloatEqual(t, 0, rootChild2.LayoutGetLeft()) 187 | assertFloatEqual(t, 20, rootChild2.LayoutGetTop()) 188 | assertFloatEqual(t, 100, rootChild2.LayoutGetWidth()) 189 | assertFloatEqual(t, 10, rootChild2.LayoutGetHeight()) 190 | } 191 | 192 | func TestFlex_direction_row(t *testing.T) { 193 | config := NewConfig() 194 | 195 | root := NewNodeWithConfig(config) 196 | root.StyleSetFlexDirection(FlexDirectionRow) 197 | root.StyleSetWidth(100) 198 | root.StyleSetHeight(100) 199 | 200 | rootChild0 := NewNodeWithConfig(config) 201 | rootChild0.StyleSetWidth(10) 202 | root.InsertChild(rootChild0, 0) 203 | 204 | rootChild1 := NewNodeWithConfig(config) 205 | rootChild1.StyleSetWidth(10) 206 | root.InsertChild(rootChild1, 1) 207 | 208 | rootChild2 := NewNodeWithConfig(config) 209 | rootChild2.StyleSetWidth(10) 210 | root.InsertChild(rootChild2, 2) 211 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 212 | 213 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 214 | assertFloatEqual(t, 0, root.LayoutGetTop()) 215 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 216 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 217 | 218 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 219 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 220 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 221 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 222 | 223 | assertFloatEqual(t, 10, rootChild1.LayoutGetLeft()) 224 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 225 | assertFloatEqual(t, 10, rootChild1.LayoutGetWidth()) 226 | assertFloatEqual(t, 100, rootChild1.LayoutGetHeight()) 227 | 228 | assertFloatEqual(t, 20, rootChild2.LayoutGetLeft()) 229 | assertFloatEqual(t, 0, rootChild2.LayoutGetTop()) 230 | assertFloatEqual(t, 10, rootChild2.LayoutGetWidth()) 231 | assertFloatEqual(t, 100, rootChild2.LayoutGetHeight()) 232 | 233 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 234 | 235 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 236 | assertFloatEqual(t, 0, root.LayoutGetTop()) 237 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 238 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 239 | 240 | assertFloatEqual(t, 90, rootChild0.LayoutGetLeft()) 241 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 242 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 243 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 244 | 245 | assertFloatEqual(t, 80, rootChild1.LayoutGetLeft()) 246 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 247 | assertFloatEqual(t, 10, rootChild1.LayoutGetWidth()) 248 | assertFloatEqual(t, 100, rootChild1.LayoutGetHeight()) 249 | 250 | assertFloatEqual(t, 70, rootChild2.LayoutGetLeft()) 251 | assertFloatEqual(t, 0, rootChild2.LayoutGetTop()) 252 | assertFloatEqual(t, 10, rootChild2.LayoutGetWidth()) 253 | assertFloatEqual(t, 100, rootChild2.LayoutGetHeight()) 254 | } 255 | 256 | func TestFlex_direction_column_reverse(t *testing.T) { 257 | config := NewConfig() 258 | 259 | root := NewNodeWithConfig(config) 260 | root.StyleSetFlexDirection(FlexDirectionColumnReverse) 261 | root.StyleSetWidth(100) 262 | root.StyleSetHeight(100) 263 | 264 | rootChild0 := NewNodeWithConfig(config) 265 | rootChild0.StyleSetHeight(10) 266 | root.InsertChild(rootChild0, 0) 267 | 268 | rootChild1 := NewNodeWithConfig(config) 269 | rootChild1.StyleSetHeight(10) 270 | root.InsertChild(rootChild1, 1) 271 | 272 | rootChild2 := NewNodeWithConfig(config) 273 | rootChild2.StyleSetHeight(10) 274 | root.InsertChild(rootChild2, 2) 275 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 276 | 277 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 278 | assertFloatEqual(t, 0, root.LayoutGetTop()) 279 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 280 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 281 | 282 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 283 | assertFloatEqual(t, 90, rootChild0.LayoutGetTop()) 284 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 285 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 286 | 287 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 288 | assertFloatEqual(t, 80, rootChild1.LayoutGetTop()) 289 | assertFloatEqual(t, 100, rootChild1.LayoutGetWidth()) 290 | assertFloatEqual(t, 10, rootChild1.LayoutGetHeight()) 291 | 292 | assertFloatEqual(t, 0, rootChild2.LayoutGetLeft()) 293 | assertFloatEqual(t, 70, rootChild2.LayoutGetTop()) 294 | assertFloatEqual(t, 100, rootChild2.LayoutGetWidth()) 295 | assertFloatEqual(t, 10, rootChild2.LayoutGetHeight()) 296 | 297 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 298 | 299 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 300 | assertFloatEqual(t, 0, root.LayoutGetTop()) 301 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 302 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 303 | 304 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 305 | assertFloatEqual(t, 90, rootChild0.LayoutGetTop()) 306 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 307 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 308 | 309 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 310 | assertFloatEqual(t, 80, rootChild1.LayoutGetTop()) 311 | assertFloatEqual(t, 100, rootChild1.LayoutGetWidth()) 312 | assertFloatEqual(t, 10, rootChild1.LayoutGetHeight()) 313 | 314 | assertFloatEqual(t, 0, rootChild2.LayoutGetLeft()) 315 | assertFloatEqual(t, 70, rootChild2.LayoutGetTop()) 316 | assertFloatEqual(t, 100, rootChild2.LayoutGetWidth()) 317 | assertFloatEqual(t, 10, rootChild2.LayoutGetHeight()) 318 | } 319 | 320 | func TestFlex_direction_row_reverse(t *testing.T) { 321 | config := NewConfig() 322 | 323 | root := NewNodeWithConfig(config) 324 | root.StyleSetFlexDirection(FlexDirectionRowReverse) 325 | root.StyleSetWidth(100) 326 | root.StyleSetHeight(100) 327 | 328 | rootChild0 := NewNodeWithConfig(config) 329 | rootChild0.StyleSetWidth(10) 330 | root.InsertChild(rootChild0, 0) 331 | 332 | rootChild1 := NewNodeWithConfig(config) 333 | rootChild1.StyleSetWidth(10) 334 | root.InsertChild(rootChild1, 1) 335 | 336 | rootChild2 := NewNodeWithConfig(config) 337 | rootChild2.StyleSetWidth(10) 338 | root.InsertChild(rootChild2, 2) 339 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 340 | 341 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 342 | assertFloatEqual(t, 0, root.LayoutGetTop()) 343 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 344 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 345 | 346 | assertFloatEqual(t, 90, rootChild0.LayoutGetLeft()) 347 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 348 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 349 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 350 | 351 | assertFloatEqual(t, 80, rootChild1.LayoutGetLeft()) 352 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 353 | assertFloatEqual(t, 10, rootChild1.LayoutGetWidth()) 354 | assertFloatEqual(t, 100, rootChild1.LayoutGetHeight()) 355 | 356 | assertFloatEqual(t, 70, rootChild2.LayoutGetLeft()) 357 | assertFloatEqual(t, 0, rootChild2.LayoutGetTop()) 358 | assertFloatEqual(t, 10, rootChild2.LayoutGetWidth()) 359 | assertFloatEqual(t, 100, rootChild2.LayoutGetHeight()) 360 | 361 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 362 | 363 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 364 | assertFloatEqual(t, 0, root.LayoutGetTop()) 365 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 366 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 367 | 368 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 369 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 370 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 371 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 372 | 373 | assertFloatEqual(t, 10, rootChild1.LayoutGetLeft()) 374 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 375 | assertFloatEqual(t, 10, rootChild1.LayoutGetWidth()) 376 | assertFloatEqual(t, 100, rootChild1.LayoutGetHeight()) 377 | 378 | assertFloatEqual(t, 20, rootChild2.LayoutGetLeft()) 379 | assertFloatEqual(t, 0, rootChild2.LayoutGetTop()) 380 | assertFloatEqual(t, 10, rootChild2.LayoutGetWidth()) 381 | assertFloatEqual(t, 100, rootChild2.LayoutGetHeight()) 382 | } 383 | -------------------------------------------------------------------------------- /flex_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import "testing" 4 | 5 | func TestFlex_basis_flex_grow_column(t *testing.T) { 6 | config := NewConfig() 7 | 8 | root := NewNodeWithConfig(config) 9 | root.StyleSetWidth(100) 10 | root.StyleSetHeight(100) 11 | 12 | rootChild0 := NewNodeWithConfig(config) 13 | rootChild0.StyleSetFlexGrow(1) 14 | rootChild0.StyleSetFlexBasis(50) 15 | root.InsertChild(rootChild0, 0) 16 | 17 | rootChild1 := NewNodeWithConfig(config) 18 | rootChild1.StyleSetFlexGrow(1) 19 | root.InsertChild(rootChild1, 1) 20 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 21 | 22 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 23 | assertFloatEqual(t, 0, root.LayoutGetTop()) 24 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 25 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 26 | 27 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 28 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 29 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 30 | assertFloatEqual(t, 75, rootChild0.LayoutGetHeight()) 31 | 32 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 33 | assertFloatEqual(t, 75, rootChild1.LayoutGetTop()) 34 | assertFloatEqual(t, 100, rootChild1.LayoutGetWidth()) 35 | assertFloatEqual(t, 25, rootChild1.LayoutGetHeight()) 36 | 37 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 38 | 39 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 40 | assertFloatEqual(t, 0, root.LayoutGetTop()) 41 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 42 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 43 | 44 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 45 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 46 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 47 | assertFloatEqual(t, 75, rootChild0.LayoutGetHeight()) 48 | 49 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 50 | assertFloatEqual(t, 75, rootChild1.LayoutGetTop()) 51 | assertFloatEqual(t, 100, rootChild1.LayoutGetWidth()) 52 | assertFloatEqual(t, 25, rootChild1.LayoutGetHeight()) 53 | } 54 | 55 | func TestFlex_basis_flex_grow_row(t *testing.T) { 56 | config := NewConfig() 57 | 58 | root := NewNodeWithConfig(config) 59 | root.StyleSetFlexDirection(FlexDirectionRow) 60 | root.StyleSetWidth(100) 61 | root.StyleSetHeight(100) 62 | 63 | rootChild0 := NewNodeWithConfig(config) 64 | rootChild0.StyleSetFlexGrow(1) 65 | rootChild0.StyleSetFlexBasis(50) 66 | root.InsertChild(rootChild0, 0) 67 | 68 | rootChild1 := NewNodeWithConfig(config) 69 | rootChild1.StyleSetFlexGrow(1) 70 | root.InsertChild(rootChild1, 1) 71 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 72 | 73 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 74 | assertFloatEqual(t, 0, root.LayoutGetTop()) 75 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 76 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 77 | 78 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 79 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 80 | assertFloatEqual(t, 75, rootChild0.LayoutGetWidth()) 81 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 82 | 83 | assertFloatEqual(t, 75, rootChild1.LayoutGetLeft()) 84 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 85 | assertFloatEqual(t, 25, rootChild1.LayoutGetWidth()) 86 | assertFloatEqual(t, 100, rootChild1.LayoutGetHeight()) 87 | 88 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 89 | 90 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 91 | assertFloatEqual(t, 0, root.LayoutGetTop()) 92 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 93 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 94 | 95 | assertFloatEqual(t, 25, rootChild0.LayoutGetLeft()) 96 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 97 | assertFloatEqual(t, 75, rootChild0.LayoutGetWidth()) 98 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 99 | 100 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 101 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 102 | assertFloatEqual(t, 25, rootChild1.LayoutGetWidth()) 103 | assertFloatEqual(t, 100, rootChild1.LayoutGetHeight()) 104 | } 105 | 106 | func TestFlex_basis_flex_shrink_column(t *testing.T) { 107 | config := NewConfig() 108 | 109 | root := NewNodeWithConfig(config) 110 | root.StyleSetWidth(100) 111 | root.StyleSetHeight(100) 112 | 113 | rootChild0 := NewNodeWithConfig(config) 114 | rootChild0.StyleSetFlexShrink(1) 115 | rootChild0.StyleSetFlexBasis(100) 116 | root.InsertChild(rootChild0, 0) 117 | 118 | rootChild1 := NewNodeWithConfig(config) 119 | rootChild1.StyleSetFlexBasis(50) 120 | root.InsertChild(rootChild1, 1) 121 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 122 | 123 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 124 | assertFloatEqual(t, 0, root.LayoutGetTop()) 125 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 126 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 127 | 128 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 129 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 130 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 131 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 132 | 133 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 134 | assertFloatEqual(t, 50, rootChild1.LayoutGetTop()) 135 | assertFloatEqual(t, 100, rootChild1.LayoutGetWidth()) 136 | assertFloatEqual(t, 50, rootChild1.LayoutGetHeight()) 137 | 138 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 139 | 140 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 141 | assertFloatEqual(t, 0, root.LayoutGetTop()) 142 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 143 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 144 | 145 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 146 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 147 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 148 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 149 | 150 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 151 | assertFloatEqual(t, 50, rootChild1.LayoutGetTop()) 152 | assertFloatEqual(t, 100, rootChild1.LayoutGetWidth()) 153 | assertFloatEqual(t, 50, rootChild1.LayoutGetHeight()) 154 | } 155 | 156 | func TestFlex_basis_flex_shrink_row(t *testing.T) { 157 | config := NewConfig() 158 | 159 | root := NewNodeWithConfig(config) 160 | root.StyleSetFlexDirection(FlexDirectionRow) 161 | root.StyleSetWidth(100) 162 | root.StyleSetHeight(100) 163 | 164 | rootChild0 := NewNodeWithConfig(config) 165 | rootChild0.StyleSetFlexShrink(1) 166 | rootChild0.StyleSetFlexBasis(100) 167 | root.InsertChild(rootChild0, 0) 168 | 169 | rootChild1 := NewNodeWithConfig(config) 170 | rootChild1.StyleSetFlexBasis(50) 171 | root.InsertChild(rootChild1, 1) 172 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 173 | 174 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 175 | assertFloatEqual(t, 0, root.LayoutGetTop()) 176 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 177 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 178 | 179 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 180 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 181 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 182 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 183 | 184 | assertFloatEqual(t, 50, rootChild1.LayoutGetLeft()) 185 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 186 | assertFloatEqual(t, 50, rootChild1.LayoutGetWidth()) 187 | assertFloatEqual(t, 100, rootChild1.LayoutGetHeight()) 188 | 189 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 190 | 191 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 192 | assertFloatEqual(t, 0, root.LayoutGetTop()) 193 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 194 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 195 | 196 | assertFloatEqual(t, 50, rootChild0.LayoutGetLeft()) 197 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 198 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 199 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 200 | 201 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 202 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 203 | assertFloatEqual(t, 50, rootChild1.LayoutGetWidth()) 204 | assertFloatEqual(t, 100, rootChild1.LayoutGetHeight()) 205 | } 206 | 207 | func TestFlex_shrink_to_zero(t *testing.T) { 208 | config := NewConfig() 209 | 210 | root := NewNodeWithConfig(config) 211 | root.StyleSetHeight(75) 212 | 213 | rootChild0 := NewNodeWithConfig(config) 214 | rootChild0.StyleSetWidth(50) 215 | rootChild0.StyleSetHeight(50) 216 | root.InsertChild(rootChild0, 0) 217 | 218 | rootChild1 := NewNodeWithConfig(config) 219 | rootChild1.StyleSetFlexShrink(1) 220 | rootChild1.StyleSetWidth(50) 221 | rootChild1.StyleSetHeight(50) 222 | root.InsertChild(rootChild1, 1) 223 | 224 | rootChild2 := NewNodeWithConfig(config) 225 | rootChild2.StyleSetWidth(50) 226 | rootChild2.StyleSetHeight(50) 227 | root.InsertChild(rootChild2, 2) 228 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 229 | 230 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 231 | assertFloatEqual(t, 0, root.LayoutGetTop()) 232 | assertFloatEqual(t, 50, root.LayoutGetWidth()) 233 | assertFloatEqual(t, 75, root.LayoutGetHeight()) 234 | 235 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 236 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 237 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 238 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 239 | 240 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 241 | assertFloatEqual(t, 50, rootChild1.LayoutGetTop()) 242 | assertFloatEqual(t, 50, rootChild1.LayoutGetWidth()) 243 | assertFloatEqual(t, 0, rootChild1.LayoutGetHeight()) 244 | 245 | assertFloatEqual(t, 0, rootChild2.LayoutGetLeft()) 246 | assertFloatEqual(t, 50, rootChild2.LayoutGetTop()) 247 | assertFloatEqual(t, 50, rootChild2.LayoutGetWidth()) 248 | assertFloatEqual(t, 50, rootChild2.LayoutGetHeight()) 249 | 250 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 251 | 252 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 253 | assertFloatEqual(t, 0, root.LayoutGetTop()) 254 | assertFloatEqual(t, 50, root.LayoutGetWidth()) 255 | assertFloatEqual(t, 75, root.LayoutGetHeight()) 256 | 257 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 258 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 259 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 260 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 261 | 262 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 263 | assertFloatEqual(t, 50, rootChild1.LayoutGetTop()) 264 | assertFloatEqual(t, 50, rootChild1.LayoutGetWidth()) 265 | assertFloatEqual(t, 0, rootChild1.LayoutGetHeight()) 266 | 267 | assertFloatEqual(t, 0, rootChild2.LayoutGetLeft()) 268 | assertFloatEqual(t, 50, rootChild2.LayoutGetTop()) 269 | assertFloatEqual(t, 50, rootChild2.LayoutGetWidth()) 270 | assertFloatEqual(t, 50, rootChild2.LayoutGetHeight()) 271 | } 272 | 273 | func TestFlex_basis_overrides_main_size(t *testing.T) { 274 | config := NewConfig() 275 | 276 | root := NewNodeWithConfig(config) 277 | root.StyleSetWidth(100) 278 | root.StyleSetHeight(100) 279 | 280 | rootChild0 := NewNodeWithConfig(config) 281 | rootChild0.StyleSetFlexGrow(1) 282 | rootChild0.StyleSetFlexBasis(50) 283 | rootChild0.StyleSetHeight(20) 284 | root.InsertChild(rootChild0, 0) 285 | 286 | rootChild1 := NewNodeWithConfig(config) 287 | rootChild1.StyleSetFlexGrow(1) 288 | rootChild1.StyleSetHeight(10) 289 | root.InsertChild(rootChild1, 1) 290 | 291 | rootChild2 := NewNodeWithConfig(config) 292 | rootChild2.StyleSetFlexGrow(1) 293 | rootChild2.StyleSetHeight(10) 294 | root.InsertChild(rootChild2, 2) 295 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 296 | 297 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 298 | assertFloatEqual(t, 0, root.LayoutGetTop()) 299 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 300 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 301 | 302 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 303 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 304 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 305 | assertFloatEqual(t, 60, rootChild0.LayoutGetHeight()) 306 | 307 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 308 | assertFloatEqual(t, 60, rootChild1.LayoutGetTop()) 309 | assertFloatEqual(t, 100, rootChild1.LayoutGetWidth()) 310 | assertFloatEqual(t, 20, rootChild1.LayoutGetHeight()) 311 | 312 | assertFloatEqual(t, 0, rootChild2.LayoutGetLeft()) 313 | assertFloatEqual(t, 80, rootChild2.LayoutGetTop()) 314 | assertFloatEqual(t, 100, rootChild2.LayoutGetWidth()) 315 | assertFloatEqual(t, 20, rootChild2.LayoutGetHeight()) 316 | 317 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 318 | 319 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 320 | assertFloatEqual(t, 0, root.LayoutGetTop()) 321 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 322 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 323 | 324 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 325 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 326 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 327 | assertFloatEqual(t, 60, rootChild0.LayoutGetHeight()) 328 | 329 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 330 | assertFloatEqual(t, 60, rootChild1.LayoutGetTop()) 331 | assertFloatEqual(t, 100, rootChild1.LayoutGetWidth()) 332 | assertFloatEqual(t, 20, rootChild1.LayoutGetHeight()) 333 | 334 | assertFloatEqual(t, 0, rootChild2.LayoutGetLeft()) 335 | assertFloatEqual(t, 80, rootChild2.LayoutGetTop()) 336 | assertFloatEqual(t, 100, rootChild2.LayoutGetWidth()) 337 | assertFloatEqual(t, 20, rootChild2.LayoutGetHeight()) 338 | } 339 | 340 | func TestFlex_grow_shrink_at_most(t *testing.T) { 341 | config := NewConfig() 342 | 343 | root := NewNodeWithConfig(config) 344 | root.StyleSetWidth(100) 345 | root.StyleSetHeight(100) 346 | 347 | rootChild0 := NewNodeWithConfig(config) 348 | root.InsertChild(rootChild0, 0) 349 | 350 | rootChild0Child0 := NewNodeWithConfig(config) 351 | rootChild0Child0.StyleSetFlexGrow(1) 352 | rootChild0Child0.StyleSetFlexShrink(1) 353 | rootChild0.InsertChild(rootChild0Child0, 0) 354 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 355 | 356 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 357 | assertFloatEqual(t, 0, root.LayoutGetTop()) 358 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 359 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 360 | 361 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 362 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 363 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 364 | assertFloatEqual(t, 0, rootChild0.LayoutGetHeight()) 365 | 366 | assertFloatEqual(t, 0, rootChild0Child0.LayoutGetLeft()) 367 | assertFloatEqual(t, 0, rootChild0Child0.LayoutGetTop()) 368 | assertFloatEqual(t, 100, rootChild0Child0.LayoutGetWidth()) 369 | assertFloatEqual(t, 0, rootChild0Child0.LayoutGetHeight()) 370 | 371 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 372 | 373 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 374 | assertFloatEqual(t, 0, root.LayoutGetTop()) 375 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 376 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 377 | 378 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 379 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 380 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 381 | assertFloatEqual(t, 0, rootChild0.LayoutGetHeight()) 382 | 383 | assertFloatEqual(t, 0, rootChild0Child0.LayoutGetLeft()) 384 | assertFloatEqual(t, 0, rootChild0Child0.LayoutGetTop()) 385 | assertFloatEqual(t, 100, rootChild0Child0.LayoutGetWidth()) 386 | assertFloatEqual(t, 0, rootChild0Child0.LayoutGetHeight()) 387 | } 388 | 389 | func TestFlex_grow_less_than_factor_one(t *testing.T) { 390 | config := NewConfig() 391 | 392 | root := NewNodeWithConfig(config) 393 | root.StyleSetWidth(200) 394 | root.StyleSetHeight(500) 395 | 396 | rootChild0 := NewNodeWithConfig(config) 397 | rootChild0.StyleSetFlexGrow(0.2) 398 | rootChild0.StyleSetFlexBasis(40) 399 | root.InsertChild(rootChild0, 0) 400 | 401 | rootChild1 := NewNodeWithConfig(config) 402 | rootChild1.StyleSetFlexGrow(0.2) 403 | root.InsertChild(rootChild1, 1) 404 | 405 | rootChild2 := NewNodeWithConfig(config) 406 | rootChild2.StyleSetFlexGrow(0.4) 407 | root.InsertChild(rootChild2, 2) 408 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 409 | 410 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 411 | assertFloatEqual(t, 0, root.LayoutGetTop()) 412 | assertFloatEqual(t, 200, root.LayoutGetWidth()) 413 | assertFloatEqual(t, 500, root.LayoutGetHeight()) 414 | 415 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 416 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 417 | assertFloatEqual(t, 200, rootChild0.LayoutGetWidth()) 418 | assertFloatEqual(t, 132, rootChild0.LayoutGetHeight()) 419 | 420 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 421 | assertFloatEqual(t, 132, rootChild1.LayoutGetTop()) 422 | assertFloatEqual(t, 200, rootChild1.LayoutGetWidth()) 423 | assertFloatEqual(t, 92, rootChild1.LayoutGetHeight()) 424 | 425 | assertFloatEqual(t, 0, rootChild2.LayoutGetLeft()) 426 | assertFloatEqual(t, 224, rootChild2.LayoutGetTop()) 427 | assertFloatEqual(t, 200, rootChild2.LayoutGetWidth()) 428 | assertFloatEqual(t, 184, rootChild2.LayoutGetHeight()) 429 | 430 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 431 | 432 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 433 | assertFloatEqual(t, 0, root.LayoutGetTop()) 434 | assertFloatEqual(t, 200, root.LayoutGetWidth()) 435 | assertFloatEqual(t, 500, root.LayoutGetHeight()) 436 | 437 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 438 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 439 | assertFloatEqual(t, 200, rootChild0.LayoutGetWidth()) 440 | assertFloatEqual(t, 132, rootChild0.LayoutGetHeight()) 441 | 442 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 443 | assertFloatEqual(t, 132, rootChild1.LayoutGetTop()) 444 | assertFloatEqual(t, 200, rootChild1.LayoutGetWidth()) 445 | assertFloatEqual(t, 92, rootChild1.LayoutGetHeight()) 446 | 447 | assertFloatEqual(t, 0, rootChild2.LayoutGetLeft()) 448 | assertFloatEqual(t, 224, rootChild2.LayoutGetTop()) 449 | assertFloatEqual(t, 200, rootChild2.LayoutGetWidth()) 450 | assertFloatEqual(t, 184, rootChild2.LayoutGetHeight()) 451 | } 452 | -------------------------------------------------------------------------------- /had_overflow_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func newHadOverflowTests() (*Config, *Node) { 10 | config := NewConfig() 11 | root := NewNodeWithConfig(config) 12 | root.StyleSetWidth(200) 13 | root.StyleSetHeight(100) 14 | root.StyleSetFlexDirection(FlexDirectionColumn) 15 | root.StyleSetFlexWrap(WrapNoWrap) 16 | return config, root 17 | } 18 | 19 | func TestChildren_overflow_no_wrap_and_no_flex_children(t *testing.T) { 20 | config, root := newHadOverflowTests() 21 | child0 := NewNodeWithConfig(config) 22 | child0.StyleSetWidth(80) 23 | child0.StyleSetHeight(40) 24 | child0.StyleSetMargin(EdgeTop, 10) 25 | child0.StyleSetMargin(EdgeBottom, 15) 26 | root.InsertChild(child0, 0) 27 | child1 := NewNodeWithConfig(config) 28 | child1.StyleSetWidth(80) 29 | child1.StyleSetHeight(40) 30 | child1.StyleSetMargin(EdgeBottom, 5) 31 | root.InsertChild(child1, 1) 32 | 33 | CalculateLayout(root, 200, 100, DirectionLTR) 34 | 35 | assert.True(t, root.Layout.HadOverflow) 36 | } 37 | 38 | func TestSpacing_overflow_no_wrap_and_no_flex_children(t *testing.T) { 39 | config, root := newHadOverflowTests() 40 | child0 := NewNodeWithConfig(config) 41 | child0.StyleSetWidth(80) 42 | child0.StyleSetHeight(40) 43 | child0.StyleSetMargin(EdgeTop, 10) 44 | child0.StyleSetMargin(EdgeBottom, 10) 45 | root.InsertChild(child0, 0) 46 | child1 := NewNodeWithConfig(config) 47 | child1.StyleSetWidth(80) 48 | child1.StyleSetHeight(40) 49 | child1.StyleSetMargin(EdgeBottom, 5) 50 | root.InsertChild(child1, 1) 51 | 52 | CalculateLayout(root, 200, 100, DirectionLTR) 53 | 54 | assert.True(t, root.Layout.HadOverflow) 55 | } 56 | 57 | func TestNo_overflow_no_wrap_and_flex_children(t *testing.T) { 58 | config, root := newHadOverflowTests() 59 | child0 := NewNodeWithConfig(config) 60 | child0.StyleSetWidth(80) 61 | child0.StyleSetHeight(40) 62 | child0.StyleSetMargin(EdgeTop, 10) 63 | child0.StyleSetMargin(EdgeBottom, 10) 64 | root.InsertChild(child0, 0) 65 | child1 := NewNodeWithConfig(config) 66 | child1.StyleSetWidth(80) 67 | child1.StyleSetHeight(40) 68 | child1.StyleSetMargin(EdgeBottom, 5) 69 | child1.StyleSetFlexShrink(1) 70 | root.InsertChild(child1, 1) 71 | 72 | CalculateLayout(root, 200, 100, DirectionLTR) 73 | 74 | assert.False(t, root.Layout.HadOverflow) 75 | } 76 | 77 | func TestHadOverflow_gets_reset_if_not_logger_valid(t *testing.T) { 78 | config, root := newHadOverflowTests() 79 | child0 := NewNodeWithConfig(config) 80 | child0.StyleSetWidth(80) 81 | child0.StyleSetHeight(40) 82 | child0.StyleSetMargin(EdgeTop, 10) 83 | child0.StyleSetMargin(EdgeBottom, 10) 84 | root.InsertChild(child0, 0) 85 | child1 := NewNodeWithConfig(config) 86 | child1.StyleSetWidth(80) 87 | child1.StyleSetHeight(40) 88 | child1.StyleSetMargin(EdgeBottom, 5) 89 | root.InsertChild(child1, 1) 90 | 91 | CalculateLayout(root, 200, 100, DirectionLTR) 92 | 93 | assert.True(t, root.Layout.HadOverflow) 94 | 95 | child1.StyleSetFlexShrink(1) 96 | 97 | CalculateLayout(root, 200, 100, DirectionLTR) 98 | 99 | assert.False(t, root.Layout.HadOverflow) 100 | } 101 | 102 | func TestSpacing_overflow_in_nested_nodes(t *testing.T) { 103 | config, root := newHadOverflowTests() 104 | child0 := NewNodeWithConfig(config) 105 | child0.StyleSetWidth(80) 106 | child0.StyleSetHeight(40) 107 | child0.StyleSetMargin(EdgeTop, 10) 108 | child0.StyleSetMargin(EdgeBottom, 10) 109 | root.InsertChild(child0, 0) 110 | child1 := NewNodeWithConfig(config) 111 | child1.StyleSetWidth(80) 112 | child1.StyleSetHeight(40) 113 | root.InsertChild(child1, 1) 114 | child1_1 := NewNodeWithConfig(config) 115 | child1_1.StyleSetWidth(80) 116 | child1_1.StyleSetHeight(40) 117 | child1_1.StyleSetMargin(EdgeBottom, 5) 118 | child1.InsertChild(child1_1, 0) 119 | 120 | CalculateLayout(root, 200, 100, DirectionLTR) 121 | 122 | assert.True(t, root.Layout.HadOverflow) 123 | } 124 | -------------------------------------------------------------------------------- /issue5_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestIssue5(t *testing.T) { 11 | config := NewConfig() 12 | config.Context = "test" 13 | 14 | // check that "padding" set with EdgeAll is printed out 15 | root := NewNodeWithConfig(config) 16 | root.StyleSetFlexDirection(FlexDirectionColumn) 17 | root.StyleSetHeightPercent(100) 18 | 19 | child := NewNodeWithConfig(config) 20 | child.StyleSetPadding(EdgeAll, 20) 21 | root.InsertChild(child, 0) 22 | 23 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 24 | 25 | w := &bytes.Buffer{} 26 | printer := NewNodePrinter(w, PrintOptionsLayout|PrintOptionsStyle|PrintOptionsChildren) 27 | printer.Print(root) 28 | got := w.String() 29 | exp := `
30 |
31 |
` 32 | assert.Equal(t, got, exp) 33 | } 34 | -------------------------------------------------------------------------------- /math.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import "math" 4 | 5 | // from https://github.com/rkusa/gm/blob/master/math32/bits.go 6 | 7 | const ( 8 | uvnan = 0x7FC00001 9 | ) 10 | 11 | var ( 12 | NAN = math.Float32frombits(uvnan) 13 | ) 14 | 15 | // NaN returns an IEEE 754 ``not-a-number'' value. 16 | func NaN() float32 { return math.Float32frombits(uvnan) } 17 | 18 | // IsNaN reports whether f is an IEEE 754 ``not-a-number'' value. 19 | func IsNaN(f float32) (is bool) { 20 | return f != f 21 | } 22 | 23 | func feq(a, b float32) bool { 24 | if IsNaN(a) && IsNaN(b) { 25 | return true 26 | } 27 | return a == b 28 | } 29 | 30 | // https://github.com/evanphx/ulysses-libc/blob/master/src/math/fmaxf.c 31 | func fmaxf(a float32, b float32) float32 { 32 | if IsNaN(a) { 33 | return b 34 | } 35 | if IsNaN(b) { 36 | return a 37 | } 38 | // TODO: signed zeros 39 | if a > b { 40 | return a 41 | } 42 | return b 43 | } 44 | 45 | // https://github.com/evanphx/ulysses-libc/blob/master/src/math/fminf.c 46 | func fminf(a float32, b float32) float32 { 47 | if IsNaN(a) { 48 | return b 49 | } 50 | if IsNaN(b) { 51 | return a 52 | } 53 | // TODO: signed zeros 54 | if a < b { 55 | return a 56 | } 57 | return b 58 | } 59 | 60 | func fabs(x float32) float32 { 61 | switch { 62 | case x < 0: 63 | return -x 64 | case x == 0: 65 | return 0 // return correctly abs(-0) 66 | } 67 | return x 68 | } 69 | 70 | func fmodf(x, y float32) float32 { 71 | res := math.Mod(float64(x), float64(y)) 72 | return float32(res) 73 | } 74 | -------------------------------------------------------------------------------- /math_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestNaN(t *testing.T) { 10 | isNan := IsNaN(NAN) 11 | assert.True(t, isNan) 12 | isNan = IsNaN(5) 13 | assert.False(t, isNan) 14 | } 15 | -------------------------------------------------------------------------------- /measure_cache_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func measureMax(node *Node, width float32, widthMode MeasureMode, height float32, heightMode MeasureMode) Size { 10 | measureCount := node.Context.(int) 11 | measureCount++ 12 | node.Context = measureCount 13 | 14 | if widthMode == MeasureModeUndefined { 15 | width = 10 16 | } 17 | if heightMode == MeasureModeUndefined { 18 | height = 10 19 | } 20 | return Size{ 21 | Width: width, 22 | Height: height, 23 | } 24 | } 25 | 26 | func measureMin(node *Node, width float32, widthMode MeasureMode, height float32, heightMode MeasureMode) Size { 27 | measureCount := node.Context.(int) 28 | measureCount++ 29 | node.Context = measureCount 30 | 31 | if widthMode == MeasureModeUndefined || (widthMode == MeasureModeAtMost && width > 10) { 32 | width = 10 33 | } 34 | if heightMode == MeasureModeUndefined || (heightMode == MeasureModeAtMost && height > 10) { 35 | height = 10 36 | } 37 | return Size{ 38 | Width: width, 39 | Height: height, 40 | } 41 | } 42 | 43 | func measure8449(node *Node, width float32, widthMode MeasureMode, height float32, heightMode MeasureMode) Size { 44 | measureCount, ok := node.Context.(int) 45 | if ok { 46 | measureCount++ 47 | node.Context = measureCount 48 | } 49 | 50 | return Size{ 51 | Width: 84, 52 | Height: 49, 53 | } 54 | } 55 | 56 | func TestMeasure_once_single_flexible_child(t *testing.T) { 57 | root := NewNode() 58 | root.StyleSetFlexDirection(FlexDirectionRow) 59 | root.StyleSetAlignItems(AlignFlexStart) 60 | root.StyleSetWidth(100) 61 | root.StyleSetHeight(100) 62 | 63 | rootChild0 := NewNode() 64 | measureCount := 0 65 | rootChild0.Context = measureCount 66 | rootChild0.SetMeasureFunc(measureMax) 67 | rootChild0.StyleSetFlexGrow(1) 68 | root.InsertChild(rootChild0, 0) 69 | 70 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 71 | 72 | measureCount = rootChild0.Context.(int) 73 | assert.Equal(t, 1, measureCount) 74 | 75 | } 76 | 77 | func TestRemeasure_with_same_exact_width_larger_than_needed_height(t *testing.T) { 78 | root := NewNode() 79 | 80 | rootChild0 := NewNode() 81 | measureCount := 0 82 | rootChild0.Context = measureCount 83 | rootChild0.SetMeasureFunc(measureMin) 84 | root.InsertChild(rootChild0, 0) 85 | 86 | CalculateLayout(root, 100, 100, DirectionLTR) 87 | CalculateLayout(root, 100, 50, DirectionLTR) 88 | 89 | measureCount = rootChild0.Context.(int) 90 | assert.Equal(t, 1, measureCount) 91 | 92 | } 93 | 94 | func TestRemeasure_with_same_atmost_width_larger_than_needed_height(t *testing.T) { 95 | root := NewNode() 96 | root.StyleSetAlignItems(AlignFlexStart) 97 | 98 | rootChild0 := NewNode() 99 | measureCount := 0 100 | rootChild0.Context = measureCount 101 | rootChild0.SetMeasureFunc(measureMin) 102 | root.InsertChild(rootChild0, 0) 103 | 104 | CalculateLayout(root, 100, 100, DirectionLTR) 105 | CalculateLayout(root, 100, 50, DirectionLTR) 106 | 107 | measureCount = rootChild0.Context.(int) 108 | assert.Equal(t, 1, measureCount) 109 | 110 | } 111 | 112 | func TestRemeasure_with_computed_width_larger_than_needed_height(t *testing.T) { 113 | root := NewNode() 114 | root.StyleSetAlignItems(AlignFlexStart) 115 | 116 | rootChild0 := NewNode() 117 | measureCount := 0 118 | rootChild0.Context = measureCount 119 | rootChild0.SetMeasureFunc(measureMin) 120 | root.InsertChild(rootChild0, 0) 121 | 122 | CalculateLayout(root, 100, 100, DirectionLTR) 123 | root.StyleSetAlignItems(AlignStretch) 124 | CalculateLayout(root, 10, 50, DirectionLTR) 125 | 126 | measureCount = rootChild0.Context.(int) 127 | assert.Equal(t, 1, measureCount) 128 | 129 | } 130 | 131 | func TestRemeasure_with_atmost_computed_width_undefined_height(t *testing.T) { 132 | root := NewNode() 133 | root.StyleSetAlignItems(AlignFlexStart) 134 | 135 | rootChild0 := NewNode() 136 | measureCount := 0 137 | rootChild0.Context = measureCount 138 | rootChild0.SetMeasureFunc(measureMin) 139 | root.InsertChild(rootChild0, 0) 140 | 141 | CalculateLayout(root, 100, Undefined, DirectionLTR) 142 | CalculateLayout(root, 10, Undefined, DirectionLTR) 143 | 144 | measureCount = rootChild0.Context.(int) 145 | assert.Equal(t, 1, measureCount) 146 | } 147 | 148 | func TestRemeasure_with_already_measured_value_smaller_but_still_float_equal(t *testing.T) { 149 | measureCount := 0 150 | 151 | root := NewNode() 152 | root.StyleSetWidth(288) 153 | root.StyleSetHeight(288) 154 | root.StyleSetFlexDirection(FlexDirectionRow) 155 | 156 | rootChild0 := NewNode() 157 | rootChild0.StyleSetPadding(EdgeAll, 2.88) 158 | rootChild0.StyleSetFlexDirection(FlexDirectionRow) 159 | root.InsertChild(rootChild0, 0) 160 | 161 | rootChild0Child0 := NewNode() 162 | rootChild0Child0.Context = measureCount 163 | rootChild0Child0.SetMeasureFunc(measure8449) 164 | rootChild0.InsertChild(rootChild0Child0, 0) 165 | 166 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 167 | 168 | measureCount = rootChild0Child0.Context.(int) 169 | assert.Equal(t, 1, measureCount) 170 | } 171 | -------------------------------------------------------------------------------- /measure_mode_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | type measureConstraint struct { 10 | width float32 11 | widthMode MeasureMode 12 | height float32 13 | heightMode MeasureMode 14 | } 15 | 16 | type measureConstraintList struct { 17 | length int 18 | constraints []measureConstraint 19 | } 20 | 21 | func _measure2(node *Node, 22 | width float32, 23 | widthMode MeasureMode, 24 | height float32, 25 | heightMode MeasureMode) Size { 26 | constraintList := node.Context.(*measureConstraintList) 27 | constraints := constraintList.constraints 28 | currentIndex := constraintList.length 29 | (&constraints[currentIndex]).width = width 30 | (&constraints[currentIndex]).widthMode = widthMode 31 | (&constraints[currentIndex]).height = height 32 | (&constraints[currentIndex]).heightMode = heightMode 33 | constraintList.length = currentIndex + 1 34 | 35 | if widthMode == MeasureModeUndefined { 36 | width = 10 37 | } 38 | 39 | if heightMode == MeasureModeUndefined { 40 | height = 10 41 | } else { 42 | height = width // TODO:: is it a bug in tests ? 43 | } 44 | return Size{ 45 | Width: width, 46 | Height: height, 47 | } 48 | } 49 | 50 | func TestExactly_measure_stretched_child_column(t *testing.T) { 51 | constraintList := measureConstraintList{ 52 | constraints: make([]measureConstraint, 10), 53 | } 54 | 55 | root := NewNode() 56 | root.StyleSetWidth(100) 57 | root.StyleSetHeight(100) 58 | 59 | rootChild0 := NewNode() 60 | rootChild0.Context = &constraintList 61 | rootChild0.SetMeasureFunc(_measure2) 62 | root.InsertChild(rootChild0, 0) 63 | 64 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 65 | 66 | assert.Equal(t, 1, constraintList.length) 67 | 68 | assertFloatEqual(t, 100, constraintList.constraints[0].width) 69 | assert.Equal(t, MeasureModeExactly, constraintList.constraints[0].widthMode) 70 | } 71 | 72 | func TestExactly_measure_stretched_child_row(t *testing.T) { 73 | constraintList := measureConstraintList{ 74 | constraints: make([]measureConstraint, 10), 75 | } 76 | 77 | root := NewNode() 78 | root.StyleSetFlexDirection(FlexDirectionRow) 79 | root.StyleSetWidth(100) 80 | root.StyleSetHeight(100) 81 | 82 | rootChild0 := NewNode() 83 | rootChild0.Context = &constraintList 84 | rootChild0.SetMeasureFunc(_measure2) 85 | root.InsertChild(rootChild0, 0) 86 | 87 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 88 | 89 | assert.Equal(t, 1, constraintList.length) 90 | 91 | assertFloatEqual(t, 100, constraintList.constraints[0].height) 92 | assert.Equal(t, MeasureModeExactly, constraintList.constraints[0].heightMode) 93 | } 94 | 95 | func TestAt_most_main_axis_column(t *testing.T) { 96 | constraintList := measureConstraintList{ 97 | constraints: make([]measureConstraint, 10), 98 | } 99 | 100 | root := NewNode() 101 | root.StyleSetWidth(100) 102 | root.StyleSetHeight(100) 103 | 104 | rootChild0 := NewNode() 105 | rootChild0.Context = &constraintList 106 | rootChild0.SetMeasureFunc(_measure2) 107 | root.InsertChild(rootChild0, 0) 108 | 109 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 110 | 111 | assert.Equal(t, 1, constraintList.length) 112 | 113 | assertFloatEqual(t, 100, constraintList.constraints[0].height) 114 | assert.Equal(t, MeasureModeAtMost, constraintList.constraints[0].heightMode) 115 | } 116 | 117 | func TestAt_most_cross_axis_column(t *testing.T) { 118 | constraintList := measureConstraintList{ 119 | constraints: make([]measureConstraint, 10), 120 | } 121 | 122 | root := NewNode() 123 | root.StyleSetAlignItems(AlignFlexStart) 124 | root.StyleSetWidth(100) 125 | root.StyleSetHeight(100) 126 | 127 | rootChild0 := NewNode() 128 | rootChild0.Context = &constraintList 129 | rootChild0.SetMeasureFunc(_measure2) 130 | root.InsertChild(rootChild0, 0) 131 | 132 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 133 | 134 | assert.Equal(t, 1, constraintList.length) 135 | 136 | assertFloatEqual(t, 100, constraintList.constraints[0].width) 137 | assert.Equal(t, MeasureModeAtMost, constraintList.constraints[0].widthMode) 138 | } 139 | 140 | func TestAt_most_main_axis_row(t *testing.T) { 141 | constraintList := measureConstraintList{ 142 | constraints: make([]measureConstraint, 10), 143 | } 144 | 145 | root := NewNode() 146 | root.StyleSetFlexDirection(FlexDirectionRow) 147 | root.StyleSetWidth(100) 148 | root.StyleSetHeight(100) 149 | 150 | rootChild0 := NewNode() 151 | rootChild0.Context = &constraintList 152 | rootChild0.SetMeasureFunc(_measure2) 153 | root.InsertChild(rootChild0, 0) 154 | 155 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 156 | 157 | assert.Equal(t, 1, constraintList.length) 158 | 159 | assertFloatEqual(t, 100, constraintList.constraints[0].width) 160 | assert.Equal(t, MeasureModeAtMost, constraintList.constraints[0].widthMode) 161 | } 162 | 163 | func TestAt_most_cross_axis_row(t *testing.T) { 164 | constraintList := measureConstraintList{ 165 | constraints: make([]measureConstraint, 10), 166 | } 167 | 168 | root := NewNode() 169 | root.StyleSetFlexDirection(FlexDirectionRow) 170 | root.StyleSetAlignItems(AlignFlexStart) 171 | root.StyleSetWidth(100) 172 | root.StyleSetHeight(100) 173 | 174 | rootChild0 := NewNode() 175 | rootChild0.Context = &constraintList 176 | rootChild0.SetMeasureFunc(_measure2) 177 | root.InsertChild(rootChild0, 0) 178 | 179 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 180 | 181 | assert.Equal(t, 1, constraintList.length) 182 | 183 | assertFloatEqual(t, 100, constraintList.constraints[0].height) 184 | assert.Equal(t, MeasureModeAtMost, constraintList.constraints[0].heightMode) 185 | } 186 | 187 | func TestFlex_child(t *testing.T) { 188 | constraintList := measureConstraintList{ 189 | constraints: make([]measureConstraint, 10), 190 | } 191 | 192 | root := NewNode() 193 | root.StyleSetHeight(100) 194 | 195 | rootChild0 := NewNode() 196 | rootChild0.StyleSetFlexGrow(1) 197 | rootChild0.Context = &constraintList 198 | rootChild0.SetMeasureFunc(_measure2) 199 | root.InsertChild(rootChild0, 0) 200 | 201 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 202 | 203 | assert.Equal(t, 2, constraintList.length) 204 | 205 | assertFloatEqual(t, 100, constraintList.constraints[0].height) 206 | assert.Equal(t, MeasureModeAtMost, constraintList.constraints[0].heightMode) 207 | 208 | assertFloatEqual(t, 100, constraintList.constraints[1].height) 209 | assert.Equal(t, MeasureModeExactly, constraintList.constraints[1].heightMode) 210 | } 211 | 212 | func TestFlex_child_with_flex_basis(t *testing.T) { 213 | constraintList := measureConstraintList{ 214 | constraints: make([]measureConstraint, 10), 215 | } 216 | 217 | root := NewNode() 218 | root.StyleSetHeight(100) 219 | 220 | rootChild0 := NewNode() 221 | rootChild0.StyleSetFlexGrow(1) 222 | rootChild0.StyleSetFlexBasis(0) 223 | rootChild0.Context = &constraintList 224 | rootChild0.SetMeasureFunc(_measure2) 225 | root.InsertChild(rootChild0, 0) 226 | 227 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 228 | 229 | assert.Equal(t, 1, constraintList.length) 230 | 231 | assertFloatEqual(t, 100, constraintList.constraints[0].height) 232 | assert.Equal(t, MeasureModeExactly, constraintList.constraints[0].heightMode) 233 | } 234 | 235 | func TestOverflow_scroll_column(t *testing.T) { 236 | constraintList := measureConstraintList{ 237 | constraints: make([]measureConstraint, 10), 238 | } 239 | 240 | root := NewNode() 241 | root.StyleSetAlignItems(AlignFlexStart) 242 | root.StyleSetOverflow(OverflowScroll) 243 | root.StyleSetHeight(100) 244 | root.StyleSetWidth(100) 245 | 246 | rootChild0 := NewNode() 247 | rootChild0.Context = &constraintList 248 | rootChild0.SetMeasureFunc(_measure2) 249 | root.InsertChild(rootChild0, 0) 250 | 251 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 252 | 253 | assert.Equal(t, 1, constraintList.length) 254 | 255 | assertFloatEqual(t, 100, constraintList.constraints[0].width) 256 | assert.Equal(t, MeasureModeAtMost, constraintList.constraints[0].widthMode) 257 | 258 | assert.True(t, FloatIsUndefined(constraintList.constraints[0].height)) 259 | assert.Equal(t, MeasureModeUndefined, constraintList.constraints[0].heightMode) 260 | } 261 | 262 | func TestOverflow_scroll_row(t *testing.T) { 263 | constraintList := measureConstraintList{ 264 | constraints: make([]measureConstraint, 10), 265 | } 266 | 267 | root := NewNode() 268 | root.StyleSetAlignItems(AlignFlexStart) 269 | root.StyleSetFlexDirection(FlexDirectionRow) 270 | root.StyleSetOverflow(OverflowScroll) 271 | root.StyleSetHeight(100) 272 | root.StyleSetWidth(100) 273 | 274 | rootChild0 := NewNode() 275 | rootChild0.Context = &constraintList 276 | rootChild0.SetMeasureFunc(_measure2) 277 | root.InsertChild(rootChild0, 0) 278 | 279 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 280 | 281 | assert.Equal(t, 1, constraintList.length) 282 | 283 | assert.True(t, FloatIsUndefined(constraintList.constraints[0].width)) 284 | assert.Equal(t, MeasureModeUndefined, constraintList.constraints[0].widthMode) 285 | 286 | assertFloatEqual(t, 100, constraintList.constraints[0].height) 287 | assert.Equal(t, MeasureModeAtMost, constraintList.constraints[0].heightMode) 288 | } 289 | -------------------------------------------------------------------------------- /measure_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func _measure3(node *Node, width float32, widthMode MeasureMode, height float32, heightMode MeasureMode) Size { 11 | measureCount, ok := node.Context.(*int) 12 | if ok { 13 | (*measureCount)++ 14 | } 15 | 16 | return Size{Width: 10, Height: 10} 17 | } 18 | 19 | func _simulate_wrapping_text(node *Node, width float32, widthMode MeasureMode, height float32, heightMode MeasureMode) Size { 20 | if widthMode == MeasureModeUndefined || width >= 68 { 21 | return Size{Width: 68, Height: 16} 22 | } 23 | 24 | return Size{Width: 50, Height: 32} 25 | } 26 | 27 | func _measure_assert_negative(node *Node, width float32, widthMode MeasureMode, height float32, heightMode MeasureMode) Size { 28 | if width < 0 { 29 | panic(fmt.Sprintf("width is %.2f and should be >= 0", width)) 30 | } 31 | if height < 0 { 32 | panic(fmt.Sprintf("height is %.2f should be >= 0, height", height)) 33 | } 34 | // EXPECT_GE(width, 0); 35 | //EXPECT_GE(height, 0); 36 | 37 | return Size{ 38 | Width: 0, Height: 0, 39 | } 40 | } 41 | 42 | func TestDont_measure_single_grow_shrink_child(t *testing.T) { 43 | root := NewNode() 44 | root.StyleSetWidth(100) 45 | root.StyleSetHeight(100) 46 | 47 | measureCount := 0 48 | 49 | rootChild0 := NewNode() 50 | rootChild0.Context = &measureCount 51 | rootChild0.SetMeasureFunc(_measure) 52 | rootChild0.StyleSetFlexGrow(1) 53 | rootChild0.StyleSetFlexShrink(1) 54 | root.InsertChild(rootChild0, 0) 55 | 56 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 57 | 58 | assert.Equal(t, 0, measureCount) 59 | } 60 | 61 | func TestMeasure_absolute_child_with_no_constraints(t *testing.T) { 62 | root := NewNode() 63 | 64 | rootChild0 := NewNode() 65 | root.InsertChild(rootChild0, 0) 66 | 67 | measureCount := 0 68 | 69 | rootChild0Child0 := NewNode() 70 | rootChild0Child0.StyleSetPositionType(PositionTypeAbsolute) 71 | rootChild0Child0.Context = &measureCount 72 | rootChild0Child0.SetMeasureFunc(_measure3) 73 | rootChild0.InsertChild(rootChild0Child0, 0) 74 | 75 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 76 | 77 | assert.Equal(t, 1, measureCount) 78 | } 79 | 80 | func TestDont_measure_when_min_equals_max(t *testing.T) { 81 | root := NewNode() 82 | root.StyleSetAlignItems(AlignFlexStart) 83 | root.StyleSetWidth(100) 84 | root.StyleSetHeight(100) 85 | 86 | measureCount := 0 87 | 88 | rootChild0 := NewNode() 89 | rootChild0.Context = &measureCount 90 | rootChild0.SetMeasureFunc(_measure3) 91 | rootChild0.StyleSetMinWidth(10) 92 | rootChild0.StyleSetMaxWidth(10) 93 | rootChild0.StyleSetMinHeight(10) 94 | rootChild0.StyleSetMaxHeight(10) 95 | root.InsertChild(rootChild0, 0) 96 | 97 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 98 | 99 | assert.Equal(t, 0, measureCount) 100 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 101 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 102 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 103 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 104 | } 105 | 106 | func TestDont_measure_when_min_equals_max_percentages(t *testing.T) { 107 | root := NewNode() 108 | root.StyleSetAlignItems(AlignFlexStart) 109 | root.StyleSetWidth(100) 110 | root.StyleSetHeight(100) 111 | 112 | measureCount := 0 113 | 114 | rootChild0 := NewNode() 115 | rootChild0.Context = &measureCount 116 | rootChild0.SetMeasureFunc(_measure3) 117 | rootChild0.StyleSetMinWidthPercent(10) 118 | rootChild0.StyleSetMaxWidthPercent(10) 119 | rootChild0.StyleSetMinHeightPercent(10) 120 | rootChild0.StyleSetMaxHeightPercent(10) 121 | root.InsertChild(rootChild0, 0) 122 | 123 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 124 | 125 | assert.Equal(t, 0, measureCount) 126 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 127 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 128 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 129 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 130 | } 131 | 132 | func TestDont_measure_when_min_equals_max_mixed_width_percent(t *testing.T) { 133 | root := NewNode() 134 | root.StyleSetAlignItems(AlignFlexStart) 135 | root.StyleSetWidth(100) 136 | root.StyleSetHeight(100) 137 | 138 | measureCount := 0 139 | 140 | rootChild0 := NewNode() 141 | rootChild0.Context = &measureCount 142 | rootChild0.SetMeasureFunc(_measure3) 143 | rootChild0.StyleSetMinWidthPercent(10) 144 | rootChild0.StyleSetMaxWidthPercent(10) 145 | rootChild0.StyleSetMinHeight(10) 146 | rootChild0.StyleSetMaxHeight(10) 147 | root.InsertChild(rootChild0, 0) 148 | 149 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 150 | 151 | assert.Equal(t, 0, measureCount) 152 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 153 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 154 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 155 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 156 | } 157 | 158 | func TestDont_measure_when_min_equals_max_mixed_height_percent(t *testing.T) { 159 | root := NewNode() 160 | root.StyleSetAlignItems(AlignFlexStart) 161 | root.StyleSetWidth(100) 162 | root.StyleSetHeight(100) 163 | 164 | measureCount := 0 165 | 166 | rootChild0 := NewNode() 167 | rootChild0.Context = &measureCount 168 | rootChild0.SetMeasureFunc(_measure3) 169 | rootChild0.StyleSetMinWidth(10) 170 | rootChild0.StyleSetMaxWidth(10) 171 | rootChild0.StyleSetMinHeightPercent(10) 172 | rootChild0.StyleSetMaxHeightPercent(10) 173 | root.InsertChild(rootChild0, 0) 174 | 175 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 176 | 177 | assert.Equal(t, 0, measureCount) 178 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 179 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 180 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 181 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 182 | } 183 | 184 | func TestMeasure_enough_size_should_be_in_single_line(t *testing.T) { 185 | root := NewNode() 186 | root.StyleSetWidth(100) 187 | 188 | rootChild0 := NewNode() 189 | rootChild0.StyleSetAlignSelf(AlignFlexStart) 190 | rootChild0.SetMeasureFunc(_simulate_wrapping_text) 191 | 192 | root.InsertChild(rootChild0, 0) 193 | 194 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 195 | 196 | assertFloatEqual(t, 68, rootChild0.LayoutGetWidth()) 197 | assertFloatEqual(t, 16, rootChild0.LayoutGetHeight()) 198 | } 199 | 200 | func TestMeasure_not_enough_size_should_wrap(t *testing.T) { 201 | root := NewNode() 202 | root.StyleSetWidth(55) 203 | 204 | rootChild0 := NewNode() 205 | rootChild0.StyleSetAlignSelf(AlignFlexStart) 206 | rootChild0.SetMeasureFunc(_simulate_wrapping_text) 207 | 208 | root.InsertChild(rootChild0, 0) 209 | 210 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 211 | 212 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 213 | assertFloatEqual(t, 32, rootChild0.LayoutGetHeight()) 214 | } 215 | 216 | func TestMeasure_zero_space_should_grow(t *testing.T) { 217 | root := NewNode() 218 | root.StyleSetHeight(200) 219 | root.StyleSetFlexDirection(FlexDirectionColumn) 220 | root.StyleSetFlexGrow(0) 221 | 222 | measureCount := 0 223 | 224 | rootChild0 := NewNode() 225 | rootChild0.StyleSetFlexDirection(FlexDirectionColumn) 226 | rootChild0.StyleSetPadding(EdgeAll, 100) 227 | rootChild0.Context = &measureCount 228 | rootChild0.SetMeasureFunc(_measure3) 229 | 230 | root.InsertChild(rootChild0, 0) 231 | 232 | CalculateLayout(root, 282, Undefined, DirectionLTR) 233 | 234 | assertFloatEqual(t, 282, rootChild0.LayoutGetWidth()) 235 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 236 | } 237 | 238 | func TestMeasure_flex_direction_row_and_padding(t *testing.T) { 239 | config := NewConfig() 240 | 241 | root := NewNodeWithConfig(config) 242 | root.StyleSetFlexDirection(FlexDirectionRow) 243 | root.StyleSetPadding(EdgeLeft, 25) 244 | root.StyleSetPadding(EdgeTop, 25) 245 | root.StyleSetPadding(EdgeRight, 25) 246 | root.StyleSetPadding(EdgeBottom, 25) 247 | root.StyleSetWidth(50) 248 | root.StyleSetHeight(50) 249 | 250 | rootChild0 := NewNodeWithConfig(config) 251 | rootChild0.SetMeasureFunc(_simulate_wrapping_text) 252 | root.InsertChild(rootChild0, 0) 253 | 254 | rootChild1 := NewNodeWithConfig(config) 255 | rootChild1.StyleSetWidth(5) 256 | rootChild1.StyleSetHeight(5) 257 | root.InsertChild(rootChild1, 1) 258 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 259 | 260 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 261 | assertFloatEqual(t, 0, root.LayoutGetTop()) 262 | assertFloatEqual(t, 50, root.LayoutGetWidth()) 263 | assertFloatEqual(t, 50, root.LayoutGetHeight()) 264 | 265 | assertFloatEqual(t, 25, rootChild0.LayoutGetLeft()) 266 | assertFloatEqual(t, 25, rootChild0.LayoutGetTop()) 267 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 268 | assertFloatEqual(t, 0, rootChild0.LayoutGetHeight()) 269 | 270 | assertFloatEqual(t, 75, rootChild1.LayoutGetLeft()) 271 | assertFloatEqual(t, 25, rootChild1.LayoutGetTop()) 272 | assertFloatEqual(t, 5, rootChild1.LayoutGetWidth()) 273 | assertFloatEqual(t, 5, rootChild1.LayoutGetHeight()) 274 | } 275 | 276 | func TestMeasure_flex_direction_column_and_padding(t *testing.T) { 277 | config := NewConfig() 278 | 279 | root := NewNodeWithConfig(config) 280 | root.StyleSetMargin(EdgeTop, 20) 281 | root.StyleSetPadding(EdgeAll, 25) 282 | root.StyleSetWidth(50) 283 | root.StyleSetHeight(50) 284 | 285 | rootChild0 := NewNodeWithConfig(config) 286 | rootChild0.SetMeasureFunc(_simulate_wrapping_text) 287 | root.InsertChild(rootChild0, 0) 288 | 289 | rootChild1 := NewNodeWithConfig(config) 290 | rootChild1.StyleSetWidth(5) 291 | rootChild1.StyleSetHeight(5) 292 | root.InsertChild(rootChild1, 1) 293 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 294 | 295 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 296 | assertFloatEqual(t, 20, root.LayoutGetTop()) 297 | assertFloatEqual(t, 50, root.LayoutGetWidth()) 298 | assertFloatEqual(t, 50, root.LayoutGetHeight()) 299 | 300 | assertFloatEqual(t, 25, rootChild0.LayoutGetLeft()) 301 | assertFloatEqual(t, 25, rootChild0.LayoutGetTop()) 302 | assertFloatEqual(t, 0, rootChild0.LayoutGetWidth()) 303 | assertFloatEqual(t, 32, rootChild0.LayoutGetHeight()) 304 | 305 | assertFloatEqual(t, 25, rootChild1.LayoutGetLeft()) 306 | assertFloatEqual(t, 57, rootChild1.LayoutGetTop()) 307 | assertFloatEqual(t, 5, rootChild1.LayoutGetWidth()) 308 | assertFloatEqual(t, 5, rootChild1.LayoutGetHeight()) 309 | } 310 | 311 | func TestMeasure_flex_direction_row_no_padding(t *testing.T) { 312 | config := NewConfig() 313 | 314 | root := NewNodeWithConfig(config) 315 | root.StyleSetFlexDirection(FlexDirectionRow) 316 | root.StyleSetMargin(EdgeTop, 20) 317 | root.StyleSetWidth(50) 318 | root.StyleSetHeight(50) 319 | 320 | rootChild0 := NewNodeWithConfig(config) 321 | rootChild0.SetMeasureFunc(_simulate_wrapping_text) 322 | root.InsertChild(rootChild0, 0) 323 | 324 | rootChild1 := NewNodeWithConfig(config) 325 | rootChild1.StyleSetWidth(5) 326 | rootChild1.StyleSetHeight(5) 327 | root.InsertChild(rootChild1, 1) 328 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 329 | 330 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 331 | assertFloatEqual(t, 20, root.LayoutGetTop()) 332 | assertFloatEqual(t, 50, root.LayoutGetWidth()) 333 | assertFloatEqual(t, 50, root.LayoutGetHeight()) 334 | 335 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 336 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 337 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 338 | assertFloatEqual(t, 50, rootChild0.LayoutGetHeight()) 339 | 340 | assertFloatEqual(t, 50, rootChild1.LayoutGetLeft()) 341 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 342 | assertFloatEqual(t, 5, rootChild1.LayoutGetWidth()) 343 | assertFloatEqual(t, 5, rootChild1.LayoutGetHeight()) 344 | } 345 | 346 | func TestMeasure_flex_direction_row_no_padding_align_items_flexstart(t *testing.T) { 347 | config := NewConfig() 348 | 349 | root := NewNodeWithConfig(config) 350 | root.StyleSetFlexDirection(FlexDirectionRow) 351 | root.StyleSetMargin(EdgeTop, 20) 352 | root.StyleSetWidth(50) 353 | root.StyleSetHeight(50) 354 | root.StyleSetAlignItems(AlignFlexStart) 355 | 356 | rootChild0 := NewNodeWithConfig(config) 357 | rootChild0.SetMeasureFunc(_simulate_wrapping_text) 358 | root.InsertChild(rootChild0, 0) 359 | 360 | rootChild1 := NewNodeWithConfig(config) 361 | rootChild1.StyleSetWidth(5) 362 | rootChild1.StyleSetHeight(5) 363 | root.InsertChild(rootChild1, 1) 364 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 365 | 366 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 367 | assertFloatEqual(t, 20, root.LayoutGetTop()) 368 | assertFloatEqual(t, 50, root.LayoutGetWidth()) 369 | assertFloatEqual(t, 50, root.LayoutGetHeight()) 370 | 371 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 372 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 373 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 374 | assertFloatEqual(t, 32, rootChild0.LayoutGetHeight()) 375 | 376 | assertFloatEqual(t, 50, rootChild1.LayoutGetLeft()) 377 | assertFloatEqual(t, 0, rootChild1.LayoutGetTop()) 378 | assertFloatEqual(t, 5, rootChild1.LayoutGetWidth()) 379 | assertFloatEqual(t, 5, rootChild1.LayoutGetHeight()) 380 | } 381 | 382 | func TestMeasure_with_fixed_size(t *testing.T) { 383 | config := NewConfig() 384 | 385 | root := NewNodeWithConfig(config) 386 | root.StyleSetMargin(EdgeTop, 20) 387 | root.StyleSetPadding(EdgeAll, 25) 388 | root.StyleSetWidth(50) 389 | root.StyleSetHeight(50) 390 | 391 | rootChild0 := NewNodeWithConfig(config) 392 | rootChild0.SetMeasureFunc(_simulate_wrapping_text) 393 | rootChild0.StyleSetWidth(10) 394 | rootChild0.StyleSetHeight(10) 395 | root.InsertChild(rootChild0, 0) 396 | 397 | rootChild1 := NewNodeWithConfig(config) 398 | rootChild1.StyleSetWidth(5) 399 | rootChild1.StyleSetHeight(5) 400 | root.InsertChild(rootChild1, 1) 401 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 402 | 403 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 404 | assertFloatEqual(t, 20, root.LayoutGetTop()) 405 | assertFloatEqual(t, 50, root.LayoutGetWidth()) 406 | assertFloatEqual(t, 50, root.LayoutGetHeight()) 407 | 408 | assertFloatEqual(t, 25, rootChild0.LayoutGetLeft()) 409 | assertFloatEqual(t, 25, rootChild0.LayoutGetTop()) 410 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 411 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 412 | 413 | assertFloatEqual(t, 25, rootChild1.LayoutGetLeft()) 414 | assertFloatEqual(t, 35, rootChild1.LayoutGetTop()) 415 | assertFloatEqual(t, 5, rootChild1.LayoutGetWidth()) 416 | assertFloatEqual(t, 5, rootChild1.LayoutGetHeight()) 417 | } 418 | 419 | func TestMeasure_with_flex_shrink(t *testing.T) { 420 | config := NewConfig() 421 | 422 | root := NewNodeWithConfig(config) 423 | root.StyleSetMargin(EdgeTop, 20) 424 | root.StyleSetPadding(EdgeAll, 25) 425 | root.StyleSetWidth(50) 426 | root.StyleSetHeight(50) 427 | 428 | rootChild0 := NewNodeWithConfig(config) 429 | rootChild0.SetMeasureFunc(_simulate_wrapping_text) 430 | rootChild0.StyleSetFlexShrink(1) 431 | root.InsertChild(rootChild0, 0) 432 | 433 | rootChild1 := NewNodeWithConfig(config) 434 | rootChild1.StyleSetWidth(5) 435 | rootChild1.StyleSetHeight(5) 436 | root.InsertChild(rootChild1, 1) 437 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 438 | 439 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 440 | assertFloatEqual(t, 20, root.LayoutGetTop()) 441 | assertFloatEqual(t, 50, root.LayoutGetWidth()) 442 | assertFloatEqual(t, 50, root.LayoutGetHeight()) 443 | 444 | assertFloatEqual(t, 25, rootChild0.LayoutGetLeft()) 445 | assertFloatEqual(t, 25, rootChild0.LayoutGetTop()) 446 | assertFloatEqual(t, 0, rootChild0.LayoutGetWidth()) 447 | assertFloatEqual(t, 0, rootChild0.LayoutGetHeight()) 448 | 449 | assertFloatEqual(t, 25, rootChild1.LayoutGetLeft()) 450 | assertFloatEqual(t, 25, rootChild1.LayoutGetTop()) 451 | assertFloatEqual(t, 5, rootChild1.LayoutGetWidth()) 452 | assertFloatEqual(t, 5, rootChild1.LayoutGetHeight()) 453 | } 454 | 455 | func TestMeasure_no_padding(t *testing.T) { 456 | config := NewConfig() 457 | 458 | root := NewNodeWithConfig(config) 459 | root.StyleSetMargin(EdgeTop, 20) 460 | root.StyleSetWidth(50) 461 | root.StyleSetHeight(50) 462 | 463 | rootChild0 := NewNodeWithConfig(config) 464 | rootChild0.SetMeasureFunc(_simulate_wrapping_text) 465 | rootChild0.StyleSetFlexShrink(1) 466 | root.InsertChild(rootChild0, 0) 467 | 468 | rootChild1 := NewNodeWithConfig(config) 469 | rootChild1.StyleSetWidth(5) 470 | rootChild1.StyleSetHeight(5) 471 | root.InsertChild(rootChild1, 1) 472 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 473 | 474 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 475 | assertFloatEqual(t, 20, root.LayoutGetTop()) 476 | assertFloatEqual(t, 50, root.LayoutGetWidth()) 477 | assertFloatEqual(t, 50, root.LayoutGetHeight()) 478 | 479 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 480 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 481 | assertFloatEqual(t, 50, rootChild0.LayoutGetWidth()) 482 | assertFloatEqual(t, 32, rootChild0.LayoutGetHeight()) 483 | 484 | assertFloatEqual(t, 0, rootChild1.LayoutGetLeft()) 485 | assertFloatEqual(t, 32, rootChild1.LayoutGetTop()) 486 | assertFloatEqual(t, 5, rootChild1.LayoutGetWidth()) 487 | assertFloatEqual(t, 5, rootChild1.LayoutGetHeight()) 488 | } 489 | 490 | /* 491 | #if GTEST_HAS_DEATH_TEST 492 | TEST(YogaDeathTest, cannot_add_child_to_node_with_measure_func) { 493 | root := YGNodeNew(); 494 | YGroot.SetMeasureFunc(_measure3); 495 | 496 | rootChild0 := YGNodeNew(); 497 | ASSERT_DEATH(YGroot.InsertChild(rootChild0, 0), "Cannot add child.*"); 498 | YGNodeFree(rootChild0); 499 | ; 500 | } 501 | 502 | TEST(YogaDeathTest, cannot_add_nonnull_measure_func_to_non_leaf_node) { 503 | root := YGNodeNew(); 504 | rootChild0 := YGNodeNew(); 505 | YGroot.InsertChild(rootChild0, 0); 506 | 507 | ASSERT_DEATH(YGroot.SetMeasureFunc(_measure3), "Cannot set measure function.*"); 508 | ; 509 | } 510 | #endif 511 | */ 512 | 513 | func TestCan_nullify_measure_func_on_any_node(t *testing.T) { 514 | root := NewNode() 515 | root.InsertChild(NewNode(), 0) 516 | 517 | root.SetMeasureFunc(nil) 518 | assert.True(t, root.Measure == nil) 519 | } 520 | 521 | func TestCant_call_negative_measure(t *testing.T) { 522 | config := NewConfig() 523 | 524 | root := NewNodeWithConfig(config) 525 | root.StyleSetFlexDirection(FlexDirectionColumn) 526 | root.StyleSetWidth(50) 527 | root.StyleSetHeight(10) 528 | 529 | rootChild0 := NewNodeWithConfig(config) 530 | rootChild0.SetMeasureFunc(_measure_assert_negative) 531 | rootChild0.StyleSetMargin(EdgeTop, 20) 532 | root.InsertChild(rootChild0, 0) 533 | 534 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 535 | } 536 | 537 | func TestCant_call_negative_measure_horizontal(t *testing.T) { 538 | config := NewConfig() 539 | 540 | root := NewNodeWithConfig(config) 541 | root.StyleSetFlexDirection(FlexDirectionRow) 542 | root.StyleSetWidth(10) 543 | root.StyleSetHeight(20) 544 | 545 | rootChild0 := NewNodeWithConfig(config) 546 | rootChild0.SetMeasureFunc(_measure_assert_negative) 547 | rootChild0.StyleSetMargin(EdgeStart, 20) 548 | root.InsertChild(rootChild0, 0) 549 | 550 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 551 | } 552 | -------------------------------------------------------------------------------- /node_child_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestReset_layout_when_child_removed(t *testing.T) { 10 | root := NewNode() 11 | 12 | rootChild0 := NewNode() 13 | rootChild0.StyleSetWidth(100) 14 | rootChild0.StyleSetHeight(100) 15 | root.InsertChild(rootChild0, 0) 16 | 17 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 18 | 19 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 20 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 21 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 22 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 23 | 24 | root.RemoveChild(rootChild0) 25 | 26 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 27 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 28 | assert.True(t, FloatIsUndefined(rootChild0.LayoutGetWidth())) 29 | assert.True(t, FloatIsUndefined(rootChild0.LayoutGetHeight())) 30 | } 31 | -------------------------------------------------------------------------------- /padding_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import "testing" 4 | 5 | func TestPadding_no_size(t *testing.T) { 6 | config := NewConfig() 7 | 8 | root := NewNodeWithConfig(config) 9 | root.StyleSetPadding(EdgeLeft, 10) 10 | root.StyleSetPadding(EdgeTop, 10) 11 | root.StyleSetPadding(EdgeRight, 10) 12 | root.StyleSetPadding(EdgeBottom, 10) 13 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 14 | 15 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 16 | assertFloatEqual(t, 0, root.LayoutGetTop()) 17 | assertFloatEqual(t, 20, root.LayoutGetWidth()) 18 | assertFloatEqual(t, 20, root.LayoutGetHeight()) 19 | 20 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 21 | 22 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 23 | assertFloatEqual(t, 0, root.LayoutGetTop()) 24 | assertFloatEqual(t, 20, root.LayoutGetWidth()) 25 | assertFloatEqual(t, 20, root.LayoutGetHeight()) 26 | } 27 | 28 | func TestPadding_container_match_child(t *testing.T) { 29 | config := NewConfig() 30 | 31 | root := NewNodeWithConfig(config) 32 | root.StyleSetPadding(EdgeLeft, 10) 33 | root.StyleSetPadding(EdgeTop, 10) 34 | root.StyleSetPadding(EdgeRight, 10) 35 | root.StyleSetPadding(EdgeBottom, 10) 36 | 37 | rootChild0 := NewNodeWithConfig(config) 38 | rootChild0.StyleSetWidth(10) 39 | rootChild0.StyleSetHeight(10) 40 | root.InsertChild(rootChild0, 0) 41 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 42 | 43 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 44 | assertFloatEqual(t, 0, root.LayoutGetTop()) 45 | assertFloatEqual(t, 30, root.LayoutGetWidth()) 46 | assertFloatEqual(t, 30, root.LayoutGetHeight()) 47 | 48 | assertFloatEqual(t, 10, rootChild0.LayoutGetLeft()) 49 | assertFloatEqual(t, 10, rootChild0.LayoutGetTop()) 50 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 51 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 52 | 53 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 54 | 55 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 56 | assertFloatEqual(t, 0, root.LayoutGetTop()) 57 | assertFloatEqual(t, 30, root.LayoutGetWidth()) 58 | assertFloatEqual(t, 30, root.LayoutGetHeight()) 59 | 60 | assertFloatEqual(t, 10, rootChild0.LayoutGetLeft()) 61 | assertFloatEqual(t, 10, rootChild0.LayoutGetTop()) 62 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 63 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 64 | } 65 | 66 | func TestPadding_flex_child(t *testing.T) { 67 | config := NewConfig() 68 | 69 | root := NewNodeWithConfig(config) 70 | root.StyleSetPadding(EdgeLeft, 10) 71 | root.StyleSetPadding(EdgeTop, 10) 72 | root.StyleSetPadding(EdgeRight, 10) 73 | root.StyleSetPadding(EdgeBottom, 10) 74 | root.StyleSetWidth(100) 75 | root.StyleSetHeight(100) 76 | 77 | rootChild0 := NewNodeWithConfig(config) 78 | rootChild0.StyleSetFlexGrow(1) 79 | rootChild0.StyleSetWidth(10) 80 | root.InsertChild(rootChild0, 0) 81 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 82 | 83 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 84 | assertFloatEqual(t, 0, root.LayoutGetTop()) 85 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 86 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 87 | 88 | assertFloatEqual(t, 10, rootChild0.LayoutGetLeft()) 89 | assertFloatEqual(t, 10, rootChild0.LayoutGetTop()) 90 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 91 | assertFloatEqual(t, 80, rootChild0.LayoutGetHeight()) 92 | 93 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 94 | 95 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 96 | assertFloatEqual(t, 0, root.LayoutGetTop()) 97 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 98 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 99 | 100 | assertFloatEqual(t, 80, rootChild0.LayoutGetLeft()) 101 | assertFloatEqual(t, 10, rootChild0.LayoutGetTop()) 102 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 103 | assertFloatEqual(t, 80, rootChild0.LayoutGetHeight()) 104 | } 105 | 106 | func TestPadding_stretch_child(t *testing.T) { 107 | config := NewConfig() 108 | 109 | root := NewNodeWithConfig(config) 110 | root.StyleSetPadding(EdgeLeft, 10) 111 | root.StyleSetPadding(EdgeTop, 10) 112 | root.StyleSetPadding(EdgeRight, 10) 113 | root.StyleSetPadding(EdgeBottom, 10) 114 | root.StyleSetWidth(100) 115 | root.StyleSetHeight(100) 116 | 117 | rootChild0 := NewNodeWithConfig(config) 118 | rootChild0.StyleSetHeight(10) 119 | root.InsertChild(rootChild0, 0) 120 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 121 | 122 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 123 | assertFloatEqual(t, 0, root.LayoutGetTop()) 124 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 125 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 126 | 127 | assertFloatEqual(t, 10, rootChild0.LayoutGetLeft()) 128 | assertFloatEqual(t, 10, rootChild0.LayoutGetTop()) 129 | assertFloatEqual(t, 80, rootChild0.LayoutGetWidth()) 130 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 131 | 132 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 133 | 134 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 135 | assertFloatEqual(t, 0, root.LayoutGetTop()) 136 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 137 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 138 | 139 | assertFloatEqual(t, 10, rootChild0.LayoutGetLeft()) 140 | assertFloatEqual(t, 10, rootChild0.LayoutGetTop()) 141 | assertFloatEqual(t, 80, rootChild0.LayoutGetWidth()) 142 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 143 | } 144 | 145 | func TestPadding_center_child(t *testing.T) { 146 | config := NewConfig() 147 | 148 | root := NewNodeWithConfig(config) 149 | root.StyleSetJustifyContent(JustifyCenter) 150 | root.StyleSetAlignItems(AlignCenter) 151 | root.StyleSetPadding(EdgeStart, 10) 152 | root.StyleSetPadding(EdgeEnd, 20) 153 | root.StyleSetPadding(EdgeBottom, 20) 154 | root.StyleSetWidth(100) 155 | root.StyleSetHeight(100) 156 | 157 | rootChild0 := NewNodeWithConfig(config) 158 | rootChild0.StyleSetWidth(10) 159 | rootChild0.StyleSetHeight(10) 160 | root.InsertChild(rootChild0, 0) 161 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 162 | 163 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 164 | assertFloatEqual(t, 0, root.LayoutGetTop()) 165 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 166 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 167 | 168 | assertFloatEqual(t, 40, rootChild0.LayoutGetLeft()) 169 | assertFloatEqual(t, 35, rootChild0.LayoutGetTop()) 170 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 171 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 172 | 173 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 174 | 175 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 176 | assertFloatEqual(t, 0, root.LayoutGetTop()) 177 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 178 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 179 | 180 | assertFloatEqual(t, 50, rootChild0.LayoutGetLeft()) 181 | assertFloatEqual(t, 35, rootChild0.LayoutGetTop()) 182 | assertFloatEqual(t, 10, rootChild0.LayoutGetWidth()) 183 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 184 | } 185 | 186 | func TestChild_with_padding_align_end(t *testing.T) { 187 | config := NewConfig() 188 | 189 | root := NewNodeWithConfig(config) 190 | root.StyleSetJustifyContent(JustifyFlexEnd) 191 | root.StyleSetAlignItems(AlignFlexEnd) 192 | root.StyleSetWidth(200) 193 | root.StyleSetHeight(200) 194 | 195 | rootChild0 := NewNodeWithConfig(config) 196 | rootChild0.StyleSetPadding(EdgeLeft, 20) 197 | rootChild0.StyleSetPadding(EdgeTop, 20) 198 | rootChild0.StyleSetPadding(EdgeRight, 20) 199 | rootChild0.StyleSetPadding(EdgeBottom, 20) 200 | rootChild0.StyleSetWidth(100) 201 | rootChild0.StyleSetHeight(100) 202 | root.InsertChild(rootChild0, 0) 203 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 204 | 205 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 206 | assertFloatEqual(t, 0, root.LayoutGetTop()) 207 | assertFloatEqual(t, 200, root.LayoutGetWidth()) 208 | assertFloatEqual(t, 200, root.LayoutGetHeight()) 209 | 210 | assertFloatEqual(t, 100, rootChild0.LayoutGetLeft()) 211 | assertFloatEqual(t, 100, rootChild0.LayoutGetTop()) 212 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 213 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 214 | 215 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 216 | 217 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 218 | assertFloatEqual(t, 0, root.LayoutGetTop()) 219 | assertFloatEqual(t, 200, root.LayoutGetWidth()) 220 | assertFloatEqual(t, 200, root.LayoutGetHeight()) 221 | 222 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 223 | assertFloatEqual(t, 100, rootChild0.LayoutGetTop()) 224 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 225 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 226 | } 227 | -------------------------------------------------------------------------------- /print.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | // NodePrinter node printer. 11 | type NodePrinter struct { 12 | writer io.Writer 13 | options PrintOptions 14 | } 15 | 16 | // NodePrint prints node to standard output. 17 | func NodePrint(node *Node, options PrintOptions) { 18 | printer := NewNodePrinter(os.Stdout, options) 19 | printer.Print(node) 20 | } 21 | 22 | // NewNodePrinter creates new node printer. 23 | func NewNodePrinter(writer io.Writer, options PrintOptions) *NodePrinter { 24 | return &NodePrinter{ 25 | writer: writer, 26 | options: options, 27 | } 28 | } 29 | 30 | // Print prints node. 31 | func (printer *NodePrinter) Print(node *Node) { 32 | printer.printNode(node, 0) 33 | } 34 | 35 | func (printer *NodePrinter) printNode(node *Node, level int) { 36 | printer.printIndent(level) 37 | printer.printf("
") 116 | 117 | childCount := len(node.Children) 118 | if printer.options&PrintOptionsChildren != 0 && childCount > 0 { 119 | for i := 0; i < childCount; i++ { 120 | printer.printf("\n") 121 | printer.printNode(node.Children[i], level+1) 122 | } 123 | printer.printIndent(level) 124 | printer.printf("\n") 125 | } 126 | if childCount != 0 { 127 | printer.printIndent(level) 128 | } 129 | printer.printf("
") 130 | } 131 | 132 | func (printer *NodePrinter) printEdges(node *Node, str string, edges []Value) { 133 | if fourValuesEqual(edges) { 134 | printer.printNumberIfNotZero(node, str, &edges[EdgeLeft]) 135 | // bugfix for issue #5 136 | // if we set EdgeAll, the values are 137 | // [{NaN 0} {NaN 0} {NaN 0} {NaN 0} {NaN 0} {NaN 0} {NaN 0} {NaN 0} {20 1}] 138 | // so EdgeLeft is not printed and we won't print padding 139 | // for simplicity, I assume that EdgeAll is exclusive with setting specific edges 140 | // so we can print both and only one should show up 141 | // C code has this bug: https://github.com/facebook/yoga/blob/26481a6553a33d9c005f2b8d24a7952fc58df32c/yoga/Yoga.c#L1036 142 | printer.printNumberIfNotZero(node, str, &edges[EdgeAll]) 143 | } else { 144 | for edge := EdgeLeft; edge < EdgeCount; edge++ { 145 | buf := fmt.Sprintf("%s-%s", str, EdgeToString(edge)) 146 | printer.printNumberIfNotZero(node, buf, &edges[edge]) 147 | } 148 | } 149 | } 150 | 151 | func (printer *NodePrinter) printEdgeIfNotUndefined(node *Node, str string, edges []Value, edge Edge) { 152 | printer.printNumberIfNotUndefined(node, str, computedEdgeValue(edges, edge, &ValueUndefined)) 153 | } 154 | 155 | func (printer *NodePrinter) printFloatIfNotUndefined(node *Node, str string, number float32) { 156 | if !FloatIsUndefined(number) { 157 | printer.printf("%s: %g; ", str, number) 158 | } 159 | } 160 | 161 | func (printer *NodePrinter) printNumberIfNotUndefined(node *Node, str string, number *Value) { 162 | if number.Unit != UnitUndefined { 163 | if number.Unit == UnitAuto { 164 | printer.printf("%s: auto; ", str) 165 | } else { 166 | unit := "%" 167 | 168 | if number.Unit == UnitPoint { 169 | unit = "px" 170 | } 171 | printer.printf("%s: %g%s; ", str, number.Value, unit) 172 | } 173 | } 174 | } 175 | 176 | func (printer *NodePrinter) printNumberIfNotAuto(node *Node, str string, number *Value) { 177 | if number.Unit != UnitAuto { 178 | printer.printNumberIfNotUndefined(node, str, number) 179 | } 180 | } 181 | 182 | func (printer *NodePrinter) printNumberIfNotZero(node *Node, str string, number *Value) { 183 | if !FloatsEqual(number.Value, 0) { 184 | printer.printNumberIfNotUndefined(node, str, number) 185 | } 186 | } 187 | 188 | func (printer *NodePrinter) printf(format string, args ...interface{}) { 189 | fmt.Fprintf(printer.writer, format, args...) 190 | } 191 | 192 | func (printer *NodePrinter) printIndent(n int) { 193 | printer.writer.Write([]byte(strings.Repeat(" ", n))) 194 | } 195 | 196 | func fourValuesEqual(four []Value) bool { 197 | return ValueEqual(four[0], four[1]) && ValueEqual(four[0], four[2]) && 198 | ValueEqual(four[0], four[3]) 199 | } 200 | -------------------------------------------------------------------------------- /relayout_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import "testing" 4 | 5 | func TestDont_cache_computed_flex_basis_between_layouts(t *testing.T) { 6 | config := NewConfig() 7 | config.SetExperimentalFeatureEnabled(ExperimentalFeatureWebFlexBasis, true) 8 | 9 | root := NewNodeWithConfig(config) 10 | root.StyleSetHeightPercent(100) 11 | root.StyleSetWidthPercent(100) 12 | 13 | rootChild0 := NewNodeWithConfig(config) 14 | rootChild0.StyleSetFlexBasisPercent(100) 15 | root.InsertChild(rootChild0, 0) 16 | 17 | CalculateLayout(root, 100, Undefined, DirectionLTR) 18 | CalculateLayout(root, 100, 100, DirectionLTR) 19 | 20 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 21 | } 22 | 23 | func TestRecalculate_resolvedDimonsion_onchange(t *testing.T) { 24 | root := NewNode() 25 | 26 | rootChild0 := NewNode() 27 | rootChild0.StyleSetMinHeight(10) 28 | rootChild0.StyleSetMaxHeight(10) 29 | root.InsertChild(rootChild0, 0) 30 | 31 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 32 | assertFloatEqual(t, 10, rootChild0.LayoutGetHeight()) 33 | 34 | rootChild0.StyleSetMinHeight(Undefined) 35 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 36 | 37 | assertFloatEqual(t, 0, rootChild0.LayoutGetHeight()) 38 | } 39 | -------------------------------------------------------------------------------- /rounding_function_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import "testing" 4 | 5 | func TestRounding_value(t *testing.T) { 6 | 7 | // Test that whole numbers are rounded to whole despite ceil/floor flags 8 | assertFloatEqual(t, 6.0, roundValueToPixelGrid(6.000001, 2.0, false, false)) 9 | assertFloatEqual(t, 6.0, roundValueToPixelGrid(6.000001, 2.0, true, false)) 10 | assertFloatEqual(t, 6.0, roundValueToPixelGrid(6.000001, 2.0, false, true)) 11 | assertFloatEqual(t, 6.0, roundValueToPixelGrid(5.999999, 2.0, false, false)) 12 | assertFloatEqual(t, 6.0, roundValueToPixelGrid(5.999999, 2.0, true, false)) 13 | assertFloatEqual(t, 6.0, roundValueToPixelGrid(5.999999, 2.0, false, true)) 14 | 15 | // Test that numbers with fraction are rounded correctly accounting for ceil/floor flags 16 | assertFloatEqual(t, 6.0, roundValueToPixelGrid(6.01, 2.0, false, false)) 17 | assertFloatEqual(t, 6.5, roundValueToPixelGrid(6.01, 2.0, true, false)) 18 | assertFloatEqual(t, 6.0, roundValueToPixelGrid(6.01, 2.0, false, true)) 19 | assertFloatEqual(t, 6.0, roundValueToPixelGrid(5.99, 2.0, false, false)) 20 | assertFloatEqual(t, 6.0, roundValueToPixelGrid(5.99, 2.0, true, false)) 21 | assertFloatEqual(t, 5.5, roundValueToPixelGrid(5.99, 2.0, false, true)) 22 | } 23 | -------------------------------------------------------------------------------- /rounding_measure_func_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import "testing" 4 | 5 | func _measureFloor(node *Node, width float32, widthMode MeasureMode, height float32, heightMode MeasureMode) Size { 6 | return Size{ 7 | Width: 10.2, Height: 10.2, 8 | } 9 | } 10 | 11 | func _measureCeil(node *Node, width float32, widthMode MeasureMode, height float32, heightMode MeasureMode) Size { 12 | return Size{ 13 | Width: 10.5, Height: 10.5, 14 | } 15 | } 16 | 17 | func _measureFractial(node *Node, width float32, widthMode MeasureMode, height float32, heightMode MeasureMode) Size { 18 | return Size{ 19 | Width: 0.5, Height: 0.5, 20 | } 21 | } 22 | 23 | func TestRounding_feature_with_custom_measure_func_floor(t *testing.T) { 24 | config := NewConfig() 25 | root := NewNodeWithConfig(config) 26 | 27 | rootChild0 := NewNodeWithConfig(config) 28 | rootChild0.SetMeasureFunc(_measureFloor) 29 | root.InsertChild(rootChild0, 0) 30 | 31 | config.SetPointScaleFactor(0) 32 | 33 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 34 | 35 | assertFloatEqual(t, 10.2, rootChild0.LayoutGetWidth()) 36 | assertFloatEqual(t, 10.2, rootChild0.LayoutGetHeight()) 37 | 38 | config.SetPointScaleFactor(1) 39 | 40 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 41 | 42 | assertFloatEqual(t, 11, rootChild0.LayoutGetWidth()) 43 | assertFloatEqual(t, 11, rootChild0.LayoutGetHeight()) 44 | 45 | config.SetPointScaleFactor(2) 46 | 47 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 48 | 49 | assertFloatEqual(t, 10.5, rootChild0.LayoutGetWidth()) 50 | assertFloatEqual(t, 10.5, rootChild0.LayoutGetHeight()) 51 | 52 | config.SetPointScaleFactor(4) 53 | 54 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 55 | 56 | assertFloatEqual(t, 10.25, rootChild0.LayoutGetWidth()) 57 | assertFloatEqual(t, 10.25, rootChild0.LayoutGetHeight()) 58 | 59 | config.SetPointScaleFactor(float32(1) / float32(3)) 60 | 61 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 62 | 63 | assertFloatEqual(t, 12.0, rootChild0.LayoutGetWidth()) 64 | assertFloatEqual(t, 12.0, rootChild0.LayoutGetHeight()) 65 | } 66 | 67 | func TestRounding_feature_with_custom_measure_func_ceil(t *testing.T) { 68 | config := NewConfig() 69 | root := NewNodeWithConfig(config) 70 | 71 | rootChild0 := NewNodeWithConfig(config) 72 | rootChild0.SetMeasureFunc(_measureCeil) 73 | root.InsertChild(rootChild0, 0) 74 | 75 | config.SetPointScaleFactor(1) 76 | 77 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 78 | 79 | assertFloatEqual(t, 11, rootChild0.LayoutGetWidth()) 80 | assertFloatEqual(t, 11, rootChild0.LayoutGetHeight()) 81 | } 82 | 83 | func TestRounding_feature_with_custom_measure_and_fractial_matching_scale(t *testing.T) { 84 | config := NewConfig() 85 | root := NewNodeWithConfig(config) 86 | 87 | rootChild0 := NewNodeWithConfig(config) 88 | rootChild0.StyleSetPosition(EdgeLeft, 73.625) 89 | rootChild0.SetMeasureFunc(_measureFractial) 90 | root.InsertChild(rootChild0, 0) 91 | 92 | config.SetPointScaleFactor(2) 93 | 94 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 95 | 96 | assertFloatEqual(t, 0.5, rootChild0.LayoutGetWidth()) 97 | assertFloatEqual(t, 0.5, rootChild0.LayoutGetHeight()) 98 | assertFloatEqual(t, 73.5, rootChild0.LayoutGetLeft()) 99 | } 100 | -------------------------------------------------------------------------------- /size_overflow_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import "testing" 4 | 5 | func TestNested_overflowing_child(t *testing.T) { 6 | config := NewConfig() 7 | 8 | root := NewNodeWithConfig(config) 9 | root.StyleSetWidth(100) 10 | root.StyleSetHeight(100) 11 | 12 | rootChild0 := NewNodeWithConfig(config) 13 | root.InsertChild(rootChild0, 0) 14 | 15 | rootChild0Child0 := NewNodeWithConfig(config) 16 | rootChild0Child0.StyleSetWidth(200) 17 | rootChild0Child0.StyleSetHeight(200) 18 | rootChild0.InsertChild(rootChild0Child0, 0) 19 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 20 | 21 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 22 | assertFloatEqual(t, 0, root.LayoutGetTop()) 23 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 24 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 25 | 26 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 27 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 28 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 29 | assertFloatEqual(t, 200, rootChild0.LayoutGetHeight()) 30 | 31 | assertFloatEqual(t, 0, rootChild0Child0.LayoutGetLeft()) 32 | assertFloatEqual(t, 0, rootChild0Child0.LayoutGetTop()) 33 | assertFloatEqual(t, 200, rootChild0Child0.LayoutGetWidth()) 34 | assertFloatEqual(t, 200, rootChild0Child0.LayoutGetHeight()) 35 | 36 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 37 | 38 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 39 | assertFloatEqual(t, 0, root.LayoutGetTop()) 40 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 41 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 42 | 43 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 44 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 45 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 46 | assertFloatEqual(t, 200, rootChild0.LayoutGetHeight()) 47 | 48 | assertFloatEqual(t, -100, rootChild0Child0.LayoutGetLeft()) 49 | assertFloatEqual(t, 0, rootChild0Child0.LayoutGetTop()) 50 | assertFloatEqual(t, 200, rootChild0Child0.LayoutGetWidth()) 51 | assertFloatEqual(t, 200, rootChild0Child0.LayoutGetHeight()) 52 | } 53 | 54 | func TestNested_overflowing_child_in_constraint_parent(t *testing.T) { 55 | config := NewConfig() 56 | 57 | root := NewNodeWithConfig(config) 58 | root.StyleSetWidth(100) 59 | root.StyleSetHeight(100) 60 | 61 | rootChild0 := NewNodeWithConfig(config) 62 | rootChild0.StyleSetWidth(100) 63 | rootChild0.StyleSetHeight(100) 64 | root.InsertChild(rootChild0, 0) 65 | 66 | rootChild0Child0 := NewNodeWithConfig(config) 67 | rootChild0Child0.StyleSetWidth(200) 68 | rootChild0Child0.StyleSetHeight(200) 69 | rootChild0.InsertChild(rootChild0Child0, 0) 70 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 71 | 72 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 73 | assertFloatEqual(t, 0, root.LayoutGetTop()) 74 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 75 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 76 | 77 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 78 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 79 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 80 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 81 | 82 | assertFloatEqual(t, 0, rootChild0Child0.LayoutGetLeft()) 83 | assertFloatEqual(t, 0, rootChild0Child0.LayoutGetTop()) 84 | assertFloatEqual(t, 200, rootChild0Child0.LayoutGetWidth()) 85 | assertFloatEqual(t, 200, rootChild0Child0.LayoutGetHeight()) 86 | 87 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 88 | 89 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 90 | assertFloatEqual(t, 0, root.LayoutGetTop()) 91 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 92 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 93 | 94 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 95 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 96 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 97 | assertFloatEqual(t, 100, rootChild0.LayoutGetHeight()) 98 | 99 | assertFloatEqual(t, -100, rootChild0Child0.LayoutGetLeft()) 100 | assertFloatEqual(t, 0, rootChild0Child0.LayoutGetTop()) 101 | assertFloatEqual(t, 200, rootChild0Child0.LayoutGetWidth()) 102 | assertFloatEqual(t, 200, rootChild0Child0.LayoutGetHeight()) 103 | } 104 | 105 | func TestParent_wrap_child_size_overflowing_parent(t *testing.T) { 106 | config := NewConfig() 107 | 108 | root := NewNodeWithConfig(config) 109 | root.StyleSetWidth(100) 110 | root.StyleSetHeight(100) 111 | 112 | rootChild0 := NewNodeWithConfig(config) 113 | rootChild0.StyleSetWidth(100) 114 | root.InsertChild(rootChild0, 0) 115 | 116 | rootChild0Child0 := NewNodeWithConfig(config) 117 | rootChild0Child0.StyleSetWidth(100) 118 | rootChild0Child0.StyleSetHeight(200) 119 | rootChild0.InsertChild(rootChild0Child0, 0) 120 | CalculateLayout(root, Undefined, Undefined, DirectionLTR) 121 | 122 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 123 | assertFloatEqual(t, 0, root.LayoutGetTop()) 124 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 125 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 126 | 127 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 128 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 129 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 130 | assertFloatEqual(t, 200, rootChild0.LayoutGetHeight()) 131 | 132 | assertFloatEqual(t, 0, rootChild0Child0.LayoutGetLeft()) 133 | assertFloatEqual(t, 0, rootChild0Child0.LayoutGetTop()) 134 | assertFloatEqual(t, 100, rootChild0Child0.LayoutGetWidth()) 135 | assertFloatEqual(t, 200, rootChild0Child0.LayoutGetHeight()) 136 | 137 | CalculateLayout(root, Undefined, Undefined, DirectionRTL) 138 | 139 | assertFloatEqual(t, 0, root.LayoutGetLeft()) 140 | assertFloatEqual(t, 0, root.LayoutGetTop()) 141 | assertFloatEqual(t, 100, root.LayoutGetWidth()) 142 | assertFloatEqual(t, 100, root.LayoutGetHeight()) 143 | 144 | assertFloatEqual(t, 0, rootChild0.LayoutGetLeft()) 145 | assertFloatEqual(t, 0, rootChild0.LayoutGetTop()) 146 | assertFloatEqual(t, 100, rootChild0.LayoutGetWidth()) 147 | assertFloatEqual(t, 200, rootChild0.LayoutGetHeight()) 148 | 149 | assertFloatEqual(t, 0, rootChild0Child0.LayoutGetLeft()) 150 | assertFloatEqual(t, 0, rootChild0Child0.LayoutGetTop()) 151 | assertFloatEqual(t, 100, rootChild0Child0.LayoutGetWidth()) 152 | assertFloatEqual(t, 200, rootChild0Child0.LayoutGetHeight()) 153 | } 154 | -------------------------------------------------------------------------------- /style_test.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestCopy_style_same(t *testing.T) { 10 | node0 := NewNode() 11 | node1 := NewNode() 12 | assert.False(t, node0.IsDirty) 13 | 14 | NodeCopyStyle(node0, node1) 15 | assert.False(t, node0.IsDirty) 16 | } 17 | 18 | func TestCopy_style_modified(t *testing.T) { 19 | node0 := NewNode() 20 | assert.False(t, node0.IsDirty) 21 | assert.Equal(t, FlexDirectionColumn, node0.Style.FlexDirection) 22 | assert.False(t, node0.StyleGetMaxHeight().Unit != UnitUndefined) 23 | 24 | node1 := NewNode() 25 | node1.StyleSetFlexDirection(FlexDirectionRow) 26 | node1.StyleSetMaxHeight(10) 27 | 28 | NodeCopyStyle(node0, node1) 29 | assert.True(t, node0.IsDirty) 30 | assert.Equal(t, FlexDirectionRow, node0.Style.FlexDirection) 31 | assertFloatEqual(t, 10, node0.StyleGetMaxHeight().Value) 32 | } 33 | 34 | func TestCopy_style_modified_same(t *testing.T) { 35 | node0 := NewNode() 36 | node0.StyleSetFlexDirection(FlexDirectionRow) 37 | node0.StyleSetMaxHeight(10) 38 | CalculateLayout(node0, Undefined, Undefined, DirectionLTR) 39 | assert.False(t, node0.IsDirty) 40 | 41 | node1 := NewNode() 42 | node1.StyleSetFlexDirection(FlexDirectionRow) 43 | node1.StyleSetMaxHeight(10) 44 | 45 | NodeCopyStyle(node0, node1) 46 | assert.False(t, node0.IsDirty) 47 | } 48 | -------------------------------------------------------------------------------- /yoga_h.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | var ( 4 | // Undefined defines undefined value 5 | Undefined = NAN 6 | ) 7 | 8 | // Size describes size 9 | type Size struct { 10 | Width float32 11 | Height float32 12 | } 13 | 14 | // Value describes value 15 | type Value struct { 16 | Value float32 17 | Unit Unit 18 | } 19 | 20 | var ( 21 | // ValueUndefined defines undefined YGValue 22 | ValueUndefined = Value{Undefined, UnitUndefined} 23 | // ValueAuto defines auto YGValue 24 | ValueAuto = Value{Undefined, UnitAuto} 25 | ) 26 | 27 | // MeasureFunc describes function for measuring 28 | type MeasureFunc func(node *Node, width float32, widthMode MeasureMode, height float32, heightMode MeasureMode) Size 29 | 30 | // BaselineFunc describes function for baseline 31 | type BaselineFunc func(node *Node, width float32, height float32) float32 32 | 33 | // PrintFunc defines function for printing 34 | type PrintFunc func(node *Node) 35 | 36 | // Logger defines logging function 37 | type Logger func(config *Config, node *Node, level LogLevel, format string, args ...interface{}) int 38 | -------------------------------------------------------------------------------- /yoga_props.go: -------------------------------------------------------------------------------- 1 | package flex 2 | 3 | /* 4 | 5 | Functions that get/set props, in C code generated from those C macros: 6 | 7 | YG_NODE_PROPERTY_IMPL(void *, Context, context, context); 8 | YG_NODE_PROPERTY_IMPL(YGPrintFunc, PrintFunc, printFunc, print); 9 | YG_NODE_PROPERTY_IMPL(bool, HasNewLayout, hasNewLayout, hasNewLayout); 10 | YG_NODE_PROPERTY_IMPL(YGNodeType, NodeType, nodeType, nodeType); 11 | 12 | YG_NODE_STYLE_PROPERTY_IMPL(YGDirection, Direction, direction, direction); 13 | YG_NODE_STYLE_PROPERTY_IMPL(YGFlexDirection, FlexDirection, flexDirection, flexDirection); 14 | YG_NODE_STYLE_PROPERTY_IMPL(YGJustify, JustifyContent, justifyContent, justifyContent); 15 | YG_NODE_STYLE_PROPERTY_IMPL(YGAlign, AlignContent, alignContent, alignContent); 16 | YG_NODE_STYLE_PROPERTY_IMPL(YGAlign, AlignItems, alignItems, alignItems); 17 | YG_NODE_STYLE_PROPERTY_IMPL(YGAlign, AlignSelf, alignSelf, alignSelf); 18 | YG_NODE_STYLE_PROPERTY_IMPL(YGPositionType, PositionType, positionType, positionType); 19 | YG_NODE_STYLE_PROPERTY_IMPL(YGWrap, FlexWrap, flexWrap, flexWrap); 20 | YG_NODE_STYLE_PROPERTY_IMPL(YGOverflow, Overflow, overflow, overflow); 21 | YG_NODE_STYLE_PROPERTY_IMPL(YGDisplay, Display, display, display); 22 | 23 | YG_NODE_STYLE_PROPERTY_IMPL(float, Flex, flex, flex); 24 | YG_NODE_STYLE_PROPERTY_SETTER_IMPL(float, FlexGrow, flexGrow, flexGrow); 25 | YG_NODE_STYLE_PROPERTY_SETTER_IMPL(float, FlexShrink, flexShrink, flexShrink); 26 | YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, FlexBasis, flexBasis, flexBasis); 27 | 28 | YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Position, position, position); 29 | YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Margin, margin, margin); 30 | YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Margin, margin); 31 | YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Padding, padding, padding); 32 | YG_NODE_STYLE_EDGE_PROPERTY_IMPL(float, Border, border, border); 33 | 34 | YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Width, width, dimensions[YGDimensionWidth]); 35 | YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Height, height, dimensions[YGDimensionHeight]); 36 | YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MinWidth, minWidth, minDimensions[YGDimensionWidth]); 37 | YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MinHeight, minHeight, minDimensions[YGDimensionHeight]); 38 | YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MaxWidth, maxWidth, maxDimensions[YGDimensionWidth]); 39 | YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MaxHeight, maxHeight, maxDimensions[YGDimensionHeight]); 40 | 41 | // Yoga specific properties, not compatible with flexbox specification 42 | YG_NODE_STYLE_PROPERTY_IMPL(float, AspectRatio, aspectRatio, aspectRatio); 43 | 44 | YG_NODE_LAYOUT_PROPERTY_IMPL(float, Left, position[YGEdgeLeft]); 45 | YG_NODE_LAYOUT_PROPERTY_IMPL(float, Top, position[YGEdgeTop]); 46 | YG_NODE_LAYOUT_PROPERTY_IMPL(float, Right, position[YGEdgeRight]); 47 | YG_NODE_LAYOUT_PROPERTY_IMPL(float, Bottom, position[YGEdgeBottom]); 48 | YG_NODE_LAYOUT_PROPERTY_IMPL(float, Width, dimensions[YGDimensionWidth]); 49 | YG_NODE_LAYOUT_PROPERTY_IMPL(float, Height, dimensions[YGDimensionHeight]); 50 | YG_NODE_LAYOUT_PROPERTY_IMPL(YGDirection, Direction, direction); 51 | YG_NODE_LAYOUT_PROPERTY_IMPL(bool, HadOverflow, hadOverflow); 52 | 53 | YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Margin, margin); 54 | YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Border, border); 55 | YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Padding, padding); 56 | */ 57 | 58 | // StyleSetWidth sets width 59 | func (node *Node) StyleSetWidth(width float32) { 60 | dim := &node.Style.Dimensions[DimensionWidth] 61 | if dim.Value != width || dim.Unit != UnitPoint { 62 | dim.Value = width 63 | dim.Unit = UnitPoint 64 | if FloatIsUndefined(width) { 65 | dim.Unit = UnitAuto 66 | } 67 | nodeMarkDirtyInternal(node) 68 | } 69 | } 70 | 71 | // StyleSetWidthPercent sets width percent 72 | func (node *Node) StyleSetWidthPercent(width float32) { 73 | dim := &node.Style.Dimensions[DimensionWidth] 74 | if dim.Value != width || dim.Unit != UnitPercent { 75 | dim.Value = width 76 | dim.Unit = UnitPercent 77 | if FloatIsUndefined(width) { 78 | dim.Unit = UnitAuto 79 | } 80 | nodeMarkDirtyInternal(node) 81 | } 82 | } 83 | 84 | // StyleSetWidthAuto sets width auto 85 | func (node *Node) StyleSetWidthAuto() { 86 | dim := &node.Style.Dimensions[DimensionWidth] 87 | if dim.Unit != UnitAuto { 88 | dim.Value = Undefined 89 | dim.Unit = UnitAuto 90 | nodeMarkDirtyInternal(node) 91 | } 92 | } 93 | 94 | // StyleGetWidth gets width 95 | func (node *Node) StyleGetWidth() Value { 96 | return node.Style.Dimensions[DimensionWidth] 97 | } 98 | 99 | // StyleSetHeight sets height 100 | func (node *Node) StyleSetHeight(height float32) { 101 | dim := &node.Style.Dimensions[DimensionHeight] 102 | if dim.Value != height || dim.Unit != UnitPoint { 103 | dim.Value = height 104 | dim.Unit = UnitPoint 105 | if FloatIsUndefined(height) { 106 | dim.Unit = UnitAuto 107 | } 108 | nodeMarkDirtyInternal(node) 109 | } 110 | } 111 | 112 | // StyleSetHeightPercent sets height percent 113 | func (node *Node) StyleSetHeightPercent(height float32) { 114 | dim := &node.Style.Dimensions[DimensionHeight] 115 | if dim.Value != height || dim.Unit != UnitPercent { 116 | dim.Value = height 117 | dim.Unit = UnitPercent 118 | if FloatIsUndefined(height) { 119 | dim.Unit = UnitAuto 120 | } 121 | nodeMarkDirtyInternal(node) 122 | } 123 | } 124 | 125 | // StyleSetHeightAuto sets height auto 126 | func (node *Node) StyleSetHeightAuto() { 127 | dim := &node.Style.Dimensions[DimensionHeight] 128 | if dim.Unit != UnitAuto { 129 | dim.Value = Undefined 130 | dim.Unit = UnitAuto 131 | nodeMarkDirtyInternal(node) 132 | } 133 | } 134 | 135 | // StyleGetHeight gets height 136 | func (node *Node) StyleGetHeight() Value { 137 | return node.Style.Dimensions[DimensionHeight] 138 | } 139 | 140 | // StyleSetPositionType sets position type 141 | func (node *Node) StyleSetPositionType(positionType PositionType) { 142 | if node.Style.PositionType != positionType { 143 | node.Style.PositionType = positionType 144 | nodeMarkDirtyInternal(node) 145 | } 146 | } 147 | 148 | // StyleSetPosition sets position 149 | func (node *Node) StyleSetPosition(edge Edge, position float32) { 150 | pos := &node.Style.Position[edge] 151 | if pos.Value != position || pos.Unit != UnitPoint { 152 | pos.Value = position 153 | pos.Unit = UnitPoint 154 | if FloatIsUndefined(position) { 155 | pos.Unit = UnitUndefined 156 | } 157 | nodeMarkDirtyInternal(node) 158 | } 159 | } 160 | 161 | // StyleSetPositionPercent sets position percent 162 | func (node *Node) StyleSetPositionPercent(edge Edge, position float32) { 163 | pos := &node.Style.Position[edge] 164 | if pos.Value != position || pos.Unit != UnitPercent { 165 | pos.Value = position 166 | pos.Unit = UnitPercent 167 | if FloatIsUndefined(position) { 168 | pos.Unit = UnitUndefined 169 | } 170 | nodeMarkDirtyInternal(node) 171 | } 172 | } 173 | 174 | // StyleGetPosition gets position 175 | func (node *Node) StyleGetPosition(edge Edge) Value { 176 | return node.Style.Position[edge] 177 | } 178 | 179 | // StyleSetDirection sets direction 180 | func (node *Node) StyleSetDirection(direction Direction) { 181 | if node.Style.Direction != direction { 182 | node.Style.Direction = direction 183 | nodeMarkDirtyInternal(node) 184 | } 185 | } 186 | 187 | // StyleSetFlexDirection sets flex directions 188 | func (node *Node) StyleSetFlexDirection(flexDirection FlexDirection) { 189 | if node.Style.FlexDirection != flexDirection { 190 | node.Style.FlexDirection = flexDirection 191 | nodeMarkDirtyInternal(node) 192 | } 193 | } 194 | 195 | // StyleSetJustifyContent sets justify content 196 | func (node *Node) StyleSetJustifyContent(justifyContent Justify) { 197 | if node.Style.JustifyContent != justifyContent { 198 | node.Style.JustifyContent = justifyContent 199 | nodeMarkDirtyInternal(node) 200 | } 201 | } 202 | 203 | // StyleSetAlignContent sets align content 204 | func (node *Node) StyleSetAlignContent(alignContent Align) { 205 | if node.Style.AlignContent != alignContent { 206 | node.Style.AlignContent = alignContent 207 | nodeMarkDirtyInternal(node) 208 | } 209 | } 210 | 211 | // StyleSetAlignItems sets align content 212 | func (node *Node) StyleSetAlignItems(alignItems Align) { 213 | if node.Style.AlignItems != alignItems { 214 | node.Style.AlignItems = alignItems 215 | nodeMarkDirtyInternal(node) 216 | } 217 | } 218 | 219 | // StyleSetAlignSelf sets align self 220 | func (node *Node) StyleSetAlignSelf(alignSelf Align) { 221 | if node.Style.AlignSelf != alignSelf { 222 | node.Style.AlignSelf = alignSelf 223 | nodeMarkDirtyInternal(node) 224 | } 225 | } 226 | 227 | // StyleSetFlexWrap sets flex wrap 228 | func (node *Node) StyleSetFlexWrap(flexWrap Wrap) { 229 | if node.Style.FlexWrap != flexWrap { 230 | node.Style.FlexWrap = flexWrap 231 | nodeMarkDirtyInternal(node) 232 | } 233 | } 234 | 235 | // StyleSetOverflow sets overflow 236 | func (node *Node) StyleSetOverflow(overflow Overflow) { 237 | if node.Style.Overflow != overflow { 238 | node.Style.Overflow = overflow 239 | nodeMarkDirtyInternal(node) 240 | } 241 | } 242 | 243 | // StyleSetDisplay sets display 244 | func (node *Node) StyleSetDisplay(display Display) { 245 | if node.Style.Display != display { 246 | node.Style.Display = display 247 | nodeMarkDirtyInternal(node) 248 | } 249 | } 250 | 251 | // StyleSetFlex sets flex 252 | func (node *Node) StyleSetFlex(flex float32) { 253 | if node.Style.Flex != flex { 254 | node.Style.Flex = flex 255 | nodeMarkDirtyInternal(node) 256 | } 257 | } 258 | 259 | // StyleSetFlexGrow sets flex grow 260 | func (node *Node) StyleSetFlexGrow(flexGrow float32) { 261 | if node.Style.FlexGrow != flexGrow { 262 | node.Style.FlexGrow = flexGrow 263 | nodeMarkDirtyInternal(node) 264 | } 265 | } 266 | 267 | // StyleSetFlexShrink sets flex shrink 268 | func (node *Node) StyleSetFlexShrink(flexShrink float32) { 269 | if node.Style.FlexShrink != flexShrink { 270 | node.Style.FlexShrink = flexShrink 271 | nodeMarkDirtyInternal(node) 272 | } 273 | } 274 | 275 | // StyleSetFlexBasis sets flex basis 276 | func (node *Node) StyleSetFlexBasis(flexBasis float32) { 277 | if node.Style.FlexBasis.Value != flexBasis || 278 | node.Style.FlexBasis.Unit != UnitPoint { 279 | node.Style.FlexBasis.Value = flexBasis 280 | node.Style.FlexBasis.Unit = UnitPoint 281 | if FloatIsUndefined(flexBasis) { 282 | node.Style.FlexBasis.Unit = UnitAuto 283 | } 284 | nodeMarkDirtyInternal(node) 285 | } 286 | } 287 | 288 | // StyleSetFlexBasisPercent sets flex basis percent 289 | func (node *Node) StyleSetFlexBasisPercent(flexBasis float32) { 290 | if node.Style.FlexBasis.Value != flexBasis || 291 | node.Style.FlexBasis.Unit != UnitPercent { 292 | node.Style.FlexBasis.Value = flexBasis 293 | node.Style.FlexBasis.Unit = UnitPercent 294 | if FloatIsUndefined(flexBasis) { 295 | node.Style.FlexBasis.Unit = UnitAuto 296 | } 297 | nodeMarkDirtyInternal(node) 298 | } 299 | } 300 | 301 | // NodeStyleSetFlexBasisAuto sets flex basis auto 302 | func NodeStyleSetFlexBasisAuto(node *Node) { 303 | if node.Style.FlexBasis.Unit != UnitAuto { 304 | node.Style.FlexBasis.Value = Undefined 305 | node.Style.FlexBasis.Unit = UnitAuto 306 | nodeMarkDirtyInternal(node) 307 | } 308 | } 309 | 310 | // StyleSetMargin sets margin 311 | func (node *Node) StyleSetMargin(edge Edge, margin float32) { 312 | if node.Style.Margin[edge].Value != margin || 313 | node.Style.Margin[edge].Unit != UnitPoint { 314 | node.Style.Margin[edge].Value = margin 315 | node.Style.Margin[edge].Unit = UnitPoint 316 | if FloatIsUndefined(margin) { 317 | node.Style.Margin[edge].Unit = UnitUndefined 318 | } 319 | nodeMarkDirtyInternal(node) 320 | } 321 | } 322 | 323 | // StyleSetMarginPercent sets margin percent 324 | func (node *Node) StyleSetMarginPercent(edge Edge, margin float32) { 325 | if node.Style.Margin[edge].Value != margin || 326 | node.Style.Margin[edge].Unit != UnitPercent { 327 | node.Style.Margin[edge].Value = margin 328 | node.Style.Margin[edge].Unit = UnitPercent 329 | if FloatIsUndefined(margin) { 330 | node.Style.Margin[edge].Unit = UnitUndefined 331 | } 332 | nodeMarkDirtyInternal(node) 333 | } 334 | } 335 | 336 | // StyleGetMargin gets margin 337 | func (node *Node) StyleGetMargin(edge Edge) Value { 338 | return node.Style.Margin[edge] 339 | } 340 | 341 | // StyleSetMarginAuto sets margin auto 342 | func (node *Node) StyleSetMarginAuto(edge Edge) { 343 | if node.Style.Margin[edge].Unit != UnitAuto { 344 | node.Style.Margin[edge].Value = Undefined 345 | node.Style.Margin[edge].Unit = UnitAuto 346 | nodeMarkDirtyInternal(node) 347 | } 348 | } 349 | 350 | // StyleSetPadding sets padding 351 | func (node *Node) StyleSetPadding(edge Edge, padding float32) { 352 | if node.Style.Padding[edge].Value != padding || 353 | node.Style.Padding[edge].Unit != UnitPoint { 354 | node.Style.Padding[edge].Value = padding 355 | node.Style.Padding[edge].Unit = UnitPoint 356 | if FloatIsUndefined(padding) { 357 | node.Style.Padding[edge].Unit = UnitUndefined 358 | } 359 | nodeMarkDirtyInternal(node) 360 | } 361 | } 362 | 363 | // StyleSetPaddingPercent sets padding percent 364 | func (node *Node) StyleSetPaddingPercent(edge Edge, padding float32) { 365 | if node.Style.Padding[edge].Value != padding || 366 | node.Style.Padding[edge].Unit != UnitPercent { 367 | node.Style.Padding[edge].Value = padding 368 | node.Style.Padding[edge].Unit = UnitPercent 369 | if FloatIsUndefined(padding) { 370 | node.Style.Padding[edge].Unit = UnitUndefined 371 | } 372 | nodeMarkDirtyInternal(node) 373 | } 374 | } 375 | 376 | // StyleGetPadding gets padding 377 | func (node *Node) StyleGetPadding(edge Edge) Value { 378 | return node.Style.Padding[edge] 379 | } 380 | 381 | // StyleSetBorder sets border 382 | func (node *Node) StyleSetBorder(edge Edge, border float32) { 383 | if node.Style.Border[edge].Value != border || 384 | node.Style.Border[edge].Unit != UnitPoint { 385 | node.Style.Border[edge].Value = border 386 | node.Style.Border[edge].Unit = UnitPoint 387 | if FloatIsUndefined(border) { 388 | node.Style.Border[edge].Unit = UnitUndefined 389 | } 390 | nodeMarkDirtyInternal(node) 391 | } 392 | } 393 | 394 | // StyleGetBorder gets border 395 | func (node *Node) StyleGetBorder(edge Edge) float32 { 396 | return node.Style.Border[edge].Value 397 | } 398 | 399 | // StyleSetMinWidth sets min width 400 | func (node *Node) StyleSetMinWidth(minWidth float32) { 401 | if node.Style.MinDimensions[DimensionWidth].Value != minWidth || 402 | node.Style.MinDimensions[DimensionWidth].Unit != UnitPoint { 403 | node.Style.MinDimensions[DimensionWidth].Value = minWidth 404 | node.Style.MinDimensions[DimensionWidth].Unit = UnitPoint 405 | if FloatIsUndefined(minWidth) { 406 | node.Style.MinDimensions[DimensionWidth].Unit = UnitAuto 407 | } 408 | nodeMarkDirtyInternal(node) 409 | } 410 | } 411 | 412 | // StyleSetMinWidthPercent sets width percent 413 | func (node *Node) StyleSetMinWidthPercent(minWidth float32) { 414 | if node.Style.MinDimensions[DimensionWidth].Value != minWidth || 415 | node.Style.MinDimensions[DimensionWidth].Unit != UnitPercent { 416 | node.Style.MinDimensions[DimensionWidth].Value = minWidth 417 | node.Style.MinDimensions[DimensionWidth].Unit = UnitPercent 418 | if FloatIsUndefined(minWidth) { 419 | node.Style.MinDimensions[DimensionWidth].Unit = UnitAuto 420 | } 421 | nodeMarkDirtyInternal(node) 422 | } 423 | } 424 | 425 | // StyleGetMinWidth gets min width 426 | func (node *Node) StyleGetMinWidth() Value { 427 | return node.Style.MinDimensions[DimensionWidth] 428 | } 429 | 430 | // StyleSetMinHeight sets min width 431 | func (node *Node) StyleSetMinHeight(minHeight float32) { 432 | if node.Style.MinDimensions[DimensionHeight].Value != minHeight || 433 | node.Style.MinDimensions[DimensionHeight].Unit != UnitPoint { 434 | node.Style.MinDimensions[DimensionHeight].Value = minHeight 435 | node.Style.MinDimensions[DimensionHeight].Unit = UnitPoint 436 | if FloatIsUndefined(minHeight) { 437 | node.Style.MinDimensions[DimensionHeight].Unit = UnitAuto 438 | } 439 | nodeMarkDirtyInternal(node) 440 | } 441 | } 442 | 443 | // StyleSetMinHeightPercent sets min height percent 444 | func (node *Node) StyleSetMinHeightPercent(minHeight float32) { 445 | if node.Style.MinDimensions[DimensionHeight].Value != minHeight || 446 | node.Style.MinDimensions[DimensionHeight].Unit != UnitPercent { 447 | node.Style.MinDimensions[DimensionHeight].Value = minHeight 448 | node.Style.MinDimensions[DimensionHeight].Unit = UnitPercent 449 | if FloatIsUndefined(minHeight) { 450 | node.Style.MinDimensions[DimensionHeight].Unit = UnitAuto 451 | } 452 | nodeMarkDirtyInternal(node) 453 | } 454 | } 455 | 456 | // StyleGetMinHeight gets min height 457 | func (node *Node) StyleGetMinHeight() Value { 458 | return node.Style.MinDimensions[DimensionHeight] 459 | } 460 | 461 | // StyleSetMaxWidth sets max width 462 | func (node *Node) StyleSetMaxWidth(maxWidth float32) { 463 | if node.Style.MaxDimensions[DimensionWidth].Value != maxWidth || 464 | node.Style.MaxDimensions[DimensionWidth].Unit != UnitPoint { 465 | node.Style.MaxDimensions[DimensionWidth].Value = maxWidth 466 | node.Style.MaxDimensions[DimensionWidth].Unit = UnitPoint 467 | if FloatIsUndefined(maxWidth) { 468 | node.Style.MaxDimensions[DimensionWidth].Unit = UnitAuto 469 | } 470 | nodeMarkDirtyInternal(node) 471 | } 472 | } 473 | 474 | // StyleSetMaxWidthPercent sets max width percent 475 | func (node *Node) StyleSetMaxWidthPercent(maxWidth float32) { 476 | if node.Style.MaxDimensions[DimensionWidth].Value != maxWidth || 477 | node.Style.MaxDimensions[DimensionWidth].Unit != UnitPercent { 478 | node.Style.MaxDimensions[DimensionWidth].Value = maxWidth 479 | node.Style.MaxDimensions[DimensionWidth].Unit = UnitPercent 480 | if FloatIsUndefined(maxWidth) { 481 | node.Style.MaxDimensions[DimensionWidth].Unit = UnitAuto 482 | } 483 | nodeMarkDirtyInternal(node) 484 | } 485 | } 486 | 487 | // StyleGetMaxWidth gets max width 488 | func (node *Node) StyleGetMaxWidth() Value { 489 | return node.Style.MaxDimensions[DimensionWidth] 490 | } 491 | 492 | // StyleSetMaxHeight sets max width 493 | func (node *Node) StyleSetMaxHeight(maxHeight float32) { 494 | if node.Style.MaxDimensions[DimensionHeight].Value != maxHeight || 495 | node.Style.MaxDimensions[DimensionHeight].Unit != UnitPoint { 496 | node.Style.MaxDimensions[DimensionHeight].Value = maxHeight 497 | node.Style.MaxDimensions[DimensionHeight].Unit = UnitPoint 498 | if FloatIsUndefined(maxHeight) { 499 | node.Style.MaxDimensions[DimensionHeight].Unit = UnitAuto 500 | } 501 | nodeMarkDirtyInternal(node) 502 | } 503 | } 504 | 505 | // StyleSetMaxHeightPercent sets max height percent 506 | func (node *Node) StyleSetMaxHeightPercent(maxHeight float32) { 507 | if node.Style.MaxDimensions[DimensionHeight].Value != maxHeight || 508 | node.Style.MaxDimensions[DimensionHeight].Unit != UnitPercent { 509 | node.Style.MaxDimensions[DimensionHeight].Value = maxHeight 510 | node.Style.MaxDimensions[DimensionHeight].Unit = UnitPercent 511 | if FloatIsUndefined(maxHeight) { 512 | node.Style.MaxDimensions[DimensionHeight].Unit = UnitAuto 513 | } 514 | nodeMarkDirtyInternal(node) 515 | } 516 | } 517 | 518 | // StyleGetMaxHeight gets max height 519 | func (node *Node) StyleGetMaxHeight() Value { 520 | return node.Style.MaxDimensions[DimensionHeight] 521 | } 522 | 523 | // StyleSetAspectRatio sets axpect ratio 524 | func (node *Node) StyleSetAspectRatio(aspectRatio float32) { 525 | if node.Style.AspectRatio != aspectRatio { 526 | node.Style.AspectRatio = aspectRatio 527 | nodeMarkDirtyInternal(node) 528 | } 529 | } 530 | 531 | // LayoutGetLeft gets left 532 | func (node *Node) LayoutGetLeft() float32 { 533 | return node.Layout.Position[EdgeLeft] 534 | } 535 | 536 | // LayoutGetTop gets top 537 | func (node *Node) LayoutGetTop() float32 { 538 | return node.Layout.Position[EdgeTop] 539 | } 540 | 541 | // LayoutGetRight gets right 542 | func (node *Node) LayoutGetRight() float32 { 543 | return node.Layout.Position[EdgeRight] 544 | } 545 | 546 | // LayoutGetBottom gets bottom 547 | func (node *Node) LayoutGetBottom() float32 { 548 | return node.Layout.Position[EdgeBottom] 549 | } 550 | 551 | // LayoutGetWidth gets width 552 | func (node *Node) LayoutGetWidth() float32 { 553 | return node.Layout.Dimensions[DimensionWidth] 554 | } 555 | 556 | // LayoutGetHeight gets height 557 | func (node *Node) LayoutGetHeight() float32 { 558 | return node.Layout.Dimensions[DimensionHeight] 559 | } 560 | 561 | // LayoutGetMargin gets margin 562 | func (node *Node) LayoutGetMargin(edge Edge) float32 { 563 | assertWithNode(node, edge < EdgeEnd, "Cannot get layout properties of multi-edge shorthands") 564 | if edge == EdgeLeft { 565 | if node.Layout.Direction == DirectionRTL { 566 | return node.Layout.Margin[EdgeEnd] 567 | } 568 | return node.Layout.Margin[EdgeStart] 569 | } 570 | if edge == EdgeRight { 571 | if node.Layout.Direction == DirectionRTL { 572 | return node.Layout.Margin[EdgeStart] 573 | } 574 | return node.Layout.Margin[EdgeEnd] 575 | } 576 | return node.Layout.Margin[edge] 577 | } 578 | 579 | // LayoutGetBorder gets border 580 | func (node *Node) LayoutGetBorder(edge Edge) float32 { 581 | assertWithNode(node, edge < EdgeEnd, 582 | "Cannot get layout properties of multi-edge shorthands") 583 | if edge == EdgeLeft { 584 | if node.Layout.Direction == DirectionRTL { 585 | return node.Layout.Border[EdgeEnd] 586 | } 587 | return node.Layout.Border[EdgeStart] 588 | } 589 | if edge == EdgeRight { 590 | if node.Layout.Direction == DirectionRTL { 591 | return node.Layout.Border[EdgeStart] 592 | } 593 | return node.Layout.Border[EdgeEnd] 594 | } 595 | return node.Layout.Border[edge] 596 | } 597 | 598 | // LayoutGetPadding gets padding 599 | func (node *Node) LayoutGetPadding(edge Edge) float32 { 600 | assertWithNode(node, edge < EdgeEnd, 601 | "Cannot get layout properties of multi-edge shorthands") 602 | if edge == EdgeLeft { 603 | if node.Layout.Direction == DirectionRTL { 604 | return node.Layout.Padding[EdgeEnd] 605 | } 606 | return node.Layout.Padding[EdgeStart] 607 | } 608 | if edge == EdgeRight { 609 | if node.Layout.Direction == DirectionRTL { 610 | return node.Layout.Padding[EdgeStart] 611 | } 612 | return node.Layout.Padding[EdgeEnd] 613 | } 614 | return node.Layout.Padding[edge] 615 | } 616 | --------------------------------------------------------------------------------