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 #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 // end hook in case it's not already done
134 UnhookWindowsHookEx(s_hcbtHook
);
136 Window
* child
= get_window(hwnd
);
139 if (child
&& (!hwnd
|| !child
->_hwnd
))
145 LRESULT CALLBACK
Window::MDICBTHookProc(int code
, WPARAM wparam
, LPARAM lparam
)
147 if (code
== HCBT_CREATEWND
) {
148 UnhookWindowsHookEx(s_hcbtHook
); // use the hook only for the first created window
151 HWND hwnd
= (HWND
)wparam
;
153 // create Window controller and associate it with the window handle
154 Window
* child
= get_window(hwnd
);
157 child
= create_controller(hwnd
);
160 return CallNextHookEx(s_hcbtHook
, code
, wparam
, lparam
);
165 Window* Window::create_property_sheet(PropertySheetDialog* ppsd, CREATORFUNC creator, const void* info)
167 Lock lock(GetStaticWindowData()._create_crit_sect); // protect access to s_window_creator and s_new_info
169 s_window_creator = creator;
172 s_hcbtHook = SetWindowsHookEx(WH_CBT, PropSheetCBTHookProc, 0, GetCurrentThreadId());
174 HWND hwnd = (HWND) PropertySheet(ppsd);
176 UnhookWindowsHookEx(s_hcbtHook);
178 Window* child = get_window(hwnd);
181 if (child && (!hwnd || !child->_hwnd))
188 LRESULT CALLBACK
Window::PropSheetCBTHookProc(int code
, WPARAM wparam
, LPARAM lparam
)
190 if (code
== HCBT_CREATEWND
) {
191 HWND hwnd
= (HWND
)wparam
;
193 // create Window controller and associate it with the window handle
194 Window
* child
= get_window(hwnd
);
197 child
= create_controller(hwnd
);
200 return CallNextHookEx(s_hcbtHook
, code
, wparam
, lparam
);
204 /// get window controller from window handle
206 Window
* Window::get_window(HWND hwnd
)
209 Lock
lock(GetStaticWindowData()._map_crit_sect
); // protect access to s_wnd_map
211 WindowMap::const_iterator found
= s_wnd_map
.find(hwnd
);
213 if (found
!=s_wnd_map
.end())
214 return found
->second
;
221 /// create controller for a new window
223 Window
* Window::create_controller(HWND hwnd
)
225 if (s_window_creator
) { // protect for recursion and create the window object only for the first window
226 Lock
lock(GetStaticWindowData()._create_crit_sect
); // protect access to s_window_creator and s_new_info
228 const void* info
= s_new_info
;
231 CREATORFUNC window_creator
= s_window_creator
;
232 s_window_creator
= NULL
;
235 return CREATORFUNC_INFO(window_creator
)(hwnd
, info
);
237 return CREATORFUNC(window_creator
)(hwnd
);
244 LRESULT
Window::Init(LPCREATESTRUCT pcs
)
250 LRESULT CALLBACK
Window::WindowWndProc(HWND hwnd
, UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
252 Window
* pThis
= get_window(hwnd
);
255 pThis
= create_controller(hwnd
);
260 return pThis
->Command(LOWORD(wparam
), HIWORD(wparam
));
263 return pThis
->Notify(wparam
, (NMHDR
*)lparam
);
265 case WM_NOTIFYFORMAT
:
269 return pThis
->Init((LPCREATESTRUCT
)lparam
);
276 return pThis
->WndProc(nmsg
, wparam
, lparam
);
280 return DefWindowProc(hwnd
, nmsg
, wparam
, lparam
);
283 LRESULT
Window::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
285 return DefWindowProc(_hwnd
, nmsg
, wparam
, lparam
);
288 int Window::Command(int id
, int code
)
290 return 1; // no command handler found
293 int Window::Notify(int id
, NMHDR
* pnmh
)
298 void Window::CancelModes()
300 PostMessage(HWND_BROADCAST
, WM_CANCELMODE
, 0, 0);
304 SubclassedWindow::SubclassedWindow(HWND hwnd
)
307 _orgWndProc
= SubclassWindow(_hwnd
, SubclassedWndProc
);
313 LRESULT CALLBACK
SubclassedWindow::SubclassedWndProc(HWND hwnd
, UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
315 SubclassedWindow
* pThis
= GET_WINDOW(SubclassedWindow
, hwnd
);
321 if (!pThis
->Command(LOWORD(wparam
), HIWORD(wparam
)))
326 return pThis
->Notify(wparam
, (NMHDR
*)lparam
);
328 case WM_NOTIFYFORMAT
:
332 return pThis
->Init((LPCREATESTRUCT
)lparam
);
339 return pThis
->WndProc(nmsg
, wparam
, lparam
);
343 return CallWindowProc(pThis
->_orgWndProc
, hwnd
, nmsg
, wparam
, lparam
);
346 LRESULT
SubclassedWindow::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
348 return CallWindowProc(_orgWndProc
, _hwnd
, nmsg
, wparam
, lparam
);
351 int SubclassedWindow::Command(int id
, int code
)
353 return 1; // no command handler found
356 int SubclassedWindow::Notify(int id
, NMHDR
* pnmh
)
358 return CallWindowProc(_orgWndProc
, _hwnd
, WM_NOTIFY
, id
, (LPARAM
)pnmh
);
362 ChildWindow::ChildWindow(HWND hwnd
, const ChildWndInfo
& info
)
364 _hwndFrame(GetParent(info
._hmdiclient
))
367 _split_pos
= DEFAULT_SPLIT_POS
;
368 _last_split
= DEFAULT_SPLIT_POS
;
372 ChildWindow
* ChildWindow::create(const ChildWndInfo
& info
, const RECT
& rect
, CREATORFUNC_INFO creator
,
373 LPCTSTR classname
, LPCTSTR title
, DWORD style
)
377 mcs
.szClass
= classname
;
379 mcs
.hOwner
= g_Globals
._hInstance
;
382 mcs
.cx
= rect
.right
- rect
.left
;
383 mcs
.cy
= rect
.bottom
- rect
.top
;
387 return static_cast<ChildWindow
*>(create_mdi_child(info
, mcs
, creator
));
391 LRESULT
ChildWindow::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
396 PaintCanvas
canvas(_hwnd
);
397 ClientRect
rt(_hwnd
);
398 rt
.left
= _split_pos
-SPLIT_WIDTH
/2;
399 rt
.right
= _split_pos
+SPLIT_WIDTH
/2+1;
400 HBRUSH lastBrush
= SelectBrush(canvas
, GetStockBrush(COLOR_SPLITBAR
));
401 Rectangle(canvas
, rt
.left
, rt
.top
-1, rt
.right
, rt
.bottom
+1);
402 SetRect(&rc
, rt
.left
, rt
.top
-1, rt
.right
, rt
.bottom
+1);
403 DrawEdge(canvas
, &rc
, EDGE_RAISED
, BF_RECT
);
404 SelectObject(canvas
, lastBrush
);
408 if (LOWORD(lparam
) == HTCLIENT
) {
411 ScreenToClient(_hwnd
, &pt
);
413 if (pt
.x
>=_split_pos
-SPLIT_WIDTH
/2 && pt
.x
<_split_pos
+SPLIT_WIDTH
/2+1) {
414 SetCursor(LoadCursor(0, IDC_SIZEWE
));
421 if (wparam
!= SIZE_MINIMIZED
)
422 resize_children(LOWORD(lparam
), HIWORD(lparam
));
425 case WM_GETMINMAXINFO
:
426 DefMDIChildProc(_hwnd
, nmsg
, wparam
, lparam
);
428 {LPMINMAXINFO lpmmi
= (LPMINMAXINFO
)lparam
;
430 lpmmi
->ptMaxTrackSize
.x
<<= 1; // 2*GetSystemMetrics(SM_CXSCREEN) / SM_CXVIRTUALSCREEN
431 lpmmi
->ptMaxTrackSize
.y
<<= 1; // 2*GetSystemMetrics(SM_CYSCREEN) / SM_CYVIRTUALSCREEN
434 case WM_LBUTTONDOWN
: {
435 int x
= GET_X_LPARAM(lparam
);
437 ClientRect
rt(_hwnd
);
439 if (x
>=_split_pos
-SPLIT_WIDTH
/2 && x
<_split_pos
+SPLIT_WIDTH
/2+1) {
440 _last_split
= _split_pos
;
447 if (GetCapture() == _hwnd
)
452 if (wparam
== VK_ESCAPE
)
453 if (GetCapture() == _hwnd
) {
454 _split_pos
= _last_split
;
455 ClientRect
rt(_hwnd
);
456 resize_children(rt
.right
, rt
.bottom
);
459 SetCursor(LoadCursor(0, IDC_ARROW
));
464 if (GetCapture() == _hwnd
) {
465 int x
= GET_X_LPARAM(lparam
);
467 ClientRect
rt(_hwnd
);
469 if (x
>=0 && x
<rt
.right
) {
471 resize_children(rt
.right
, rt
.bottom
);
472 rt
.left
= x
-SPLIT_WIDTH
/2;
473 rt
.right
= x
+SPLIT_WIDTH
/2+1;
474 InvalidateRect(_hwnd
, &rt
, FALSE
);
475 UpdateWindow(_left_hwnd
);
477 UpdateWindow(_right_hwnd
);
482 case PM_DISPATCH_COMMAND
:
483 switch(LOWORD(wparam
)) {
485 if (!_url_history
.empty()) {
486 const String
& url
= jump_to_int(_url_history
.top());
488 if (jump_to_int(url
))
513 if ((HWND
)lparam
== _hwnd
) {
514 SendMessage(_hwndFrame
, PM_SETSTATUSTEXT
, 0, (LPARAM
)_statusText
.c_str());
515 SendMessage(_hwndFrame
, PM_URL_CHANGED
, 0, (LPARAM
)_url
.c_str());
520 return go_to((LPCTSTR
)lparam
)? TRUE
: FALSE
;
523 return DefMDIChildProc(_hwnd
, nmsg
, wparam
, lparam
);
530 void ChildWindow::resize_children(int cx
, int cy
)
532 HDWP hdwp
= BeginDeferWindowPos(2);
541 cx
= _split_pos
+ SPLIT_WIDTH
/2;
543 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
);
550 hdwp
= DeferWindowPos(hdwp
, _right_hwnd
, 0, rt
.left
+cx
+1, rt
.top
, rt
.right
-cx
, rt
.bottom
-rt
.top
, SWP_NOZORDER
|SWP_NOACTIVATE
);
552 EndDeferWindowPos(hdwp
);
556 bool ChildWindow::go_to(LPCTSTR url
)
558 const String
& url_str
= jump_to_int(url
);
560 if (!url_str
.empty()) {
563 _url_history
.push(url_str
);
570 void ChildWindow::set_url(LPCTSTR url
)
575 SendMessage(_hwndFrame
, PM_URL_CHANGED
, 0, (LPARAM
)url
);
580 WindowSet
Window::s_pretranslate_windows
;
582 void Window::register_pretranslate(HWND hwnd
)
584 s_pretranslate_windows
.insert(hwnd
);
587 void Window::unregister_pretranslate(HWND hwnd
)
589 s_pretranslate_windows
.erase(hwnd
);
592 BOOL
Window::pretranslate_msg(LPMSG pmsg
)
594 for(WindowSet::const_iterator it
=Window::s_pretranslate_windows
.begin(); it
!=s_pretranslate_windows
.end(); ++it
)
595 if (SendMessage(*it
, PM_TRANSLATE_MSG
, 0, (LPARAM
)pmsg
))
602 WindowSet
Window::s_dialogs
;
604 void Window::register_dialog(HWND hwnd
)
606 s_dialogs
.insert(hwnd
);
609 void Window::unregister_dialog(HWND hwnd
)
611 s_dialogs
.erase(hwnd
);
614 BOOL
Window::dispatch_dialog_msg(MSG
* pmsg
)
616 for(WindowSet::const_iterator it
=Window::s_dialogs
.begin(); it
!=s_dialogs
.end(); ++it
)
617 if (IsDialogMessage(*it
, pmsg
))
624 int Window::MessageLoop()
628 while(GetMessage(&msg
, 0, 0, 0)) {
630 if (pretranslate_msg(&msg
))
633 if (dispatch_dialog_msg(&msg
))
636 TranslateMessage(&msg
);
639 DispatchMessage(&msg
);
640 } catch(COMException
& e
) {
641 HandleException(e
, 0);
643 } catch(COMException
& e
) {
644 HandleException(e
, 0);
652 LRESULT
Window::SendParent(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
654 HWND parent
= GetParent(_hwnd
);
659 return SendMessage(parent
, nmsg
, wparam
, lparam
);
662 LRESULT
Window::PostParent(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
664 HWND parent
= GetParent(_hwnd
);
669 return PostMessage(parent
, nmsg
, wparam
, lparam
);
673 PreTranslateWindow::PreTranslateWindow(HWND hwnd
)
676 register_pretranslate(hwnd
);
679 PreTranslateWindow::~PreTranslateWindow()
681 unregister_pretranslate(_hwnd
);
685 Dialog::Dialog(HWND hwnd
)
688 register_dialog(hwnd
);
693 unregister_dialog(_hwnd
);
696 int Dialog::DoModal(UINT nid
, CREATORFUNC creator
, HWND hwndParent
)
698 Lock
lock(GetStaticWindowData()._create_crit_sect
); // protect access to s_window_creator and s_new_info
700 s_window_creator
= creator
;
703 ///@todo call Window::pretranslate_msg()
705 return DialogBoxParam(g_Globals
._hInstance
, MAKEINTRESOURCE(nid
), hwndParent
, DialogProc
, 0/*lpParam*/);
708 int Dialog::DoModal(UINT nid
, CREATORFUNC_INFO creator
, const void* info
, HWND hwndParent
)
710 Lock
lock(GetStaticWindowData()._create_crit_sect
); // protect access to s_window_creator and s_new_info
712 s_window_creator
= (CREATORFUNC
) creator
;
715 ///@todo call Window::pretranslate_msg()
717 return DialogBoxParam(g_Globals
._hInstance
, MAKEINTRESOURCE(nid
), hwndParent
, DialogProc
, 0/*lpParam*/);
720 INT_PTR CALLBACK
Window::DialogProc(HWND hwnd
, UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
722 Window
* pThis
= get_window(hwnd
);
727 pThis
->Command(LOWORD(wparam
), HIWORD(wparam
));
728 return TRUE
; // message has been processed
731 pThis
->Notify(wparam
, (NMHDR
*)lparam
);
732 return TRUE
; // message has been processed
734 case WM_NOTIFYFORMAT
:
735 SetWindowLongPtr(hwnd
, DWLP_MSGRESULT
, NFR_CURRENT
); // set return value NFR_CURRENT
736 return TRUE
; // message has been processed
740 return TRUE
; // message has been processed
743 return pThis
->WndProc(nmsg
, wparam
, lparam
);
745 } else if (nmsg
== WM_INITDIALOG
) {
746 pThis
= create_controller(hwnd
);
749 return pThis
->Init(NULL
);
752 return FALSE
; // message has not been processed
755 LRESULT
Dialog::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
757 return FALSE
; // message has not been processed
760 int Dialog::Command(int id
, int code
)
762 if (code
== BN_CLICKED
) {
763 EndDialog(_hwnd
, id
);
764 return 0; // message has been processed
771 ResizeManager::ResizeManager(HWND hwnd
)
774 ClientRect
clnt(hwnd
);
775 _last_size
.cx
= clnt
.right
;
776 _last_size
.cy
= clnt
.bottom
;
778 WindowRect
rect(hwnd
);
779 _min_wnd_size
.cx
= rect
.right
- rect
.left
;
780 _min_wnd_size
.cy
= rect
.bottom
- rect
.top
;
783 void ResizeManager::HandleSize(int cx
, int cy
)
785 ClientRect
clnt_rect(_hwnd
);
786 SIZE new_size
= {cx
, cy
};
788 int dx
= new_size
.cx
- _last_size
.cx
;
789 int dy
= new_size
.cy
- _last_size
.cy
;
794 _last_size
= new_size
;
796 HDWP hDWP
= BeginDeferWindowPos(size());
798 for(ResizeManager::const_iterator it
=begin(); it
!=end(); ++it
) {
799 const ResizeEntry
& e
= *it
;
802 if (e
._flags
& MOVE_LEFT
)
805 if (e
._flags
& MOVE_RIGHT
)
808 if (e
._flags
& MOVE_TOP
)
811 if (e
._flags
& MOVE_BOTTOM
)
816 if (!move
.left
&& !move
.top
)
819 if (move
.right
==move
.left
&& move
.bottom
==move
.top
)
822 if (flags
!= (SWP_NOMOVE
|SWP_NOSIZE
)) {
823 HWND hwnd
= GetDlgItem(_hwnd
, e
._id
);
826 WindowRect
rect(hwnd
);
827 ScreenToClient(_hwnd
, rect
);
829 rect
.left
+= move
.left
;
830 rect
.right
+= move
.right
;
831 rect
.top
+= move
.top
;
832 rect
.bottom
+= move
.bottom
;
834 hDWP
= DeferWindowPos(hDWP
, hwnd
, 0, rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
, flags
|SWP_NOACTIVATE
|SWP_NOZORDER
);
839 EndDeferWindowPos(hDWP
);
842 void ResizeManager::Resize(int dx
, int dy
)
844 ::SetWindowPos(_hwnd
, 0, 0, 0, _min_wnd_size
.cx
+dx
, _min_wnd_size
.cy
+dy
, SWP_NOMOVE
|SWP_NOACTIVATE
);
847 ClientRect
clnt_rect(_hwnd
);
848 HandleSize(clnt_rect
.right
, clnt_rect
.bottom
);
852 Button::Button(HWND parent
, LPCTSTR title
, int left
, int top
, int width
, int height
,
853 int id
, DWORD flags
, DWORD exStyle
)
854 : WindowHandle(CreateWindowEx(exStyle
, TEXT("BUTTON"), title
, flags
, left
, top
, width
, height
,
855 parent
, (HMENU
)id
, g_Globals
._hInstance
, 0))
860 LRESULT
OwnerdrawnButton::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
862 if (nmsg
== PM_DISPATCH_DRAWITEM
) {
863 DrawItem((LPDRAWITEMSTRUCT
)lparam
);
866 return super::WndProc(nmsg
, wparam
, lparam
);
870 Static::Static(HWND parent
, LPCTSTR title
, int left
, int top
, int width
, int height
,
871 int id
, DWORD flags
, DWORD exStyle
)
872 : WindowHandle(CreateWindowEx(exStyle
, TEXT("STATIC"), title
, flags
, left
, top
, width
, height
,
873 parent
, (HMENU
)id
, g_Globals
._hInstance
, 0))
878 static RECT s_MyDrawText_Rect
= {0, 0, 0, 0};
880 static BOOL CALLBACK
MyDrawText(HDC hdc
, LPARAM data
, int cnt
)
882 ::DrawText(hdc
, (LPCTSTR
)data
, cnt
, &s_MyDrawText_Rect
, DT_SINGLELINE
);
886 void DrawGrayText(HDC hdc
, LPRECT pRect
, LPCTSTR title
, int dt_flags
)
888 COLORREF gray
= GetSysColor(COLOR_GRAYTEXT
);
891 TextColor
lcColor(hdc
, GetSysColor(COLOR_BTNHIGHLIGHT
));
892 RECT shadowRect
= {pRect
->left
+1, pRect
->top
+1, pRect
->right
+1, pRect
->bottom
+1};
893 DrawText(hdc
, title
, -1, &shadowRect
, dt_flags
);
895 SetTextColor(hdc
, gray
);
896 DrawText(hdc
, title
, -1, pRect
, dt_flags
);
898 int old_r
= pRect
->right
;
899 int old_b
= pRect
->bottom
;
901 DrawText(hdc
, title
, -1, pRect
, dt_flags
|DT_CALCRECT
);
903 int x
= pRect
->left
+ (old_r
-pRect
->right
)/2;
904 int y
= pRect
->top
+ (old_b
-pRect
->bottom
)/2;
905 int w
= pRect
->right
-pRect
->left
;
906 int h
= pRect
->bottom
-pRect
->top
;
907 s_MyDrawText_Rect
.right
= w
;
908 s_MyDrawText_Rect
.bottom
= h
;
910 GrayString(hdc
, GetSysColorBrush(COLOR_GRAYTEXT
), MyDrawText
, (LPARAM
)title
, -1, x
, y
, w
, h
);
916 void ColorButton::DrawItem(LPDRAWITEMSTRUCT dis)
918 UINT state = DFCS_BUTTONPUSH;
920 if (dis->itemState & ODS_DISABLED)
921 state |= DFCS_INACTIVE;
923 RECT textRect = {dis->rcItem.left+2, dis->rcItem.top+2, dis->rcItem.right-4, dis->rcItem.bottom-4};
925 if (dis->itemState & ODS_SELECTED) {
926 state |= DFCS_PUSHED;
927 ++textRect.left; ++textRect.top;
928 ++textRect.right; ++textRect.bottom;
931 DrawFrameControl(dis->hDC, &dis->rcItem, DFC_BUTTON, state);
933 TCHAR title[BUFFER_LEN];
934 GetWindowText(_hwnd, title, BUFFER_LEN);
936 BkMode bk_mode(dis->hDC, TRANSPARENT);
938 if (dis->itemState & (ODS_DISABLED|ODS_GRAYED))
939 DrawGrayText(dis, &textRect, title, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
941 TextColor lcColor(dis->hDC, _textColor);
942 DrawText(dis->hDC, title, -1, &textRect, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
945 if (dis->itemState & ODS_FOCUS) {
947 dis->rcItem.left+3, dis->rcItem.top+3,
948 dis->rcItem.right-dis->rcItem.left-4, dis->rcItem.bottom-dis->rcItem.top-4
950 if (dis->itemState & ODS_SELECTED) {
951 ++rect.left; ++rect.top;
952 ++rect.right; ++rect.bottom;
954 DrawFocusRect(dis->hDC, &rect);
960 void PictureButton::DrawItem(LPDRAWITEMSTRUCT dis
)
962 UINT state
= DFCS_BUTTONPUSH
;
963 int style
= GetWindowStyle(_hwnd
);
965 if (dis
->itemState
& ODS_DISABLED
)
966 state
|= DFCS_INACTIVE
;
972 if (style
& BS_BOTTOM
) {
973 // align horizontal centered, vertical floating
974 imagePos
.x
= (dis
->rcItem
.left
+ dis
->rcItem
.right
- _cx
) / 2;
975 imagePos
.y
= dis
->rcItem
.top
+ 3;
977 textRect
.left
= dis
->rcItem
.left
+ 2;
978 textRect
.top
= dis
->rcItem
.top
+ _cy
+ 4;
979 textRect
.right
= dis
->rcItem
.right
- 4;
980 textRect
.bottom
= dis
->rcItem
.bottom
- 4;
982 dt_flags
= DT_SINGLELINE
|DT_CENTER
|DT_VCENTER
;
984 // horizontal floating, vertical centered
985 imagePos
.x
= dis
->rcItem
.left
+ 3;
986 imagePos
.y
= (dis
->rcItem
.top
+ dis
->rcItem
.bottom
- _cy
)/2;
988 textRect
.left
= dis
->rcItem
.left
+ _cx
+ 4;
989 textRect
.top
= dis
->rcItem
.top
+ 2;
990 textRect
.right
= dis
->rcItem
.right
- 4;
991 textRect
.bottom
= dis
->rcItem
.bottom
- 4;
993 dt_flags
= DT_SINGLELINE
|DT_VCENTER
/*|DT_CENTER*/;
996 if (dis
->itemState
& ODS_SELECTED
) {
997 state
|= DFCS_PUSHED
;
998 ++imagePos
.x
; ++imagePos
.y
;
999 ++textRect
.left
; ++textRect
.top
;
1000 ++textRect
.right
; ++textRect
.bottom
;
1004 FillRect(dis
->hDC
, &dis
->rcItem
, _hBrush
);
1006 if (style
& BS_FLAT
) // Only with BS_FLAT set, there will be drawn a frame without highlight.
1007 DrawEdge(dis
->hDC
, &dis
->rcItem
, EDGE_RAISED
, BF_RECT
|BF_FLAT
);
1009 DrawFrameControl(dis
->hDC
, &dis
->rcItem
, DFC_BUTTON
, state
);
1012 DrawIconEx(dis
->hDC
, imagePos
.x
, imagePos
.y
, _hIcon
, _cx
, _cy
, 0, _hBrush
, DI_NORMAL
);
1015 BitmapSelection
sel(mem_dc
, _hBmp
);
1016 BitBlt(dis
->hDC
, imagePos
.x
, imagePos
.y
, _cx
, _cy
, mem_dc
, 0, 0, SRCCOPY
);
1019 TCHAR title
[BUFFER_LEN
];
1020 GetWindowText(_hwnd
, title
, BUFFER_LEN
);
1022 BkMode
bk_mode(dis
->hDC
, TRANSPARENT
);
1024 if (dis
->itemState
& (ODS_DISABLED
|ODS_GRAYED
))
1025 DrawGrayText(dis
->hDC
, &textRect
, title
, dt_flags
);
1027 TextColor
lcColor(dis
->hDC
, GetSysColor(COLOR_BTNTEXT
));
1028 DrawText(dis
->hDC
, title
, -1, &textRect
, dt_flags
);
1031 if (dis
->itemState
& ODS_FOCUS
) {
1033 dis
->rcItem
.left
+3, dis
->rcItem
.top
+3,
1034 dis
->rcItem
.right
-dis
->rcItem
.left
-4, dis
->rcItem
.bottom
-dis
->rcItem
.top
-4
1036 if (dis
->itemState
& ODS_SELECTED
) {
1037 ++rect
.left
; ++rect
.top
;
1038 ++rect
.right
; ++rect
.bottom
;
1040 DrawFocusRect(dis
->hDC
, &rect
);
1045 void FlatButton::DrawItem(LPDRAWITEMSTRUCT dis
)
1047 UINT style
= DFCS_BUTTONPUSH
;
1049 if (dis
->itemState
& ODS_DISABLED
)
1050 style
|= DFCS_INACTIVE
;
1052 RECT textRect
= {dis
->rcItem
.left
+2, dis
->rcItem
.top
+2, dis
->rcItem
.right
-4, dis
->rcItem
.bottom
-4};
1054 if (dis
->itemState
& ODS_SELECTED
) {
1055 style
|= DFCS_PUSHED
;
1056 ++textRect
.left
; ++textRect
.top
;
1057 ++textRect
.right
; ++textRect
.bottom
;
1060 FillRect(dis
->hDC
, &dis
->rcItem
, GetSysColorBrush(COLOR_BTNFACE
));
1062 // highlight the button?
1064 DrawEdge(dis
->hDC
, &dis
->rcItem
, EDGE_ETCHED
, BF_RECT
);
1065 else if (GetWindowStyle(_hwnd
) & BS_FLAT
) // Only with BS_FLAT there will be drawn a frame to show highlighting.
1066 DrawEdge(dis
->hDC
, &dis
->rcItem
, EDGE_RAISED
, BF_RECT
|BF_FLAT
);
1068 TCHAR txt
[BUFFER_LEN
];
1069 int txt_len
= GetWindowText(_hwnd
, txt
, BUFFER_LEN
);
1071 if (dis
->itemState
& (ODS_DISABLED
|ODS_GRAYED
)) {
1072 COLORREF gray
= GetSysColor(COLOR_GRAYTEXT
);
1076 TextColor
lcColor(dis
->hDC
, GetSysColor(COLOR_BTNHIGHLIGHT
));
1077 RECT shadowRect
= {textRect
.left
+1, textRect
.top
+1, textRect
.right
+1, textRect
.bottom
+1};
1078 DrawText(dis
->hDC
, txt
, txt_len
, &shadowRect
, DT_SINGLELINE
|DT_VCENTER
|DT_CENTER
);
1081 BkMode
mode(dis
->hDC
, TRANSPARENT
);
1082 TextColor
lcColor(dis
->hDC
, gray
);
1083 DrawText(dis
->hDC
, txt
, txt_len
, &textRect
, DT_SINGLELINE
|DT_VCENTER
|DT_CENTER
);
1085 int old_r
= textRect
.right
;
1086 int old_b
= textRect
.bottom
;
1087 DrawText(dis
->hDC
, txt
, txt_len
, &textRect
, DT_SINGLELINE
|DT_VCENTER
|DT_CENTER
|DT_CALCRECT
);
1088 int x
= textRect
.left
+ (old_r
-textRect
.right
)/2;
1089 int y
= textRect
.top
+ (old_b
-textRect
.bottom
)/2;
1090 int w
= textRect
.right
-textRect
.left
;
1091 int h
= textRect
.bottom
-textRect
.top
;
1092 s_MyDrawText_Rect
.right
= w
;
1093 s_MyDrawText_Rect
.bottom
= h
;
1094 GrayString(dis
->hDC
, GetSysColorBrush(COLOR_GRAYTEXT
), MyDrawText
, (LPARAM
)txt
, txt_len
, x
, y
, w
, h
);
1097 TextColor
lcColor(dis
->hDC
, _active
? _activeColor
: _textColor
);
1098 DrawText(dis
->hDC
, txt
, txt_len
, &textRect
, DT_SINGLELINE
|DT_VCENTER
|DT_CENTER
);
1101 if (dis
->itemState
& ODS_FOCUS
) {
1103 dis
->rcItem
.left
+3, dis
->rcItem
.top
+3,
1104 dis
->rcItem
.right
-dis
->rcItem
.left
-4, dis
->rcItem
.bottom
-dis
->rcItem
.top
-4
1106 if (dis
->itemState
& ODS_SELECTED
) {
1107 ++rect
.left
; ++rect
.top
;
1108 ++rect
.right
; ++rect
.bottom
;
1110 DrawFocusRect(dis
->hDC
, &rect
);
1114 LRESULT
FlatButton::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
1117 case WM_MOUSEMOVE
: {
1118 bool active
= false;
1120 if (IsWindowEnabled(_hwnd
)) {
1121 DWORD pid_foreground
;
1122 HWND hwnd_foreground
= GetForegroundWindow(); //@@ may be better look for WM_ACTIVATEAPP ?
1123 GetWindowThreadProcessId(hwnd_foreground
, &pid_foreground
);
1125 if (GetCurrentProcessId() == pid_foreground
) {
1126 POINT pt
= {GET_X_LPARAM(lparam
), GET_Y_LPARAM(lparam
)};
1127 ClientRect
clntRect(_hwnd
);
1129 // highlight the button?
1130 if (pt
.x
>=clntRect
.left
&& pt
.x
<clntRect
.right
&& pt
.y
>=clntRect
.top
&& pt
.y
<clntRect
.bottom
)
1135 if (active
!= _active
) {
1139 TRACKMOUSEEVENT tme
= {sizeof(tme
), /*TME_HOVER|*/TME_LEAVE
, _hwnd
/*, HOVER_DEFAULT*/};
1140 _TrackMouseEvent(&tme
);
1143 InvalidateRect(_hwnd
, NULL
, TRUE
);
1148 case WM_LBUTTONUP
: {
1149 POINT pt
= {GET_X_LPARAM(lparam
), GET_Y_LPARAM(lparam
)};
1150 ClientRect
clntRect(_hwnd
);
1152 // no more in the active rectangle?
1153 if (pt
.x
<clntRect
.left
|| pt
.x
>=clntRect
.right
|| pt
.y
<clntRect
.top
|| pt
.y
>=clntRect
.bottom
)
1160 TRACKMOUSEEVENT tme
= {sizeof(tme
), /*TME_HOVER|*/TME_LEAVE
|TME_CANCEL
, _hwnd
/*, HOVER_DEFAULT*/};
1161 _TrackMouseEvent(&tme
);
1170 InvalidateRect(_hwnd
, NULL
, TRUE
);
1176 return super::WndProc(nmsg
, wparam
, lparam
);
1181 HyperlinkCtrl::HyperlinkCtrl(HWND hwnd
, COLORREF colorLink
, COLORREF colorVisited
)
1183 _cmd(ResString(GetDlgCtrlID(hwnd
))),
1184 _textColor(colorLink
),
1185 _colorVisited(colorVisited
),
1192 HyperlinkCtrl::HyperlinkCtrl(HWND owner
, int id
, COLORREF colorLink
, COLORREF colorVisited
)
1193 : super(GetDlgItem(owner
, id
)),
1194 _cmd(ResString(id
)),
1195 _textColor(colorLink
),
1196 _colorVisited(colorVisited
),
1203 void HyperlinkCtrl::init()
1206 TCHAR txt
[BUFFER_LEN
];
1207 _cmd
.assign(txt
, GetWindowText(_hwnd
, txt
, BUFFER_LEN
));
1211 HyperlinkCtrl::~HyperlinkCtrl()
1214 DeleteObject(_hfont
);
1217 LRESULT
HyperlinkCtrl::WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
1220 case PM_DISPATCH_CTLCOLOR
: {
1222 HFONT hfont
= (HFONT
) SendMessage(_hwnd
, WM_GETFONT
, 0, 0);
1223 LOGFONT lf
; GetObject(hfont
, sizeof(lf
), &lf
);
1224 lf
.lfUnderline
= TRUE
;
1225 _hfont
= CreateFontIndirect(&lf
);
1228 HDC hdc
= (HDC
) wparam
;
1229 SetTextColor(hdc
, _textColor
); //@@
1230 SelectFont(hdc
, _hfont
);
1231 SetBkMode(hdc
, TRANSPARENT
);
1232 return (LRESULT
)GetStockObject(HOLLOW_BRUSH
);
1237 _crsr_link
= LoadCursor(0, IDC_HAND
);
1240 SetCursor(_crsr_link
);
1244 return HTCLIENT
; // Aktivierung von Maus-Botschaften
1246 case WM_LBUTTONDOWN
:
1248 _textColor
= _colorVisited
;
1249 InvalidateRect(_hwnd
, NULL
, FALSE
);
1255 return super::WndProc(nmsg
, wparam
, lparam
);
1260 ToolTip::ToolTip(HWND owner
)
1261 : super(CreateWindowEx(WS_EX_TOPMOST
|WS_EX_NOPARENTNOTIFY
, TOOLTIPS_CLASS
, 0,
1262 WS_POPUP
|TTS_NOPREFIX
|TTS_ALWAYSTIP
, CW_USEDEFAULT
,CW_USEDEFAULT
,CW_USEDEFAULT
,CW_USEDEFAULT
,
1263 owner
, 0, g_Globals
._hInstance
, 0))
1269 ListSort::ListSort(HWND hwndListview
, PFNLVCOMPARE compare_fct
)
1270 : WindowHandle(hwndListview
),
1271 _compare_fct(compare_fct
)
1277 void ListSort::toggle_sort(int idx
)
1279 if (_sort_crit
== idx
)
1280 _direction
= !_direction
;
1287 void ListSort::sort()
1289 int idx
= ListView_GetSelectionMark(_hwnd
);
1290 LPARAM param
= ListView_GetItemData(_hwnd
, idx
);
1292 ListView_SortItems(_hwnd
, _compare_fct
, (LPARAM
)this);
1295 idx
= ListView_FindItemPara(_hwnd
, param
);
1296 ListView_EnsureVisible(_hwnd
, idx
, FALSE
);
1301 PropSheetPage::PropSheetPage(UINT nid
, Window::CREATORFUNC dlg_creator
)
1302 : _dlg_creator(dlg_creator
)
1304 PROPSHEETPAGE::dwSize
= sizeof(PROPSHEETPAGE
);
1305 PROPSHEETPAGE::dwFlags
= 0;
1306 PROPSHEETPAGE::hInstance
= g_Globals
._hInstance
;
1307 PROPSHEETPAGE::pszTemplate
= MAKEINTRESOURCE(nid
);
1308 PROPSHEETPAGE::pfnDlgProc
= PropSheetPageDlg::DialogProc
;
1309 PROPSHEETPAGE::lParam
= (LPARAM
) this;
1313 #ifndef PSM_GETRESULT // currently (as of 18.01.2004) missing in MinGW headers
1314 #define PSM_GETRESULT (WM_USER + 135)
1315 #define PropSheet_GetResult(hDlg) SNDMSG(hDlg, PSM_GETRESULT, 0, 0)
1319 PropertySheetDialog::PropertySheetDialog(HWND owner
)
1322 PROPSHEETHEADER::dwSize
= sizeof(PROPSHEETHEADER
);
1323 PROPSHEETHEADER::dwFlags
= PSH_PROPSHEETPAGE
| PSH_MODELESS
;
1324 PROPSHEETHEADER::hwndParent
= owner
;
1325 PROPSHEETHEADER::hInstance
= g_Globals
._hInstance
;
1328 void PropertySheetDialog::add(PropSheetPage
& psp
)
1330 _pages
.push_back(psp
);
1333 int PropertySheetDialog::DoModal(int start_page
)
1335 PROPSHEETHEADER::ppsp
= (LPCPROPSHEETPAGE
) &_pages
[0];
1336 PROPSHEETHEADER::nPages
= _pages
.size();
1337 PROPSHEETHEADER::nStartPage
= start_page
;
1339 Window* pwnd = Window::create_property_sheet(this, WINDOW_CREATOR(PropertySheetDlg), NULL);
1343 HWND hwndPropSheet = *pwnd;
1345 int ret
= PropertySheet(this);
1349 HWND hwndPropSheet
= (HWND
) ret
;
1350 HWND hwndparent
= GetParent(hwndPropSheet
);
1353 EnableWindow(hwndparent
, FALSE
);
1358 while(GetMessage(&msg
, 0, 0, 0)) {
1360 if (Window::pretranslate_msg(&msg
))
1363 if (PropSheet_IsDialogMessage(hwndPropSheet
, &msg
))
1366 if (Window::dispatch_dialog_msg(&msg
))
1369 TranslateMessage(&msg
);
1372 DispatchMessage(&msg
);
1373 } catch(COMException
& e
) {
1374 HandleException(e
, 0);
1377 if (!PropSheet_GetCurrentPageHwnd(hwndPropSheet
)) {
1378 ret
= PropSheet_GetResult(hwndPropSheet
);
1381 } catch(COMException
& e
) {
1382 HandleException(e
, 0);
1387 EnableWindow(hwndparent
, TRUE
);
1389 DestroyWindow(hwndPropSheet
);
1394 HWND
PropertySheetDialog::GetCurrentPage()
1396 HWND hdlg
= PropSheet_GetCurrentPageHwnd(_hwnd
);
1401 PropSheetPageDlg::PropSheetPageDlg(HWND hwnd
)
1406 INT_PTR CALLBACK
PropSheetPageDlg::DialogProc(HWND hwnd
, UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
1408 PropSheetPageDlg
* pThis
= GET_WINDOW(PropSheetPageDlg
, hwnd
);
1413 pThis
->Command(LOWORD(wparam
), HIWORD(wparam
));
1414 return TRUE
; // message has been processed
1417 pThis
->Notify(wparam
, (NMHDR
*)lparam
);
1418 return TRUE
; // message has been processed
1420 case WM_NOTIFYFORMAT
:
1421 SetWindowLongPtr(hwnd
, DWLP_MSGRESULT
, NFR_CURRENT
); // set return value NFR_CURRENT
1422 return TRUE
; // message has been processed
1426 return TRUE
; // message has been processed
1429 return pThis
->WndProc(nmsg
, wparam
, lparam
);
1431 } else if (nmsg
== WM_INITDIALOG
) {
1432 PROPSHEETPAGE
* psp
= (PROPSHEETPAGE
*) lparam
;
1433 PropSheetPage
* ppsp
= (PropSheetPage
*) psp
->lParam
;
1435 if (ppsp
->_dlg_creator
) {
1436 pThis
= static_cast<PropSheetPageDlg
*>(ppsp
->_dlg_creator(hwnd
));
1439 return pThis
->Init(NULL
);
1443 return FALSE
; // message has not been processed
1446 int PropSheetPageDlg::Command(int id
, int code
)
1448 // override call to EndDialog in Dialog::Command();