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