1 /** DGui project file. 2 3 Copyright: Trogu Antonio Davide 2011-2013 4 5 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). 6 7 Authors: Trogu Antonio Davide 8 */ 9 10 11 module dgui.layout.splitpanel; 12 13 import dgui.core.events.event; 14 import dgui.core.events.eventargs; 15 import dgui.layout.layoutcontrol; 16 import dgui.layout.panel; 17 18 enum SplitOrientation 19 { 20 vertical = 1, 21 horizontal = 2, 22 } 23 24 class SplitPanel: LayoutControl 25 { 26 private enum int splitterSize = 8; 27 28 private SplitOrientation _splitOrientation = SplitOrientation.vertical; 29 private bool _downing = false; 30 private int _splitPos = 0; 31 private Panel _panel1; 32 private Panel _panel2; 33 34 public this() 35 { 36 this._panel1 = new Panel(); 37 this._panel1.parent = this; 38 39 this._panel2 = new Panel(); 40 this._panel2.parent = this; 41 } 42 43 @property public void splitPosition(int sp) 44 { 45 this._splitPos = sp; 46 47 if(this.created) 48 { 49 this.updateLayout(); 50 } 51 } 52 53 @property public Panel panel1() 54 { 55 return this._panel1; 56 } 57 58 @property public Panel panel2() 59 { 60 return this._panel2; 61 } 62 63 @property SplitOrientation splitOrientation() 64 { 65 return this._splitOrientation; 66 } 67 68 @property void splitOrientation(SplitOrientation so) 69 { 70 this._splitOrientation = so; 71 } 72 73 public override void updateLayout() 74 { 75 scope ResizeManager rm = new ResizeManager(2); //Fixed Panel 76 77 bool changed = false; 78 79 switch(this._splitOrientation) 80 { 81 case SplitOrientation.vertical: 82 { 83 if(this._splitPos >= 0 && (this._splitPos + splitterSize) < this.width) 84 { 85 rm.setSize(this._panel1, this._splitPos, this.height); 86 rm.resizeControl(this._panel2, this._splitPos + splitterSize, 0, this.width - (this._splitPos + splitterSize), this.height); 87 changed = true; 88 } 89 } 90 break; 91 92 default: // SplitOrientation.horizontal 93 { 94 if(this._splitPos >= 0 && (this._splitPos + splitterSize) < this.height) 95 { 96 rm.setSize(this._panel1, this.width, this._splitPos); 97 rm.resizeControl(this._panel2, 0, this._splitPos + splitterSize, this.width, this.height - (this._splitPos + splitterSize)); 98 changed = true; 99 } 100 } 101 break; 102 } 103 104 if(changed) 105 { 106 this.invalidate(); 107 } 108 } 109 110 protected override void onMouseKeyDown(MouseEventArgs e) 111 { 112 if(e.keys == MouseKeys.left) 113 { 114 this._downing = true; 115 SetCapture(this._handle); 116 } 117 118 super.onMouseKeyDown(e); 119 } 120 121 protected override void onMouseKeyUp(MouseEventArgs e) 122 { 123 if(this._downing) 124 { 125 this._downing = false; 126 ReleaseCapture(); 127 } 128 129 super.onMouseKeyUp(e); 130 } 131 132 protected override void onMouseMove(MouseEventArgs e) 133 { 134 if(this._downing) 135 { 136 Point pt = Cursor.position; 137 convertPoint(pt, null, this); 138 139 switch(this._splitOrientation) 140 { 141 case SplitOrientation.vertical: 142 this._splitPos = pt.x; 143 break; 144 145 default: // SplitOrientation.horizontal 146 this._splitPos = pt.y; 147 break; 148 } 149 150 this.updateLayout(); 151 } 152 153 super.onMouseMove(e); 154 } 155 156 protected override void createControlParams(ref CreateControlParams ccp) 157 { 158 ccp.className = WC_DSPLITPANEL; 159 160 switch(this._splitOrientation) 161 { 162 case SplitOrientation.vertical: 163 ccp.defaultCursor = SystemCursors.sizeWE; 164 break; 165 166 default: // SplitOrientation.horizontal 167 ccp.defaultCursor = SystemCursors.sizeNS; 168 break; 169 } 170 171 if(!this._splitPos) 172 { 173 switch(this._splitOrientation) 174 { 175 case SplitOrientation.vertical: 176 this._splitPos = this.width / 3; 177 break; 178 179 default: // SplitOrientation.horizontal 180 this._splitPos = this.height - (this.height / 3); 181 break; 182 } 183 } 184 185 super.createControlParams(ccp); 186 } 187 188 protected override void onDGuiMessage(ref Message m) 189 { 190 switch(m.msg) 191 { 192 case DGUI_ADDCHILDCONTROL: 193 { 194 Control c = winCast!(Control)(m.wParam); 195 196 if(c is this._panel1 || c is this._panel2) 197 { 198 super.onDGuiMessage(m); 199 } 200 else 201 { 202 throwException!(DGuiException)("SplitPanel doesn't accept child controls"); 203 } 204 } 205 break; 206 207 default: 208 super.onDGuiMessage(m); 209 break; 210 } 211 } 212 213 protected override void onHandleCreated(EventArgs e) 214 { 215 switch(this._splitOrientation) 216 { 217 case SplitOrientation.vertical: 218 this.cursor = SystemCursors.sizeWE; 219 break; 220 221 default: // SplitOrientation.horizontal 222 this.cursor = SystemCursors.sizeNS; 223 break; 224 } 225 226 super.onHandleCreated(e); 227 } 228 229 protected override void onPaint(PaintEventArgs e) 230 { 231 Canvas c = e.canvas; 232 Rect cr = e.clipRectangle; 233 int mid = this._splitPos + (splitterSize / 2); 234 scope Pen dp = new Pen(SystemColors.color3DDarkShadow, 2, PenStyle.dot); 235 scope Pen lp = new Pen(SystemColors.colorButtonFace, 2, PenStyle.dot); 236 237 switch(this._splitOrientation) 238 { 239 case SplitOrientation.vertical: 240 { 241 c.drawEdge(Rect(this._splitPos, cr.top, splitterSize, cr.bottom), EdgeType.raised, EdgeMode.left | EdgeMode.right); 242 243 for(int p = (this.height / 2) - 15, i = 0; i < 8; i++, p += 5) 244 { 245 c.drawLine(dp, mid, p, mid, p + 1); 246 c.drawLine(lp, mid - 1, p - 1, mid - 1, p); 247 } 248 } 249 break; 250 251 default: // SplitOrientation.horizontal 252 { 253 c.drawEdge(Rect(cr.left, this._splitPos, cr.right, splitterSize), EdgeType.raised, EdgeMode.top | EdgeMode.bottom); 254 255 for(int p = (this.width / 2) - 15, i = 0; i < 8; i++, p += 5) 256 { 257 c.drawLine(dp, p, mid, p + 1, mid); 258 c.drawLine(lp, p - 1, mid + 1, p - 1, mid); 259 } 260 } 261 break; 262 } 263 264 super.onPaint(e); 265 } 266 267 protected override void wndProc(ref Message m) 268 { 269 if(m.msg == WM_WINDOWPOSCHANGING) 270 { 271 WINDOWPOS* pWndPos = cast(WINDOWPOS*)m.lParam; 272 273 if(!(pWndPos.flags & SWP_NOSIZE)) 274 { 275 switch(this._splitOrientation) 276 { 277 case SplitOrientation.vertical: 278 { 279 if(this.width) // Avoid division by 0 280 this._splitPos = MulDiv(pWndPos.cx, this._splitPos, this.width); 281 } 282 break; 283 284 default: // SplitOrientation.horizontal 285 { 286 if(this.height) // Avoid division by 0 287 this._splitPos = MulDiv(pWndPos.cy, this._splitPos, this.height); 288 } 289 break; 290 } 291 } 292 } 293 294 super.wndProc(m); 295 } 296 }