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 module dguihub.core.controls.control; 10 11 public import dguihub.core.interfaces.idisposable; 12 public import dguihub.core.events.controlcodeeventargs; 13 public import dguihub.core.events.scrolleventargs; 14 public import dguihub.core.events.mouseeventargs; 15 public import dguihub.core.events.painteventargs; 16 public import dguihub.core.events.keyeventargs; 17 public import dguihub.core.events.event; 18 public import dguihub.core.windowclass; 19 public import dguihub.core.message; 20 public import dguihub.core.charset; 21 public import dguihub.core.winapi; 22 public import dguihub.core.exception; 23 public import dguihub.core.geometry; 24 public import dguihub.core.collection; 25 public import dguihub.core.handle; 26 public import dguihub.core.utils; 27 public import dguihub.core.tag; 28 public import dguihub.contextmenu; 29 public import dguihub.canvas; 30 31 enum DockStyle : ubyte { 32 none = 0, 33 left = 1, 34 top = 2, 35 right = 4, 36 bottom = 8, 37 fill = 16, 38 } 39 40 enum PositionSpecified { 41 position = 0, 42 size = 1, 43 all = 2, 44 } 45 46 enum ControlBits : ulong { 47 none = 0, 48 erased = 1, 49 mouseEnter = 2, 50 canNotify = 4, 51 modalControl = 8, // For Modal Dialogs 52 doubleBuffered = 16, // Use DGui's double buffered routine to draw components (be careful with this one!) 53 ownClickMsg = 32, // Does the component Handles click itself? 54 cannotAddChild = 64, // The child window will not be added to the parent's child controls' list 55 useCachedText = 128, // Does not send WM_SETTEXT / WM_GETTEXT messages, but it uses it's internal variable only. 56 } 57 58 enum BorderStyle : ubyte { 59 none = 0, 60 manual = 1, // Internal Use 61 fixedSingle = 2, 62 fixed3d = 4, 63 } 64 65 struct CreateControlParams { 66 string className; 67 string superclassName; //Used in Superlassing 68 Color defaultBackColor; 69 Color defaultForeColor; 70 Cursor defaultCursor; 71 ClassStyles classStyle; 72 } 73 74 abstract class Control : Handle!(HWND), IDisposable { 75 private ContextMenu _menu; 76 private Control _parent; 77 private ContextMenu _ctxMenu; 78 private Font _defaultFont; 79 private Cursor _defaultCursor; 80 private HBRUSH _foreBrush; 81 private HBRUSH _backBrush; 82 private uint _extendedStyle = 0; 83 private uint _style = WS_VISIBLE; 84 protected string _text; 85 protected Rect _bounds; 86 protected Color _foreColor; 87 protected Color _backColor; 88 protected DockStyle _dock = DockStyle.none; 89 protected ControlBits _cBits = ControlBits.canNotify; 90 91 public Event!(Control, PaintEventArgs) paint; 92 public Event!(Control, EventArgs) focusChanged; 93 public Event!(Control, KeyCharEventArgs) keyChar; 94 public Event!(Control, ControlCodeEventArgs) controlCode; 95 public Event!(Control, KeyEventArgs) keyDown; 96 public Event!(Control, KeyEventArgs) keyUp; 97 public Event!(Control, MouseEventArgs) doubleClick; 98 public Event!(Control, MouseEventArgs) mouseKeyDown; 99 public Event!(Control, MouseEventArgs) mouseKeyUp; 100 public Event!(Control, MouseEventArgs) mouseMove; 101 public Event!(Control, MouseEventArgs) mouseEnter; 102 public Event!(Control, MouseEventArgs) mouseLeave; 103 public Event!(Control, EventArgs) visibleChanged; 104 public Event!(Control, EventArgs) handleCreated; 105 public Event!(Control, EventArgs) resize; 106 public Event!(Control, EventArgs) click; 107 108 mixin tagProperty; // Insert tag() property in Control 109 110 public this() { 111 112 } 113 114 public ~this() { 115 this.dispose(); 116 } 117 118 public void dispose() { 119 if (this._backBrush) { 120 DeleteObject(this._backBrush); 121 } 122 123 if (this._foreBrush) { 124 DeleteObject(this._foreBrush); 125 } 126 127 if (this._handle) { 128 /* From MSDN: Destroys the specified window. 129 The function sends WM_DESTROY and WM_NCDESTROY messages to the window 130 to deactivate it and remove the keyboard focus from it. 131 The function also destroys the window's menu, flushes the thread message queue, 132 destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain 133 (if the window is at the top of the viewer chain). If the specified window is a parent 134 or owner window, DestroyWindow automatically destroys the associated child or owned 135 windows when it destroys the parent or owner window. The function first destroys child 136 or owned windows, and then it destroys the parent or owner window 137 */ 138 139 DestroyWindow(this._handle); 140 } 141 142 this._handle = null; 143 } 144 145 public static void convertRect(ref Rect rect, Control from, Control to) { 146 MapWindowPoints(from ? from.handle : null, to ? to.handle : null, cast(POINT*)&rect.rect, 2); 147 } 148 149 public static void convertPoint(ref Point pt, Control from, Control to) { 150 MapWindowPoints(from ? from.handle : null, to ? to.handle : null, &pt.point, 1); 151 } 152 153 public static void convertSize(ref Size sz, Control from, Control to) { 154 MapWindowPoints(from ? from.handle : null, to ? to.handle : null, cast(POINT*)&sz.size, 1); 155 } 156 157 @property public final Rect bounds() { 158 return this._bounds; 159 } 160 161 @property public void bounds(Rect rect) { 162 this._bounds = rect; 163 164 if (this.created) { 165 this.setWindowPos(rect.left, rect.top, rect.width, rect.height); 166 } 167 } 168 169 @property public final BorderStyle borderStyle() { 170 if (this.getExStyle() & WS_EX_CLIENTEDGE) { 171 return BorderStyle.fixed3d; 172 } else if (this.getStyle() & WS_BORDER) { 173 return BorderStyle.fixedSingle; 174 } 175 176 return BorderStyle.none; 177 } 178 179 @property public final void borderStyle(BorderStyle bs) { 180 switch (bs) { 181 case BorderStyle.fixed3d: 182 this.setStyle(WS_BORDER, false); 183 this.setExStyle(WS_EX_CLIENTEDGE, true); 184 break; 185 186 case BorderStyle.fixedSingle: 187 this.setStyle(WS_BORDER, true); 188 this.setExStyle(WS_EX_CLIENTEDGE, false); 189 break; 190 191 case BorderStyle.none: 192 this.setStyle(WS_BORDER, false); 193 this.setExStyle(WS_EX_CLIENTEDGE, false); 194 break; 195 196 default: 197 assert(0, "Unknown Border Style"); 198 //break; 199 } 200 } 201 202 @property public final Control parent() { 203 return this._parent; 204 } 205 206 @property public void parent(Control c) { 207 this._parent = c; 208 209 if (!Control.hasBit(this._cBits, ControlBits.cannotAddChild)) { 210 c.sendMessage(DGUI_ADDCHILDCONTROL, winCast!(WPARAM)(this), 0); 211 } 212 } 213 214 @property public final Control topLevelControl() { 215 Control topCtrl = this; 216 217 while (topCtrl.parent) { 218 topCtrl = topCtrl.parent; 219 } 220 221 return topCtrl; 222 } 223 224 public final Canvas createCanvas() { 225 return Canvas.fromHDC(GetDC(this._handle)); 226 } 227 228 public final void focus() { 229 if (this.created) { 230 SetFocus(this._handle); 231 } 232 } 233 234 @property public bool focused() { 235 if (this.created) { 236 return GetFocus() == this._handle; 237 } 238 239 return false; 240 } 241 242 @property public final Color backColor() { 243 return this._backColor; 244 } 245 246 @property public final void backColor(Color c) { 247 if (this._backBrush) { 248 DeleteObject(this._backBrush); 249 } 250 251 this._backColor = c; 252 this._backBrush = CreateSolidBrush(c.colorref); 253 254 if (this.created) { 255 this.invalidate(); 256 } 257 } 258 259 @property public final Color foreColor() { 260 return this._foreColor; 261 } 262 263 @property public final void foreColor(Color c) { 264 if (this._foreBrush) { 265 DeleteObject(this._foreBrush); 266 } 267 268 this._foreColor = c; 269 this._foreBrush = CreateSolidBrush(c.colorref); 270 271 if (this.created) { 272 this.invalidate(); 273 } 274 } 275 276 @property public final bool scrollBars() { 277 return cast(bool)(this.getStyle() & (WS_VSCROLL | WS_HSCROLL)); 278 } 279 280 @property public final void scrollBars(bool b) { 281 this.setStyle(WS_VSCROLL | WS_HSCROLL, true); 282 } 283 284 @property public string text() { 285 if (this.created && !Control.hasBit(this._cBits, ControlBits.useCachedText)) { 286 return getWindowText(this._handle); 287 } 288 289 return this._text; 290 } 291 292 @property public void text(string s) //Overwritten in TabPage 293 { 294 this._text = s; 295 296 if (this.created && !Control.hasBit(this._cBits, ControlBits.useCachedText)) { 297 Control.setBit(this._cBits, ControlBits.canNotify, false); //Do not trigger TextChanged Event 298 setWindowText(this._handle, s); 299 Control.setBit(this._cBits, ControlBits.canNotify, true); 300 } 301 } 302 303 @property public final Font font() { 304 if (!this._defaultFont) { 305 /* Font is not set, use Windows Font */ 306 this._defaultFont = SystemFonts.windowsFont; 307 } 308 309 return this._defaultFont; 310 } 311 312 @property public final void font(Font f) { 313 if (this.created) { 314 if (this._defaultFont) { 315 this._defaultFont.dispose(); 316 } 317 318 this.sendMessage(WM_SETFONT, cast(WPARAM)f.handle, true); 319 } 320 321 this._defaultFont = f; 322 } 323 324 @property public final Point position() { 325 return this.bounds.position; 326 } 327 328 @property public final void position(Point pt) { 329 this._bounds.position = pt; 330 331 if (this.created) { 332 this.setPosition(pt.x, pt.y); 333 } 334 } 335 336 @property public final Size size() { 337 return this._bounds.size; 338 } 339 340 @property public final void size(Size sz) { 341 this._bounds.size = sz; 342 343 if (this.created) { 344 this.setSize(sz.width, sz.height); 345 } 346 } 347 348 @property public final Size clientSize() { 349 if (this.created) { 350 Rect r = void; 351 352 GetClientRect(this._handle, &r.rect); 353 return r.size; 354 } 355 356 return this.size; 357 } 358 359 @property public final ContextMenu contextMenu() { 360 return this._ctxMenu; 361 } 362 363 @property public final void contextMenu(ContextMenu cm) { 364 if (this._ctxMenu !is cm) { 365 if (this._ctxMenu) { 366 this._ctxMenu.dispose(); 367 } 368 369 this._ctxMenu = cm; 370 } 371 } 372 373 @property public final int width() { 374 return this._bounds.width; 375 } 376 377 @property public final void width(int w) { 378 this._bounds.width = w; 379 380 if (this.created) { 381 this.setSize(w, this._bounds.height); 382 } 383 } 384 385 @property public final int height() { 386 return this._bounds.height; 387 } 388 389 @property public final void height(int h) { 390 this._bounds.height = h; 391 392 if (this.created) { 393 this.setSize(this._bounds.width, h); 394 } 395 } 396 397 @property public final DockStyle dock() { 398 return this._dock; 399 } 400 401 @property public final void dock(DockStyle ds) { 402 this._dock = ds; 403 } 404 405 @property public final Cursor cursor() { 406 if (this.created) { 407 return Cursor.fromHCURSOR(cast(HCURSOR)GetClassLongW(this._handle, GCL_HCURSOR), false); 408 } 409 410 return this._defaultCursor; 411 } 412 413 @property public final void cursor(Cursor c) { 414 if (this._defaultCursor) { 415 this._defaultCursor.dispose(); 416 } 417 418 this._defaultCursor = c; 419 420 if (this.created) { 421 this.sendMessage(WM_SETCURSOR, cast(WPARAM)this._handle, 0); 422 } 423 } 424 425 @property public final bool visible() { 426 return cast(bool)(this.getStyle() & WS_VISIBLE); 427 } 428 429 @property public final void visible(bool b) { 430 b ? this.show() : this.hide(); 431 } 432 433 @property public final bool enabled() { 434 return !(this.getStyle() & WS_DISABLED); 435 } 436 437 @property public final void enabled(bool b) { 438 if (this.created) { 439 EnableWindow(this._handle, b); 440 } else { 441 this.setStyle(WS_DISABLED, !b); 442 } 443 } 444 445 public void show() { 446 if (this.created) { 447 SetWindowPos(this._handle, null, 0, 0, 0, 0, 448 SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); 449 450 if (this._parent) { 451 this._parent.sendMessage(DGUI_DOLAYOUT, 0, 0); 452 } 453 } else { 454 this.setStyle(WS_VISIBLE, true); 455 this.create(); //The component is not created, create it now 456 } 457 } 458 459 public final void hide() { 460 if (this.created) { 461 SetWindowPos(this._handle, null, 0, 0, 0, 0, 462 SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW); 463 } else { 464 this.setStyle(WS_VISIBLE, false); 465 } 466 } 467 468 public final void redraw() { 469 SetWindowPos(this._handle, null, 0, 0, 0, 0, 470 SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); 471 } 472 473 public final void invalidate() { 474 RedrawWindow(this._handle, null, null, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW); 475 } 476 477 public final void sendMessage(ref Message m) { 478 /* 479 * SendMessage() emulation: it allows to send messages even if the control is not created, 480 * it is useful in order to send custom messages to components. 481 */ 482 483 if (m.msg >= DGUI_BASE) /* DGui's Custom Message Handling */ { 484 this.onDGuiMessage(m); 485 } else /* Window Procedure Message Handling */ { 486 //Control.setBit(this._cBits, ControlBits.canNotify, false); 487 this.wndProc(m); 488 //Control.setBit(this._cBits, ControlBits.canNotify, true); 489 } 490 } 491 492 public final uint sendMessage(uint msg, WPARAM wParam, LPARAM lParam) { 493 Message m = Message(this._handle, msg, wParam, lParam); 494 this.sendMessage(m); 495 496 return m.result; 497 } 498 499 extern (Windows) package static LRESULT msgRouter(HWND hWnd, uint msg, 500 WPARAM wParam, LPARAM lParam) { 501 if (msg == WM_NCCREATE) { 502 /* 503 * TRICK: Id == hWnd 504 * --- 505 * Inizializzazione Componente 506 */ 507 508 CREATESTRUCTW* pCreateStruct = cast(CREATESTRUCTW*)lParam; 509 LPARAM param = cast(LPARAM)pCreateStruct.lpCreateParams; 510 SetWindowLongW(hWnd, GWL_USERDATA, param); 511 SetWindowLongW(hWnd, GWL_ID, cast(uint)hWnd); 512 513 Control theThis = winCast!(Control)(param); 514 theThis._handle = hWnd; //Assign handle. 515 } 516 517 Control theThis = winCast!(Control)(GetWindowLongW(hWnd, GWL_USERDATA)); 518 Message m = Message(hWnd, msg, wParam, lParam); 519 520 if (theThis) { 521 theThis.wndProc(m); 522 } else { 523 Control.defWindowProc(m); 524 } 525 526 return m.result; 527 } 528 529 private void onMenuCommand(WPARAM wParam, LPARAM lParam) { 530 MENUITEMINFOW minfo; 531 532 minfo.cbSize = MENUITEMINFOW.sizeof; 533 minfo.fMask = MIIM_DATA; 534 535 if (GetMenuItemInfoW(cast(HMENU)lParam, cast(UINT)wParam, TRUE, &minfo)) { 536 MenuItem sender = winCast!(MenuItem)(minfo.dwItemData); 537 sender.performClick(); 538 } 539 } 540 541 private void create() { 542 CreateControlParams ccp; 543 ccp.defaultBackColor = SystemColors.colorButtonFace; 544 ccp.defaultForeColor = SystemColors.colorButtonText; 545 546 this.createControlParams(ccp); 547 548 this._backBrush = CreateSolidBrush(ccp.defaultBackColor.colorref); 549 this._foreBrush = CreateSolidBrush(ccp.defaultForeColor.colorref); 550 551 if (ccp.defaultCursor) { 552 this._defaultCursor = ccp.defaultCursor; 553 } 554 555 if (!this._defaultFont) { 556 this._defaultFont = SystemFonts.windowsFont; 557 } 558 559 if (!this._backColor.valid) // Invalid Color 560 { 561 this.backColor = ccp.defaultBackColor; 562 } 563 564 if (!this._foreColor.valid) // Invalid Color 565 { 566 this.foreColor = ccp.defaultForeColor; 567 } 568 569 HWND hParent = null; 570 571 if (Control.hasBit(this._cBits, ControlBits.modalControl)) //Is Modal ? 572 { 573 hParent = GetActiveWindow(); 574 this.setStyle(WS_CHILD, false); 575 this.setStyle(WS_POPUP, true); 576 } else if (this._parent) { 577 hParent = this._parent.handle; 578 579 /* As MSDN says: 580 WS_POPUP: The windows is a pop-up window. *** This style cannot be used with the WS_CHILD style. *** */ 581 582 if (!(this.getStyle() & WS_POPUP)) //The windows doesn't have WS_POPUP style, set WS_CHILD style. 583 { 584 this.setStyle(WS_CHILD, true); 585 } 586 587 this.setStyle(WS_CLIPSIBLINGS, true); 588 } 589 590 createWindowEx(this.getExStyle(), ccp.className, this._text, 591 this.getStyle(), this._bounds.x, this._bounds.y, 592 this._bounds.width, this._bounds.height, hParent, winCast!(void*)(this)); 593 594 if (!this._handle) { 595 throwException!(Win32Exception)("Control Creation failed: (ClassName: '%s', Text: '%s')", 596 ccp.className, this._text); 597 } 598 599 UpdateWindow(this._handle); 600 601 if (this._parent) { 602 this._parent.sendMessage(DGUI_CHILDCONTROLCREATED, winCast!(WPARAM)(this), 0); //Notify the parent window 603 } 604 } 605 606 private void setPosition(int x, int y) { 607 this.setWindowPos(x, y, 0, 0, PositionSpecified.position); 608 } 609 610 private void setSize(int w, int h) { 611 this.setWindowPos(0, 0, w, h, PositionSpecified.size); 612 } 613 614 private void setWindowPos(int x, int y, int w, int h, 615 PositionSpecified ps = PositionSpecified.all) { 616 uint wpf = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE; 617 618 if (ps !is PositionSpecified.all) { 619 if (ps is PositionSpecified.position) { 620 wpf &= ~SWP_NOMOVE; 621 } else //if(ps is PositionSpecified.size) 622 { 623 wpf &= ~SWP_NOSIZE; 624 } 625 } else { 626 wpf &= ~(SWP_NOMOVE | SWP_NOSIZE); 627 } 628 629 SetWindowPos(this._handle, null, x, y, w, h, wpf); //Bounds updated in WM_WINDOWPOSCHANGED 630 } 631 632 private void drawMenuItemImage(DRAWITEMSTRUCT* pDrawItem) { 633 MenuItem mi = winCast!(MenuItem)(pDrawItem.itemData); 634 635 if (mi) { 636 scope Canvas c = Canvas.fromHDC(pDrawItem.hDC, false); //HDC *Not* Owned by Canvas Object 637 int icoSize = GetSystemMetrics(SM_CYMENU); 638 c.drawImage(mi.rootMenu.imageList.images[mi.imageIndex], Rect(0, 0, icoSize, icoSize)); 639 } 640 } 641 642 protected final uint getStyle() { 643 if (this.created) { 644 return GetWindowLongW(this._handle, GWL_STYLE); 645 } 646 647 return this._style; 648 } 649 650 protected final void setStyle(uint cstyle, bool set) { 651 if (this.created) { 652 uint style = this.getStyle(); 653 set ? (style |= cstyle) : (style &= ~cstyle); 654 655 SetWindowLongW(this._handle, GWL_STYLE, style); 656 this.redraw(); 657 this._style = style; 658 } else { 659 set ? (this._style |= cstyle) : (this._style &= ~cstyle); 660 } 661 } 662 663 protected static final void setBit(T)(ref T rBits, T rBit, bool set) 664 if (is(T B == enum) && is(B == ulong)) { 665 set ? (rBits |= rBit) : (rBits &= ~rBit); 666 } 667 668 protected static final bool hasBit(T)(ref T rBits, T rBit) 669 if (is(T B == enum) && is(B == ulong)) { 670 return cast(bool)(rBits & rBit); 671 } 672 673 protected final uint getExStyle() { 674 if (this.created) { 675 return GetWindowLongW(this._handle, GWL_EXSTYLE); 676 } 677 678 return this._extendedStyle; 679 } 680 681 protected final void setExStyle(uint cstyle, bool set) { 682 if (this.created) { 683 uint exStyle = this.getExStyle(); 684 set ? (exStyle |= cstyle) : (exStyle &= ~cstyle); 685 686 SetWindowLongW(this._handle, GWL_EXSTYLE, exStyle); 687 this.redraw(); 688 this._extendedStyle = exStyle; 689 } else { 690 set ? (this._extendedStyle |= cstyle) : (this._extendedStyle &= ~cstyle); 691 } 692 } 693 694 protected void createControlParams(ref CreateControlParams ccp) { 695 ClassStyles cstyle = ccp.classStyle | ClassStyles.doubleClicks; 696 697 WindowClass.register(ccp.className, cstyle, ccp.defaultCursor, 698 cast(WNDPROC) /*FIXME may throw*/ &Control.msgRouter); 699 } 700 701 protected uint originalWndProc(ref Message m) { 702 return Control.defWindowProc(m); 703 } 704 705 protected static uint defWindowProc(ref Message m) { 706 if (IsWindowUnicode(m.hWnd)) { 707 m.result = DefWindowProcW(m.hWnd, m.msg, m.wParam, m.lParam); 708 } else { 709 m.result = DefWindowProcA(m.hWnd, m.msg, m.wParam, m.lParam); 710 } 711 712 return m.result; 713 } 714 715 protected void onDGuiMessage(ref Message m) { 716 switch (m.msg) { 717 case DGUI_REFLECTMESSAGE: 718 Message rm = *(cast(Message*)m.wParam); 719 this.onReflectedMessage(rm); 720 *(cast(Message*)m.wParam) = rm; //Copy the result, so the parent can return result. 721 //m.result = rm.result; // No result here! 722 break; 723 724 case DGUI_CREATEONLY: { 725 if (!this.created) { 726 this.create(); 727 } 728 } 729 break; 730 731 default: 732 m.result = 0; 733 break; 734 } 735 } 736 737 protected void onReflectedMessage(ref Message m) { 738 switch (m.msg) { 739 case WM_CTLCOLOREDIT, WM_CTLCOLORBTN: 740 SetBkColor(cast(HDC)m.wParam, 741 this.backColor.colorref); 742 SetTextColor(cast(HDC)m.wParam, this.foreColor.colorref); 743 m.result = cast(LRESULT)this._backBrush; 744 break; 745 746 case WM_MEASUREITEM: { 747 MEASUREITEMSTRUCT* pMeasureItem = cast(MEASUREITEMSTRUCT*)m.lParam; 748 749 if (pMeasureItem.CtlType == ODT_MENU) { 750 MenuItem mi = winCast!(MenuItem)(pMeasureItem.itemData); 751 752 if (mi) { 753 if (mi.parent.handle == GetMenu(this._handle)) // Check if parent of 'mi' is the menu bar 754 { 755 FontMetrics fm = this.font.metrics; 756 757 int icoSize = GetSystemMetrics(SM_CYMENU); 758 pMeasureItem.itemWidth = icoSize + fm.maxCharWidth; 759 } else { 760 pMeasureItem.itemWidth = 10; 761 } 762 } 763 } 764 } 765 break; 766 767 case WM_DRAWITEM: { 768 DRAWITEMSTRUCT* pDrawItem = cast(DRAWITEMSTRUCT*)m.lParam; 769 770 if (pDrawItem.CtlType == ODT_MENU) { 771 this.drawMenuItemImage(pDrawItem); 772 } 773 } 774 break; 775 776 default: 777 //Control.defWindowProc(m); 778 break; 779 } 780 } 781 782 protected void onClick(EventArgs e) { 783 this.click(this, e); 784 } 785 786 protected void onKeyUp(KeyEventArgs e) { 787 this.keyUp(this, e); 788 } 789 790 protected void onKeyDown(KeyEventArgs e) { 791 this.keyDown(this, e); 792 } 793 794 protected void onKeyChar(KeyCharEventArgs e) { 795 this.keyChar(this, e); 796 } 797 798 protected void onPaint(PaintEventArgs e) { 799 this.paint(this, e); 800 } 801 802 protected void onHandleCreated(EventArgs e) { 803 this.handleCreated(this, e); 804 } 805 806 protected void onResize(EventArgs e) { 807 this.resize(this, e); 808 } 809 810 protected void onVisibleChanged(EventArgs e) { 811 this.visibleChanged(this, e); 812 } 813 814 protected void onMouseKeyDown(MouseEventArgs e) { 815 this.mouseKeyDown(this, e); 816 } 817 818 protected void onMouseKeyUp(MouseEventArgs e) { 819 this.mouseKeyUp(this, e); 820 } 821 822 protected void onDoubleClick(MouseEventArgs e) { 823 this.doubleClick(this, e); 824 } 825 826 protected void onMouseMove(MouseEventArgs e) { 827 this.mouseMove(this, e); 828 } 829 830 protected void onMouseEnter(MouseEventArgs e) { 831 this.mouseEnter(this, e); 832 } 833 834 protected void onMouseLeave(MouseEventArgs e) { 835 this.mouseLeave(this, e); 836 } 837 838 protected void onFocusChanged(EventArgs e) { 839 this.focusChanged(this, e); 840 } 841 842 protected void onControlCode(ControlCodeEventArgs e) { 843 this.controlCode(this, e); 844 } 845 846 protected void wndProc(ref Message m) { 847 switch (m.msg) { 848 case WM_ERASEBKGND: 849 m.result = 0; // Do nothing here, handle it in WM_PAINT 850 break; 851 852 case WM_PAINT: { 853 HDC hdc; 854 Rect clipRect; 855 PAINTSTRUCT ps; 856 857 if (!m.wParam) { 858 hdc = BeginPaint(this._handle, &ps); 859 clipRect = Rect.fromRECT(&ps.rcPaint); //Clip Rectangle 860 } else // Assume WPARAM as HDC 861 { 862 hdc = cast(HDC)m.wParam; 863 GetUpdateRect(this._handle, &clipRect.rect, false); 864 } 865 866 FillRect(hdc, &clipRect.rect, this._backBrush); //Fill with background color; 867 868 scope Canvas c = Canvas.fromHDC(hdc, false); 869 scope PaintEventArgs e = new PaintEventArgs(c, clipRect); 870 this.onPaint(e); 871 872 if (!m.wParam) { 873 EndPaint(this._handle, &ps); 874 } 875 876 m.result = 0; 877 } 878 break; 879 880 case WM_CREATE: // Aggiornamento Font, rimuove FIXED SYS 881 { 882 this.sendMessage(WM_SETFONT, cast(WPARAM)this._defaultFont.handle, true); 883 884 if (this._ctxMenu) { 885 HMENU hDefaultMenu = GetMenu(this._handle); 886 887 if (hDefaultMenu) { 888 DestroyMenu(hDefaultMenu); //Destroy default menu (if exists) 889 } 890 891 this._ctxMenu.create(); 892 } 893 894 this.onHandleCreated(EventArgs.empty); 895 m.result = 0; //Continue.. 896 } 897 break; 898 899 case WM_WINDOWPOSCHANGED: { 900 WINDOWPOS* pWndPos = cast(WINDOWPOS*)m.lParam; 901 902 if (!(pWndPos.flags & SWP_NOMOVE) || !(pWndPos.flags & SWP_NOSIZE)) { 903 /* Note: 'pWndPos' has NonClient coordinates */ 904 905 if (!(pWndPos.flags & SWP_NOMOVE)) { 906 this._bounds.x = pWndPos.x; 907 this._bounds.y = pWndPos.y; 908 } 909 910 if (!(pWndPos.flags & SWP_NOSIZE)) { 911 this._bounds.width = pWndPos.cx; 912 this._bounds.height = pWndPos.cy; 913 } 914 915 if (!(pWndPos.flags & SWP_NOSIZE)) { 916 this.onResize(EventArgs.empty); 917 } 918 } else if (pWndPos.flags & SWP_SHOWWINDOW || pWndPos.flags & SWP_HIDEWINDOW) { 919 if (pWndPos.flags & SWP_SHOWWINDOW && this._parent) { 920 this._parent.sendMessage(DGUI_DOLAYOUT, 0, 0); 921 } 922 923 this.onVisibleChanged(EventArgs.empty); 924 } 925 926 this.originalWndProc(m); //Send WM_SIZE too 927 } 928 break; 929 930 case WM_KEYDOWN: { 931 scope KeyEventArgs e = new KeyEventArgs(cast(Keys)m.wParam); 932 this.onKeyDown(e); 933 934 if (e.handled) { 935 this.originalWndProc(m); 936 } else { 937 m.result = 0; 938 } 939 } 940 break; 941 942 case WM_KEYUP: { 943 scope KeyEventArgs e = new KeyEventArgs(cast(Keys)m.wParam); 944 this.onKeyUp(e); 945 946 if (e.handled) { 947 this.originalWndProc(m); 948 } else { 949 m.result = 0; 950 } 951 } 952 break; 953 954 case WM_CHAR: { 955 scope KeyCharEventArgs e = new KeyCharEventArgs(cast(Keys)m.wParam, cast(char)m.wParam); 956 this.onKeyChar(e); 957 958 if (e.handled) { 959 this.originalWndProc(m); 960 } else { 961 m.result = 0; 962 } 963 } 964 break; 965 966 case WM_MOUSELEAVE: { 967 Control.setBit(this._cBits, ControlBits.mouseEnter, false); 968 969 scope MouseEventArgs e = new MouseEventArgs(Point(LOWORD(m.lParam), 970 HIWORD(m.lParam)), cast(MouseKeys)m.wParam); 971 this.onMouseLeave(e); 972 973 this.originalWndProc(m); 974 } 975 break; 976 977 case WM_MOUSEMOVE: { 978 scope MouseEventArgs e = new MouseEventArgs(Point(LOWORD(m.lParam), 979 HIWORD(m.lParam)), cast(MouseKeys)m.wParam); 980 this.onMouseMove(e); 981 982 if (!Control.hasBit(this._cBits, ControlBits.mouseEnter)) { 983 Control.setBit(this._cBits, ControlBits.mouseEnter, true); 984 985 TRACKMOUSEEVENT tme; 986 987 tme.cbSize = TRACKMOUSEEVENT.sizeof; 988 tme.dwFlags = TME_LEAVE; 989 tme.hwndTrack = this._handle; 990 991 TrackMouseEvent(&tme); 992 993 this.onMouseEnter(e); 994 } 995 996 this.originalWndProc(m); 997 } 998 break; 999 1000 case WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN: { 1001 scope MouseEventArgs e = new MouseEventArgs(Point(LOWORD(m.lParam), 1002 HIWORD(m.lParam)), cast(MouseKeys)m.wParam); 1003 this.onMouseKeyDown(e); 1004 1005 this.originalWndProc(m); 1006 } 1007 break; 1008 1009 case WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP: { 1010 MouseKeys mk = MouseKeys.none; 1011 1012 if (GetAsyncKeyState(MK_LBUTTON)) { 1013 mk |= MouseKeys.left; 1014 } 1015 1016 if (GetAsyncKeyState(MK_MBUTTON)) { 1017 mk |= MouseKeys.middle; 1018 } 1019 1020 if (GetAsyncKeyState(MK_RBUTTON)) { 1021 mk |= MouseKeys.right; 1022 } 1023 1024 Point p = Point(LOWORD(m.lParam), HIWORD(m.lParam)); 1025 scope MouseEventArgs e = new MouseEventArgs(p, mk); 1026 this.onMouseKeyUp(e); 1027 1028 Control.convertPoint(p, this, null); 1029 1030 if (m.msg == WM_LBUTTONUP && !Control.hasBit(this._cBits, 1031 ControlBits.ownClickMsg) && WindowFromPoint(p.point) == this._handle) { 1032 this.onClick(EventArgs.empty); 1033 } 1034 1035 this.originalWndProc(m); 1036 } 1037 break; 1038 1039 case WM_LBUTTONDBLCLK, WM_MBUTTONDBLCLK, WM_RBUTTONDBLCLK: { 1040 scope MouseEventArgs e = new MouseEventArgs(Point(LOWORD(m.lParam), 1041 HIWORD(m.lParam)), cast(MouseKeys)m.wParam); 1042 this.onDoubleClick(e); 1043 1044 this.originalWndProc(m); 1045 } 1046 break; 1047 1048 case WM_SETCURSOR: { 1049 if (cast(HWND)m.wParam == this._handle && this._defaultCursor 1050 && cast(LONG)this._defaultCursor.handle != GetClassLongW(this._handle, 1051 GCL_HCURSOR)) { 1052 SetClassLongW(this._handle, GCL_HCURSOR, cast(LONG)this._defaultCursor.handle); 1053 } 1054 1055 this.originalWndProc(m); //Continue cursor selection 1056 } 1057 break; 1058 1059 case WM_MENUCOMMAND: 1060 this.onMenuCommand(m.wParam, m.lParam); 1061 break; 1062 1063 case WM_CONTEXTMENU: { 1064 if (this._ctxMenu) { 1065 this._ctxMenu.popupMenu(this._handle, Cursor.position); 1066 } else { 1067 this.originalWndProc(m); 1068 } 1069 } 1070 break; 1071 1072 case WM_SETFOCUS, WM_KILLFOCUS: { 1073 this.onFocusChanged(EventArgs.empty); 1074 this.originalWndProc(m); 1075 } 1076 break; 1077 1078 case WM_GETDLGCODE: { 1079 scope ControlCodeEventArgs e = new ControlCodeEventArgs(); 1080 this.onControlCode(e); 1081 1082 if (e.controlCode is ControlCode.ignore) { 1083 this.originalWndProc(m); 1084 } else { 1085 m.result = e.controlCode; 1086 } 1087 } 1088 break; 1089 1090 case WM_INITMENU: { 1091 if (this._ctxMenu) { 1092 this._ctxMenu.onPopup(EventArgs.empty); 1093 } 1094 1095 m.result = 0; 1096 } 1097 break; 1098 1099 default: 1100 this.originalWndProc(m); 1101 break; 1102 } 1103 } 1104 }