2 * Copyright 2003, 2004, 2005 Martin Fuchs
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.
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.
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
25 // Martin Fuchs, 23.07.2003
31 WindowClass::WindowClass(LPCTSTR classname
, UINT style_
, WNDPROC wndproc
)
33 memset(this, 0, sizeof(WNDCLASSEX
));
35 cbSize
= sizeof(WNDCLASSEX
);
37 hInstance
= g_Globals
._hInstance
;
38 hCursor
= LoadCursor(0, IDC_ARROW
);
39 this->hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+1);
40 lpszClassName
= classname
;
41 lpfnWndProc
= wndproc
;
47 IconWindowClass::IconWindowClass(LPCTSTR classname
, UINT nid
, UINT style
, WNDPROC wndproc
)
48 : WindowClass(classname
, style
, wndproc
)
51 hIconSm
= SmallIcon(nid
);
55 Window::WindowMap
Window::s_wnd_map
;
57 Window::CREATORFUNC
Window::s_window_creator
= NULL
;
58 const void* Window::s_new_info
= NULL
;
60 HHOOK
Window::s_hcbtHook
= 0;
63 Window::StaticWindowData
& Window::GetStaticWindowData()
65 static StaticWindowData s_initialized_data
;
67 return s_initialized_data
;
71 Window::Window(HWND hwnd
)
74 Lock
lock(GetStaticWindowData()._map_crit_sect
); // protect access to s_wnd_map
76 s_wnd_map
[_hwnd
] = this;
81 Lock
lock(GetStaticWindowData()._map_crit_sect
); // protect access to s_wnd_map
83 s_wnd_map
.erase(_hwnd
);
87 HWND
Window::Create(CREATORFUNC creator
, DWORD dwExStyle
,
88 LPCTSTR lpClassName
, LPCTSTR lpWindowName
,
89 DWORD dwStyle
, int x
, int y
, int w
, int h
,
90 HWND hwndParent
, HMENU hMenu
/*, LPVOID lpParam*/)
92 Lock
lock(GetStaticWindowData()._create_crit_sect
); // protect access to s_window_creator and s_new_info
94 s_window_creator
= creator
;
97 return CreateWindowEx(dwExStyle
, lpClassName
, lpWindowName
, dwStyle
,
99 hwndParent
, hMenu
, g_Globals
._hInstance
, 0/*lpParam*/);
102 HWND
Window::Create(CREATORFUNC_INFO creator
, const void* info
, DWORD dwExStyle
,
103 LPCTSTR lpClassName
, LPCTSTR lpWindowName
,
104 DWORD dwStyle
, int x
, int y
, int w
, int h
,
105 HWND hwndParent
, HMENU hMenu
/*, LPVOID lpParam*/)
107 Lock
lock(GetStaticWindowData()._create_crit_sect
); // protect access to s_window_creator and s_new_info
109 s_window_creator
= (CREATORFUNC
) creator
;
112 return CreateWindowEx(dwExStyle
, lpClassName
, lpWindowName
, dwStyle
,
114 hwndParent
, hMenu
, g_Globals
._hInstance
, 0/*lpParam*/);
118 Window
* Window::create_mdi_child(const ChildWndInfo
& info
, const MDICREATESTRUCT
& mcs
, CREATORFUNC_INFO creator
)
120 Lock
lock(GetStaticWindowData()._create_crit_sect
); // protect access to s_window_creator and s_new_info
122 s_window_creator
= (CREATORFUNC
) creator
;
125 s_hcbtHook
= SetWindowsHookEx(WH_CBT
, MDICBTHookProc
, 0, GetCurrentThreadId());
127 HWND hwnd
= (HWND
) SendMessage(info
._hmdiclient
, WM_MDICREATE
, 0, (LPARAM
)&mcs
);
129 // end hook in case it's not already done
131 UnhookWindowsHookEx(s_hcbtHook
);
133 Window
* child
= get_window(hwnd
);
136 if (child
&& (!hwnd
|| !child
->_hwnd
))
142 LRESULT CALLBACK
Window::MDICBTHookProc(int code
, WPARAM wparam
, LPARAM lparam
)
144 if (code
== HCBT_CREATEWND
) {
145 UnhookWindowsHookEx(s_hcbtHook
); // use the hook only for the first created window
148 HWND hwnd
= (HWND
)wparam
;
150 // create Window controller and associate it with the window handle
151 Window
* child
= get_window(hwnd
);
154 child
= create_controller(hwnd
);
157 return CallNextHookEx(s_hcbtHook
, code
, wparam
, lparam
);
162 Window* Window::create_property_sheet(PropertySheetDialog* ppsd, CREATORFUNC creator, const void* info)
164 Lock lock(GetStaticWindowData()._create_crit_sect); // protect access to s_window_creator and s_new_info
166 s_window_creator = creator;
169 s_hcbtHook = SetWindowsHookEx(WH_CBT, PropSheetCBTHookProc, 0, GetCurrentThreadId());
171 HWND hwnd = (HWND) PropertySheet(ppsd);
173 UnhookWindowsHookEx(s_hcbtHook);
175 Window* child = get_window(hwnd);
178 if (child && (!hwnd || !child->_hwnd))
185 LRESULT CALLBACK
Window::PropSheetCBTHookProc(int code
, WPARAM wparam
, LPARAM lparam
)
187 if (code
== HCBT_CREATEWND
) {
188 HWND hwnd
= (HWND
)wparam
;
190 // create Window controller and associate it with the window handle
191 Window
* child
= get_window(hwnd
);
194 child
= create_controller(hwnd
);
197 return CallNextHookEx(s_hcbtHook
, code
, wparam
, lparam
);
201 /// get window controller from window handle
203 Window
* Window::get_window(HWND hwnd
)
206 Lock
lock(GetStaticWindowData()._map_crit_sect
); // protect access to s_wnd_map
208 WindowMap::const_iterator found
= s_wnd_map
.find(hwnd
);
210 if (found
!=s_wnd_map
.end())
211 return found
->second
;
218 /// create controller for a new window
220 Window
* Window::create_controller(HWND hwnd
)
222 if (s_window_creator
) { // protect for recursion and create the window object only for the first window
223 Lock
lock(GetStaticWindowData()._create_crit_sect
); // protect access to s_window_creator and s_new_info
225 const void* info
= s_new_info
;
228 CREATORFUNC window_creator
= s_window_creator
;
229 s_window_creator
= NULL
;
232 return CREATORFUNC_INFO(window_creator
)(hwnd
, info
);
234 return CREATORFUNC(window_creator
)(hwnd
);
241 LRESULT
Window::Init(LPCREATESTRUCT pcs
)
247 LRESULT CALLBACK
Window::WindowWndProc(HWND hwnd
, UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
249 Window
* pThis
= get_window(hwnd
);
252 pThis
= create_controller(hwnd
);
257 return pThis
->Command(LOWORD(wparam
), HIWORD(wparam
));
260 return pThis
->Notify(wparam
, (NMHDR
*)lparam
);
262 case WM_NOTIFYFORMAT
:
266 return pThis
->Init((LPCREATESTRUCT
)lparam
);
273 return pThis
->WndProc(nmsg
, wparam
, lparam
);
277 return DefWindowProc(hwnd
, nmsg
, wparam
, lparam
);
280 LRESULT
Window::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
282 return DefWindowProc(_hwnd
, nmsg
, wparam
, lparam
);
285 int Window::Command(int id
, int code
)
287 return 1; // no command handler found
290 int Window::Notify(int id
, NMHDR
* pnmh
)
295 void Window::CancelModes()
297 PostMessage(HWND_BROADCAST
, WM_CANCELMODE
, 0, 0);
301 SubclassedWindow::SubclassedWindow(HWND hwnd
)
304 _orgWndProc
= SubclassWindow(_hwnd
, SubclassedWndProc
);
310 LRESULT CALLBACK
SubclassedWindow::SubclassedWndProc(HWND hwnd
, UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
312 SubclassedWindow
* pThis
= GET_WINDOW(SubclassedWindow
, hwnd
);
318 if (!pThis
->Command(LOWORD(wparam
), HIWORD(wparam
)))
323 return pThis
->Notify(wparam
, (NMHDR
*)lparam
);
325 case WM_NOTIFYFORMAT
:
329 return pThis
->Init((LPCREATESTRUCT
)lparam
);
336 return pThis
->WndProc(nmsg
, wparam
, lparam
);
340 return CallWindowProc(pThis
->_orgWndProc
, hwnd
, nmsg
, wparam
, lparam
);
343 LRESULT
SubclassedWindow::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
345 return CallWindowProc(_orgWndProc
, _hwnd
, nmsg
, wparam
, lparam
);
348 int SubclassedWindow::Command(int id
, int code
)
350 return 1; // no command handler found
353 int SubclassedWindow::Notify(int id
, NMHDR
* pnmh
)
355 return CallWindowProc(_orgWndProc
, _hwnd
, WM_NOTIFY
, id
, (LPARAM
)pnmh
);
359 ChildWindow::ChildWindow(HWND hwnd
, const ChildWndInfo
& info
)
361 _hwndFrame(GetParent(info
._hmdiclient
))
364 _split_pos
= DEFAULT_SPLIT_POS
;
365 _last_split
= DEFAULT_SPLIT_POS
;
369 ChildWindow
* ChildWindow::create(const ChildWndInfo
& info
, const RECT
& rect
, CREATORFUNC_INFO creator
,
370 LPCTSTR classname
, LPCTSTR title
, DWORD style
)
374 mcs
.szClass
= classname
;
376 mcs
.hOwner
= g_Globals
._hInstance
;
379 mcs
.cx
= rect
.right
- rect
.left
;
380 mcs
.cy
= rect
.bottom
- rect
.top
;
384 return static_cast<ChildWindow
*>(create_mdi_child(info
, mcs
, creator
));
388 LRESULT
ChildWindow::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
393 PaintCanvas
canvas(_hwnd
);
394 ClientRect
rt(_hwnd
);
395 rt
.left
= _split_pos
-SPLIT_WIDTH
/2;
396 rt
.right
= _split_pos
+SPLIT_WIDTH
/2+1;
397 HBRUSH lastBrush
= SelectBrush(canvas
, GetStockBrush(COLOR_SPLITBAR
));
398 Rectangle(canvas
, rt
.left
, rt
.top
-1, rt
.right
, rt
.bottom
+1);
399 SetRect(&rc
, rt
.left
, rt
.top
-1, rt
.right
, rt
.bottom
+1);
400 DrawEdge(canvas
, &rc
, EDGE_RAISED
, BF_RECT
);
401 SelectObject(canvas
, lastBrush
);
405 if (LOWORD(lparam
) == HTCLIENT
) {
408 ScreenToClient(_hwnd
, &pt
);
410 if (pt
.x
>=_split_pos
-SPLIT_WIDTH
/2 && pt
.x
<_split_pos
+SPLIT_WIDTH
/2+1) {
411 SetCursor(LoadCursor(0, IDC_SIZEWE
));
418 if (wparam
!= SIZE_MINIMIZED
)
419 resize_children(LOWORD(lparam
), HIWORD(lparam
));
422 case WM_GETMINMAXINFO
:
423 DefMDIChildProc(_hwnd
, nmsg
, wparam
, lparam
);
425 {LPMINMAXINFO lpmmi
= (LPMINMAXINFO
)lparam
;
427 lpmmi
->ptMaxTrackSize
.x
<<= 1; // 2*GetSystemMetrics(SM_CXSCREEN) / SM_CXVIRTUALSCREEN
428 lpmmi
->ptMaxTrackSize
.y
<<= 1; // 2*GetSystemMetrics(SM_CYSCREEN) / SM_CYVIRTUALSCREEN
431 case WM_LBUTTONDOWN
: {
432 int x
= GET_X_LPARAM(lparam
);
434 ClientRect
rt(_hwnd
);
436 if (x
>=_split_pos
-SPLIT_WIDTH
/2 && x
<_split_pos
+SPLIT_WIDTH
/2+1) {
437 _last_split
= _split_pos
;
444 if (GetCapture() == _hwnd
)
449 if (wparam
== VK_ESCAPE
)
450 if (GetCapture() == _hwnd
) {
451 _split_pos
= _last_split
;
452 ClientRect
rt(_hwnd
);
453 resize_children(rt
.right
, rt
.bottom
);
456 SetCursor(LoadCursor(0, IDC_ARROW
));
461 if (GetCapture() == _hwnd
) {
462 int x
= GET_X_LPARAM(lparam
);
464 ClientRect
rt(_hwnd
);
466 if (x
>=0 && x
<rt
.right
) {
468 resize_children(rt
.right
, rt
.bottom
);
469 rt
.left
= x
-SPLIT_WIDTH
/2;
470 rt
.right
= x
+SPLIT_WIDTH
/2+1;
471 InvalidateRect(_hwnd
, &rt
, FALSE
);
472 UpdateWindow(_left_hwnd
);
474 UpdateWindow(_right_hwnd
);
479 case PM_DISPATCH_COMMAND
:
480 switch(LOWORD(wparam
)) {
482 if (!_url_history
.empty()) {
483 const String
& url
= jump_to_int(_url_history
.top());
485 if (jump_to_int(url
))
510 if ((HWND
)lparam
== _hwnd
) {
511 SendMessage(_hwndFrame
, PM_SETSTATUSTEXT
, 0, (LPARAM
)_statusText
.c_str());
512 SendMessage(_hwndFrame
, PM_URL_CHANGED
, 0, (LPARAM
)_url
.c_str());
517 return go_to((LPCTSTR
)lparam
)? TRUE
: FALSE
;
520 return DefMDIChildProc(_hwnd
, nmsg
, wparam
, lparam
);
527 void ChildWindow::resize_children(int cx
, int cy
)
529 HDWP hdwp
= BeginDeferWindowPos(2);
538 cx
= _split_pos
+ SPLIT_WIDTH
/2;
540 hdwp
= DeferWindowPos(hdwp
, _left_hwnd
, 0, rt
.left
, rt
.top
, _split_pos
-SPLIT_WIDTH
/2-rt
.left
, rt
.bottom
-rt
.top
, SWP_NOZORDER
|SWP_NOACTIVATE
);
547 hdwp
= DeferWindowPos(hdwp
, _right_hwnd
, 0, rt
.left
+cx
+1, rt
.top
, rt
.right
-cx
, rt
.bottom
-rt
.top
, SWP_NOZORDER
|SWP_NOACTIVATE
);
549 EndDeferWindowPos(hdwp
);
553 bool ChildWindow::go_to(LPCTSTR url
)
555 const String
& url_str
= jump_to_int(url
);
557 if (!url_str
.empty()) {
560 _url_history
.push(url_str
);
567 void ChildWindow::set_url(LPCTSTR url
)
572 SendMessage(_hwndFrame
, PM_URL_CHANGED
, 0, (LPARAM
)url
);
577 WindowSet
Window::s_pretranslate_windows
;
579 void Window::register_pretranslate(HWND hwnd
)
581 s_pretranslate_windows
.insert(hwnd
);
584 void Window::unregister_pretranslate(HWND hwnd
)
586 s_pretranslate_windows
.erase(hwnd
);
589 BOOL
Window::pretranslate_msg(LPMSG pmsg
)
591 if ((pmsg
->message
!= WM_KEYDOWN
) &&
592 (pmsg
->message
!= WM_SYSKEYDOWN
) &&
593 (pmsg
->message
!= WM_SYSCHAR
) &&
594 (pmsg
->message
!= WM_CHAR
))
599 for(WindowSet::const_iterator it
=Window::s_pretranslate_windows
.begin(); it
!=s_pretranslate_windows
.end(); ++it
)
600 if (SendMessage(*it
, PM_TRANSLATE_MSG
, 0, (LPARAM
)pmsg
))
607 WindowSet
Window::s_dialogs
;
609 void Window::register_dialog(HWND hwnd
)
611 s_dialogs
.insert(hwnd
);
614 void Window::unregister_dialog(HWND hwnd
)
616 s_dialogs
.erase(hwnd
);
619 BOOL
Window::dispatch_dialog_msg(MSG
* pmsg
)
621 for(WindowSet::const_iterator it
=Window::s_dialogs
.begin(); it
!=s_dialogs
.end(); ++it
)
622 if (IsDialogMessage(*it
, pmsg
))
629 int Window::MessageLoop()
633 while(GetMessage(&msg
, 0, 0, 0)) {
635 if (pretranslate_msg(&msg
))
638 if (dispatch_dialog_msg(&msg
))
641 TranslateMessage(&msg
);
644 DispatchMessage(&msg
);
645 } catch(COMException
& e
) {
646 HandleException(e
, 0);
648 } catch(COMException
& e
) {
649 HandleException(e
, 0);
657 LRESULT
Window::SendParent(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
659 HWND parent
= GetParent(_hwnd
);
664 return SendMessage(parent
, nmsg
, wparam
, lparam
);
667 LRESULT
Window::PostParent(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
669 HWND parent
= GetParent(_hwnd
);
674 return PostMessage(parent
, nmsg
, wparam
, lparam
);
678 PreTranslateWindow::PreTranslateWindow(HWND hwnd
)
681 register_pretranslate(hwnd
);
684 PreTranslateWindow::~PreTranslateWindow()
686 unregister_pretranslate(_hwnd
);
690 Dialog::Dialog(HWND hwnd
)
693 register_dialog(hwnd
);
698 unregister_dialog(_hwnd
);
701 int Dialog::DoModal(UINT nid
, CREATORFUNC creator
, HWND hwndParent
)
703 Lock
lock(GetStaticWindowData()._create_crit_sect
); // protect access to s_window_creator and s_new_info
705 s_window_creator
= creator
;
708 ///@todo call Window::pretranslate_msg()
710 return DialogBoxParam(g_Globals
._hInstance
, MAKEINTRESOURCE(nid
), hwndParent
, DialogProc
, 0/*lpParam*/);
713 int Dialog::DoModal(UINT nid
, CREATORFUNC_INFO creator
, const void* info
, HWND hwndParent
)
715 Lock
lock(GetStaticWindowData()._create_crit_sect
); // protect access to s_window_creator and s_new_info
717 s_window_creator
= (CREATORFUNC
) creator
;
720 ///@todo call Window::pretranslate_msg()
722 return DialogBoxParam(g_Globals
._hInstance
, MAKEINTRESOURCE(nid
), hwndParent
, DialogProc
, 0/*lpParam*/);
725 INT_PTR CALLBACK
Window::DialogProc(HWND hwnd
, UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
727 Window
* pThis
= get_window(hwnd
);
732 pThis
->Command(LOWORD(wparam
), HIWORD(wparam
));
733 return TRUE
; // message has been processed
736 pThis
->Notify(wparam
, (NMHDR
*)lparam
);
737 return TRUE
; // message has been processed
739 case WM_NOTIFYFORMAT
:
740 SetWindowLongPtr(hwnd
, DWLP_MSGRESULT
, NFR_CURRENT
); // set return value NFR_CURRENT
741 return TRUE
; // message has been processed
745 return TRUE
; // message has been processed
748 return pThis
->WndProc(nmsg
, wparam
, lparam
);
750 } else if (nmsg
== WM_INITDIALOG
) {
751 pThis
= create_controller(hwnd
);
754 return pThis
->Init(NULL
);
757 return FALSE
; // message has not been processed
760 LRESULT
Dialog::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
762 return FALSE
; // message has not been processed
765 int Dialog::Command(int id
, int code
)
767 if (code
== BN_CLICKED
) {
768 EndDialog(_hwnd
, id
);
769 return 0; // message has been processed
776 ResizeManager::ResizeManager(HWND hwnd
)
779 ClientRect
clnt(hwnd
);
780 _last_size
.cx
= clnt
.right
;
781 _last_size
.cy
= clnt
.bottom
;
783 WindowRect
rect(hwnd
);
784 _min_wnd_size
.cx
= rect
.right
- rect
.left
;
785 _min_wnd_size
.cy
= rect
.bottom
- rect
.top
;
788 void ResizeManager::HandleSize(int cx
, int cy
)
790 ClientRect
clnt_rect(_hwnd
);
791 SIZE new_size
= {cx
, cy
};
793 int dx
= new_size
.cx
- _last_size
.cx
;
794 int dy
= new_size
.cy
- _last_size
.cy
;
799 _last_size
= new_size
;
801 HDWP hDWP
= BeginDeferWindowPos(size());
803 for(ResizeManager::const_iterator it
=begin(); it
!=end(); ++it
) {
804 const ResizeEntry
& e
= *it
;
807 if (e
._flags
& MOVE_LEFT
)
810 if (e
._flags
& MOVE_RIGHT
)
813 if (e
._flags
& MOVE_TOP
)
816 if (e
._flags
& MOVE_BOTTOM
)
821 if (!move
.left
&& !move
.top
)
824 if (move
.right
==move
.left
&& move
.bottom
==move
.top
)
827 if (flags
!= (SWP_NOMOVE
|SWP_NOSIZE
)) {
828 HWND hwnd
= GetDlgItem(_hwnd
, e
._id
);
831 WindowRect
rect(hwnd
);
832 ScreenToClient(_hwnd
, rect
);
834 rect
.left
+= move
.left
;
835 rect
.right
+= move
.right
;
836 rect
.top
+= move
.top
;
837 rect
.bottom
+= move
.bottom
;
839 hDWP
= DeferWindowPos(hDWP
, hwnd
, 0, rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
, flags
|SWP_NOACTIVATE
|SWP_NOZORDER
);
844 EndDeferWindowPos(hDWP
);
847 void ResizeManager::Resize(int dx
, int dy
)
849 ::SetWindowPos(_hwnd
, 0, 0, 0, _min_wnd_size
.cx
+dx
, _min_wnd_size
.cy
+dy
, SWP_NOMOVE
|SWP_NOACTIVATE
);
852 ClientRect
clnt_rect(_hwnd
);
853 HandleSize(clnt_rect
.right
, clnt_rect
.bottom
);
857 Button::Button(HWND parent
, LPCTSTR title
, int left
, int top
, int width
, int height
,
858 int id
, DWORD flags
, DWORD exStyle
)
859 : WindowHandle(CreateWindowEx(exStyle
, TEXT("BUTTON"), title
, flags
, left
, top
, width
, height
,
860 parent
, (HMENU
)id
, g_Globals
._hInstance
, 0))
865 LRESULT
OwnerdrawnButton::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
867 if (nmsg
== PM_DISPATCH_DRAWITEM
) {
868 DrawItem((LPDRAWITEMSTRUCT
)lparam
);
871 return super::WndProc(nmsg
, wparam
, lparam
);
875 Static::Static(HWND parent
, LPCTSTR title
, int left
, int top
, int width
, int height
,
876 int id
, DWORD flags
, DWORD exStyle
)
877 : WindowHandle(CreateWindowEx(exStyle
, TEXT("STATIC"), title
, flags
, left
, top
, width
, height
,
878 parent
, (HMENU
)id
, g_Globals
._hInstance
, 0))
883 static RECT s_MyDrawText_Rect
= {0, 0, 0, 0};
885 static BOOL CALLBACK
MyDrawText(HDC hdc
, LPARAM data
, int cnt
)
887 ::DrawText(hdc
, (LPCTSTR
)data
, cnt
, &s_MyDrawText_Rect
, DT_SINGLELINE
);
891 void DrawGrayText(HDC hdc
, LPRECT pRect
, LPCTSTR title
, int dt_flags
)
893 COLORREF gray
= GetSysColor(COLOR_GRAYTEXT
);
896 TextColor
lcColor(hdc
, GetSysColor(COLOR_BTNHIGHLIGHT
));
897 RECT shadowRect
= {pRect
->left
+1, pRect
->top
+1, pRect
->right
+1, pRect
->bottom
+1};
898 DrawText(hdc
, title
, -1, &shadowRect
, dt_flags
);
900 SetTextColor(hdc
, gray
);
901 DrawText(hdc
, title
, -1, pRect
, dt_flags
);
903 int old_r
= pRect
->right
;
904 int old_b
= pRect
->bottom
;
906 DrawText(hdc
, title
, -1, pRect
, dt_flags
|DT_CALCRECT
);
908 int x
= pRect
->left
+ (old_r
-pRect
->right
)/2;
909 int y
= pRect
->top
+ (old_b
-pRect
->bottom
)/2;
910 int w
= pRect
->right
-pRect
->left
;
911 int h
= pRect
->bottom
-pRect
->top
;
912 s_MyDrawText_Rect
.right
= w
;
913 s_MyDrawText_Rect
.bottom
= h
;
915 GrayString(hdc
, GetSysColorBrush(COLOR_GRAYTEXT
), MyDrawText
, (LPARAM
)title
, -1, x
, y
, w
, h
);
921 void ColorButton::DrawItem(LPDRAWITEMSTRUCT dis)
923 UINT state = DFCS_BUTTONPUSH;
925 if (dis->itemState & ODS_DISABLED)
926 state |= DFCS_INACTIVE;
928 RECT textRect = {dis->rcItem.left+2, dis->rcItem.top+2, dis->rcItem.right-4, dis->rcItem.bottom-4};
930 if (dis->itemState & ODS_SELECTED) {
931 state |= DFCS_PUSHED;
932 ++textRect.left; ++textRect.top;
933 ++textRect.right; ++textRect.bottom;
936 DrawFrameControl(dis->hDC, &dis->rcItem, DFC_BUTTON, state);
938 TCHAR title[BUFFER_LEN];
939 GetWindowText(_hwnd, title, BUFFER_LEN);
941 BkMode bk_mode(dis->hDC, TRANSPARENT);
943 if (dis->itemState & (ODS_DISABLED|ODS_GRAYED))
944 DrawGrayText(dis, &textRect, title, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
946 TextColor lcColor(dis->hDC, _textColor);
947 DrawText(dis->hDC, title, -1, &textRect, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
950 if (dis->itemState & ODS_FOCUS) {
952 dis->rcItem.left+3, dis->rcItem.top+3,
953 dis->rcItem.right-dis->rcItem.left-4, dis->rcItem.bottom-dis->rcItem.top-4
955 if (dis->itemState & ODS_SELECTED) {
956 ++rect.left; ++rect.top;
957 ++rect.right; ++rect.bottom;
959 DrawFocusRect(dis->hDC, &rect);
965 void PictureButton::DrawItem(LPDRAWITEMSTRUCT dis
)
967 UINT state
= DFCS_BUTTONPUSH
;
968 int style
= GetWindowStyle(_hwnd
);
970 if (dis
->itemState
& ODS_DISABLED
)
971 state
|= DFCS_INACTIVE
;
977 if (style
& BS_BOTTOM
) {
978 // align horizontal centered, vertical floating
979 imagePos
.x
= (dis
->rcItem
.left
+ dis
->rcItem
.right
- _cx
) / 2;
980 imagePos
.y
= dis
->rcItem
.top
+ 3;
982 textRect
.left
= dis
->rcItem
.left
+ 2;
983 textRect
.top
= dis
->rcItem
.top
+ _cy
+ 4;
984 textRect
.right
= dis
->rcItem
.right
- 4;
985 textRect
.bottom
= dis
->rcItem
.bottom
- 4;
987 dt_flags
= DT_SINGLELINE
|DT_CENTER
|DT_VCENTER
;
989 // horizontal floating, vertical centered
990 imagePos
.x
= dis
->rcItem
.left
+ 3;
991 imagePos
.y
= (dis
->rcItem
.top
+ dis
->rcItem
.bottom
- _cy
)/2;
993 textRect
.left
= dis
->rcItem
.left
+ _cx
+ 4;
994 textRect
.top
= dis
->rcItem
.top
+ 2;
995 textRect
.right
= dis
->rcItem
.right
- 4;
996 textRect
.bottom
= dis
->rcItem
.bottom
- 4;
998 dt_flags
= DT_SINGLELINE
|DT_VCENTER
/*|DT_CENTER*/;
1001 if (dis
->itemState
& ODS_SELECTED
) {
1002 state
|= DFCS_PUSHED
;
1003 ++imagePos
.x
; ++imagePos
.y
;
1004 ++textRect
.left
; ++textRect
.top
;
1005 ++textRect
.right
; ++textRect
.bottom
;
1009 FillRect(dis
->hDC
, &dis
->rcItem
, _hBrush
);
1011 if (style
& BS_FLAT
) // Only with BS_FLAT set, there will be drawn a frame without highlight.
1012 DrawEdge(dis
->hDC
, &dis
->rcItem
, EDGE_RAISED
, BF_RECT
|BF_FLAT
);
1014 DrawFrameControl(dis
->hDC
, &dis
->rcItem
, DFC_BUTTON
, state
);
1017 DrawIconEx(dis
->hDC
, imagePos
.x
, imagePos
.y
, _hIcon
, _cx
, _cy
, 0, _hBrush
, DI_NORMAL
);
1020 BitmapSelection
sel(mem_dc
, _hBmp
);
1021 BitBlt(dis
->hDC
, imagePos
.x
, imagePos
.y
, _cx
, _cy
, mem_dc
, 0, 0, SRCCOPY
);
1024 TCHAR title
[BUFFER_LEN
];
1025 GetWindowText(_hwnd
, title
, BUFFER_LEN
);
1027 BkMode
bk_mode(dis
->hDC
, TRANSPARENT
);
1029 if (dis
->itemState
& (ODS_DISABLED
|ODS_GRAYED
))
1030 DrawGrayText(dis
->hDC
, &textRect
, title
, dt_flags
);
1032 TextColor
lcColor(dis
->hDC
, GetSysColor(COLOR_BTNTEXT
));
1033 DrawText(dis
->hDC
, title
, -1, &textRect
, dt_flags
);
1036 if (dis
->itemState
& ODS_FOCUS
) {
1038 dis
->rcItem
.left
+3, dis
->rcItem
.top
+3,
1039 dis
->rcItem
.right
-dis
->rcItem
.left
-4, dis
->rcItem
.bottom
-dis
->rcItem
.top
-4
1041 if (dis
->itemState
& ODS_SELECTED
) {
1042 ++rect
.left
; ++rect
.top
;
1043 ++rect
.right
; ++rect
.bottom
;
1045 DrawFocusRect(dis
->hDC
, &rect
);
1050 void FlatButton::DrawItem(LPDRAWITEMSTRUCT dis
)
1052 UINT style
= DFCS_BUTTONPUSH
;
1054 if (dis
->itemState
& ODS_DISABLED
)
1055 style
|= DFCS_INACTIVE
;
1057 RECT textRect
= {dis
->rcItem
.left
+2, dis
->rcItem
.top
+2, dis
->rcItem
.right
-4, dis
->rcItem
.bottom
-4};
1059 if (dis
->itemState
& ODS_SELECTED
) {
1060 style
|= DFCS_PUSHED
;
1061 ++textRect
.left
; ++textRect
.top
;
1062 ++textRect
.right
; ++textRect
.bottom
;
1065 FillRect(dis
->hDC
, &dis
->rcItem
, GetSysColorBrush(COLOR_BTNFACE
));
1067 // highlight the button?
1069 DrawEdge(dis
->hDC
, &dis
->rcItem
, EDGE_ETCHED
, BF_RECT
);
1070 else if (GetWindowStyle(_hwnd
) & BS_FLAT
) // Only with BS_FLAT there will be drawn a frame to show highlighting.
1071 DrawEdge(dis
->hDC
, &dis
->rcItem
, EDGE_RAISED
, BF_RECT
|BF_FLAT
);
1073 TCHAR txt
[BUFFER_LEN
];
1074 int txt_len
= GetWindowText(_hwnd
, txt
, BUFFER_LEN
);
1076 if (dis
->itemState
& (ODS_DISABLED
|ODS_GRAYED
)) {
1077 COLORREF gray
= GetSysColor(COLOR_GRAYTEXT
);
1081 TextColor
lcColor(dis
->hDC
, GetSysColor(COLOR_BTNHIGHLIGHT
));
1082 RECT shadowRect
= {textRect
.left
+1, textRect
.top
+1, textRect
.right
+1, textRect
.bottom
+1};
1083 DrawText(dis
->hDC
, txt
, txt_len
, &shadowRect
, DT_SINGLELINE
|DT_VCENTER
|DT_CENTER
);
1086 BkMode
mode(dis
->hDC
, TRANSPARENT
);
1087 TextColor
lcColor(dis
->hDC
, gray
);
1088 DrawText(dis
->hDC
, txt
, txt_len
, &textRect
, DT_SINGLELINE
|DT_VCENTER
|DT_CENTER
);
1090 int old_r
= textRect
.right
;
1091 int old_b
= textRect
.bottom
;
1092 DrawText(dis
->hDC
, txt
, txt_len
, &textRect
, DT_SINGLELINE
|DT_VCENTER
|DT_CENTER
|DT_CALCRECT
);
1093 int x
= textRect
.left
+ (old_r
-textRect
.right
)/2;
1094 int y
= textRect
.top
+ (old_b
-textRect
.bottom
)/2;
1095 int w
= textRect
.right
-textRect
.left
;
1096 int h
= textRect
.bottom
-textRect
.top
;
1097 s_MyDrawText_Rect
.right
= w
;
1098 s_MyDrawText_Rect
.bottom
= h
;
1099 GrayString(dis
->hDC
, GetSysColorBrush(COLOR_GRAYTEXT
), MyDrawText
, (LPARAM
)txt
, txt_len
, x
, y
, w
, h
);
1102 TextColor
lcColor(dis
->hDC
, _active
? _activeColor
: _textColor
);
1103 DrawText(dis
->hDC
, txt
, txt_len
, &textRect
, DT_SINGLELINE
|DT_VCENTER
|DT_CENTER
);
1106 if (dis
->itemState
& ODS_FOCUS
) {
1108 dis
->rcItem
.left
+3, dis
->rcItem
.top
+3,
1109 dis
->rcItem
.right
-dis
->rcItem
.left
-4, dis
->rcItem
.bottom
-dis
->rcItem
.top
-4
1111 if (dis
->itemState
& ODS_SELECTED
) {
1112 ++rect
.left
; ++rect
.top
;
1113 ++rect
.right
; ++rect
.bottom
;
1115 DrawFocusRect(dis
->hDC
, &rect
);
1119 LRESULT
FlatButton::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
1122 case WM_MOUSEMOVE
: {
1123 bool active
= false;
1125 if (IsWindowEnabled(_hwnd
)) {
1126 DWORD pid_foreground
;
1127 HWND hwnd_foreground
= GetForegroundWindow(); //@@ may be better look for WM_ACTIVATEAPP ?
1128 GetWindowThreadProcessId(hwnd_foreground
, &pid_foreground
);
1130 if (GetCurrentProcessId() == pid_foreground
) {
1131 POINT pt
= {GET_X_LPARAM(lparam
), GET_Y_LPARAM(lparam
)};
1132 ClientRect
clntRect(_hwnd
);
1134 // highlight the button?
1135 if (pt
.x
>=clntRect
.left
&& pt
.x
<clntRect
.right
&& pt
.y
>=clntRect
.top
&& pt
.y
<clntRect
.bottom
)
1140 if (active
!= _active
) {
1144 TRACKMOUSEEVENT tme
= {sizeof(tme
), /*TME_HOVER|*/TME_LEAVE
, _hwnd
/*, HOVER_DEFAULT*/};
1145 _TrackMouseEvent(&tme
);
1148 InvalidateRect(_hwnd
, NULL
, TRUE
);
1153 case WM_LBUTTONUP
: {
1154 POINT pt
= {GET_X_LPARAM(lparam
), GET_Y_LPARAM(lparam
)};
1155 ClientRect
clntRect(_hwnd
);
1157 // no more in the active rectangle?
1158 if (pt
.x
<clntRect
.left
|| pt
.x
>=clntRect
.right
|| pt
.y
<clntRect
.top
|| pt
.y
>=clntRect
.bottom
)
1165 TRACKMOUSEEVENT tme
= {sizeof(tme
), /*TME_HOVER|*/TME_LEAVE
|TME_CANCEL
, _hwnd
/*, HOVER_DEFAULT*/};
1166 _TrackMouseEvent(&tme
);
1175 InvalidateRect(_hwnd
, NULL
, TRUE
);
1181 return super::WndProc(nmsg
, wparam
, lparam
);
1186 HyperlinkCtrl::HyperlinkCtrl(HWND hwnd
, COLORREF colorLink
, COLORREF colorVisited
)
1188 _cmd(ResString(GetDlgCtrlID(hwnd
))),
1189 _textColor(colorLink
),
1190 _colorVisited(colorVisited
),
1197 HyperlinkCtrl::HyperlinkCtrl(HWND owner
, int id
, COLORREF colorLink
, COLORREF colorVisited
)
1198 : super(GetDlgItem(owner
, id
)),
1199 _cmd(ResString(id
)),
1200 _textColor(colorLink
),
1201 _colorVisited(colorVisited
),
1208 void HyperlinkCtrl::init()
1211 TCHAR txt
[BUFFER_LEN
];
1212 _cmd
.assign(txt
, GetWindowText(_hwnd
, txt
, BUFFER_LEN
));
1216 HyperlinkCtrl::~HyperlinkCtrl()
1219 DeleteObject(_hfont
);
1222 LRESULT
HyperlinkCtrl::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
1225 case PM_DISPATCH_CTLCOLOR
: {
1227 HFONT hfont
= (HFONT
) SendMessage(_hwnd
, WM_GETFONT
, 0, 0);
1228 LOGFONT lf
; GetObject(hfont
, sizeof(lf
), &lf
);
1229 lf
.lfUnderline
= TRUE
;
1230 _hfont
= CreateFontIndirect(&lf
);
1233 HDC hdc
= (HDC
) wparam
;
1234 SetTextColor(hdc
, _textColor
); //@@
1235 SelectFont(hdc
, _hfont
);
1236 SetBkMode(hdc
, TRANSPARENT
);
1237 return (LRESULT
)GetStockObject(HOLLOW_BRUSH
);
1242 _crsr_link
= LoadCursor(0, IDC_HAND
);
1245 SetCursor(_crsr_link
);
1249 return HTCLIENT
; // Aktivierung von Maus-Botschaften
1251 case WM_LBUTTONDOWN
:
1253 _textColor
= _colorVisited
;
1254 InvalidateRect(_hwnd
, NULL
, FALSE
);
1260 return super::WndProc(nmsg
, wparam
, lparam
);
1265 ToolTip::ToolTip(HWND owner
)
1266 : super(CreateWindowEx(WS_EX_TOPMOST
|WS_EX_NOPARENTNOTIFY
, TOOLTIPS_CLASS
, 0,
1267 WS_POPUP
|TTS_NOPREFIX
|TTS_ALWAYSTIP
, CW_USEDEFAULT
,CW_USEDEFAULT
,CW_USEDEFAULT
,CW_USEDEFAULT
,
1268 owner
, 0, g_Globals
._hInstance
, 0))
1274 ListSort::ListSort(HWND hwndListview
, PFNLVCOMPARE compare_fct
)
1275 : WindowHandle(hwndListview
),
1276 _compare_fct(compare_fct
)
1282 void ListSort::toggle_sort(int idx
)
1284 if (_sort_crit
== idx
)
1285 _direction
= !_direction
;
1292 void ListSort::sort()
1294 int idx
= ListView_GetSelectionMark(_hwnd
);
1295 LPARAM param
= ListView_GetItemData(_hwnd
, idx
);
1297 ListView_SortItems(_hwnd
, _compare_fct
, (LPARAM
)this);
1300 idx
= ListView_FindItemPara(_hwnd
, param
);
1301 ListView_EnsureVisible(_hwnd
, idx
, FALSE
);
1306 PropSheetPage::PropSheetPage(UINT nid
, Window::CREATORFUNC dlg_creator
)
1307 : _dlg_creator(dlg_creator
)
1309 PROPSHEETPAGE::dwSize
= sizeof(PROPSHEETPAGE
);
1310 PROPSHEETPAGE::dwFlags
= 0;
1311 PROPSHEETPAGE::hInstance
= g_Globals
._hInstance
;
1312 PROPSHEETPAGE::pszTemplate
= MAKEINTRESOURCE(nid
);
1313 PROPSHEETPAGE::pfnDlgProc
= PropSheetPageDlg::DialogProc
;
1314 PROPSHEETPAGE::lParam
= (LPARAM
) this;
1318 #ifndef PSM_GETRESULT // currently (as of 18.01.2004) missing in MinGW headers
1319 #define PSM_GETRESULT (WM_USER + 135)
1320 #define PropSheet_GetResult(hDlg) SNDMSG(hDlg, PSM_GETRESULT, 0, 0)
1324 PropertySheetDialog::PropertySheetDialog(HWND owner
)
1327 PROPSHEETHEADER::dwSize
= sizeof(PROPSHEETHEADER
);
1328 PROPSHEETHEADER::dwFlags
= PSH_PROPSHEETPAGE
| PSH_MODELESS
;
1329 PROPSHEETHEADER::hwndParent
= owner
;
1330 PROPSHEETHEADER::hInstance
= g_Globals
._hInstance
;
1333 void PropertySheetDialog::add(PropSheetPage
& psp
)
1335 _pages
.push_back(psp
);
1338 int PropertySheetDialog::DoModal(int start_page
)
1340 PROPSHEETHEADER::ppsp
= (LPCPROPSHEETPAGE
) &_pages
[0];
1341 PROPSHEETHEADER::nPages
= _pages
.size();
1342 PROPSHEETHEADER::nStartPage
= start_page
;
1344 Window* pwnd = Window::create_property_sheet(this, WINDOW_CREATOR(PropertySheetDlg), NULL);
1348 HWND hwndPropSheet = *pwnd;
1350 int ret
= PropertySheet(this);
1354 HWND hwndPropSheet
= (HWND
) ret
;
1355 HWND hwndparent
= GetParent(hwndPropSheet
);
1358 EnableWindow(hwndparent
, FALSE
);
1363 while(GetMessage(&msg
, 0, 0, 0)) {
1365 if (Window::pretranslate_msg(&msg
))
1368 if (PropSheet_IsDialogMessage(hwndPropSheet
, &msg
))
1371 if (Window::dispatch_dialog_msg(&msg
))
1374 TranslateMessage(&msg
);
1377 DispatchMessage(&msg
);
1378 } catch(COMException
& e
) {
1379 HandleException(e
, 0);
1382 if (!PropSheet_GetCurrentPageHwnd(hwndPropSheet
)) {
1383 ret
= PropSheet_GetResult(hwndPropSheet
);
1386 } catch(COMException
& e
) {
1387 HandleException(e
, 0);
1392 EnableWindow(hwndparent
, TRUE
);
1394 DestroyWindow(hwndPropSheet
);
1399 HWND
PropertySheetDialog::GetCurrentPage()
1401 HWND hdlg
= PropSheet_GetCurrentPageHwnd(_hwnd
);
1406 PropSheetPageDlg::PropSheetPageDlg(HWND hwnd
)
1411 INT_PTR CALLBACK
PropSheetPageDlg::DialogProc(HWND hwnd
, UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
1413 PropSheetPageDlg
* pThis
= GET_WINDOW(PropSheetPageDlg
, hwnd
);
1418 pThis
->Command(LOWORD(wparam
), HIWORD(wparam
));
1419 return TRUE
; // message has been processed
1422 pThis
->Notify(wparam
, (NMHDR
*)lparam
);
1423 return TRUE
; // message has been processed
1425 case WM_NOTIFYFORMAT
:
1426 SetWindowLongPtr(hwnd
, DWLP_MSGRESULT
, NFR_CURRENT
); // set return value NFR_CURRENT
1427 return TRUE
; // message has been processed
1431 return TRUE
; // message has been processed
1434 return pThis
->WndProc(nmsg
, wparam
, lparam
);
1436 } else if (nmsg
== WM_INITDIALOG
) {
1437 PROPSHEETPAGE
* psp
= (PROPSHEETPAGE
*) lparam
;
1438 PropSheetPage
* ppsp
= (PropSheetPage
*) psp
->lParam
;
1440 if (ppsp
->_dlg_creator
) {
1441 pThis
= static_cast<PropSheetPageDlg
*>(ppsp
->_dlg_creator(hwnd
));
1444 return pThis
->Init(NULL
);
1448 return FALSE
; // message has not been processed
1451 int PropSheetPageDlg::Command(int id
, int code
)
1453 // override call to EndDialog in Dialog::Command();