1 /* 2 * Copyright 2003, 2004, 2005 Martin Fuchs 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19 20 // 21 // Explorer clone 22 // 23 // window.h 24 // 25 // Martin Fuchs, 23.07.2003 26 // 27 28 29 typedef set<HWND> WindowSet; 30 31 32 /* 33 Classes are declared using "struct", not "class" because the default 34 access mode is "public". This way we can list the member functions in a 35 natural order without explicitly specifying any access mode at the begin 36 of the definition. 37 First are public constructors and destructor, then public member functions. 38 After that we list protected member varibables and functions. If needed, 39 private implemenation varibales and functions are positioned at the end. 40 */ 41 42 43 /// information structure for creation of a MDI child window 44 struct ChildWndInfo 45 { 46 ChildWndInfo(HWND hmdiclient) 47 : _hmdiclient(hmdiclient) {} 48 49 HWND _hmdiclient; 50 }; 51 52 53 /** 54 Class Window is the base class for several C++ window wrapper classes. 55 Window objects are allocated from the heap. They are automatically freed 56 when the window gets destroyed. 57 */ 58 struct Window : public WindowHandle 59 { 60 Window(HWND hwnd); 61 virtual ~Window(); 62 63 64 typedef map<HWND,Window*> WindowMap; 65 66 typedef Window* (*CREATORFUNC)(HWND); 67 typedef Window* (*CREATORFUNC_INFO)(HWND, const void*); 68 69 static HWND Create(CREATORFUNC creator, 70 DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName, 71 DWORD dwStyle, int x, int y, int w, int h, 72 HWND hwndParent=0, HMENU hMenu=0/*, LPVOID lpParam=0*/); 73 74 static HWND Create(CREATORFUNC_INFO creator, const void* info, 75 DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName, 76 DWORD dwStyle, int x, int y, int w, int h, 77 HWND hwndParent=0, HMENU hMenu=0/*, LPVOID lpParam=0*/); 78 79 static Window* create_mdi_child(const ChildWndInfo& info, const MDICREATESTRUCT& mcs, CREATORFUNC_INFO creator); 80 // static Window* create_property_sheet(struct PropertySheetDialog* ppsd, CREATORFUNC creator, const void* info); 81 82 static LRESULT CALLBACK WindowWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam); 83 static INT_PTR CALLBACK DialogProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam); 84 85 static Window* get_window(HWND hwnd); 86 #ifndef _MSC_VER 87 template<typename CLASS> static CLASS* get_window(HWND hwnd) {return static_cast<CLASS*>(get_window(hwnd));} 88 #define GET_WINDOW(CLASS, hwnd) Window::get_window<CLASS>(hwnd) 89 #endif 90 91 static void register_pretranslate(HWND hwnd); 92 static void unregister_pretranslate(HWND hwnd); 93 static BOOL pretranslate_msg(LPMSG pmsg); 94 95 static void register_dialog(HWND hwnd); 96 static void unregister_dialog(HWND hwnd); 97 static BOOL dispatch_dialog_msg(LPMSG pmsg); 98 99 static int MessageLoop(); 100 101 102 LRESULT SendParent(UINT nmsg, WPARAM wparam=0, LPARAM lparam=0); 103 LRESULT PostParent(UINT nmsg, WPARAM wparam=0, LPARAM lparam=0); 104 105 static void CancelModes(); 106 107 108 protected: 109 virtual LRESULT Init(LPCREATESTRUCT pcs); // WM_CREATE processing 110 virtual LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam); 111 virtual int Command(int id, int code); // WM_COMMAND processing 112 virtual int Notify(int id, NMHDR* pnmh); // WM_NOTIFY processing 113 114 static Window* create_controller(HWND hwnd); 115 116 117 static WindowMap s_wnd_map; 118 119 static const void* s_new_info; 120 static CREATORFUNC s_window_creator; 121 122 123 /// structure for managing critical sections as static class information in struct Window 124 struct StaticWindowData { 125 CritSect _map_crit_sect; 126 CritSect _create_crit_sect; 127 }; 128 129 static StaticWindowData& GetStaticWindowData(); 130 131 132 // MDI child creation 133 static HHOOK s_hcbtHook; 134 static LRESULT CALLBACK MDICBTHookProc(int code, WPARAM wparam, LPARAM lparam); 135 static LRESULT CALLBACK PropSheetCBTHookProc(int code, WPARAM wparam, LPARAM lparam); 136 137 static WindowSet s_pretranslate_windows; 138 static WindowSet s_dialogs; 139 }; 140 141 #ifdef UNICODE 142 #define NFR_CURRENT NFR_UNICODE 143 #else 144 #define NFR_CURRENT NFR_ANSI 145 #endif 146 147 148 #ifdef _MSC_VER 149 template<typename CLASS> struct GetWindowHelper 150 { 151 static CLASS* get_window(HWND hwnd) { 152 return static_cast<CLASS*>(Window::get_window(hwnd)); 153 } 154 }; 155 #define GET_WINDOW(CLASS, hwnd) GetWindowHelper<CLASS>::get_window(hwnd) 156 #endif 157 158 159 /// dynamic casting of Window pointers 160 template<typename CLASS> struct TypeCheck 161 { 162 static CLASS* dyn_cast(Window* wnd) 163 {return dynamic_cast<CLASS*>(wnd);} 164 }; 165 166 #define WINDOW_DYNAMIC_CAST(CLASS, hwnd) \ 167 TypeCheck<CLASS>::dyn_cast(Window::get_window(hwnd)) 168 169 170 /** 171 SubclassedWindow is used to wrap already existing window handles 172 into C++ Window objects. To construct a object, use the "new" operator 173 to put it in the heap. It is automatically freed, when the window 174 gets destroyed. 175 */ 176 struct SubclassedWindow : public Window 177 { 178 typedef Window super; 179 180 SubclassedWindow(HWND); 181 182 protected: 183 WNDPROC _orgWndProc; 184 185 static LRESULT CALLBACK SubclassedWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam); 186 187 virtual LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam); 188 virtual int Command(int id, int code); 189 virtual int Notify(int id, NMHDR* pnmh); 190 }; 191 192 193 /// template class used in macro WINDOW_CREATOR to define the creater functions for Window objects 194 template<typename WND_CLASS> struct WindowCreator 195 { 196 static WND_CLASS* window_creator(HWND hwnd) 197 { 198 return new WND_CLASS(hwnd); 199 } 200 }; 201 202 #define WINDOW_CREATOR(WND_CLASS) \ 203 ((Window::CREATORFUNC) WindowCreator<WND_CLASS>::window_creator) 204 205 206 /// template class used in macro WINDOW_CREATOR_INFO to the define creater functions for Window objects with additional creation information 207 template<typename WND_CLASS, typename INFO_CLASS> struct WindowCreatorInfo 208 { 209 static WND_CLASS* window_creator(HWND hwnd, const void* info) 210 { 211 return new WND_CLASS(hwnd, *static_cast<const INFO_CLASS*>(info)); 212 } 213 }; 214 215 #define WINDOW_CREATOR_INFO(WND_CLASS, INFO_CLASS) \ 216 ((Window::CREATORFUNC_INFO) WindowCreatorInfo<WND_CLASS, INFO_CLASS>::window_creator) 217 218 219 /** 220 WindowClass is a neat wrapper for RegisterClassEx(). 221 Just construct a WindowClass object, override the attributes you want 222 to change, then call Register() or simply request the ATOM value to 223 register the window class. You don't have to worry calling Register() 224 more than once. It checks if, the class has already been registered. 225 */ 226 struct WindowClass : public WNDCLASSEX 227 { 228 WindowClass(LPCTSTR classname, UINT style=0, WNDPROC wndproc=Window::WindowWndProc); 229 230 ATOM Register() 231 { 232 if (!_atomClass) 233 _atomClass = RegisterClassEx(this); 234 235 return _atomClass; 236 } 237 238 operator ATOM() {return Register();} 239 240 // return LPCTSTR for the CreateWindowEx() parameter 241 operator LPCTSTR() {return (LPCTSTR)(int)Register();} 242 243 protected: 244 ATOM _atomClass; 245 }; 246 247 /// window class with gray background color 248 struct BtnWindowClass : public WindowClass 249 { 250 BtnWindowClass(LPCTSTR classname, UINT style=0, WNDPROC wndproc=Window::WindowWndProc) 251 : WindowClass(classname, style, wndproc) 252 { 253 hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); 254 } 255 }; 256 257 /// window class with specified icon from resources 258 struct IconWindowClass : public WindowClass 259 { 260 IconWindowClass(LPCTSTR classname, UINT nid, UINT style=0, WNDPROC wndproc=Window::WindowWndProc); 261 }; 262 263 264 // private message constants 265 #define PM_DISPATCH_COMMAND (WM_APP+0x00) 266 #define PM_TRANSLATE_MSG (WM_APP+0x01) 267 268 269 #define SPLIT_WIDTH 5 270 #define DEFAULT_SPLIT_POS 300 271 #define COLOR_SPLITBAR LTGRAY_BRUSH 272 273 274 /// menu info structure 275 struct MenuInfo 276 { 277 HMENU _hMenuView; 278 }; 279 280 #define PM_FRM_GET_MENUINFO (WM_APP+0x02) 281 282 #define Frame_GetMenuInfo(hwnd) ((MenuInfo*)SNDMSG(hwnd, PM_FRM_GET_MENUINFO, 0, 0)) 283 284 285 /** 286 PreTranslateWindow is used to register windows to be called by Window::pretranslate_msg(). 287 This way you get PM_TRANSLATE_MSG messages before the message loop dispatches messages. 288 You can then for example use TranslateAccelerator() to implement key shortcuts. 289 */ 290 struct PreTranslateWindow : public Window 291 { 292 typedef Window super; 293 294 PreTranslateWindow(HWND); 295 ~PreTranslateWindow(); 296 }; 297 298 299 300 /** 301 Class ChildWindow represents MDI child windows. 302 It is used with class MainFrame. 303 */ 304 struct ChildWindow : public PreTranslateWindow 305 { 306 typedef PreTranslateWindow super; 307 308 ChildWindow(HWND hwnd, const ChildWndInfo& info); 309 310 static ChildWindow* create(const ChildWndInfo& info, const RECT& rect, CREATORFUNC_INFO creator, 311 LPCTSTR classname, LPCTSTR title=NULL, DWORD style=0); 312 313 bool go_to(LPCTSTR url); 314 315 protected: 316 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam); 317 318 virtual void resize_children(int cx, int cy); 319 virtual String jump_to_int(LPCTSTR url) = 0; 320 321 protected: 322 MenuInfo*_menu_info; 323 324 WindowHandle _left_hwnd; 325 WindowHandle _right_hwnd; 326 int _focus_pane; // 0: left 1: right 327 328 int _split_pos; 329 int _last_split; 330 331 HWND _hwndFrame; 332 String _statusText; 333 String _url; 334 335 stack<String> _url_history; 336 337 void set_url(LPCTSTR url); 338 }; 339 340 #define PM_SETSTATUSTEXT (WM_APP+0x1E) 341 342 343 /** 344 The class DialogWindow implements modeless dialogs, which are managed by 345 Window::dispatch_dialog_msg() in Window::MessageLoop(). 346 A DialogWindow object should be constructed by calling Window::Create() 347 and specifying the class using the WINDOW_CREATOR() macro. 348 */ 349 struct DialogWindow : public Window 350 { 351 typedef Window super; 352 353 DialogWindow(HWND hwnd) 354 : super(hwnd) 355 { 356 register_dialog(hwnd); 357 } 358 359 ~DialogWindow() 360 { 361 unregister_dialog(_hwnd); 362 } 363 }; 364 365 366 /** 367 The class Dialog implements modal dialogs. 368 A Dialog object should be constructed by calling Dialog::DoModal() 369 and specifying the class using the WINDOW_CREATOR() macro. 370 */ 371 struct Dialog : public Window 372 { 373 typedef Window super; 374 375 Dialog(HWND); 376 ~Dialog(); 377 378 static int DoModal(UINT nid, CREATORFUNC creator, HWND hwndParent=0); 379 static int DoModal(UINT nid, CREATORFUNC_INFO creator, const void* info, HWND hwndParent=0); 380 381 protected: 382 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam); 383 int Command(int id, int code); 384 }; 385 386 387 #define PM_FRM_CALC_CLIENT (WM_APP+0x03) 388 #define Frame_CalcFrameClient(hwnd, prt) ((BOOL)SNDMSG(hwnd, PM_FRM_CALC_CLIENT, 0, (LPARAM)(PRECT)prt)) 389 390 #define PM_JUMP_TO_URL (WM_APP+0x25) 391 #define PM_URL_CHANGED (WM_APP+0x26) 392 393 394 struct PropSheetPage : public PROPSHEETPAGE 395 { 396 PropSheetPage(UINT nid, Window::CREATORFUNC dlg_creator); 397 398 void init(struct PropertySheetDialog*); 399 400 protected: 401 friend struct PropSheetPageDlg; 402 403 Window::CREATORFUNC _dlg_creator; 404 }; 405 406 407 /// Property Sheet dialog 408 struct PropertySheetDialog : public PROPSHEETHEADER 409 { 410 PropertySheetDialog(HWND owner); 411 412 void add(PropSheetPage& psp); 413 int DoModal(int start_page=0); 414 415 HWND GetCurrentPage(); 416 417 protected: 418 typedef vector<PROPSHEETPAGE> Vector; 419 Vector _pages; 420 HWND _hwnd; 421 }; 422 423 424 /// Property Sheet Page (inner dialog) 425 struct PropSheetPageDlg : public Dialog 426 { 427 typedef Dialog super; 428 429 PropSheetPageDlg(HWND); 430 431 protected: 432 friend struct PropertySheetDialog; 433 friend struct PropSheetPage; 434 435 static INT_PTR CALLBACK DialogProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam); 436 437 int Command(int id, int code); 438 }; 439 440 441 /* 442 /// Property Sheet Dialog (outer dialog) 443 struct PropertySheetDlg : public SubclassedWindow 444 { 445 typedef SubclassedWindow super; 446 447 PropertySheetDlg(HWND hwnd) : super(hwnd) {} 448 }; 449 */ 450 451 452 // Layouting of resizable windows 453 454 /// Flags to specify how to move and resize controls when resizing their parent window 455 enum RESIZE_FLAGS { 456 MOVE_LEFT = 0x1, 457 MOVE_RIGHT = 0x2, 458 MOVE_TOP = 0x4, 459 MOVE_BOTTOM = 0x8, 460 461 MOVE_X = MOVE_LEFT | MOVE_RIGHT, 462 MOVE_Y = MOVE_TOP | MOVE_BOTTOM, 463 RESIZE_X= MOVE_RIGHT, 464 RESIZE_Y= MOVE_BOTTOM, 465 466 MOVE = MOVE_X | MOVE_Y, 467 RESIZE = RESIZE_X | RESIZE_Y 468 }; 469 470 /// structure to assign RESIZE_FLAGS to dialogs control 471 struct ResizeEntry 472 { 473 ResizeEntry(UINT id, int flags) 474 : _id(id), _flags(flags) {} 475 476 ResizeEntry(HWND hwnd, int flags) 477 : _id(GetDlgCtrlID(hwnd)), _flags(flags) {} 478 479 UINT _id; 480 int _flags; 481 }; 482 483 484 /// Management of controls in resizable dialogs 485 struct ResizeManager : public std::list<ResizeEntry> 486 { 487 typedef std::list<ResizeEntry> super; 488 489 ResizeManager(HWND hwnd); 490 491 void Add(UINT id, int flags) 492 {push_back(ResizeEntry(id, flags));} 493 494 void Add(HWND hwnd, int flags) 495 {push_back(ResizeEntry(hwnd, flags));} 496 497 void HandleSize(int cx, int cy); 498 void Resize(int dx, int dy); 499 500 void SetMinMaxInfo(LPMINMAXINFO lpmmi) 501 { 502 lpmmi->ptMinTrackSize.x = _min_wnd_size.cx; 503 lpmmi->ptMinTrackSize.y = _min_wnd_size.cy; 504 } 505 506 SIZE _min_wnd_size; 507 508 protected: 509 HWND _hwnd; 510 SIZE _last_size; 511 }; 512 513 514 /// Controller base template class for resizable dialogs 515 template<typename BASE> struct ResizeController : public BASE 516 { 517 typedef BASE super; 518 519 ResizeController(HWND hwnd) 520 : super(hwnd), 521 _resize_mgr(hwnd) 522 { 523 } 524 525 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) 526 { 527 switch(nmsg) { 528 case PM_FRM_CALC_CLIENT: 529 GetClientSpace((PRECT)lparam); 530 return TRUE; 531 532 case WM_SIZE: 533 if (wparam != SIZE_MINIMIZED) 534 _resize_mgr.HandleSize(LOWORD(lparam), HIWORD(lparam)); 535 goto def; 536 537 case WM_GETMINMAXINFO: 538 _resize_mgr.SetMinMaxInfo((LPMINMAXINFO)lparam); 539 goto def; 540 541 default: def: 542 return super::WndProc(nmsg, wparam, lparam); 543 } 544 } 545 546 virtual void GetClientSpace(PRECT prect) 547 { 548 if (!IsIconic(this->_hwnd)) { 549 GetClientRect(this->_hwnd, prect); 550 } else { 551 WINDOWPLACEMENT wp; 552 GetWindowPlacement(this->_hwnd, &wp); 553 prect->left = prect->top = 0; 554 prect->right = wp.rcNormalPosition.right-wp.rcNormalPosition.left- 555 2*(GetSystemMetrics(SM_CXSIZEFRAME)+GetSystemMetrics(SM_CXEDGE)); 556 prect->bottom = wp.rcNormalPosition.bottom-wp.rcNormalPosition.top- 557 2*(GetSystemMetrics(SM_CYSIZEFRAME)+GetSystemMetrics(SM_CYEDGE))- 558 GetSystemMetrics(SM_CYCAPTION)-GetSystemMetrics(SM_CYMENUSIZE); 559 } 560 } 561 562 protected: 563 ResizeManager _resize_mgr; 564 }; 565 566 567 /** 568 This class constructs button controls. 569 The button will remain existent when the C++ Button object is destroyed. 570 There is no conjunction between C++ object and windows control life time. 571 */ 572 struct Button : public WindowHandle 573 { 574 Button(HWND parent, LPCTSTR text, int left, int top, int width, int height, 575 int id, DWORD flags=WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, DWORD exStyle=0); 576 }; 577 578 579 /** 580 This class constructs static controls. 581 The control will remain existent when the C++ object is destroyed. 582 There is no conjunction between C++ object and windows control life time. 583 */ 584 struct Static : public WindowHandle 585 { 586 Static(HWND parent, LPCTSTR text, int left, int top, int width, int height, 587 int id, DWORD flags=WS_VISIBLE|WS_CHILD|SS_SIMPLE, DWORD ex_flags=0); 588 }; 589 590 591 // control color message routing for ColorStatic and HyperlinkCtrl 592 593 #define PM_DISPATCH_CTLCOLOR (WM_APP+0x08) 594 595 template<typename BASE> struct CtlColorParent : public BASE 596 { 597 typedef BASE super; 598 599 CtlColorParent(HWND hwnd) 600 : super(hwnd) {} 601 602 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) 603 { 604 switch(nmsg) { 605 case WM_CTLCOLOR: 606 case WM_CTLCOLORBTN: 607 case WM_CTLCOLORDLG: 608 case WM_CTLCOLORSCROLLBAR: 609 case WM_CTLCOLORSTATIC: { 610 HWND hctl = (HWND) lparam; 611 return SendMessage(hctl, PM_DISPATCH_CTLCOLOR, wparam, nmsg); 612 } 613 614 default: 615 return super::WndProc(nmsg, wparam, lparam); 616 } 617 } 618 }; 619 620 621 #define PM_DISPATCH_DRAWITEM (WM_APP+0x09) 622 623 /// draw message routing for ColorButton and PictureButton 624 template<typename BASE> struct OwnerDrawParent : public BASE 625 { 626 typedef BASE super; 627 628 OwnerDrawParent(HWND hwnd) 629 : super(hwnd) {} 630 631 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) 632 { 633 switch(nmsg) { 634 case WM_DRAWITEM: 635 if (wparam) { // should there be drawn a control? 636 HWND hctl = GetDlgItem(this->_hwnd, wparam); 637 638 if (hctl) 639 return SendMessage(hctl, PM_DISPATCH_DRAWITEM, wparam, lparam); 640 } /*else // or is it a menu entry? 641 ; */ 642 643 return 0; 644 645 default: 646 return super::WndProc(nmsg, wparam, lparam); 647 } 648 } 649 }; 650 651 652 /** 653 Subclass button controls to draw them by using PM_DISPATCH_DRAWITEM 654 The owning window should use the OwnerDrawParent template to route owner draw messages to the buttons. 655 */ 656 struct OwnerdrawnButton : public SubclassedWindow 657 { 658 typedef SubclassedWindow super; 659 660 OwnerdrawnButton(HWND hwnd) 661 : super(hwnd) {} 662 663 protected: 664 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam); 665 666 virtual void DrawItem(LPDRAWITEMSTRUCT dis) = 0; 667 }; 668 669 extern void DrawGrayText(HDC hdc, LPRECT pRect, LPCTSTR text, int dt_flags); 670 671 672 /** 673 Subclass button controls to paint colored text labels. 674 The owning window should use the OwnerDrawParent template to route owner draw messages to the buttons. 675 */ 676 /* not yet used 677 struct ColorButton : public OwnerdrawnButton 678 { 679 typedef OwnerdrawnButton super; 680 681 ColorButton(HWND hwnd, COLORREF textColor) 682 : super(hwnd), _textColor(textColor) {} 683 684 protected: 685 virtual void DrawItem(LPDRAWITEMSTRUCT dis); 686 687 COLORREF _textColor; 688 }; 689 */ 690 691 692 struct FlatButton : public OwnerdrawnButton 693 { 694 typedef OwnerdrawnButton super; 695 696 FlatButton(HWND hwnd) 697 : super(hwnd), _active(false) {} 698 699 FlatButton(HWND owner, int id) 700 : super(GetDlgItem(owner, IDOK)), _active(false) {} 701 702 protected: 703 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam); 704 virtual void DrawItem(LPDRAWITEMSTRUCT dis); 705 706 COLORREF _textColor; 707 COLORREF _activeColor; 708 bool _active; 709 }; 710 711 712 /** 713 Subclass button controls to paint pictures left to the labels. 714 The buttons should have set the style bit BS_OWNERDRAW. 715 The owning window should use the OwnerDrawParent template to route owner draw messages to the buttons. 716 */ 717 struct PictureButton : public OwnerdrawnButton 718 { 719 typedef OwnerdrawnButton super; 720 721 PictureButton(HWND hwnd, HICON hIcon, HBRUSH hbrush=GetSysColorBrush(COLOR_BTNFACE), bool flat=false) 722 : super(hwnd), _hIcon(hIcon), _hBmp(0), _hBrush(hbrush), _flat(flat) 723 { 724 _cx = 16; 725 _cy = 16; 726 } 727 728 PictureButton(HWND hparent, int id, HICON hIcon, HBRUSH hbrush=GetSysColorBrush(COLOR_BTNFACE), bool flat=false) 729 : super(GetDlgItem(hparent, id)), _hIcon(hIcon), _hBmp(0), _hBrush(hbrush), _flat(flat) 730 { 731 _cx = 16; 732 _cy = 16; 733 } 734 735 PictureButton(HWND hwnd, HBITMAP hBmp, HBRUSH hbrush=GetSysColorBrush(COLOR_BTNFACE), bool flat=false) 736 : super(hwnd), _hIcon(0), _hBmp(hBmp), _hBrush(hbrush), _flat(flat) 737 { 738 BITMAP bmp; 739 GetObject(hBmp, sizeof(bmp), &bmp); 740 _cx = bmp.bmWidth; 741 _cy = bmp.bmHeight; 742 } 743 744 PictureButton(HWND hparent, int id, HBITMAP hBmp, HBRUSH hbrush=GetSysColorBrush(COLOR_BTNFACE), bool flat=false) 745 : super(GetDlgItem(hparent, id)), _hIcon(0), _hBmp(hBmp), _hBrush(hbrush), _flat(flat) 746 { 747 BITMAP bmp; 748 GetObject(hBmp, sizeof(bmp), &bmp); 749 _cx = bmp.bmWidth; 750 _cy = bmp.bmHeight; 751 } 752 753 protected: 754 virtual void DrawItem(LPDRAWITEMSTRUCT dis); 755 756 HICON _hIcon; 757 HBITMAP _hBmp; 758 HBRUSH _hBrush; 759 760 int _cx; 761 int _cy; 762 763 bool _flat; 764 }; 765 766 767 struct ColorStatic : public SubclassedWindow 768 { 769 typedef SubclassedWindow super; 770 771 ColorStatic(HWND hwnd, COLORREF textColor=RGB(255,0,0), HBRUSH hbrush_bkgnd=0, HFONT hfont=0) 772 : super(hwnd), 773 _textColor(textColor), 774 _hbrush_bkgnd(hbrush_bkgnd), 775 _hfont(hfont) 776 { 777 } 778 779 ColorStatic(HWND owner, int id, COLORREF textColor=RGB(255,0,0), HBRUSH hbrush_bkgnd=0, HFONT hfont=0) 780 : super(GetDlgItem(owner, id)), 781 _textColor(textColor), 782 _hbrush_bkgnd(hbrush_bkgnd), 783 _hfont(hfont) 784 { 785 } 786 787 protected: 788 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) 789 { 790 if (nmsg == PM_DISPATCH_CTLCOLOR) { 791 HDC hdc = (HDC) wparam; 792 793 SetTextColor(hdc, _textColor); 794 795 if (_hfont) 796 SelectFont(hdc, _hfont); 797 798 if (_hbrush_bkgnd) 799 return (LRESULT)_hbrush_bkgnd; 800 else { 801 SetBkMode(hdc, TRANSPARENT); 802 return (LRESULT)GetStockBrush(HOLLOW_BRUSH); 803 } 804 } else 805 return super::WndProc(nmsg, wparam, lparam); 806 } 807 808 COLORREF _textColor; 809 HBRUSH _hbrush_bkgnd; 810 HFONT _hfont; 811 }; 812 813 814 /// Hyperlink Controls 815 816 struct HyperlinkCtrl : public SubclassedWindow 817 { 818 typedef SubclassedWindow super; 819 820 HyperlinkCtrl(HWND hwnd, COLORREF colorLink=RGB(0,0,255), COLORREF colorVisited=RGB(128,0,128)); 821 HyperlinkCtrl(HWND owner, int id, COLORREF colorLink=RGB(0,0,255), COLORREF colorVisited=RGB(128,0,128)); 822 823 ~HyperlinkCtrl(); 824 825 String _cmd; 826 827 protected: 828 COLORREF _textColor; 829 COLORREF _colorVisited; 830 HFONT _hfont; 831 HCURSOR _crsr_link; 832 833 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam); 834 835 void init(); 836 837 bool LaunchLink() 838 { 839 if (!_cmd.empty()) { 840 HINSTANCE hinst = ShellExecute(GetParent(_hwnd), _T("open"), _cmd, 0, 0, SW_SHOWNORMAL); 841 return (INT_PTR)hinst > HINSTANCE_ERROR; 842 } 843 844 return true; 845 } 846 }; 847 848 849 /// encapsulation of tool tip controls 850 struct ToolTip : public WindowHandle 851 { 852 typedef WindowHandle super; 853 854 ToolTip(HWND owner); 855 856 void activate(BOOL active=TRUE) 857 { 858 SendMessage(_hwnd, TTM_ACTIVATE, active, 0); 859 } 860 861 void add(HWND hparent, HWND htool, LPCTSTR txt=LPSTR_TEXTCALLBACK, LPARAM lparam=0) 862 { 863 TOOLINFO ti = { 864 sizeof(TOOLINFO), TTF_SUBCLASS|TTF_IDISHWND|TTF_TRANSPARENT, hparent, (UINT_PTR)htool, 865 {0,0,0,0}, 0, (LPTSTR)txt, lparam 866 }; 867 868 #ifdef UNICODE ///@todo Why is it neccesary to try both TTM_ADDTOOLW and TTM_ADDTOOLW ?! 869 if (!SendMessage(_hwnd, TTM_ADDTOOLW, 0, (LPARAM)&ti)) 870 SendMessage(_hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti); 871 #else 872 if (!SendMessage(_hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti)) 873 SendMessage(_hwnd, TTM_ADDTOOLW, 0, (LPARAM)&ti); 874 #endif 875 } 876 877 void add(HWND hparent, UINT id, const RECT& rect, LPCTSTR txt=LPSTR_TEXTCALLBACK, LPARAM lparam=0) 878 { 879 TOOLINFO ti = { 880 sizeof(TOOLINFO), TTF_SUBCLASS|TTF_TRANSPARENT, hparent, id, 881 {rect.left,rect.top,rect.right,rect.bottom}, 0, (LPTSTR)txt, lparam 882 }; 883 884 #ifdef UNICODE 885 if (!SendMessage(_hwnd, TTM_ADDTOOLW, 0, (LPARAM)&ti)) 886 SendMessage(_hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti); 887 #else 888 if (!SendMessage(_hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti)) 889 SendMessage(_hwnd, TTM_ADDTOOLW, 0, (LPARAM)&ti); 890 #endif 891 } 892 893 void remove(HWND hparent, HWND htool) 894 { 895 TOOLINFO ti = { 896 sizeof(TOOLINFO), TTF_IDISHWND, hparent, (UINT_PTR)htool, 897 {0,0,0,0}, 0, 0, 0 898 }; 899 900 SendMessage(_hwnd, TTM_DELTOOL, 0, (LPARAM)&ti); 901 } 902 903 void remove(HWND hparent, UINT id) 904 { 905 TOOLINFO ti = { 906 sizeof(TOOLINFO), 0, hparent, id, 907 {0,0,0,0}, 0, 0, 0 908 }; 909 910 SendMessage(_hwnd, TTM_DELTOOL, 0, (LPARAM)&ti); 911 } 912 }; 913 914 915 inline int ListView_GetItemData(HWND list_ctrl, int idx) 916 { 917 LV_ITEM item; 918 919 item.mask = LVIF_PARAM; 920 item.iItem = idx; 921 922 if (!ListView_GetItem(list_ctrl, &item)) 923 return 0; 924 925 return item.lParam; 926 } 927 928 inline int ListView_FindItemPara(HWND list_ctrl, LPARAM param) 929 { 930 LVFINDINFO fi; 931 932 fi.flags = LVFI_PARAM; 933 fi.lParam = param; 934 935 return ListView_FindItem(list_ctrl, (unsigned)-1, &fi); 936 } 937 938 inline int ListView_GetFocusedItem(HWND list_ctrl) 939 { 940 int idx = ListView_GetItemCount(list_ctrl); 941 942 while(--idx >= 0) 943 if (ListView_GetItemState(list_ctrl, idx, LVIS_FOCUSED)) 944 break; 945 946 return idx; 947 } 948 949 950 /// sorting of list controls 951 struct ListSort : public WindowHandle 952 { 953 ListSort(HWND hwndListview, PFNLVCOMPARE compare_fct); 954 955 void toggle_sort(int idx); 956 void sort(); 957 958 int _sort_crit; 959 bool _direction; 960 961 protected: 962 PFNLVCOMPARE _compare_fct; 963 964 static int CALLBACK CompareFunc(LPARAM lparam1, LPARAM lparam2, LPARAM lparamSort); 965 }; 966 967 968 inline LPARAM TreeView_GetItemData(HWND hwndTreeView, HTREEITEM hItem) 969 { 970 TVITEM tvItem; 971 972 tvItem.mask = TVIF_PARAM; 973 tvItem.hItem = hItem; 974 975 if (!TreeView_GetItem(hwndTreeView, &tvItem)) 976 return 0; 977 978 return tvItem.lParam; 979 } 980 981 982 enum {TRAYBUTTON_LEFT=0, TRAYBUTTON_RIGHT, TRAYBUTTON_MIDDLE}; 983 984 #define PM_TRAYICON (WM_APP+0x20) 985 986 #define WINMSG_TASKBARCREATED TEXT("TaskbarCreated") 987 988 #define WINMSG_SHELLHOOK TEXT("SHELLHOOK") 989 990 991 struct TrayIcon 992 { 993 TrayIcon(HWND hparent, UINT id) 994 : _hparent(hparent), _id(id) {} 995 996 ~TrayIcon() 997 {Remove();} 998 999 void Add(HICON hIcon, LPCTSTR tooltip=NULL) 1000 {Set(NIM_ADD, _id, hIcon, tooltip);} 1001 1002 void Modify(HICON hIcon, LPCTSTR tooltip=NULL) 1003 {Set(NIM_MODIFY, _id, hIcon, tooltip);} 1004 1005 void Remove() 1006 { 1007 NOTIFYICONDATA nid = { 1008 sizeof(NOTIFYICONDATA), // cbSize 1009 _hparent, // hWnd 1010 _id, // uID 1011 }; 1012 1013 Shell_NotifyIcon(NIM_DELETE, &nid); 1014 } 1015 1016 protected: 1017 HWND _hparent; 1018 UINT _id; 1019 1020 void Set(DWORD dwMessage, UINT id, HICON hIcon, LPCTSTR tooltip=NULL) 1021 { 1022 NOTIFYICONDATA nid = { 1023 sizeof(NOTIFYICONDATA), // cbSize 1024 _hparent, // hWnd 1025 id, // uID 1026 NIF_MESSAGE|NIF_ICON, // uFlags 1027 PM_TRAYICON, // uCallbackMessage 1028 hIcon // hIcon 1029 }; 1030 1031 if (tooltip) 1032 lstrcpyn(nid.szTip, tooltip, COUNTOF(nid.szTip)); 1033 1034 if (nid.szTip[0]) 1035 nid.uFlags |= NIF_TIP; 1036 1037 Shell_NotifyIcon(dwMessage, &nid); 1038 } 1039 }; 1040 1041 1042 template<typename BASE> struct TrayIconControllerTemplate : public BASE 1043 { 1044 typedef BASE super; 1045 1046 TrayIconControllerTemplate(HWND hwnd) : BASE(hwnd), 1047 WM_TASKBARCREATED(RegisterWindowMessage(WINMSG_TASKBARCREATED)) 1048 { 1049 } 1050 1051 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) 1052 { 1053 if (nmsg == PM_TRAYICON) { 1054 switch(lparam) { 1055 case WM_MOUSEMOVE: 1056 TrayMouseOver(wparam); 1057 break; 1058 1059 case WM_LBUTTONDOWN: 1060 TrayClick(wparam, TRAYBUTTON_LEFT); 1061 break; 1062 1063 case WM_LBUTTONDBLCLK: 1064 TrayDblClick(wparam, TRAYBUTTON_LEFT); 1065 break; 1066 1067 case WM_RBUTTONDOWN: 1068 TrayClick(wparam, TRAYBUTTON_RIGHT); 1069 break; 1070 1071 case WM_RBUTTONDBLCLK: 1072 TrayDblClick(wparam, TRAYBUTTON_RIGHT); 1073 break; 1074 1075 case WM_MBUTTONDOWN: 1076 TrayClick(wparam, TRAYBUTTON_MIDDLE); 1077 break; 1078 1079 case WM_MBUTTONDBLCLK: 1080 TrayDblClick(wparam, TRAYBUTTON_MIDDLE); 1081 break; 1082 } 1083 1084 return 0; 1085 } else if (nmsg == WM_TASKBARCREATED) { 1086 AddTrayIcons(); 1087 return 0; 1088 } else 1089 return super::WndProc(nmsg, wparam, lparam); 1090 } 1091 1092 virtual void AddTrayIcons() = 0; 1093 virtual void TrayMouseOver(UINT id) {} 1094 virtual void TrayClick(UINT id, int btn) {} 1095 virtual void TrayDblClick(UINT id, int btn) {} 1096 1097 protected: 1098 const UINT WM_TASKBARCREATED; 1099 }; 1100 1101 1102 struct EditController : public SubclassedWindow 1103 { 1104 typedef SubclassedWindow super; 1105 1106 EditController(HWND hwnd) 1107 : super(hwnd) 1108 { 1109 } 1110 1111 protected: 1112 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) 1113 { 1114 if (nmsg==WM_KEYDOWN && wparam==VK_RETURN) { 1115 SendParent(WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(_hwnd),1), (LPARAM)_hwnd); 1116 return 0; 1117 } else 1118 return super::WndProc(nmsg, wparam, lparam); 1119 } 1120 }; 1121