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