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