1 /** 2 Copyright: Copyright (c) 2013-2014 Andrey Penechko. 3 License: a$(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 7 module anchovy.gui.layouts.linearlayout; 8 9 import anchovy.gui; 10 11 public import anchovy.gui.interfaces.ilayout; 12 13 alias VerticalLayout = LinearLayout!true; 14 alias HorizontalLayout = LinearLayout!false; 15 16 //version = debug_linear; 17 18 class LinearLayout(bool vertical) : ILayout 19 { 20 21 override void minimize(Widget root) 22 { 23 Widget[] children = root.getPropertyAs!("children", Widget[]); 24 ivec2 rootSize = root.getPropertyAs!("size", ivec2); 25 int rootSpacing = root.coercePropertyAs!("spacing", int)(0); 26 int rootPadding = root.coercePropertyAs!("padding", int)(0); 27 28 int minRootWidth = int.min; // Will be max child width. Then padding will be added 29 int minRootLength = rootPadding * 2; 30 int childrenLength; 31 uint numExpandableChildren; 32 33 foreach(child; children) 34 { 35 ivec2 childSize = child.getPropertyAs!("prefSize", ivec2); 36 ivec2 childMinSize = child.getPropertyAs!("minSize", ivec2); 37 38 childrenLength += max(*sizeLength(childSize), *sizeLength(childMinSize)); 39 minRootWidth = max(max(*sizeWidth(childSize), minRootWidth), *sizeWidth(childMinSize)); 40 41 if (isExpandableLength(child)) ++numExpandableChildren; 42 } 43 44 minRootLength += (children.length-1) * rootSpacing; 45 minRootLength += childrenLength; 46 minRootWidth += rootPadding * 2; 47 48 version(debug_linear) 49 { 50 writeln("minRootLength ", minRootLength); 51 writeln("minRootWidth ", minRootWidth); 52 writeln("rootSize ", rootSize); 53 } 54 55 *sizeWidth(rootSize) = minRootWidth; 56 *sizeLength(rootSize) = minRootLength; 57 58 version(debug_linear) writeln("rootSize ", rootSize); 59 60 root.setProperty!("prefSize")(rootSize); 61 root.setProperty!("numExpandable")(numExpandableChildren); 62 63 version(debug_linear) writeln("linear minimize end\n"); 64 } 65 66 override void expand(Widget root) 67 { 68 Widget[] children = root.getPropertyAs!("children", Widget[]); 69 70 int rootSpacing = root.coercePropertyAs!("spacing", int)(0); 71 int rootPadding = root.coercePropertyAs!("padding", int)(0); 72 73 uint numExpandableChildren = root.getPropertyAs!("numExpandable", uint); 74 75 ivec2 rootSize = root.getPropertyAs!("size", ivec2); 76 ivec2 rootPrefSize = root.getPropertyAs!("prefSize", ivec2); 77 78 version(debug_linear) 79 { 80 writeln("Root: ", root["name"]); 81 writeln("rootSize ", rootSize); 82 writeln("rootPrefSize ", rootPrefSize); 83 } 84 85 int maxChildWidth = *sizeWidth(rootSize) - rootPadding * 2; 86 87 int extraLength = *sizeLength(rootSize) - *sizeLength(rootPrefSize); 88 int extraPerWidget = extraLength / cast(int)(numExpandableChildren > 0 ? numExpandableChildren : 1); 89 extraPerWidget = extraPerWidget > 0 ? extraPerWidget : 0; 90 91 version(debug_linear) 92 { 93 writeln("numChildren ", children.length); 94 writeln("numExpandableChildren ", numExpandableChildren); 95 writeln("extraPerWidget ", extraPerWidget); 96 writeln("extraLength ", extraLength); 97 writeln("rootPrefSize ", rootPrefSize); 98 } 99 100 int topOffset = rootPadding - rootSpacing; 101 102 foreach(child; children) 103 { 104 topOffset += rootSpacing; 105 static if(vertical) 106 child.setProperty!("position")(ivec2(rootPadding, topOffset)); 107 else 108 child.setProperty!("position")(ivec2(topOffset, rootPadding)); 109 110 ivec2 childSize = child.getPropertyAs!("prefSize", ivec2); 111 ivec2 childMinSize = child.getPropertyAs!("minSize", ivec2); 112 childSize = ivec2(max(childSize.x, childMinSize.x), max(childSize.y, childMinSize.y)); 113 114 if (isExpandableLength(child)) 115 { 116 version(debug_linear) writeln(" expandable ", child["type"]); 117 *sizeLength(childSize) += extraPerWidget; 118 } 119 120 if (isExpandableWidth(child)) 121 { 122 version(debug_linear) writeln("expandable width ", child["type"]); 123 *sizeWidth(childSize) = maxChildWidth; 124 } 125 126 topOffset += *sizeLength(childSize); // Offset for next child 127 128 child.setProperty!("size")(childSize); 129 } 130 131 version(debug_linear) writeln("linear expand end\n"); 132 } 133 134 override void onContainerResized(Widget root, ivec2 oldSize, ivec2 newSize) 135 { 136 version(debug_linear) writeln("onContainerResized"); 137 } 138 139 private: 140 141 static bool isExpandableWidth(Widget widget) 142 { 143 static if (vertical) 144 return widget.hasProperty!"hexpand"; 145 else 146 return widget.hasProperty!"vexpand"; 147 } 148 149 static bool isExpandableLength(Widget widget) 150 { 151 static if (vertical) 152 return widget.hasProperty!"vexpand"; 153 else 154 return widget.hasProperty!"hexpand"; 155 } 156 157 static pure int* sizeLength(ref ivec2 vector) 158 { 159 static if (vertical) 160 return &(vector.arrayof[1]); 161 else 162 return &(vector.arrayof[0]); 163 } 164 165 static pure int* sizeWidth(ref ivec2 vector) 166 { 167 static if (vertical) 168 return &(vector.arrayof[0]); 169 else 170 return &(vector.arrayof[1]); 171 } 172 }