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 {
ChildWndInfoChildWndInfo46 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
get_windowWindow87 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 {
get_windowGetWindowHelper151 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 {
dyn_castTypeCheck162 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 {
window_creatorWindowCreator196 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 {
window_creatorWindowCreatorInfo209 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
RegisterWindowClass230 ATOM Register()
231 {
232 if (!_atomClass)
233 _atomClass = RegisterClassEx(this);
234
235 return _atomClass;
236 }
237
ATOMWindowClass238 operator ATOM() {return Register();}
239
240 // return LPCTSTR for the CreateWindowEx() parameter
LPCTSTRWindowClass241 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)
WindowClassBtnWindowClass251 : 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
DialogWindowDialogWindow353 DialogWindow(HWND hwnd)
354 : super(hwnd)
355 {
356 register_dialog(hwnd);
357 }
358
~DialogWindowDialogWindow359 ~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 {
ResizeEntryResizeEntry473 ResizeEntry(UINT id, int flags)
474 : _id(id), _flags(flags) {}
475
ResizeEntryResizeEntry476 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
AddResizeManager491 void Add(UINT id, int flags)
492 {push_back(ResizeEntry(id, flags));}
493
AddResizeManager494 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
SetMinMaxInfoResizeManager500 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
ResizeControllerResizeController519 ResizeController(HWND hwnd)
520 : super(hwnd),
521 _resize_mgr(hwnd)
522 {
523 }
524
WndProcResizeController525 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
GetClientSpaceResizeController546 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
CtlColorParentCtlColorParent599 CtlColorParent(HWND hwnd)
600 : super(hwnd) {}
601
WndProcCtlColorParent602 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
OwnerDrawParentOwnerDrawParent628 OwnerDrawParent(HWND hwnd)
629 : super(hwnd) {}
630
WndProcOwnerDrawParent631 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
OwnerdrawnButtonOwnerdrawnButton660 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
FlatButtonFlatButton696 FlatButton(HWND hwnd)
697 : super(hwnd), _active(false) {}
698
FlatButtonFlatButton699 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)
superPictureButton722 : 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)
superPictureButton729 : 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)
superPictureButton736 : 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)
superPictureButton745 : 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)
superColorStatic772 : 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)
superColorStatic780 : super(GetDlgItem(owner, id)),
781 _textColor(textColor),
782 _hbrush_bkgnd(hbrush_bkgnd),
783 _hfont(hfont)
784 {
785 }
786
787 protected:
WndProcColorStatic788 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
LaunchLinkHyperlinkCtrl837 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
removeToolTip893 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
removeToolTip903 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
ListView_GetItemData(HWND list_ctrl,int idx)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
ListView_FindItemPara(HWND list_ctrl,LPARAM param)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
ListView_GetFocusedItem(HWND list_ctrl)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
TreeView_GetItemData(HWND hwndTreeView,HTREEITEM hItem)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 {
TrayIconTrayIcon993 TrayIcon(HWND hparent, UINT id)
994 : _hparent(hparent), _id(id) {}
995
~TrayIconTrayIcon996 ~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
RemoveTrayIcon1005 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
TrayIconControllerTemplateTrayIconControllerTemplate1046 TrayIconControllerTemplate(HWND hwnd) : BASE(hwnd),
1047 WM_TASKBARCREATED(RegisterWindowMessage(WINMSG_TASKBARCREATED))
1048 {
1049 }
1050
WndProcTrayIconControllerTemplate1051 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;
TrayMouseOverTrayIconControllerTemplate1093 virtual void TrayMouseOver(UINT id) {}
TrayClickTrayIconControllerTemplate1094 virtual void TrayClick(UINT id, int btn) {}
TrayDblClickTrayIconControllerTemplate1095 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
EditControllerEditController1106 EditController(HWND hwnd)
1107 : super(hwnd)
1108 {
1109 }
1110
1111 protected:
WndProcEditController1112 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