1e60a7382506e93071ac317420cfda0500e0372d
[reactos.git] / reactos / subsys / system / explorer / utility / window.h
1 /*
2 * Copyright 2003, 2004 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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, DWORD dwExStyle,
70 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(HWND hwnd=0);
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 Class ChildWindow represents MDI child windows.
287 It is used with class MainFrame.
288 */
289 struct ChildWindow : public Window
290 {
291 typedef Window super;
292
293 ChildWindow(HWND hwnd, const ChildWndInfo& info);
294
295 static ChildWindow* create(const ChildWndInfo& info, const RECT& rect, CREATORFUNC_INFO creator,
296 LPCTSTR classname, LPCTSTR title=NULL, DWORD style=0);
297
298 bool go_to(LPCTSTR url);
299
300 protected:
301 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam);
302
303 virtual void resize_children(int cx, int cy);
304 virtual String jump_to_int(LPCTSTR url) = 0;
305
306 protected:
307 MenuInfo*_menu_info;
308
309 WindowHandle _left_hwnd;
310 WindowHandle _right_hwnd;
311 int _focus_pane; // 0: left 1: right
312
313 int _split_pos;
314 int _last_split;
315
316 HWND _hwndFrame;
317 String _statusText;
318 String _url;
319
320 stack<String> _url_history;
321
322 void set_url(LPCTSTR url);
323 };
324
325 #define PM_SETSTATUSTEXT (WM_APP+0x1E)
326
327
328 /**
329 PreTranslateWindow is used to register windows to be called by Window::pretranslate_msg().
330 This way you get PM_TRANSLATE_MSG messages before the message loop dispatches messages.
331 You can then for example use TranslateAccelerator() to implement key shortcuts.
332 */
333 struct PreTranslateWindow : public Window
334 {
335 typedef Window super;
336
337 PreTranslateWindow(HWND);
338 ~PreTranslateWindow();
339 };
340
341
342 /**
343 The class DialogWindow implements modeless dialogs, which are managed by
344 Window::dispatch_dialog_msg() in Window::MessageLoop().
345 A DialogWindow object should be constructed by calling Window::Create()
346 and specifying the class using the WINDOW_CREATOR() macro.
347 */
348 struct DialogWindow : public Window
349 {
350 typedef Window super;
351
352 DialogWindow(HWND hwnd)
353 : super(hwnd)
354 {
355 register_dialog(hwnd);
356 }
357
358 ~DialogWindow()
359 {
360 unregister_dialog(_hwnd);
361 }
362 };
363
364
365 /**
366 The class Dialog implements modal dialogs.
367 A Dialog object should be constructed by calling Dialog::DoModal()
368 and specifying the class using the WINDOW_CREATOR() macro.
369 */
370 struct Dialog : public Window
371 {
372 typedef Window super;
373
374 Dialog(HWND);
375 ~Dialog();
376
377 static int DoModal(UINT nid, CREATORFUNC creator, HWND hwndParent=0);
378 static int DoModal(UINT nid, CREATORFUNC_INFO creator, const void* info, HWND hwndParent=0);
379
380 protected:
381 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam);
382 int Command(int id, int code);
383 };
384
385
386 #define PM_FRM_CALC_CLIENT (WM_APP+0x03)
387 #define Frame_CalcFrameClient(hwnd, prt) ((BOOL)SNDMSG(hwnd, PM_FRM_CALC_CLIENT, 0, (LPARAM)(PRECT)prt))
388
389 #define PM_JUMP_TO_URL (WM_APP+0x25)
390 #define PM_URL_CHANGED (WM_APP+0x26)
391
392
393 struct PropSheetPage : public PROPSHEETPAGE
394 {
395 PropSheetPage(UINT nid, Window::CREATORFUNC dlg_creator);
396
397 void init(struct PropertySheetDialog*);
398
399 protected:
400 friend struct PropSheetPageDlg;
401
402 Window::CREATORFUNC _dlg_creator;
403 };
404
405
406 /// Property Sheet dialog
407 struct PropertySheetDialog : public PROPSHEETHEADER
408 {
409 PropertySheetDialog(HWND owner);
410
411 void add(PropSheetPage& psp);
412 int DoModal(int start_page=0);
413
414 HWND GetCurrentPage();
415
416 protected:
417 typedef vector<PROPSHEETPAGE> Vector;
418 Vector _pages;
419 HWND _hwnd;
420 };
421
422
423 /// Property Sheet Page (inner dialog)
424 struct PropSheetPageDlg : public Dialog
425 {
426 typedef Dialog super;
427
428 PropSheetPageDlg(HWND);
429
430 protected:
431 friend struct PropertySheetDialog;
432 friend struct PropSheetPage;
433
434 static INT_PTR CALLBACK DialogProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam);
435
436 int Command(int id, int code);
437 };
438
439
440 /*
441 /// Property Sheet Dialog (outer dialog)
442 struct PropertySheetDlg : public SubclassedWindow
443 {
444 typedef SubclassedWindow super;
445
446 PropertySheetDlg(HWND hwnd) : super(hwnd) {}
447 };
448 */
449
450
451 // Layouting of resizable windows
452
453 /// Flags to specify how to move and resize controls when resizing their parent window
454 enum RESIZE_FLAGS {
455 MOVE_LEFT = 0x1,
456 MOVE_RIGHT = 0x2,
457 MOVE_TOP = 0x4,
458 MOVE_BOTTOM = 0x8,
459
460 MOVE_X = MOVE_LEFT | MOVE_RIGHT,
461 MOVE_Y = MOVE_TOP | MOVE_BOTTOM,
462 RESIZE_X= MOVE_RIGHT,
463 RESIZE_Y= MOVE_BOTTOM,
464
465 MOVE = MOVE_X | MOVE_Y,
466 RESIZE = RESIZE_X | RESIZE_Y
467 };
468
469 /// structure to assign RESIZE_FLAGS to dialogs control
470 struct ResizeEntry
471 {
472 ResizeEntry(UINT id, int flags)
473 : _id(id), _flags(flags) {}
474
475 ResizeEntry(HWND hwnd, int flags)
476 : _id(GetDlgCtrlID(hwnd)), _flags(flags) {}
477
478 UINT _id;
479 int _flags;
480 };
481
482
483 /// Management of controls in resizable dialogs
484 struct ResizeManager : public std::list<ResizeEntry>
485 {
486 typedef std::list<ResizeEntry> super;
487
488 ResizeManager(HWND hwnd);
489
490 void Add(UINT id, int flags)
491 {push_back(ResizeEntry(id, flags));}
492
493 void Add(HWND hwnd, int flags)
494 {push_back(ResizeEntry(hwnd, flags));}
495
496 void HandleSize(int cx, int cy);
497 void Resize(int dx, int dy);
498
499 void SetMinMaxInfo(LPMINMAXINFO lpmmi)
500 {
501 lpmmi->ptMinTrackSize.x = _min_wnd_size.cx;
502 lpmmi->ptMinTrackSize.y = _min_wnd_size.cy;
503 }
504
505 SIZE _min_wnd_size;
506
507 protected:
508 HWND _hwnd;
509 SIZE _last_size;
510 };
511
512
513 /// Controller base template class for resizable dialogs
514 template<typename BASE> struct ResizeController : public BASE
515 {
516 typedef BASE super;
517
518 ResizeController(HWND hwnd)
519 : super(hwnd),
520 _resize_mgr(hwnd)
521 {
522 }
523
524 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
525 {
526 switch(nmsg) {
527 case PM_FRM_CALC_CLIENT:
528 GetClientSpace((PRECT)lparam);
529 return TRUE;
530
531 case WM_SIZE:
532 if (wparam != SIZE_MINIMIZED)
533 _resize_mgr.HandleSize(LOWORD(lparam), HIWORD(lparam));
534 goto def;
535
536 case WM_GETMINMAXINFO:
537 _resize_mgr.SetMinMaxInfo((LPMINMAXINFO)lparam);
538 goto def;
539
540 default: def:
541 return super::WndProc(nmsg, wparam, lparam);
542 }
543 }
544
545 virtual void GetClientSpace(PRECT prect)
546 {
547 if (!IsIconic(this->_hwnd)) {
548 GetClientRect(this->_hwnd, prect);
549 } else {
550 WINDOWPLACEMENT wp;
551 GetWindowPlacement(this->_hwnd, &wp);
552 prect->left = prect->top = 0;
553 prect->right = wp.rcNormalPosition.right-wp.rcNormalPosition.left-
554 2*(GetSystemMetrics(SM_CXSIZEFRAME)+GetSystemMetrics(SM_CXEDGE));
555 prect->bottom = wp.rcNormalPosition.bottom-wp.rcNormalPosition.top-
556 2*(GetSystemMetrics(SM_CYSIZEFRAME)+GetSystemMetrics(SM_CYEDGE))-
557 GetSystemMetrics(SM_CYCAPTION)-GetSystemMetrics(SM_CYMENUSIZE);
558 }
559 }
560
561 protected:
562 ResizeManager _resize_mgr;
563 };
564
565
566 /**
567 This class constructs button controls.
568 The button will remain existent when the C++ Button object is destroyed.
569 There is no conjunction between C++ object and windows control life time.
570 */
571 struct Button : public WindowHandle
572 {
573 Button(HWND parent, LPCTSTR text, int left, int top, int width, int height,
574 int id, DWORD flags=WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, DWORD exStyle=0);
575 };
576
577
578 /**
579 This class constructs static controls.
580 The control will remain existent when the C++ object is destroyed.
581 There is no conjunction between C++ object and windows control life time.
582 */
583 struct Static : public WindowHandle
584 {
585 Static(HWND parent, LPCTSTR text, int left, int top, int width, int height,
586 int id, DWORD flags=WS_VISIBLE|WS_CHILD|SS_SIMPLE, DWORD ex_flags=0);
587 };
588
589
590 // control color message routing for ColorStatic and HyperlinkCtrl
591
592 #define PM_DISPATCH_CTLCOLOR (WM_APP+0x08)
593
594 template<typename BASE> struct CtlColorParent : public BASE
595 {
596 typedef BASE super;
597
598 CtlColorParent(HWND hwnd)
599 : super(hwnd) {}
600
601 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
602 {
603 switch(nmsg) {
604 case WM_CTLCOLOR:
605 case WM_CTLCOLORBTN:
606 case WM_CTLCOLORDLG:
607 case WM_CTLCOLORSCROLLBAR:
608 case WM_CTLCOLORSTATIC: {
609 HWND hctl = (HWND) lparam;
610 return SendMessage(hctl, PM_DISPATCH_CTLCOLOR, wparam, nmsg);
611 }
612
613 default:
614 return super::WndProc(nmsg, wparam, lparam);
615 }
616 }
617 };
618
619
620 #define PM_DISPATCH_DRAWITEM (WM_APP+0x09)
621
622 /// draw message routing for ColorButton and PictureButton
623 template<typename BASE> struct OwnerDrawParent : public BASE
624 {
625 typedef BASE super;
626
627 OwnerDrawParent(HWND hwnd)
628 : super(hwnd) {}
629
630 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
631 {
632 switch(nmsg) {
633 case WM_DRAWITEM:
634 if (wparam) { // should there be drawn a control?
635 HWND hctl = GetDlgItem(this->_hwnd, wparam);
636
637 if (hctl)
638 return SendMessage(hctl, PM_DISPATCH_DRAWITEM, wparam, lparam);
639 } /*else // or is it a menu entry?
640 ; */
641
642 return 0;
643
644 default:
645 return super::WndProc(nmsg, wparam, lparam);
646 }
647 }
648 };
649
650
651 /**
652 Subclass button controls to draw them by using PM_DISPATCH_DRAWITEM
653 The owning window should use the OwnerDrawParent template to route owner draw messages to the buttons.
654 */
655 struct OwnerdrawnButton : public SubclassedWindow
656 {
657 typedef SubclassedWindow super;
658
659 OwnerdrawnButton(HWND hwnd)
660 : super(hwnd) {}
661
662 protected:
663 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam);
664
665 virtual void DrawItem(LPDRAWITEMSTRUCT dis) = 0;
666 };
667
668 extern void DrawGrayText(HDC hdc, LPRECT pRect, LPCTSTR text, int dt_flags);
669
670
671 /**
672 Subclass button controls to paint colored text labels.
673 The owning window should use the OwnerDrawParent template to route owner draw messages to the buttons.
674 */
675 /* not yet used
676 struct ColorButton : public OwnerdrawnButton
677 {
678 typedef OwnerdrawnButton super;
679
680 ColorButton(HWND hwnd, COLORREF textColor)
681 : super(hwnd), _textColor(textColor) {}
682
683 protected:
684 virtual void DrawItem(LPDRAWITEMSTRUCT dis);
685
686 COLORREF _textColor;
687 };
688 */
689
690
691 struct FlatButton : public OwnerdrawnButton
692 {
693 typedef OwnerdrawnButton super;
694
695 FlatButton(HWND hwnd)
696 : super(hwnd), _active(false) {}
697
698 FlatButton(HWND owner, int id)
699 : super(GetDlgItem(owner, IDOK)), _active(false) {}
700
701 protected:
702 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam);
703 virtual void DrawItem(LPDRAWITEMSTRUCT dis);
704
705 COLORREF _textColor;
706 COLORREF _activeColor;
707 bool _active;
708 };
709
710
711 /**
712 Subclass button controls to paint pictures left to the labels.
713 The buttons should have set the style bit BS_OWNERDRAW.
714 The owning window should use the OwnerDrawParent template to route owner draw messages to the buttons.
715 */
716 struct PictureButton : public OwnerdrawnButton
717 {
718 typedef OwnerdrawnButton super;
719
720 PictureButton(HWND hwnd, HICON hIcon, HBRUSH hbrush=GetSysColorBrush(COLOR_BTNFACE), bool flat=false)
721 : super(hwnd), _hIcon(hIcon), _hBmp(0), _hBrush(hbrush), _flat(flat)
722 {
723 _cx = 16;
724 _cy = 16;
725 }
726
727 PictureButton(HWND hparent, int id, HICON hIcon, HBRUSH hbrush=GetSysColorBrush(COLOR_BTNFACE), bool flat=false)
728 : super(GetDlgItem(hparent, id)), _hIcon(hIcon), _hBmp(0), _hBrush(hbrush), _flat(flat)
729 {
730 _cx = 16;
731 _cy = 16;
732 }
733
734 PictureButton(HWND hwnd, HBITMAP hBmp, HBRUSH hbrush=GetSysColorBrush(COLOR_BTNFACE), bool flat=false)
735 : super(hwnd), _hIcon(0), _hBmp(hBmp), _hBrush(hbrush), _flat(flat)
736 {
737 BITMAP bmp;
738 GetObject(hBmp, sizeof(bmp), &bmp);
739 _cx = bmp.bmWidth;
740 _cy = bmp.bmHeight;
741 }
742
743 PictureButton(HWND hparent, int id, HBITMAP hBmp, HBRUSH hbrush=GetSysColorBrush(COLOR_BTNFACE), bool flat=false)
744 : super(GetDlgItem(hparent, id)), _hIcon(0), _hBmp(hBmp), _hBrush(hbrush), _flat(flat)
745 {
746 BITMAP bmp;
747 GetObject(hBmp, sizeof(bmp), &bmp);
748 _cx = bmp.bmWidth;
749 _cy = bmp.bmHeight;
750 }
751
752 protected:
753 virtual void DrawItem(LPDRAWITEMSTRUCT dis);
754
755 HICON _hIcon;
756 HBITMAP _hBmp;
757 HBRUSH _hBrush;
758
759 int _cx;
760 int _cy;
761
762 bool _flat;
763 };
764
765
766 struct ColorStatic : public SubclassedWindow
767 {
768 typedef SubclassedWindow super;
769
770 ColorStatic(HWND hwnd, COLORREF textColor=RGB(255,0,0), HBRUSH hbrush_bkgnd=0, HFONT hfont=0)
771 : super(hwnd),
772 _textColor(textColor),
773 _hbrush_bkgnd(hbrush_bkgnd),
774 _hfont(hfont)
775 {
776 }
777
778 ColorStatic(HWND owner, int id, COLORREF textColor=RGB(255,0,0), HBRUSH hbrush_bkgnd=0, HFONT hfont=0)
779 : super(GetDlgItem(owner, id)),
780 _textColor(textColor),
781 _hbrush_bkgnd(hbrush_bkgnd),
782 _hfont(hfont)
783 {
784 }
785
786 protected:
787 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
788 {
789 if (nmsg == PM_DISPATCH_CTLCOLOR) {
790 HDC hdc = (HDC) wparam;
791
792 SetTextColor(hdc, _textColor);
793
794 if (_hfont)
795 SelectFont(hdc, _hfont);
796
797 if (_hbrush_bkgnd)
798 return (LRESULT)_hbrush_bkgnd;
799 else {
800 SetBkMode(hdc, TRANSPARENT);
801 return (LRESULT)GetStockBrush(HOLLOW_BRUSH);
802 }
803 } else
804 return super::WndProc(nmsg, wparam, lparam);
805 }
806
807 COLORREF _textColor;
808 HBRUSH _hbrush_bkgnd;
809 HFONT _hfont;
810 };
811
812
813 /// Hyperlink Controls
814
815 struct HyperlinkCtrl : public SubclassedWindow
816 {
817 typedef SubclassedWindow super;
818
819 HyperlinkCtrl(HWND hwnd, COLORREF colorLink=RGB(0,0,255), COLORREF colorVisited=RGB(128,0,128));
820 HyperlinkCtrl(HWND owner, int id, COLORREF colorLink=RGB(0,0,255), COLORREF colorVisited=RGB(128,0,128));
821
822 ~HyperlinkCtrl();
823
824 String _cmd;
825
826 protected:
827 COLORREF _textColor;
828 COLORREF _colorVisited;
829 HFONT _hfont;
830 HCURSOR _crsr_link;
831
832 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam);
833
834 void init();
835
836 bool LaunchLink()
837 {
838 if (!_cmd.empty()) {
839 HINSTANCE hinst = ShellExecute(GetParent(_hwnd), _T("open"), _cmd, 0, 0, SW_SHOWNORMAL);
840 return (int)hinst > HINSTANCE_ERROR;
841 }
842
843 return true;
844 }
845 };
846
847
848 /// encapsulation of tool tip controls
849 struct ToolTip : public WindowHandle
850 {
851 typedef WindowHandle super;
852
853 ToolTip(HWND owner);
854
855 void activate(BOOL active=TRUE)
856 {
857 SendMessage(_hwnd, TTM_ACTIVATE, active, 0);
858 }
859
860 void add(HWND hparent, HWND htool, LPCTSTR txt=LPSTR_TEXTCALLBACK, LPARAM lparam=0)
861 {
862 TOOLINFO ti = {
863 sizeof(TOOLINFO), TTF_SUBCLASS|TTF_IDISHWND|TTF_TRANSPARENT, hparent, (UINT)htool,
864 {0,0,0,0}, 0, (LPTSTR)txt, lparam
865 };
866
867 #ifdef UNICODE ///@todo Why is it neccesary to try both TTM_ADDTOOLW and TTM_ADDTOOLW ?!
868 if (!SendMessage(_hwnd, TTM_ADDTOOLW, 0, (LPARAM)&ti))
869 SendMessage(_hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
870 #else
871 if (!SendMessage(_hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti))
872 SendMessage(_hwnd, TTM_ADDTOOLW, 0, (LPARAM)&ti);
873 #endif
874 }
875
876 void add(HWND hparent, UINT id, const RECT& rect, LPCTSTR txt=LPSTR_TEXTCALLBACK, LPARAM lparam=0)
877 {
878 TOOLINFO ti = {
879 sizeof(TOOLINFO), TTF_SUBCLASS|TTF_TRANSPARENT, hparent, id,
880 {rect.left,rect.top,rect.right,rect.bottom}, 0, (LPTSTR)txt, lparam
881 };
882
883 #ifdef UNICODE
884 if (!SendMessage(_hwnd, TTM_ADDTOOLW, 0, (LPARAM)&ti))
885 SendMessage(_hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
886 #else
887 if (!SendMessage(_hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti))
888 SendMessage(_hwnd, TTM_ADDTOOLW, 0, (LPARAM)&ti);
889 #endif
890 }
891
892 void remove(HWND hparent, HWND htool)
893 {
894 TOOLINFO ti = {
895 sizeof(TOOLINFO), TTF_IDISHWND, hparent, (UINT)htool,
896 {0,0,0,0}, 0, 0, 0
897 };
898
899 SendMessage(_hwnd, TTM_DELTOOL, 0, (LPARAM)&ti);
900 }
901
902 void remove(HWND hparent, UINT id)
903 {
904 TOOLINFO ti = {
905 sizeof(TOOLINFO), 0, hparent, id,
906 {0,0,0,0}, 0, 0, 0
907 };
908
909 SendMessage(_hwnd, TTM_DELTOOL, 0, (LPARAM)&ti);
910 }
911 };
912
913
914 inline int ListView_GetItemData(HWND list_ctrl, int idx)
915 {
916 LV_ITEM item;
917
918 item.mask = LVIF_PARAM;
919 item.iItem = idx;
920
921 if (!ListView_GetItem(list_ctrl, &item))
922 return 0;
923
924 return item.lParam;
925 }
926
927 inline int ListView_FindItemPara(HWND list_ctrl, LPARAM param)
928 {
929 LVFINDINFO fi;
930
931 fi.flags = LVFI_PARAM;
932 fi.lParam = param;
933
934 return ListView_FindItem(list_ctrl, (unsigned)-1, &fi);
935 }
936
937 inline int ListView_GetFocusedItem(HWND list_ctrl)
938 {
939 int idx = ListView_GetItemCount(list_ctrl);
940
941 while(--idx >= 0)
942 if (ListView_GetItemState(list_ctrl, idx, LVIS_FOCUSED))
943 break;
944
945 return idx;
946 }
947
948
949 /// sorting of list controls
950 struct ListSort : public WindowHandle
951 {
952 ListSort(HWND hwndListview, PFNLVCOMPARE compare_fct);
953
954 void toggle_sort(int idx);
955 void sort();
956
957 int _sort_crit;
958 bool _direction;
959
960 protected:
961 PFNLVCOMPARE _compare_fct;
962
963 static int CALLBACK CompareFunc(LPARAM lparam1, LPARAM lparam2, LPARAM lparamSort);
964 };
965
966
967 inline LPARAM TreeView_GetItemData(HWND hwndTreeView, HTREEITEM hItem)
968 {
969 TVITEM tvItem;
970
971 tvItem.mask = TVIF_PARAM;
972 tvItem.hItem = hItem;
973
974 if (!TreeView_GetItem(hwndTreeView, &tvItem))
975 return 0;
976
977 return tvItem.lParam;
978 }
979
980
981 enum {TRAYBUTTON_LEFT=0, TRAYBUTTON_RIGHT, TRAYBUTTON_MIDDLE};
982
983 #define PM_TRAYICON (WM_APP+0x20)
984
985 #define WINMSG_TASKBARCREATED TEXT("TaskbarCreated")
986
987 #define WINMSG_SHELLHOOK TEXT("SHELLHOOK")
988
989
990 struct TrayIcon
991 {
992 TrayIcon(HWND hparent, UINT id)
993 : _hparent(hparent), _id(id) {}
994
995 ~TrayIcon()
996 {Remove();}
997
998 void Add(HICON hIcon, LPCTSTR tooltip=NULL)
999 {Set(NIM_ADD, _id, hIcon, tooltip);}
1000
1001 void Modify(HICON hIcon, LPCTSTR tooltip=NULL)
1002 {Set(NIM_MODIFY, _id, hIcon, tooltip);}
1003
1004 void Remove()
1005 {
1006 NOTIFYICONDATA nid = {
1007 sizeof(NOTIFYICONDATA), // cbSize
1008 _hparent, // hWnd
1009 _id, // uID
1010 };
1011
1012 Shell_NotifyIcon(NIM_DELETE, &nid);
1013 }
1014
1015 protected:
1016 HWND _hparent;
1017 UINT _id;
1018
1019 void Set(DWORD dwMessage, UINT id, HICON hIcon, LPCTSTR tooltip=NULL)
1020 {
1021 NOTIFYICONDATA nid = {
1022 sizeof(NOTIFYICONDATA), // cbSize
1023 _hparent, // hWnd
1024 id, // uID
1025 NIF_MESSAGE|NIF_ICON, // uFlags
1026 PM_TRAYICON, // uCallbackMessage
1027 hIcon // hIcon
1028 };
1029
1030 if (tooltip)
1031 lstrcpyn(nid.szTip, tooltip, COUNTOF(nid.szTip));
1032
1033 if (nid.szTip[0])
1034 nid.uFlags |= NIF_TIP;
1035
1036 Shell_NotifyIcon(dwMessage, &nid);
1037 }
1038 };
1039
1040
1041 template<typename BASE> struct TrayIconControllerTemplate : public BASE
1042 {
1043 typedef BASE super;
1044
1045 TrayIconControllerTemplate(HWND hwnd) : BASE(hwnd),
1046 WM_TASKBARCREATED(RegisterWindowMessage(WINMSG_TASKBARCREATED))
1047 {
1048 }
1049
1050 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
1051 {
1052 if (nmsg == PM_TRAYICON) {
1053 switch(lparam) {
1054 case WM_MOUSEMOVE:
1055 TrayMouseOver(wparam);
1056 break;
1057
1058 case WM_LBUTTONDOWN:
1059 TrayClick(wparam, TRAYBUTTON_LEFT);
1060 break;
1061
1062 case WM_LBUTTONDBLCLK:
1063 TrayDblClick(wparam, TRAYBUTTON_LEFT);
1064 break;
1065
1066 case WM_RBUTTONDOWN:
1067 TrayClick(wparam, TRAYBUTTON_RIGHT);
1068 break;
1069
1070 case WM_RBUTTONDBLCLK:
1071 TrayDblClick(wparam, TRAYBUTTON_RIGHT);
1072 break;
1073
1074 case WM_MBUTTONDOWN:
1075 TrayClick(wparam, TRAYBUTTON_MIDDLE);
1076 break;
1077
1078 case WM_MBUTTONDBLCLK:
1079 TrayDblClick(wparam, TRAYBUTTON_MIDDLE);
1080 break;
1081 }
1082
1083 return 0;
1084 } else if (nmsg == WM_TASKBARCREATED) {
1085 AddTrayIcons();
1086 return 0;
1087 } else
1088 return super::WndProc(nmsg, wparam, lparam);
1089 }
1090
1091 virtual void AddTrayIcons() = 0;
1092 virtual void TrayMouseOver(UINT id) {}
1093 virtual void TrayClick(UINT id, int btn) {}
1094 virtual void TrayDblClick(UINT id, int btn) {}
1095
1096 protected:
1097 const UINT WM_TASKBARCREATED;
1098 };
1099
1100
1101 struct EditController : public SubclassedWindow
1102 {
1103 typedef SubclassedWindow super;
1104
1105 EditController(HWND hwnd)
1106 : super(hwnd)
1107 {
1108 }
1109
1110 protected:
1111 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
1112 {
1113 if (nmsg==WM_KEYDOWN && wparam==VK_RETURN) {
1114 SendParent(WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(_hwnd),1), (LPARAM)_hwnd);
1115 return 0;
1116 } else
1117 return super::WndProc(nmsg, wparam, lparam);
1118 }
1119 };