1 // Written by Christopher E. Miller 2 // See the included license.txt for copyright and license details. 3 4 5 6 module dfl.statusbar; 7 8 9 private import dfl.control, dfl.base, dfl.internal.winapi, dfl.event, 10 dfl.collections, dfl.internal.utf, dfl.internal.dlib, dfl.application; 11 12 private import dfl.internal.dlib; 13 14 15 private extern(Windows) void _initStatusbar(); 16 17 18 /+ 19 enum StatusBarPanelAutoSize: ubyte { 20 NONE, 21 CONTENTS, 22 SPRING, 23 } 24 +/ 25 26 27 28 enum StatusBarPanelBorderStyle: ubyte { 29 NONE, /// 30 SUNKEN, /// ditto 31 RAISED /// ditto 32 } 33 34 35 36 class StatusBarPanel: DObject { 37 38 this(Dstring text) { 39 this._txt = text; 40 } 41 42 /// ditto 43 this(Dstring text, int width) { 44 this._txt = text; 45 this._width = width; 46 } 47 48 /// ditto 49 this() { 50 } 51 52 53 override Dstring toString() { 54 return _txt; 55 } 56 57 58 override Dequ opEquals(Object o) { 59 return _txt == getObjectString(o); // ? 60 } 61 62 Dequ opEquals(StatusBarPanel pnl) { 63 return _txt == pnl._txt; 64 } 65 66 Dequ opEquals(Dstring val) { 67 return _txt == val; 68 } 69 70 71 override int opCmp(Object o) { 72 return stringICmp(_txt, getObjectString(o)); // ? 73 } 74 75 int opCmp(StatusBarPanel pnl) { 76 return stringICmp(_txt, pnl._txt); 77 } 78 79 int opCmp(Dstring val) { 80 return stringICmp(_txt, val); 81 } 82 83 84 /+ 85 86 final @property void alignment(HorizontalAlignment ha) { // setter 87 88 } 89 90 /// ditto 91 final @property HorizontalAlignment alignment() { // getter 92 //LEFT 93 } 94 +/ 95 96 97 /+ 98 99 final @property void autoSize(StatusBarPanelAutoSize asize) { // setter 100 101 } 102 103 /// ditto 104 final @property StatusBarPanelAutoSize autoSize() { // getter 105 //NONE 106 } 107 +/ 108 109 110 111 final @property void borderStyle(StatusBarPanelBorderStyle bs) { // setter 112 switch(bs) { 113 case StatusBarPanelBorderStyle.NONE: 114 _utype = (_utype & ~SBT_POPOUT) | SBT_NOBORDERS; 115 break; 116 117 case StatusBarPanelBorderStyle.RAISED: 118 _utype = (_utype & ~SBT_NOBORDERS) | SBT_POPOUT; 119 break; 120 121 case StatusBarPanelBorderStyle.SUNKEN: 122 _utype &= ~(SBT_NOBORDERS | SBT_POPOUT); 123 break; 124 125 default: 126 assert(0); 127 } 128 129 if(_parent && _parent.isHandleCreated) { 130 _parent.panels._fixtexts(); // Also fixes styles. 131 } 132 } 133 134 /// ditto 135 final @property StatusBarPanelBorderStyle borderStyle() { // getter 136 if(_utype & SBT_POPOUT) { 137 return StatusBarPanelBorderStyle.RAISED; 138 } 139 if(_utype & SBT_NOBORDERS) { 140 return StatusBarPanelBorderStyle.NONE; 141 } 142 return StatusBarPanelBorderStyle.RAISED; 143 } 144 145 146 // icon 147 148 149 /+ 150 151 final @property void minWidth(int mw) // setter 152 in { 153 assert(mw >= 0); 154 } 155 body { 156 157 } 158 159 /// ditto 160 final @property int minWidth() { // getter 161 //10 162 } 163 +/ 164 165 166 167 final @property StatusBar parent() { // getter 168 return _parent; 169 } 170 171 172 // style 173 174 175 176 final @property void text(Dstring txt) { // setter 177 if(_parent && _parent.isHandleCreated) { 178 int idx = _parent.panels.indexOf(this); 179 assert(-1 != idx); 180 _parent._sendidxtext(idx, _utype, txt); 181 } 182 183 this._txt = txt; 184 } 185 186 /// ditto 187 final @property Dstring text() { // getter 188 return _txt; 189 } 190 191 192 /+ 193 194 final @property void toolTipText(Dstring txt) { // setter 195 196 } 197 198 /// ditto 199 final @property Dstring toolTipText() { // getter 200 //null 201 } 202 +/ 203 204 205 206 final @property void width(int w) { // setter 207 _width = w; 208 209 if(_parent && _parent.isHandleCreated) { 210 _parent.panels._fixwidths(); 211 } 212 } 213 214 /// ditto 215 final @property int width() { // getter 216 return _width; 217 } 218 219 220 private: 221 222 Dstring _txt = null; 223 int _width = 100; 224 StatusBar _parent = null; 225 WPARAM _utype = 0; // StatusBarPanelBorderStyle.SUNKEN. 226 } 227 228 229 /+ 230 231 class StatusBarPanelClickEventArgs: MouseEventArgs { 232 233 this(StatusBarPanel sbpanel, MouseButtons btn, int clicks, int x, int y) { 234 this._sbpanel = sbpanel; 235 super(btn, clicks, x, y, 0); 236 } 237 238 239 private: 240 StatusBarPanel _sbpanel; 241 } 242 +/ 243 244 245 246 class StatusBar: ControlSuperClass { // docmain 247 248 class StatusBarPanelCollection { 249 protected this(StatusBar sb) 250 in { 251 assert(sb.lpanels is null); 252 } 253 body { 254 this.sb = sb; 255 } 256 257 258 private: 259 260 StatusBar sb; 261 package StatusBarPanel[] _panels; 262 263 264 package void _fixwidths() { 265 assert(isHandleCreated); 266 267 UINT[20] _pws = void; 268 UINT[] pws = _pws; 269 if(_panels.length > _pws.length) { 270 pws = new UINT[_panels.length]; 271 } 272 UINT right = 0; 273 foreach(idx, pnl; _panels) { 274 if(-1 == pnl.width) { 275 pws[idx] = -1; 276 } else { 277 right += pnl.width; 278 pws[idx] = right; 279 } 280 } 281 sb.prevwproc(SB_SETPARTS, cast(WPARAM)_panels.length, cast(LPARAM)pws.ptr); 282 } 283 284 285 void _fixtexts() { 286 assert(isHandleCreated); 287 288 if(dfl.internal.utf.useUnicode) { 289 foreach(idx, pnl; _panels) { 290 sb.prevwproc(SB_SETTEXTW, cast(WPARAM)idx | pnl._utype, cast(LPARAM)dfl.internal.utf.toUnicodez(pnl._txt)); 291 } 292 } else { 293 foreach(idx, pnl; _panels) { 294 sb.prevwproc(SB_SETTEXTA, cast(WPARAM)idx | pnl._utype, cast(LPARAM)dfl.internal.utf.toAnsiz(pnl._txt)); 295 } 296 } 297 } 298 299 300 void _setcurparts() { 301 assert(isHandleCreated); 302 303 _fixwidths(); 304 305 _fixtexts(); 306 } 307 308 309 void _removed(size_t idx, Object val) { 310 if(size_t.max == idx) { // Clear all. 311 if(sb.isHandleCreated) { 312 sb.prevwproc(SB_SETPARTS, 0, 0); // 0 parts. 313 } 314 } else { 315 if(sb.isHandleCreated) { 316 _setcurparts(); 317 } 318 } 319 } 320 321 322 void _added(size_t idx, StatusBarPanel val) { 323 if(val._parent) { 324 throw new DflException("StatusBarPanel already belongs to a StatusBar"); 325 } 326 327 val._parent = sb; 328 329 if(sb.isHandleCreated) { 330 _setcurparts(); 331 } 332 } 333 334 335 void _adding(size_t idx, StatusBarPanel val) { 336 if(_panels.length >= 254) { // Since SB_SETTEXT with 255 has special meaning. 337 throw new DflException("Too many status bar panels"); 338 } 339 } 340 341 342 public: 343 344 mixin ListWrapArray!(StatusBarPanel, _panels, 345 _adding, _added, 346 _blankListCallback!(StatusBarPanel), _removed, 347 true, /+true+/ false, false) _wraparray; 348 } 349 350 351 352 this() { 353 _initStatusbar(); 354 355 _issimple = true; 356 wstyle |= SBARS_SIZEGRIP; 357 wclassStyle = statusbarClassStyle; 358 //height = ?; 359 dock = DockStyle.BOTTOM; 360 361 lpanels = new StatusBarPanelCollection(this); 362 } 363 364 365 // backColor / font / foreColor ... 366 367 368 override @property void dock(DockStyle ds) { // setter 369 switch(ds) { 370 case DockStyle.BOTTOM: 371 case DockStyle.TOP: 372 super.dock = ds; 373 break; 374 375 default: 376 throw new DflException("Invalid status bar dock"); 377 } 378 } 379 380 alias Control.dock dock; // Overload. 381 382 383 384 final @property StatusBarPanelCollection panels() { // getter 385 return lpanels; 386 } 387 388 389 390 final @property void showPanels(bool byes) { // setter 391 if(!byes == _issimple) { 392 return; 393 } 394 395 if(isHandleCreated) { 396 prevwproc(SB_SIMPLE, cast(WPARAM)!byes, 0); 397 398 /+ // It's kept in sync even if simple. 399 if(byes) { 400 panels._setcurparts(); 401 } 402 +/ 403 404 if(!byes) { 405 _sendidxtext(255, 0, _simpletext); 406 } 407 } 408 409 _issimple = !byes; 410 } 411 412 /// ditto 413 final @property bool showPanels() { // getter 414 return !_issimple; 415 } 416 417 418 419 final @property void sizingGrip(bool byes) { // setter 420 if(byes == sizingGrip) { 421 return; 422 } 423 424 if(byes) { 425 _style(_style() | SBARS_SIZEGRIP); 426 } else { 427 _style(_style() & ~SBARS_SIZEGRIP); 428 } 429 } 430 431 /// ditto 432 final @property bool sizingGrip() { // getter 433 if(wstyle & SBARS_SIZEGRIP) { 434 return true; 435 } 436 return false; 437 } 438 439 440 override @property void text(Dstring txt) { // setter 441 if(isHandleCreated && !showPanels) { 442 _sendidxtext(255, 0, txt); 443 } 444 445 this._simpletext = txt; 446 447 onTextChanged(EventArgs.empty); 448 } 449 450 /// ditto 451 override @property Dstring text() { // getter 452 return this._simpletext; 453 } 454 455 456 protected override void onHandleCreated(EventArgs ea) { 457 super.onHandleCreated(ea); 458 459 if(_issimple) { 460 prevwproc(SB_SIMPLE, cast(WPARAM)true, 0); 461 panels._setcurparts(); 462 if(_simpletext.length) { 463 _sendidxtext(255, 0, _simpletext); 464 } 465 } else { 466 panels._setcurparts(); 467 prevwproc(SB_SIMPLE, cast(WPARAM)false, 0); 468 } 469 } 470 471 472 protected override void createParams(ref CreateParams cp) { 473 super.createParams(cp); 474 475 cp.className = STATUSBAR_CLASSNAME; 476 } 477 478 479 protected override void prevWndProc(ref Message msg) { 480 //msg.result = CallWindowProcA(statusbarPrevWndProc, msg.hWnd, msg.msg, msg.wParam, msg.lParam); 481 msg.result = dfl.internal.utf.callWindowProc(statusbarPrevWndProc, msg.hWnd, msg.msg, msg.wParam, msg.lParam); 482 } 483 484 485 /+ 486 protected override void createHandle() { 487 //CreateStatusWindow 488 } 489 +/ 490 491 492 //StatusBarPanelClickEventHandler panelClick; 493 //Event!(StatusBar, StatusBarPanelClickEventArgs) panelClick; /// 494 495 496 protected: 497 498 // onDrawItem ... 499 500 501 /+ 502 503 void onPanelClick(StatusBarPanelClickEventArgs ea) { 504 panelClick(this, ea); 505 } 506 +/ 507 508 509 private: 510 511 StatusBarPanelCollection lpanels; 512 Dstring _simpletext = null; 513 bool _issimple = true; 514 515 516 package: 517 final: 518 519 LRESULT prevwproc(UINT msg, WPARAM wparam, LPARAM lparam) { 520 //return CallWindowProcA(statusbarPrevWndProc, hwnd, msg, wparam, lparam); 521 return dfl.internal.utf.callWindowProc(statusbarPrevWndProc, hwnd, msg, wparam, lparam); 522 } 523 524 525 void _sendidxtext(int idx, WPARAM utype, Dstring txt) { 526 assert(isHandleCreated); 527 528 if(dfl.internal.utf.useUnicode) { 529 prevwproc(SB_SETTEXTW, cast(WPARAM)idx | utype, cast(LPARAM)dfl.internal.utf.toUnicodez(txt)); 530 } else { 531 prevwproc(SB_SETTEXTA, cast(WPARAM)idx | utype, cast(LPARAM)dfl.internal.utf.toAnsiz(txt)); 532 } 533 } 534 } 535