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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 // Martin Fuchs, 23.07.2003
31 #include "../resource.h" // for ID_GO_BACK, ...
34 WindowClass::WindowClass(LPCTSTR classname
, UINT style_
, WNDPROC wndproc
)
36 memset(this, 0, sizeof(WNDCLASSEX
));
38 cbSize
= sizeof(WNDCLASSEX
);
40 hInstance
= g_Globals
._hInstance
;
41 hCursor
= LoadCursor(0, IDC_ARROW
);
43 lpszClassName
= classname
;
44 lpfnWndProc
= wndproc
;
50 IconWindowClass::IconWindowClass(LPCTSTR classname
, UINT nid
, UINT style
, WNDPROC wndproc
)
51 : WindowClass(classname
, style
, wndproc
)
54 hIconSm
= SmallIcon(nid
);
58 Window::WindowMap
Window::s_wnd_map
;
60 Window::CREATORFUNC
Window::s_window_creator
= NULL
;
61 const void* Window::s_new_info
= NULL
;
63 HHOOK
Window::s_hcbtHook
= 0;
66 Window::StaticWindowData
& Window::GetStaticWindowData()
68 static StaticWindowData s_initialized_data
;
70 return s_initialized_data
;
74 Window::Window(HWND hwnd
)
77 Lock
lock(GetStaticWindowData()._map_crit_sect
); // protect access to s_wnd_map
79 s_wnd_map
[_hwnd
] = this;
84 Lock
lock(GetStaticWindowData()._map_crit_sect
); // protect access to s_wnd_map
86 s_wnd_map
.erase(_hwnd
);
90 HWND
Window::Create(CREATORFUNC creator
, DWORD dwExStyle
,
91 LPCTSTR lpClassName
, LPCTSTR lpWindowName
,
92 DWORD dwStyle
, int x
, int y
, int w
, int h
,
93 HWND hwndParent
, HMENU hMenu
/*, LPVOID lpParam*/)
95 Lock
lock(GetStaticWindowData()._create_crit_sect
); // protect access to s_window_creator and s_new_info
97 s_window_creator
= creator
;
100 return CreateWindowEx(dwExStyle
, lpClassName
, lpWindowName
, dwStyle
,
102 hwndParent
, hMenu
, g_Globals
._hInstance
, 0/*lpParam*/);
105 HWND
Window::Create(CREATORFUNC_INFO creator
, const void* info
, DWORD dwExStyle
,
106 LPCTSTR lpClassName
, LPCTSTR lpWindowName
,
107 DWORD dwStyle
, int x
, int y
, int w
, int h
,
108 HWND hwndParent
, HMENU hMenu
/*, LPVOID lpParam*/)
110 Lock
lock(GetStaticWindowData()._create_crit_sect
); // protect access to s_window_creator and s_new_info
112 s_window_creator
= (CREATORFUNC
) creator
;
115 return CreateWindowEx(dwExStyle
, lpClassName
, lpWindowName
, dwStyle
,
117 hwndParent
, hMenu
, g_Globals
._hInstance
, 0/*lpParam*/);
121 Window
* Window::create_mdi_child(const ChildWndInfo
& info
, const MDICREATESTRUCT
& mcs
, CREATORFUNC_INFO creator
)
123 Lock
lock(GetStaticWindowData()._create_crit_sect
); // protect access to s_window_creator and s_new_info
125 s_window_creator
= (CREATORFUNC
) creator
;
128 s_hcbtHook
= SetWindowsHookEx(WH_CBT
, MDICBTHookProc
, 0, GetCurrentThreadId());
130 HWND hwnd
= (HWND
) SendMessage(info
._hmdiclient
, WM_MDICREATE
, 0, (LPARAM
)&mcs
);
132 UnhookWindowsHookEx(s_hcbtHook
);
134 Window
* child
= get_window(hwnd
);
137 if (child
&& (!hwnd
|| !child
->_hwnd
))
143 LRESULT CALLBACK
Window::MDICBTHookProc(int code
, WPARAM wparam
, LPARAM lparam
)
145 if (code
== HCBT_CREATEWND
) {
146 HWND hwnd
= (HWND
)wparam
;
148 // create Window controller and associate it with the window handle
149 Window
* child
= get_window(hwnd
);
152 child
= create_controller(hwnd
);
155 return CallNextHookEx(s_hcbtHook
, code
, wparam
, lparam
);
160 Window* Window::create_property_sheet(PropertySheetDialog* ppsd, CREATORFUNC creator, const void* info)
162 Lock lock(GetStaticWindowData()._create_crit_sect); // protect access to s_window_creator and s_new_info
164 s_window_creator = creator;
167 s_hcbtHook = SetWindowsHookEx(WH_CBT, PropSheetCBTHookProc, 0, GetCurrentThreadId());
169 HWND hwnd = (HWND) PropertySheet(ppsd);
171 UnhookWindowsHookEx(s_hcbtHook);
173 Window* child = get_window(hwnd);
176 if (child && (!hwnd || !child->_hwnd))
183 LRESULT CALLBACK
Window::PropSheetCBTHookProc(int code
, WPARAM wparam
, LPARAM lparam
)
185 if (code
== HCBT_CREATEWND
) {
186 HWND hwnd
= (HWND
)wparam
;
188 // create Window controller and associate it with the window handle
189 Window
* child
= get_window(hwnd
);
192 child
= create_controller(hwnd
);
195 return CallNextHookEx(s_hcbtHook
, code
, wparam
, lparam
);
199 /// get window controller from window handle
201 Window
* Window::get_window(HWND hwnd
)
204 Lock
lock(GetStaticWindowData()._map_crit_sect
); // protect access to s_wnd_map
206 WindowMap::const_iterator found
= s_wnd_map
.find(hwnd
);
208 if (found
!=s_wnd_map
.end())
209 return found
->second
;
216 /// create controller for a new window
218 Window
* Window::create_controller(HWND hwnd
)
220 if (s_window_creator
) { // protect for recursion and create the window object only for the first window
221 Lock
lock(GetStaticWindowData()._create_crit_sect
); // protect access to s_window_creator and s_new_info
223 const void* info
= s_new_info
;
226 CREATORFUNC window_creator
= s_window_creator
;
227 s_window_creator
= NULL
;
230 return CREATORFUNC_INFO(window_creator
)(hwnd
, info
);
232 return CREATORFUNC(window_creator
)(hwnd
);
239 LRESULT
Window::Init(LPCREATESTRUCT pcs
)
245 LRESULT CALLBACK
Window::WindowWndProc(HWND hwnd
, UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
247 Window
* pThis
= get_window(hwnd
);
250 pThis
= create_controller(hwnd
);
255 return pThis
->Command(LOWORD(wparam
), HIWORD(wparam
));
258 return pThis
->Notify(wparam
, (NMHDR
*)lparam
);
260 case WM_NOTIFYFORMAT
:
264 return pThis
->Init((LPCREATESTRUCT
)lparam
);
271 return pThis
->WndProc(nmsg
, wparam
, lparam
);
275 return DefWindowProc(hwnd
, nmsg
, wparam
, lparam
);
278 LRESULT
Window::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
280 return DefWindowProc(_hwnd
, nmsg
, wparam
, lparam
);
283 int Window::Command(int id
, int code
)
285 return 1; // no command handler found
288 int Window::Notify(int id
, NMHDR
* pnmh
)
293 void Window::CancelModes()
295 PostMessage(HWND_BROADCAST
, WM_CANCELMODE
, 0, 0);
299 SubclassedWindow::SubclassedWindow(HWND hwnd
)
302 _orgWndProc
= SubclassWindow(_hwnd
, SubclassedWndProc
);
308 LRESULT CALLBACK
SubclassedWindow::SubclassedWndProc(HWND hwnd
, UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
310 SubclassedWindow
* pThis
= GET_WINDOW(SubclassedWindow
, hwnd
);
316 if (!pThis
->Command(LOWORD(wparam
), HIWORD(wparam
)))
321 return pThis
->Notify(wparam
, (NMHDR
*)lparam
);
323 case WM_NOTIFYFORMAT
:
327 return pThis
->Init((LPCREATESTRUCT
)lparam
);
334 return pThis
->WndProc(nmsg
, wparam
, lparam
);
338 return CallWindowProc(pThis
->_orgWndProc
, hwnd
, nmsg
, wparam
, lparam
);
341 LRESULT
SubclassedWindow::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
343 return CallWindowProc(_orgWndProc
, _hwnd
, nmsg
, wparam
, lparam
);
346 int SubclassedWindow::Command(int id
, int code
)
348 return 1; // no command handler found
351 int SubclassedWindow::Notify(int id
, NMHDR
* pnmh
)
353 return CallWindowProc(_orgWndProc
, _hwnd
, WM_NOTIFY
, id
, (LPARAM
)pnmh
);
357 ChildWindow::ChildWindow(HWND hwnd
, const ChildWndInfo
& info
)
359 _hwndFrame(GetParent(info
._hmdiclient
))
362 _split_pos
= DEFAULT_SPLIT_POS
;
363 _last_split
= DEFAULT_SPLIT_POS
;
367 ChildWindow
* ChildWindow::create(const ChildWndInfo
& info
, const RECT
& rect
, CREATORFUNC_INFO creator
,
368 LPCTSTR classname
, LPCTSTR title
, DWORD style
)
372 mcs
.szClass
= classname
;
374 mcs
.hOwner
= g_Globals
._hInstance
;
377 mcs
.cx
= rect
.right
- rect
.left
;
378 mcs
.cy
= rect
.bottom
- rect
.top
;
382 return static_cast<ChildWindow
*>(create_mdi_child(info
, mcs
, creator
));
386 LRESULT
ChildWindow::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
391 PaintCanvas
canvas(_hwnd
);
392 ClientRect
rt(_hwnd
);
393 rt
.left
= _split_pos
-SPLIT_WIDTH
/2;
394 rt
.right
= _split_pos
+SPLIT_WIDTH
/2+1;
395 HBRUSH lastBrush
= SelectBrush(canvas
, GetStockBrush(LTGRAY_BRUSH
));
396 Rectangle(canvas
, rt
.left
, rt
.top
-1, rt
.right
, rt
.bottom
+1);
397 SetRect(&rc
, rt
.left
, rt
.top
-1, rt
.right
, rt
.bottom
+1);
398 DrawEdge(canvas
, &rc
, EDGE_RAISED
, BF_RECT
);
399 SelectObject(canvas
, lastBrush
);
403 if (LOWORD(lparam
) == HTCLIENT
) {
406 ScreenToClient(_hwnd
, &pt
);
408 if (pt
.x
>=_split_pos
-SPLIT_WIDTH
/2 && pt
.x
<_split_pos
+SPLIT_WIDTH
/2+1) {
409 SetCursor(LoadCursor(0, IDC_SIZEWE
));
416 if (wparam
!= SIZE_MINIMIZED
)
417 resize_children(LOWORD(lparam
), HIWORD(lparam
));
420 case WM_GETMINMAXINFO
:
421 DefMDIChildProc(_hwnd
, nmsg
, wparam
, lparam
);
423 {LPMINMAXINFO lpmmi
= (LPMINMAXINFO
)lparam
;
425 lpmmi
->ptMaxTrackSize
.x
<<= 1; // 2*GetSystemMetrics(SM_CXSCREEN) / SM_CXVIRTUALSCREEN
426 lpmmi
->ptMaxTrackSize
.y
<<= 1; // 2*GetSystemMetrics(SM_CYSCREEN) / SM_CYVIRTUALSCREEN
429 case WM_LBUTTONDOWN
: {
430 int x
= GET_X_LPARAM(lparam
);
432 ClientRect
rt(_hwnd
);
434 if (x
>=_split_pos
-SPLIT_WIDTH
/2 && x
<_split_pos
+SPLIT_WIDTH
/2+1) {
435 _last_split
= _split_pos
;
442 if (GetCapture() == _hwnd
)
447 if (wparam
== VK_ESCAPE
)
448 if (GetCapture() == _hwnd
) {
449 _split_pos
= _last_split
;
450 ClientRect
rt(_hwnd
);
451 resize_children(rt
.right
, rt
.bottom
);
454 SetCursor(LoadCursor(0, IDC_ARROW
));
459 if (GetCapture() == _hwnd
) {
460 int x
= GET_X_LPARAM(lparam
);
462 ClientRect
rt(_hwnd
);
464 if (x
>=0 && x
<rt
.right
) {
466 resize_children(rt
.right
, rt
.bottom
);
467 rt
.left
= x
-SPLIT_WIDTH
/2;
468 rt
.right
= x
+SPLIT_WIDTH
/2+1;
469 InvalidateRect(_hwnd
, &rt
, FALSE
);
470 UpdateWindow(_left_hwnd
);
472 UpdateWindow(_right_hwnd
);
477 case PM_DISPATCH_COMMAND
:
478 switch(LOWORD(wparam
)) {
480 if (!_url_history
.empty()) {
481 const String
& url
= jump_to_int(_url_history
.top());
483 if (jump_to_int(url
))
508 if ((HWND
)lparam
== _hwnd
) {
509 SendMessage(_hwndFrame
, PM_SETSTATUSTEXT
, 0, (LPARAM
)_statusText
.c_str());
510 SendMessage(_hwndFrame
, PM_URL_CHANGED
, 0, (LPARAM
)_url
.c_str());
515 return go_to((LPCTSTR
)lparam
)? TRUE
: FALSE
;
518 return DefMDIChildProc(_hwnd
, nmsg
, wparam
, lparam
);
525 void ChildWindow::resize_children(int cx
, int cy
)
527 HDWP hdwp
= BeginDeferWindowPos(2);
536 cx
= _split_pos
+ SPLIT_WIDTH
/2;
538 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
);
545 hdwp
= DeferWindowPos(hdwp
, _right_hwnd
, 0, rt
.left
+cx
+1, rt
.top
, rt
.right
-cx
, rt
.bottom
-rt
.top
, SWP_NOZORDER
|SWP_NOACTIVATE
);
547 EndDeferWindowPos(hdwp
);
551 bool ChildWindow::go_to(LPCTSTR url
)
553 const String
& url_str
= jump_to_int(url
);
555 if (!url_str
.empty()) {
558 _url_history
.push(url_str
);
565 void ChildWindow::set_url(LPCTSTR url
)
570 SendMessage(_hwndFrame
, PM_URL_CHANGED
, 0, (LPARAM
)url
);
575 WindowSet
Window::s_pretranslate_windows
;
577 void Window::register_pretranslate(HWND hwnd
)
579 s_pretranslate_windows
.insert(hwnd
);
582 void Window::unregister_pretranslate(HWND hwnd
)
584 s_pretranslate_windows
.erase(hwnd
);
587 BOOL
Window::pretranslate_msg(LPMSG pmsg
)
589 for(WindowSet::const_iterator it
=Window::s_pretranslate_windows
.begin(); it
!=s_pretranslate_windows
.end(); ++it
)
590 if (SendMessage(*it
, PM_TRANSLATE_MSG
, 0, (LPARAM
)pmsg
))
597 WindowSet
Window::s_dialogs
;
599 void Window::register_dialog(HWND hwnd
)
601 s_dialogs
.insert(hwnd
);
604 void Window::unregister_dialog(HWND hwnd
)
606 s_dialogs
.erase(hwnd
);
609 BOOL
Window::dispatch_dialog_msg(MSG
* pmsg
)
611 for(WindowSet::const_iterator it
=Window::s_dialogs
.begin(); it
!=s_dialogs
.end(); ++it
)
612 if (IsDialogMessage(*it
, pmsg
))
619 int Window::MessageLoop()
623 while(GetMessage(&msg
, 0, 0, 0)) {
625 if (pretranslate_msg(&msg
))
628 if (dispatch_dialog_msg(&msg
))
631 TranslateMessage(&msg
);
634 DispatchMessage(&msg
);
635 } catch(COMException
& e
) {
636 HandleException(e
, 0);
638 } catch(COMException
& e
) {
639 HandleException(e
, 0);
647 LRESULT
Window::SendParent(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
649 HWND parent
= GetParent(_hwnd
);
654 return SendMessage(parent
, nmsg
, wparam
, lparam
);
657 LRESULT
Window::PostParent(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
659 HWND parent
= GetParent(_hwnd
);
664 return PostMessage(parent
, nmsg
, wparam
, lparam
);
668 PreTranslateWindow::PreTranslateWindow(HWND hwnd
)
671 register_pretranslate(hwnd
);
674 PreTranslateWindow::~PreTranslateWindow()
676 unregister_pretranslate(_hwnd
);
680 Dialog::Dialog(HWND hwnd
)
683 register_dialog(hwnd
);
688 unregister_dialog(_hwnd
);
691 int Dialog::DoModal(UINT nid
, CREATORFUNC creator
, HWND hwndParent
)
693 Lock
lock(GetStaticWindowData()._create_crit_sect
); // protect access to s_window_creator and s_new_info
695 s_window_creator
= creator
;
698 ///@todo call Window::pretranslate_msg()
700 return DialogBoxParam(g_Globals
._hInstance
, MAKEINTRESOURCE(nid
), hwndParent
, DialogProc
, 0/*lpParam*/);
703 int Dialog::DoModal(UINT nid
, CREATORFUNC_INFO creator
, const void* info
, HWND hwndParent
)
705 Lock
lock(GetStaticWindowData()._create_crit_sect
); // protect access to s_window_creator and s_new_info
707 s_window_creator
= (CREATORFUNC
) creator
;
710 ///@todo call Window::pretranslate_msg()
712 return DialogBoxParam(g_Globals
._hInstance
, MAKEINTRESOURCE(nid
), hwndParent
, DialogProc
, 0/*lpParam*/);
715 INT_PTR CALLBACK
Window::DialogProc(HWND hwnd
, UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
717 Window
* pThis
= get_window(hwnd
);
722 pThis
->Command(LOWORD(wparam
), HIWORD(wparam
));
723 return TRUE
; // message has been processed
726 pThis
->Notify(wparam
, (NMHDR
*)lparam
);
727 return TRUE
; // message has been processed
729 case WM_NOTIFYFORMAT
:
730 SetWindowLong(hwnd
, DWLP_MSGRESULT
, NFR_CURRENT
); // set return value NFR_CURRENT
731 return TRUE
; // message has been processed
735 return TRUE
; // message has been processed
738 return pThis
->WndProc(nmsg
, wparam
, lparam
);
740 } else if (nmsg
== WM_INITDIALOG
) {
741 pThis
= create_controller(hwnd
);
744 return pThis
->Init(NULL
);
747 return FALSE
; // message has not been processed
750 LRESULT
Dialog::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
752 return FALSE
; // message has not been processed
755 int Dialog::Command(int id
, int code
)
757 if (code
== BN_CLICKED
) {
758 EndDialog(_hwnd
, id
);
759 return 0; // message has been processed
766 ResizeManager::ResizeManager(HWND hwnd
)
769 ClientRect
clnt(hwnd
);
770 _last_size
.cx
= clnt
.right
;
771 _last_size
.cy
= clnt
.bottom
;
773 WindowRect
rect(hwnd
);
774 _min_wnd_size
.cx
= rect
.right
- rect
.left
;
775 _min_wnd_size
.cy
= rect
.bottom
- rect
.top
;
778 void ResizeManager::HandleSize(int cx
, int cy
)
780 ClientRect
clnt_rect(_hwnd
);
781 SIZE new_size
= {cx
, cy
};
783 int dx
= new_size
.cx
- _last_size
.cx
;
784 int dy
= new_size
.cy
- _last_size
.cy
;
789 _last_size
= new_size
;
791 HDWP hDWP
= BeginDeferWindowPos(size());
793 for(ResizeManager::const_iterator it
=begin(); it
!=end(); ++it
) {
794 const ResizeEntry
& e
= *it
;
797 if (e
._flags
& MOVE_LEFT
)
800 if (e
._flags
& MOVE_RIGHT
)
803 if (e
._flags
& MOVE_TOP
)
806 if (e
._flags
& MOVE_BOTTOM
)
811 if (!move
.left
&& !move
.top
)
814 if (move
.right
==move
.left
&& move
.bottom
==move
.top
)
817 if (flags
!= (SWP_NOMOVE
|SWP_NOSIZE
)) {
818 HWND hwnd
= GetDlgItem(_hwnd
, e
._id
);
821 WindowRect
rect(hwnd
);
822 ScreenToClient(_hwnd
, rect
);
824 rect
.left
+= move
.left
;
825 rect
.right
+= move
.right
;
826 rect
.top
+= move
.top
;
827 rect
.bottom
+= move
.bottom
;
829 hDWP
= DeferWindowPos(hDWP
, hwnd
, 0, rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
, flags
|SWP_NOACTIVATE
|SWP_NOZORDER
);
834 EndDeferWindowPos(hDWP
);
837 void ResizeManager::Resize(int dx
, int dy
)
839 ::SetWindowPos(_hwnd
, 0, 0, 0, _min_wnd_size
.cx
+dx
, _min_wnd_size
.cy
+dy
, SWP_NOMOVE
|SWP_NOACTIVATE
);
842 ClientRect
clnt_rect(_hwnd
);
843 HandleSize(clnt_rect
.right
, clnt_rect
.bottom
);
847 Button::Button(HWND parent
, LPCTSTR title
, int left
, int top
, int width
, int height
,
848 int id
, DWORD flags
, DWORD exStyle
)
849 : WindowHandle(CreateWindowEx(exStyle
, TEXT("BUTTON"), title
, flags
, left
, top
, width
, height
,
850 parent
, (HMENU
)id
, g_Globals
._hInstance
, 0))
855 LRESULT
OwnerdrawnButton::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
857 if (nmsg
== PM_DISPATCH_DRAWITEM
) {
858 DrawItem((LPDRAWITEMSTRUCT
)lparam
);
861 return super::WndProc(nmsg
, wparam
, lparam
);
865 Static::Static(HWND parent
, LPCTSTR title
, int left
, int top
, int width
, int height
,
866 int id
, DWORD flags
, DWORD exStyle
)
867 : WindowHandle(CreateWindowEx(exStyle
, TEXT("STATIC"), title
, flags
, left
, top
, width
, height
,
868 parent
, (HMENU
)id
, g_Globals
._hInstance
, 0))
873 static RECT s_MyDrawText_Rect
= {0, 0, 0, 0};
875 static BOOL CALLBACK
MyDrawText(HDC hdc
, LPARAM data
, int cnt
)
877 ::DrawText(hdc
, (LPCTSTR
)data
, cnt
, &s_MyDrawText_Rect
, DT_SINGLELINE
);
881 void DrawGrayText(HDC hdc
, LPRECT pRect
, LPCTSTR title
, int dt_flags
)
883 COLORREF gray
= GetSysColor(COLOR_GRAYTEXT
);
886 TextColor
lcColor(hdc
, GetSysColor(COLOR_BTNHIGHLIGHT
));
887 RECT shadowRect
= {pRect
->left
+1, pRect
->top
+1, pRect
->right
+1, pRect
->bottom
+1};
888 DrawText(hdc
, title
, -1, &shadowRect
, dt_flags
);
890 SetTextColor(hdc
, gray
);
891 DrawText(hdc
, title
, -1, pRect
, dt_flags
);
893 int old_r
= pRect
->right
;
894 int old_b
= pRect
->bottom
;
896 DrawText(hdc
, title
, -1, pRect
, dt_flags
|DT_CALCRECT
);
898 int x
= pRect
->left
+ (old_r
-pRect
->right
)/2;
899 int y
= pRect
->top
+ (old_b
-pRect
->bottom
)/2;
900 int w
= pRect
->right
-pRect
->left
;
901 int h
= pRect
->bottom
-pRect
->top
;
902 s_MyDrawText_Rect
.right
= w
;
903 s_MyDrawText_Rect
.bottom
= h
;
905 GrayString(hdc
, GetSysColorBrush(COLOR_GRAYTEXT
), MyDrawText
, (LPARAM
)title
, -1, x
, y
, w
, h
);
911 void ColorButton::DrawItem(LPDRAWITEMSTRUCT dis)
913 UINT state = DFCS_BUTTONPUSH;
915 if (dis->itemState & ODS_DISABLED)
916 state |= DFCS_INACTIVE;
918 RECT textRect = {dis->rcItem.left+2, dis->rcItem.top+2, dis->rcItem.right-4, dis->rcItem.bottom-4};
920 if (dis->itemState & ODS_SELECTED) {
921 state |= DFCS_PUSHED;
922 ++textRect.left; ++textRect.top;
923 ++textRect.right; ++textRect.bottom;
926 DrawFrameControl(dis->hDC, &dis->rcItem, DFC_BUTTON, state);
928 TCHAR title[BUFFER_LEN];
929 GetWindowText(_hwnd, title, BUFFER_LEN);
931 BkMode bk_mode(dis->hDC, TRANSPARENT);
933 if (dis->itemState & (ODS_DISABLED|ODS_GRAYED))
934 DrawGrayText(dis, &textRect, title, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
936 TextColor lcColor(dis->hDC, _textColor);
937 DrawText(dis->hDC, title, -1, &textRect, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
940 if (dis->itemState & ODS_FOCUS) {
942 dis->rcItem.left+3, dis->rcItem.top+3,
943 dis->rcItem.right-dis->rcItem.left-4, dis->rcItem.bottom-dis->rcItem.top-4
945 if (dis->itemState & ODS_SELECTED) {
946 ++rect.left; ++rect.top;
947 ++rect.right; ++rect.bottom;
949 DrawFocusRect(dis->hDC, &rect);
955 void PictureButton::DrawItem(LPDRAWITEMSTRUCT dis
)
957 UINT state
= DFCS_BUTTONPUSH
;
958 int style
= GetWindowStyle(_hwnd
);
960 if (dis
->itemState
& ODS_DISABLED
)
961 state
|= DFCS_INACTIVE
;
967 if (style
& BS_BOTTOM
) {
968 // align horizontal centered, vertical floating
969 imagePos
.x
= (dis
->rcItem
.left
+ dis
->rcItem
.right
- _cx
) / 2;
970 imagePos
.y
= dis
->rcItem
.top
+ 3;
972 textRect
.left
= dis
->rcItem
.left
+ 2;
973 textRect
.top
= dis
->rcItem
.top
+ _cy
+ 4;
974 textRect
.right
= dis
->rcItem
.right
- 4;
975 textRect
.bottom
= dis
->rcItem
.bottom
- 4;
977 dt_flags
= DT_SINGLELINE
|DT_CENTER
|DT_VCENTER
;
979 // horizontal floating, vertical centered
980 imagePos
.x
= dis
->rcItem
.left
+ 3;
981 imagePos
.y
= (dis
->rcItem
.top
+ dis
->rcItem
.bottom
- _cy
)/2;
983 textRect
.left
= dis
->rcItem
.left
+ _cx
+ 4;
984 textRect
.top
= dis
->rcItem
.top
+ 2;
985 textRect
.right
= dis
->rcItem
.right
- 4;
986 textRect
.bottom
= dis
->rcItem
.bottom
- 4;
988 dt_flags
= DT_SINGLELINE
|DT_VCENTER
/*|DT_CENTER*/;
991 if (dis
->itemState
& ODS_SELECTED
) {
992 state
|= DFCS_PUSHED
;
993 ++imagePos
.x
; ++imagePos
.y
;
994 ++textRect
.left
; ++textRect
.top
;
995 ++textRect
.right
; ++textRect
.bottom
;
999 FillRect(dis
->hDC
, &dis
->rcItem
, _hBrush
);
1001 if (style
& BS_FLAT
) // Only with BS_FLAT set, there will be drawn a frame without highlight.
1002 DrawEdge(dis
->hDC
, &dis
->rcItem
, EDGE_RAISED
, BF_RECT
|BF_FLAT
);
1004 DrawFrameControl(dis
->hDC
, &dis
->rcItem
, DFC_BUTTON
, state
);
1007 DrawIconEx(dis
->hDC
, imagePos
.x
, imagePos
.y
, _hIcon
, _cx
, _cy
, 0, _hBrush
, DI_NORMAL
);
1010 BitmapSelection
sel(mem_dc
, _hBmp
);
1011 BitBlt(dis
->hDC
, imagePos
.x
, imagePos
.y
, _cx
, _cy
, mem_dc
, 0, 0, SRCCOPY
);
1014 TCHAR title
[BUFFER_LEN
];
1015 GetWindowText(_hwnd
, title
, BUFFER_LEN
);
1017 BkMode
bk_mode(dis
->hDC
, TRANSPARENT
);
1019 if (dis
->itemState
& (ODS_DISABLED
|ODS_GRAYED
))
1020 DrawGrayText(dis
->hDC
, &textRect
, title
, dt_flags
);
1022 TextColor
lcColor(dis
->hDC
, GetSysColor(COLOR_BTNTEXT
));
1023 DrawText(dis
->hDC
, title
, -1, &textRect
, dt_flags
);
1026 if (dis
->itemState
& ODS_FOCUS
) {
1028 dis
->rcItem
.left
+3, dis
->rcItem
.top
+3,
1029 dis
->rcItem
.right
-dis
->rcItem
.left
-4, dis
->rcItem
.bottom
-dis
->rcItem
.top
-4
1031 if (dis
->itemState
& ODS_SELECTED
) {
1032 ++rect
.left
; ++rect
.top
;
1033 ++rect
.right
; ++rect
.bottom
;
1035 DrawFocusRect(dis
->hDC
, &rect
);
1040 void FlatButton::DrawItem(LPDRAWITEMSTRUCT dis
)
1042 UINT style
= DFCS_BUTTONPUSH
;
1044 if (dis
->itemState
& ODS_DISABLED
)
1045 style
|= DFCS_INACTIVE
;
1047 RECT textRect
= {dis
->rcItem
.left
+2, dis
->rcItem
.top
+2, dis
->rcItem
.right
-4, dis
->rcItem
.bottom
-4};
1049 if (dis
->itemState
& ODS_SELECTED
) {
1050 style
|= DFCS_PUSHED
;
1051 ++textRect
.left
; ++textRect
.top
;
1052 ++textRect
.right
; ++textRect
.bottom
;
1055 FillRect(dis
->hDC
, &dis
->rcItem
, GetSysColorBrush(COLOR_BTNFACE
));
1057 // highlight the button?
1059 DrawEdge(dis
->hDC
, &dis
->rcItem
, EDGE_ETCHED
, BF_RECT
);
1060 else if (GetWindowStyle(_hwnd
) & BS_FLAT
) // Only with BS_FLAT there will be drawn a frame to show highlighting.
1061 DrawEdge(dis
->hDC
, &dis
->rcItem
, EDGE_RAISED
, BF_RECT
|BF_FLAT
);
1063 TCHAR txt
[BUFFER_LEN
];
1064 int txt_len
= GetWindowText(_hwnd
, txt
, BUFFER_LEN
);
1066 if (dis
->itemState
& (ODS_DISABLED
|ODS_GRAYED
)) {
1067 COLORREF gray
= GetSysColor(COLOR_GRAYTEXT
);
1071 TextColor
lcColor(dis
->hDC
, GetSysColor(COLOR_BTNHIGHLIGHT
));
1072 RECT shadowRect
= {textRect
.left
+1, textRect
.top
+1, textRect
.right
+1, textRect
.bottom
+1};
1073 DrawText(dis
->hDC
, txt
, txt_len
, &shadowRect
, DT_SINGLELINE
|DT_VCENTER
|DT_CENTER
);
1076 BkMode
mode(dis
->hDC
, TRANSPARENT
);
1077 TextColor
lcColor(dis
->hDC
, gray
);
1078 DrawText(dis
->hDC
, txt
, txt_len
, &textRect
, DT_SINGLELINE
|DT_VCENTER
|DT_CENTER
);
1080 int old_r
= textRect
.right
;
1081 int old_b
= textRect
.bottom
;
1082 DrawText(dis
->hDC
, txt
, txt_len
, &textRect
, DT_SINGLELINE
|DT_VCENTER
|DT_CENTER
|DT_CALCRECT
);
1083 int x
= textRect
.left
+ (old_r
-textRect
.right
)/2;
1084 int y
= textRect
.top
+ (old_b
-textRect
.bottom
)/2;
1085 int w
= textRect
.right
-textRect
.left
;
1086 int h
= textRect
.bottom
-textRect
.top
;
1087 s_MyDrawText_Rect
.right
= w
;
1088 s_MyDrawText_Rect
.bottom
= h
;
1089 GrayString(dis
->hDC
, GetSysColorBrush(COLOR_GRAYTEXT
), MyDrawText
, (LPARAM
)txt
, txt_len
, x
, y
, w
, h
);
1092 TextColor
lcColor(dis
->hDC
, _active
? _activeColor
: _textColor
);
1093 DrawText(dis
->hDC
, txt
, txt_len
, &textRect
, DT_SINGLELINE
|DT_VCENTER
|DT_CENTER
);
1096 if (dis
->itemState
& ODS_FOCUS
) {
1098 dis
->rcItem
.left
+3, dis
->rcItem
.top
+3,
1099 dis
->rcItem
.right
-dis
->rcItem
.left
-4, dis
->rcItem
.bottom
-dis
->rcItem
.top
-4
1101 if (dis
->itemState
& ODS_SELECTED
) {
1102 ++rect
.left
; ++rect
.top
;
1103 ++rect
.right
; ++rect
.bottom
;
1105 DrawFocusRect(dis
->hDC
, &rect
);
1109 LRESULT
FlatButton::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
1112 case WM_MOUSEMOVE
: {
1113 bool active
= false;
1115 if (IsWindowEnabled(_hwnd
)) {
1116 DWORD pid_foreground
;
1117 HWND hwnd_foreground
= GetForegroundWindow(); //@@ may be better look for WM_ACTIVATEAPP ?
1118 GetWindowThreadProcessId(hwnd_foreground
, &pid_foreground
);
1120 if (GetCurrentProcessId() == pid_foreground
) {
1121 POINT pt
= {GET_X_LPARAM(lparam
), GET_Y_LPARAM(lparam
)};
1122 ClientRect
clntRect(_hwnd
);
1124 // highlight the button?
1125 if (pt
.x
>=clntRect
.left
&& pt
.x
<clntRect
.right
&& pt
.y
>=clntRect
.top
&& pt
.y
<clntRect
.bottom
)
1130 if (active
!= _active
) {
1134 TRACKMOUSEEVENT tme
= {sizeof(tme
), /*TME_HOVER|*/TME_LEAVE
, _hwnd
/*, HOVER_DEFAULT*/};
1135 _TrackMouseEvent(&tme
);
1138 InvalidateRect(_hwnd
, NULL
, TRUE
);
1143 case WM_LBUTTONUP
: {
1144 POINT pt
= {GET_X_LPARAM(lparam
), GET_Y_LPARAM(lparam
)};
1145 ClientRect
clntRect(_hwnd
);
1147 // no more in the active rectangle?
1148 if (pt
.x
<clntRect
.left
|| pt
.x
>=clntRect
.right
|| pt
.y
<clntRect
.top
|| pt
.y
>=clntRect
.bottom
)
1155 TRACKMOUSEEVENT tme
= {sizeof(tme
), /*TME_HOVER|*/TME_LEAVE
|TME_CANCEL
, _hwnd
/*, HOVER_DEFAULT*/};
1156 _TrackMouseEvent(&tme
);
1165 InvalidateRect(_hwnd
, NULL
, TRUE
);
1171 return super::WndProc(nmsg
, wparam
, lparam
);
1176 HyperlinkCtrl::HyperlinkCtrl(HWND hwnd
, COLORREF colorLink
, COLORREF colorVisited
)
1178 _cmd(ResString(GetDlgCtrlID(hwnd
))),
1179 _textColor(colorLink
),
1180 _colorVisited(colorVisited
),
1187 HyperlinkCtrl::HyperlinkCtrl(HWND owner
, int id
, COLORREF colorLink
, COLORREF colorVisited
)
1188 : super(GetDlgItem(owner
, id
)),
1189 _cmd(ResString(id
)),
1190 _textColor(colorLink
),
1191 _colorVisited(colorVisited
),
1198 void HyperlinkCtrl::init()
1201 TCHAR txt
[BUFFER_LEN
];
1202 _cmd
.assign(txt
, GetWindowText(_hwnd
, txt
, BUFFER_LEN
));
1206 HyperlinkCtrl::~HyperlinkCtrl()
1209 DeleteObject(_hfont
);
1212 LRESULT
HyperlinkCtrl::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
1215 case PM_DISPATCH_CTLCOLOR
: {
1217 HFONT hfont
= (HFONT
) SendMessage(_hwnd
, WM_GETFONT
, 0, 0);
1218 LOGFONT lf
; GetObject(hfont
, sizeof(lf
), &lf
);
1219 lf
.lfUnderline
= TRUE
;
1220 _hfont
= CreateFontIndirect(&lf
);
1223 HDC hdc
= (HDC
) wparam
;
1224 SetTextColor(hdc
, _textColor
); //@@
1225 SelectFont(hdc
, _hfont
);
1226 SetBkMode(hdc
, TRANSPARENT
);
1227 return (LRESULT
)GetStockObject(HOLLOW_BRUSH
);
1232 _crsr_link
= LoadCursor(0, IDC_HAND
);
1235 SetCursor(_crsr_link
);
1239 return HTCLIENT
; // Aktivierung von Maus-Botschaften
1241 case WM_LBUTTONDOWN
:
1243 _textColor
= _colorVisited
;
1244 InvalidateRect(_hwnd
, NULL
, FALSE
);
1250 return super::WndProc(nmsg
, wparam
, lparam
);
1255 ToolTip::ToolTip(HWND owner
)
1256 : super(CreateWindowEx(WS_EX_TOPMOST
|WS_EX_NOPARENTNOTIFY
, TOOLTIPS_CLASS
, 0,
1257 WS_POPUP
|TTS_NOPREFIX
|TTS_ALWAYSTIP
, CW_USEDEFAULT
,CW_USEDEFAULT
,CW_USEDEFAULT
,CW_USEDEFAULT
,
1258 owner
, 0, g_Globals
._hInstance
, 0))
1264 ListSort::ListSort(HWND hwndListview
, PFNLVCOMPARE compare_fct
)
1265 : WindowHandle(hwndListview
),
1266 _compare_fct(compare_fct
)
1272 void ListSort::toggle_sort(int idx
)
1274 if (_sort_crit
== idx
)
1275 _direction
= !_direction
;
1282 void ListSort::sort()
1284 int idx
= ListView_GetSelectionMark(_hwnd
);
1285 LPARAM param
= ListView_GetItemData(_hwnd
, idx
);
1287 ListView_SortItems(_hwnd
, _compare_fct
, (LPARAM
)this);
1290 idx
= ListView_FindItemPara(_hwnd
, param
);
1291 ListView_EnsureVisible(_hwnd
, idx
, FALSE
);
1296 PropSheetPage::PropSheetPage(UINT nid
, Window::CREATORFUNC dlg_creator
)
1297 : _dlg_creator(dlg_creator
)
1299 PROPSHEETPAGE::dwSize
= sizeof(PROPSHEETPAGE
);
1300 PROPSHEETPAGE::dwFlags
= 0;
1301 PROPSHEETPAGE::hInstance
= g_Globals
._hInstance
;
1302 PROPSHEETPAGE::pszTemplate
= MAKEINTRESOURCE(nid
);
1303 PROPSHEETPAGE::pfnDlgProc
= PropSheetPageDlg::DialogProc
;
1304 PROPSHEETPAGE::lParam
= (LPARAM
) this;
1308 #ifndef PSM_GETRESULT // currently (as of 18.01.2004) missing in MinGW headers
1309 #define PSM_GETRESULT (WM_USER + 135)
1310 #define PropSheet_GetResult(hDlg) SNDMSG(hDlg, PSM_GETRESULT, 0, 0)
1314 PropertySheetDialog::PropertySheetDialog(HWND owner
)
1317 PROPSHEETHEADER::dwSize
= sizeof(PROPSHEETHEADER
);
1318 PROPSHEETHEADER::dwFlags
= PSH_PROPSHEETPAGE
| PSH_MODELESS
;
1319 PROPSHEETHEADER::hwndParent
= owner
;
1320 PROPSHEETHEADER::hInstance
= g_Globals
._hInstance
;
1323 void PropertySheetDialog::add(PropSheetPage
& psp
)
1325 _pages
.push_back(psp
);
1328 int PropertySheetDialog::DoModal(int start_page
)
1330 PROPSHEETHEADER::ppsp
= (LPCPROPSHEETPAGE
) &_pages
[0];
1331 PROPSHEETHEADER::nPages
= _pages
.size();
1332 PROPSHEETHEADER::nStartPage
= start_page
;
1334 Window* pwnd = Window::create_property_sheet(this, WINDOW_CREATOR(PropertySheetDlg), NULL);
1338 HWND hwndPropSheet = *pwnd;
1340 int ret
= PropertySheet(this);
1344 HWND hwndPropSheet
= (HWND
) ret
;
1345 HWND hwndparent
= GetParent(hwndPropSheet
);
1348 EnableWindow(hwndparent
, FALSE
);
1353 while(GetMessage(&msg
, 0, 0, 0)) {
1355 if (Window::pretranslate_msg(&msg
))
1358 if (PropSheet_IsDialogMessage(hwndPropSheet
, &msg
))
1361 if (Window::dispatch_dialog_msg(&msg
))
1364 TranslateMessage(&msg
);
1367 DispatchMessage(&msg
);
1368 } catch(COMException
& e
) {
1369 HandleException(e
, 0);
1372 if (!PropSheet_GetCurrentPageHwnd(hwndPropSheet
)) {
1373 ret
= PropSheet_GetResult(hwndPropSheet
);
1376 } catch(COMException
& e
) {
1377 HandleException(e
, 0);
1382 EnableWindow(hwndparent
, TRUE
);
1384 DestroyWindow(hwndPropSheet
);
1389 HWND
PropertySheetDialog::GetCurrentPage()
1391 HWND hdlg
= PropSheet_GetCurrentPageHwnd(_hwnd
);
1396 PropSheetPageDlg::PropSheetPageDlg(HWND hwnd
)
1401 INT_PTR CALLBACK
PropSheetPageDlg::DialogProc(HWND hwnd
, UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
1403 PropSheetPageDlg
* pThis
= GET_WINDOW(PropSheetPageDlg
, hwnd
);
1408 pThis
->Command(LOWORD(wparam
), HIWORD(wparam
));
1409 return TRUE
; // message has been processed
1412 pThis
->Notify(wparam
, (NMHDR
*)lparam
);
1413 return TRUE
; // message has been processed
1415 case WM_NOTIFYFORMAT
:
1416 SetWindowLong(hwnd
, DWLP_MSGRESULT
, NFR_CURRENT
); // set return value NFR_CURRENT
1417 return TRUE
; // message has been processed
1421 return TRUE
; // message has been processed
1424 return pThis
->WndProc(nmsg
, wparam
, lparam
);
1426 } else if (nmsg
== WM_INITDIALOG
) {
1427 PROPSHEETPAGE
* psp
= (PROPSHEETPAGE
*) lparam
;
1428 PropSheetPage
* ppsp
= (PropSheetPage
*) psp
->lParam
;
1430 if (ppsp
->_dlg_creator
) {
1431 pThis
= static_cast<PropSheetPageDlg
*>(ppsp
->_dlg_creator(hwnd
));
1434 return pThis
->Init(NULL
);
1438 return FALSE
; // message has not been processed
1441 int PropSheetPageDlg::Command(int id
, int code
)
1443 // override call to EndDialog in Dialog::Command();