1 /*
2  * Copyright 2003, 2004, 2005 Martin Fuchs
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 
19 
20  //
21  // Explorer clone
22  //
23  // window.cpp
24  //
25  // Martin Fuchs, 23.07.2003
26  //
27 
28 
29 #include <precomp.h>
30 
WindowClass(LPCTSTR classname,UINT style_,WNDPROC wndproc)31 WindowClass::WindowClass(LPCTSTR classname, UINT style_, WNDPROC wndproc)
32 {
33 	memset(this, 0, sizeof(WNDCLASSEX));
34 
35 	cbSize = sizeof(WNDCLASSEX);
36 	style = style_;
37 	hInstance = g_Globals._hInstance;
38 	hCursor = LoadCursor(0, IDC_ARROW);
39 	this->hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
40 	lpszClassName = classname;
41 	lpfnWndProc = wndproc;
42 
43 	_atomClass = 0;
44 }
45 
46 
IconWindowClass(LPCTSTR classname,UINT nid,UINT style,WNDPROC wndproc)47 IconWindowClass::IconWindowClass(LPCTSTR classname, UINT nid, UINT style, WNDPROC wndproc)
48  :	WindowClass(classname, style, wndproc)
49 {
50 	hIcon = ResIcon(nid);
51 	hIconSm = SmallIcon(nid);
52 }
53 
54 
55 Window::WindowMap	Window::s_wnd_map;
56 
57 Window::CREATORFUNC	Window::s_window_creator = NULL;
58 const void*			Window::s_new_info = NULL;
59 
60 HHOOK				Window::s_hcbtHook = 0;
61 
62 
GetStaticWindowData()63 Window::StaticWindowData& Window::GetStaticWindowData()
64 {
65 	static StaticWindowData s_initialized_data;
66 
67 	return s_initialized_data;
68 }
69 
70 
Window(HWND hwnd)71 Window::Window(HWND hwnd)
72  :	WindowHandle(hwnd)
73 {
74 	Lock lock(GetStaticWindowData()._map_crit_sect);	// protect access to s_wnd_map
75 
76 	s_wnd_map[_hwnd] = this;
77 }
78 
~Window()79 Window::~Window()
80 {
81 	Lock lock(GetStaticWindowData()._map_crit_sect);	// protect access to s_wnd_map
82 
83 	s_wnd_map.erase(_hwnd);
84 }
85 
86 
Create(CREATORFUNC creator,DWORD dwExStyle,LPCTSTR lpClassName,LPCTSTR lpWindowName,DWORD dwStyle,int x,int y,int w,int h,HWND hwndParent,HMENU hMenu)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*/)
91 {
92 	Lock lock(GetStaticWindowData()._create_crit_sect);	// protect access to s_window_creator and s_new_info
93 
94 	s_window_creator = creator;
95 	s_new_info = NULL;
96 
97 	return CreateWindowEx(dwExStyle, lpClassName, lpWindowName, dwStyle,
98 							x, y, w, h,
99 							hwndParent, hMenu, g_Globals._hInstance, 0/*lpParam*/);
100 }
101 
Create(CREATORFUNC_INFO creator,const void * info,DWORD dwExStyle,LPCTSTR lpClassName,LPCTSTR lpWindowName,DWORD dwStyle,int x,int y,int w,int h,HWND hwndParent,HMENU hMenu)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*/)
106 {
107 	Lock lock(GetStaticWindowData()._create_crit_sect);	// protect access to s_window_creator and s_new_info
108 
109 	s_window_creator = (CREATORFUNC) creator;
110 	s_new_info = info;
111 
112 	return CreateWindowEx(dwExStyle, lpClassName, lpWindowName, dwStyle,
113 							x, y, w, h,
114 							hwndParent, hMenu, g_Globals._hInstance, 0/*lpParam*/);
115 }
116 
117 
create_mdi_child(const ChildWndInfo & info,const MDICREATESTRUCT & mcs,CREATORFUNC_INFO creator)118 Window* Window::create_mdi_child(const ChildWndInfo& info, const MDICREATESTRUCT& mcs, CREATORFUNC_INFO creator)
119 {
120 	Lock lock(GetStaticWindowData()._create_crit_sect);	// protect access to s_window_creator and s_new_info
121 
122 	s_window_creator = (CREATORFUNC) creator;
123 	s_new_info = &info;
124 
125 	s_hcbtHook = SetWindowsHookEx(WH_CBT, MDICBTHookProc, 0, GetCurrentThreadId());
126 
127 	HWND hwnd = (HWND) SendMessage(info._hmdiclient, WM_MDICREATE, 0, (LPARAM)&mcs);
128 
129 	 // end hook in case it's not already done
130 	if (s_hcbtHook)
131 		UnhookWindowsHookEx(s_hcbtHook);
132 
133 	Window* child = get_window(hwnd);
134 	s_new_info = NULL;
135 
136 	if (child && (!hwnd || !child->_hwnd))
137 		child = NULL;
138 
139 	return child;
140 }
141 
MDICBTHookProc(int code,WPARAM wparam,LPARAM lparam)142 LRESULT CALLBACK Window::MDICBTHookProc(int code, WPARAM wparam, LPARAM lparam)
143 {
144 	if (code == HCBT_CREATEWND) {
145 		UnhookWindowsHookEx(s_hcbtHook);	// use the hook only for the first created window
146 		s_hcbtHook = 0;
147 
148 		HWND hwnd = (HWND)wparam;
149 
150 		 // create Window controller and associate it with the window handle
151 		Window* child = get_window(hwnd);
152 
153 		if (!child)
154 			child = create_controller(hwnd);
155 	}
156 
157 	return CallNextHookEx(s_hcbtHook, code, wparam, lparam);
158 }
159 
160 
161 /*
162 Window* Window::create_property_sheet(PropertySheetDialog* ppsd, CREATORFUNC creator, const void* info)
163 {
164 	Lock lock(GetStaticWindowData()._create_crit_sect);	// protect access to s_window_creator and s_new_info
165 
166 	s_window_creator = creator;
167 	s_new_info = info;
168 
169 	s_hcbtHook = SetWindowsHookEx(WH_CBT, PropSheetCBTHookProc, 0, GetCurrentThreadId());
170 
171 	HWND hwnd = (HWND) PropertySheet(ppsd);
172 
173 	UnhookWindowsHookEx(s_hcbtHook);
174 
175 	Window* child = get_window(hwnd);
176 	s_new_info = NULL;
177 
178 	if (child && (!hwnd || !child->_hwnd))
179 		child = NULL;
180 
181 	return child;
182 }
183 */
184 
PropSheetCBTHookProc(int code,WPARAM wparam,LPARAM lparam)185 LRESULT CALLBACK Window::PropSheetCBTHookProc(int code, WPARAM wparam, LPARAM lparam)
186 {
187 	if (code == HCBT_CREATEWND) {
188 		HWND hwnd = (HWND)wparam;
189 
190 		 // create Window controller and associate it with the window handle
191 		Window* child = get_window(hwnd);
192 
193 		if (!child)
194 			child = create_controller(hwnd);
195 	}
196 
197 	return CallNextHookEx(s_hcbtHook, code, wparam, lparam);
198 }
199 
200 
201  /// get window controller from window handle
202 
get_window(HWND hwnd)203 Window* Window::get_window(HWND hwnd)
204 {
205 	{
206 		Lock lock(GetStaticWindowData()._map_crit_sect);	// protect access to s_wnd_map
207 
208 		WindowMap::const_iterator found = s_wnd_map.find(hwnd);
209 
210 		if (found!=s_wnd_map.end())
211 			return found->second;
212 	}
213 
214 	return NULL;
215 }
216 
217 
218  /// create controller for a new window
219 
create_controller(HWND hwnd)220 Window* Window::create_controller(HWND hwnd)
221 {
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
224 
225 		const void* info = s_new_info;
226 		s_new_info = NULL;
227 
228 		CREATORFUNC window_creator = s_window_creator;
229 		s_window_creator = NULL;
230 
231 		if (info)
232 			return CREATORFUNC_INFO(window_creator)(hwnd, info);
233 		else
234 			return CREATORFUNC(window_creator)(hwnd);
235 	}
236 
237 	return NULL;
238 }
239 
240 
Init(LPCREATESTRUCT pcs)241 LRESULT Window::Init(LPCREATESTRUCT pcs)
242 {
243 	return 0;
244 }
245 
246 
WindowWndProc(HWND hwnd,UINT nmsg,WPARAM wparam,LPARAM lparam)247 LRESULT CALLBACK Window::WindowWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
248 {
249 	Window* pThis = get_window(hwnd);
250 
251 	if (!pThis)
252 		pThis = create_controller(hwnd);
253 
254 	if (pThis) {
255 		switch(nmsg) {
256 		  case WM_COMMAND:
257 			return pThis->Command(LOWORD(wparam), HIWORD(wparam));
258 
259 		  case WM_NOTIFY:
260 			return pThis->Notify(wparam, (NMHDR*)lparam);
261 
262 		  case WM_NOTIFYFORMAT:
263 			return NFR_CURRENT;
264 
265 		  case WM_CREATE:
266 			return pThis->Init((LPCREATESTRUCT)lparam);
267 
268 		  case WM_NCDESTROY:
269 			delete pThis;
270 			return 0;
271 
272 		  default:
273 			return pThis->WndProc(nmsg, wparam, lparam);
274 		}
275 	}
276 	else
277 		return DefWindowProc(hwnd, nmsg, wparam, lparam);
278 }
279 
WndProc(UINT nmsg,WPARAM wparam,LPARAM lparam)280 LRESULT Window::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
281 {
282 	return DefWindowProc(_hwnd, nmsg, wparam, lparam);
283 }
284 
Command(int id,int code)285 int Window::Command(int id, int code)
286 {
287 	return 1;	// no command handler found
288 }
289 
Notify(int id,NMHDR * pnmh)290 int Window::Notify(int id, NMHDR* pnmh)
291 {
292 	return 0;
293 }
294 
CancelModes()295 void Window::CancelModes()
296 {
297 	PostMessage(HWND_BROADCAST, WM_CANCELMODE, 0, 0);
298 }
299 
300 
SubclassedWindow(HWND hwnd)301 SubclassedWindow::SubclassedWindow(HWND hwnd)
302  :	super(hwnd)
303 {
304 	_orgWndProc = SubclassWindow(_hwnd, SubclassedWndProc);
305 
306 	if (!_orgWndProc)
307 		delete this;
308 }
309 
SubclassedWndProc(HWND hwnd,UINT nmsg,WPARAM wparam,LPARAM lparam)310 LRESULT CALLBACK SubclassedWindow::SubclassedWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
311 {
312 	SubclassedWindow* pThis = GET_WINDOW(SubclassedWindow, hwnd);
313 	assert(pThis);
314 
315 	if (pThis) {
316 		switch(nmsg) {
317 		  case WM_COMMAND:
318 			if (!pThis->Command(LOWORD(wparam), HIWORD(wparam)))
319 				return 0;
320 			break;
321 
322 		  case WM_NOTIFY:
323 			return pThis->Notify(wparam, (NMHDR*)lparam);
324 
325 		  case WM_NOTIFYFORMAT:
326 			return NFR_CURRENT;
327 
328 		  case WM_CREATE:
329 			return pThis->Init((LPCREATESTRUCT)lparam);
330 
331 		  case WM_NCDESTROY:
332 			delete pThis;
333 			return 0;
334 
335 		  default:
336 			return pThis->WndProc(nmsg, wparam, lparam);
337 		}
338 	}
339 
340 	return CallWindowProc(pThis->_orgWndProc, hwnd, nmsg, wparam, lparam);
341 }
342 
WndProc(UINT nmsg,WPARAM wparam,LPARAM lparam)343 LRESULT SubclassedWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
344 {
345 	return CallWindowProc(_orgWndProc, _hwnd, nmsg, wparam, lparam);
346 }
347 
Command(int id,int code)348 int SubclassedWindow::Command(int id, int code)
349 {
350 	return 1;	// no command handler found
351 }
352 
Notify(int id,NMHDR * pnmh)353 int SubclassedWindow::Notify(int id, NMHDR* pnmh)
354 {
355 	return CallWindowProc(_orgWndProc, _hwnd, WM_NOTIFY, id, (LPARAM)pnmh);
356 }
357 
358 
ChildWindow(HWND hwnd,const ChildWndInfo & info)359 ChildWindow::ChildWindow(HWND hwnd, const ChildWndInfo& info)
360  :	super(hwnd),
361 	_hwndFrame(GetParent(info._hmdiclient))
362 {
363 	_focus_pane = 0;
364 	_split_pos = DEFAULT_SPLIT_POS;
365 	_last_split = DEFAULT_SPLIT_POS;
366 }
367 
368 
create(const ChildWndInfo & info,const RECT & rect,CREATORFUNC_INFO creator,LPCTSTR classname,LPCTSTR title,DWORD style)369 ChildWindow* ChildWindow::create(const ChildWndInfo& info, const RECT& rect, CREATORFUNC_INFO creator,
370 									LPCTSTR classname, LPCTSTR title, DWORD style)
371 {
372 	MDICREATESTRUCT mcs;
373 
374 	mcs.szClass = classname;
375 	mcs.szTitle = title;
376 	mcs.hOwner	= g_Globals._hInstance;
377 	mcs.x		= rect.left,
378 	mcs.y		= rect.top;
379 	mcs.cx		= rect.right - rect.left;
380 	mcs.cy		= rect.bottom - rect.top;
381 	mcs.style	= style;
382 	mcs.lParam	= 0;
383 
384 	return static_cast<ChildWindow*>(create_mdi_child(info, mcs, creator));
385 }
386 
387 
WndProc(UINT nmsg,WPARAM wparam,LPARAM lparam)388 LRESULT ChildWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
389 {
390 	switch(nmsg) {
391 	  case WM_PAINT: {
392         RECT rc;
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);
402 		break;}
403 
404 	  case WM_SETCURSOR:
405 		if (LOWORD(lparam) == HTCLIENT) {
406 			POINT pt;
407 			GetCursorPos(&pt);
408 			ScreenToClient(_hwnd, &pt);
409 
410 			if (pt.x>=_split_pos-SPLIT_WIDTH/2 && pt.x<_split_pos+SPLIT_WIDTH/2+1) {
411 				SetCursor(LoadCursor(0, IDC_SIZEWE));
412 				return TRUE;
413 			}
414 		}
415 		goto def;
416 
417 	  case WM_SIZE:
418 		if (wparam != SIZE_MINIMIZED)
419 			resize_children(LOWORD(lparam), HIWORD(lparam));
420 		goto def;
421 
422 	  case WM_GETMINMAXINFO:
423 		DefMDIChildProc(_hwnd, nmsg, wparam, lparam);
424 
425 		{LPMINMAXINFO lpmmi = (LPMINMAXINFO)lparam;
426 
427 		lpmmi->ptMaxTrackSize.x <<= 1;	// 2*GetSystemMetrics(SM_CXSCREEN) / SM_CXVIRTUALSCREEN
428 		lpmmi->ptMaxTrackSize.y <<= 1;	// 2*GetSystemMetrics(SM_CYSCREEN) / SM_CYVIRTUALSCREEN
429 		break;}
430 
431 	  case WM_LBUTTONDOWN: {
432 		int x = GET_X_LPARAM(lparam);
433 
434 		ClientRect rt(_hwnd);
435 
436 		if (x>=_split_pos-SPLIT_WIDTH/2 && x<_split_pos+SPLIT_WIDTH/2+1) {
437 			_last_split = _split_pos;
438 			SetCapture(_hwnd);
439 		}
440 
441 		break;}
442 
443 	  case WM_LBUTTONUP:
444 		if (GetCapture() == _hwnd)
445 			ReleaseCapture();
446 		break;
447 
448 	  case WM_KEYDOWN:
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);
454 				_last_split = -1;
455 				ReleaseCapture();
456 				SetCursor(LoadCursor(0, IDC_ARROW));
457 			}
458 		break;
459 
460 	  case WM_MOUSEMOVE:
461 		if (GetCapture() == _hwnd) {
462 			int x = GET_X_LPARAM(lparam);
463 
464 			ClientRect rt(_hwnd);
465 
466 			if (x>=0 && x<rt.right) {
467 				_split_pos = x;
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);
473 				UpdateWindow(_hwnd);
474 				UpdateWindow(_right_hwnd);
475 			}
476 		}
477 		break;
478 
479  	  case PM_DISPATCH_COMMAND:
480 		switch(LOWORD(wparam)) {
481 		  case ID_GO_BACK:
482 			if (!_url_history.empty()) {
483 				const String& url = jump_to_int(_url_history.top());
484 
485 				if (jump_to_int(url))
486 					set_url(url);
487 
488 				_url_history.pop();
489 			}
490 			break;
491 
492 		  case ID_GO_FORWARD:
493 			//@@
494 			break;
495 
496 		  case ID_GO_UP:
497 			///@todo
498 			break;
499 
500 		  case ID_GO_HOME:
501 			//@@
502 			break;
503 
504 		  default:
505 			return FALSE;
506 		}
507 		return TRUE;
508 
509 	  case WM_MDIACTIVATE:
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());
513 		}
514 		break;
515 
516 	  case PM_JUMP_TO_URL:
517 		return go_to((LPCTSTR)lparam)? TRUE: FALSE;
518 
519 	  default: def:
520 		return DefMDIChildProc(_hwnd, nmsg, wparam, lparam);
521 	}
522 
523 	return 0;
524 }
525 
526 
resize_children(int cx,int cy)527 void ChildWindow::resize_children(int cx, int cy)
528 {
529 	HDWP hdwp = BeginDeferWindowPos(2);
530 	RECT rt;
531 
532 	rt.left   = 0;
533 	rt.top    = 0;
534 	rt.right  = cx;
535 	rt.bottom = cy;
536 
537 	if (_left_hwnd) {
538 		cx = _split_pos + SPLIT_WIDTH/2;
539 
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);
541 	} else {
542 		_split_pos = 0;
543 		cx = 0;
544 	}
545 
546 	if (_right_hwnd)
547 		hdwp = DeferWindowPos(hdwp, _right_hwnd, 0, rt.left+cx+1, rt.top, rt.right-cx, rt.bottom-rt.top, SWP_NOZORDER|SWP_NOACTIVATE);
548 
549 	EndDeferWindowPos(hdwp);
550 }
551 
552 
go_to(LPCTSTR url)553 bool ChildWindow::go_to(LPCTSTR url)
554 {
555 	const String& url_str = jump_to_int(url);
556 
557 	if (!url_str.empty()) {
558 		set_url(url_str);
559 
560 		_url_history.push(url_str);
561 
562 		return true;
563 	} else
564 		return false;
565 }
566 
set_url(LPCTSTR url)567 void ChildWindow::set_url(LPCTSTR url)
568 {
569 	if (_url != url) {
570 		_url = url;
571 
572 		SendMessage(_hwndFrame, PM_URL_CHANGED, 0, (LPARAM)url);
573 	}
574 }
575 
576 
577 WindowSet Window::s_pretranslate_windows;
578 
register_pretranslate(HWND hwnd)579 void Window::register_pretranslate(HWND hwnd)
580 {
581 	s_pretranslate_windows.insert(hwnd);
582 }
583 
unregister_pretranslate(HWND hwnd)584 void Window::unregister_pretranslate(HWND hwnd)
585 {
586 	s_pretranslate_windows.erase(hwnd);
587 }
588 
pretranslate_msg(LPMSG pmsg)589 BOOL Window::pretranslate_msg(LPMSG pmsg)
590 {
591     if ((pmsg->message != WM_KEYDOWN) &&
592         (pmsg->message != WM_SYSKEYDOWN) &&
593         (pmsg->message != WM_SYSCHAR) &&
594         (pmsg->message != WM_CHAR))
595     {
596         return FALSE;
597     }
598 
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))
601 			return TRUE;
602 
603 	return FALSE;
604 }
605 
606 
607 WindowSet Window::s_dialogs;
608 
register_dialog(HWND hwnd)609 void Window::register_dialog(HWND hwnd)
610 {
611 	s_dialogs.insert(hwnd);
612 }
613 
unregister_dialog(HWND hwnd)614 void Window::unregister_dialog(HWND hwnd)
615 {
616 	s_dialogs.erase(hwnd);
617 }
618 
dispatch_dialog_msg(MSG * pmsg)619 BOOL Window::dispatch_dialog_msg(MSG* pmsg)
620 {
621 	for(WindowSet::const_iterator it=Window::s_dialogs.begin(); it!=s_dialogs.end(); ++it)
622 		if (IsDialogMessage(*it, pmsg))
623 			return TRUE;
624 
625 	return FALSE;
626 }
627 
628 
MessageLoop()629 int Window::MessageLoop()
630 {
631 	MSG msg;
632 
633 	while(GetMessage(&msg, 0, 0, 0)) {
634 		try {
635 			if (pretranslate_msg(&msg))
636 				continue;
637 
638 			if (dispatch_dialog_msg(&msg))
639 				continue;
640 
641 			TranslateMessage(&msg);
642 
643 			try {
644 				DispatchMessage(&msg);
645 			} catch(COMException& e) {
646 				HandleException(e, 0);
647 			}
648 		} catch(COMException& e) {
649 			HandleException(e, 0);
650 		}
651 	}
652 
653 	return msg.wParam;
654 }
655 
656 
SendParent(UINT nmsg,WPARAM wparam,LPARAM lparam)657 LRESULT	Window::SendParent(UINT nmsg, WPARAM wparam, LPARAM lparam)
658 {
659 	HWND parent = GetParent(_hwnd);
660 
661 	if (!parent)
662 		return 0;
663 
664 	return SendMessage(parent, nmsg, wparam, lparam);
665 }
666 
PostParent(UINT nmsg,WPARAM wparam,LPARAM lparam)667 LRESULT	Window::PostParent(UINT nmsg, WPARAM wparam, LPARAM lparam)
668 {
669 	HWND parent = GetParent(_hwnd);
670 
671 	if (!parent)
672 		return 0;
673 
674 	return PostMessage(parent, nmsg, wparam, lparam);
675 }
676 
677 
PreTranslateWindow(HWND hwnd)678 PreTranslateWindow::PreTranslateWindow(HWND hwnd)
679  :	super(hwnd)
680 {
681 	register_pretranslate(hwnd);
682 }
683 
~PreTranslateWindow()684 PreTranslateWindow::~PreTranslateWindow()
685 {
686 	unregister_pretranslate(_hwnd);
687 }
688 
689 
Dialog(HWND hwnd)690 Dialog::Dialog(HWND hwnd)
691  :	super(hwnd)
692 {
693 	register_dialog(hwnd);
694 }
695 
~Dialog()696 Dialog::~Dialog()
697 {
698 	unregister_dialog(_hwnd);
699 }
700 
DoModal(UINT nid,CREATORFUNC creator,HWND hwndParent)701 int Dialog::DoModal(UINT nid, CREATORFUNC creator, HWND hwndParent)
702 {
703 	Lock lock(GetStaticWindowData()._create_crit_sect);	// protect access to s_window_creator and s_new_info
704 
705 	s_window_creator = creator;
706 	s_new_info = NULL;
707 
708 	///@todo call Window::pretranslate_msg()
709 
710 	return DialogBoxParam(g_Globals._hInstance, MAKEINTRESOURCE(nid), hwndParent, DialogProc, 0/*lpParam*/);
711 }
712 
DoModal(UINT nid,CREATORFUNC_INFO creator,const void * info,HWND hwndParent)713 int Dialog::DoModal(UINT nid, CREATORFUNC_INFO creator, const void* info, HWND hwndParent)
714 {
715 	Lock lock(GetStaticWindowData()._create_crit_sect);	// protect access to s_window_creator and s_new_info
716 
717 	s_window_creator = (CREATORFUNC) creator;
718 	s_new_info = NULL;
719 
720 	///@todo call Window::pretranslate_msg()
721 
722 	return DialogBoxParam(g_Globals._hInstance, MAKEINTRESOURCE(nid), hwndParent, DialogProc, 0/*lpParam*/);
723 }
724 
DialogProc(HWND hwnd,UINT nmsg,WPARAM wparam,LPARAM lparam)725 INT_PTR CALLBACK Window::DialogProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
726 {
727 	Window* pThis = get_window(hwnd);
728 
729 	if (pThis) {
730 		switch(nmsg) {
731 		  case WM_COMMAND:
732 			pThis->Command(LOWORD(wparam), HIWORD(wparam));
733 			return TRUE;	// message has been processed
734 
735 		  case WM_NOTIFY:
736 			pThis->Notify(wparam, (NMHDR*)lparam);
737 			return TRUE;	// message has been processed
738 
739 		  case WM_NOTIFYFORMAT:
740 			SetWindowLongPtr(hwnd, DWLP_MSGRESULT, NFR_CURRENT);	// set return value NFR_CURRENT
741 			return TRUE;	// message has been processed
742 
743 		  case WM_NCDESTROY:
744 			delete pThis;
745 			return TRUE;	// message has been processed
746 
747 		  default:
748 			return pThis->WndProc(nmsg, wparam, lparam);
749 		}
750 	} else if (nmsg == WM_INITDIALOG) {
751 		pThis = create_controller(hwnd);
752 
753 		if (pThis)
754 			return pThis->Init(NULL);
755 	}
756 
757 	return FALSE;	// message has not been processed
758 }
759 
WndProc(UINT nmsg,WPARAM wparam,LPARAM lparam)760 LRESULT Dialog::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
761 {
762 	return FALSE;	// message has not been processed
763 }
764 
Command(int id,int code)765 int Dialog::Command(int id, int code)
766 {
767 	if (code == BN_CLICKED) {
768 		EndDialog(_hwnd, id);
769 		return 0;	// message has been processed
770 	}
771 
772 	return 1;
773 }
774 
775 
ResizeManager(HWND hwnd)776 ResizeManager::ResizeManager(HWND hwnd)
777  :	_hwnd(hwnd)
778 {
779 	ClientRect clnt(hwnd);
780 	_last_size.cx = clnt.right;
781 	_last_size.cy = clnt.bottom;
782 
783 	WindowRect rect(hwnd);
784 	_min_wnd_size.cx = rect.right - rect.left;
785 	_min_wnd_size.cy = rect.bottom - rect.top;
786 }
787 
HandleSize(int cx,int cy)788 void ResizeManager::HandleSize(int cx, int cy)
789 {
790 	ClientRect clnt_rect(_hwnd);
791 	SIZE new_size = {cx, cy};
792 
793 	int dx = new_size.cx - _last_size.cx;
794 	int dy = new_size.cy - _last_size.cy;
795 
796 	if (!dx && !dy)
797 		return;
798 
799 	_last_size = new_size;
800 
801 	HDWP hDWP = BeginDeferWindowPos(size());
802 
803 	for(ResizeManager::const_iterator it=begin(); it!=end(); ++it) {
804 		const ResizeEntry& e = *it;
805 		RECT move = {0};
806 
807 		if (e._flags & MOVE_LEFT)
808 			move.left += dx;
809 
810 		if (e._flags & MOVE_RIGHT)
811 			move.right += dx;
812 
813 		if (e._flags & MOVE_TOP)
814 			move.top += dy;
815 
816 		if (e._flags & MOVE_BOTTOM)
817 			move.bottom += dy;
818 
819 		UINT flags = 0;
820 
821 		if (!move.left && !move.top)
822 			flags = SWP_NOMOVE;
823 
824 		if (move.right==move.left && move.bottom==move.top)
825 			flags |= SWP_NOSIZE;
826 
827 		if (flags != (SWP_NOMOVE|SWP_NOSIZE)) {
828 			HWND hwnd = GetDlgItem(_hwnd, e._id);
829 
830 			if (hwnd) {
831 				WindowRect rect(hwnd);
832 				ScreenToClient(_hwnd, rect);
833 
834 				rect.left	+= move.left;
835 				rect.right	+= move.right;
836 				rect.top	+= move.top;
837 				rect.bottom	+= move.bottom;
838 
839 				hDWP = DeferWindowPos(hDWP, hwnd, 0, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, flags|SWP_NOACTIVATE|SWP_NOZORDER);
840 			}
841 		}
842 	}
843 
844 	EndDeferWindowPos(hDWP);
845 }
846 
Resize(int dx,int dy)847 void ResizeManager::Resize(int dx, int dy)
848 {
849 	::SetWindowPos(_hwnd, 0, 0, 0, _min_wnd_size.cx+dx, _min_wnd_size.cy+dy, SWP_NOMOVE|SWP_NOACTIVATE);
850 	MoveVisible(_hwnd);
851 
852 	ClientRect clnt_rect(_hwnd);
853 	HandleSize(clnt_rect.right, clnt_rect.bottom);
854 }
855 
856 
Button(HWND parent,LPCTSTR title,int left,int top,int width,int height,int id,DWORD flags,DWORD exStyle)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))
861 {
862 }
863 
864 
WndProc(UINT nmsg,WPARAM wparam,LPARAM lparam)865 LRESULT OwnerdrawnButton::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
866 {
867 	if (nmsg == PM_DISPATCH_DRAWITEM) {
868 		DrawItem((LPDRAWITEMSTRUCT)lparam);
869 		return TRUE;
870 	} else
871 		return super::WndProc(nmsg, wparam, lparam);
872 }
873 
874 
Static(HWND parent,LPCTSTR title,int left,int top,int width,int height,int id,DWORD flags,DWORD exStyle)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))
879 {
880 }
881 
882 
883 static RECT s_MyDrawText_Rect = {0, 0, 0, 0};
884 
MyDrawText(HDC hdc,LPARAM data,int cnt)885 static BOOL CALLBACK MyDrawText(HDC hdc, LPARAM data, int cnt)
886 {
887 	::DrawText(hdc, (LPCTSTR)data, cnt, &s_MyDrawText_Rect, DT_SINGLELINE);
888 	return TRUE;
889 }
890 
DrawGrayText(HDC hdc,LPRECT pRect,LPCTSTR title,int dt_flags)891 void DrawGrayText(HDC hdc, LPRECT pRect, LPCTSTR title, int dt_flags)
892 {
893 	COLORREF gray = GetSysColor(COLOR_GRAYTEXT);
894 
895 	if (gray) {
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);
899 
900 		SetTextColor(hdc, gray);
901 		DrawText(hdc, title, -1, pRect, dt_flags);
902 	} else {
903 		int old_r = pRect->right;
904 		int old_b = pRect->bottom;
905 
906 		DrawText(hdc, title, -1, pRect, dt_flags|DT_CALCRECT);
907 
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;
914 
915 		GrayString(hdc, GetSysColorBrush(COLOR_GRAYTEXT), MyDrawText, (LPARAM)title, -1, x, y, w, h);
916 	}
917 }
918 
919 
920 /* not yet used
921 void ColorButton::DrawItem(LPDRAWITEMSTRUCT dis)
922 {
923 	UINT state = DFCS_BUTTONPUSH;
924 
925 	if (dis->itemState & ODS_DISABLED)
926 		state |= DFCS_INACTIVE;
927 
928 	RECT textRect = {dis->rcItem.left+2, dis->rcItem.top+2, dis->rcItem.right-4, dis->rcItem.bottom-4};
929 
930 	if (dis->itemState & ODS_SELECTED) {
931 		state |= DFCS_PUSHED;
932 		++textRect.left;	++textRect.top;
933 		++textRect.right;	++textRect.bottom;
934 	}
935 
936 	DrawFrameControl(dis->hDC, &dis->rcItem, DFC_BUTTON, state);
937 
938 	TCHAR title[BUFFER_LEN];
939 	GetWindowText(_hwnd, title, BUFFER_LEN);
940 
941 	BkMode bk_mode(dis->hDC, TRANSPARENT);
942 
943 	if (dis->itemState & (ODS_DISABLED|ODS_GRAYED))
944 		DrawGrayText(dis, &textRect, title, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
945 	else {
946 		TextColor lcColor(dis->hDC, _textColor);
947 		DrawText(dis->hDC, title, -1, &textRect, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
948 	}
949 
950 	if (dis->itemState & ODS_FOCUS) {
951 		RECT rect = {
952 			dis->rcItem.left+3, dis->rcItem.top+3,
953 			dis->rcItem.right-dis->rcItem.left-4, dis->rcItem.bottom-dis->rcItem.top-4
954 		};
955 		if (dis->itemState & ODS_SELECTED) {
956 			++rect.left;	++rect.top;
957 			++rect.right;	++rect.bottom;
958 		}
959 		DrawFocusRect(dis->hDC, &rect);
960 	}
961 }
962 */
963 
964 
DrawItem(LPDRAWITEMSTRUCT dis)965 void PictureButton::DrawItem(LPDRAWITEMSTRUCT dis)
966 {
967 	UINT state = DFCS_BUTTONPUSH;
968 	int style = GetWindowStyle(_hwnd);
969 
970 	if (dis->itemState & ODS_DISABLED)
971 		state |= DFCS_INACTIVE;
972 
973 	POINT imagePos;
974 	RECT textRect;
975 	int dt_flags;
976 
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;
981 
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;
986 
987 		dt_flags = DT_SINGLELINE|DT_CENTER|DT_VCENTER;
988 	} else {
989 		 // horizontal floating, vertical centered
990 		imagePos.x = dis->rcItem.left + 3;
991 		imagePos.y = (dis->rcItem.top + dis->rcItem.bottom - _cy)/2;
992 
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;
997 
998 		dt_flags = DT_SINGLELINE|DT_VCENTER/*|DT_CENTER*/;
999 	}
1000 
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;
1006 	}
1007 
1008 	if (_flat) {
1009 		FillRect(dis->hDC, &dis->rcItem, _hBrush);
1010 
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);
1013 	} else
1014 		DrawFrameControl(dis->hDC, &dis->rcItem, DFC_BUTTON, state);
1015 
1016 	if (_hIcon)
1017 		DrawIconEx(dis->hDC, imagePos.x, imagePos.y, _hIcon, _cx, _cy, 0, _hBrush, DI_NORMAL);
1018 	else {
1019 		MemCanvas mem_dc;
1020 		BitmapSelection sel(mem_dc, _hBmp);
1021 		BitBlt(dis->hDC, imagePos.x, imagePos.y, _cx, _cy, mem_dc, 0, 0, SRCCOPY);
1022 	}
1023 
1024 	TCHAR title[BUFFER_LEN];
1025 	GetWindowText(_hwnd, title, BUFFER_LEN);
1026 
1027 	BkMode bk_mode(dis->hDC, TRANSPARENT);
1028 
1029 	if (dis->itemState & (ODS_DISABLED|ODS_GRAYED))
1030 		DrawGrayText(dis->hDC, &textRect, title, dt_flags);
1031 	else {
1032 		TextColor lcColor(dis->hDC, GetSysColor(COLOR_BTNTEXT));
1033 		DrawText(dis->hDC, title, -1, &textRect, dt_flags);
1034 	}
1035 
1036 	if (dis->itemState & ODS_FOCUS) {
1037 		RECT rect = {
1038 			dis->rcItem.left+3, dis->rcItem.top+3,
1039 			dis->rcItem.right-dis->rcItem.left-4, dis->rcItem.bottom-dis->rcItem.top-4
1040 		};
1041 		if (dis->itemState & ODS_SELECTED) {
1042 			++rect.left;	++rect.top;
1043 			++rect.right;	++rect.bottom;
1044 		}
1045 		DrawFocusRect(dis->hDC, &rect);
1046 	}
1047 }
1048 
1049 
DrawItem(LPDRAWITEMSTRUCT dis)1050 void FlatButton::DrawItem(LPDRAWITEMSTRUCT dis)
1051 {
1052 	UINT style = DFCS_BUTTONPUSH;
1053 
1054 	if (dis->itemState & ODS_DISABLED)
1055 		style |= DFCS_INACTIVE;
1056 
1057 	RECT textRect = {dis->rcItem.left+2, dis->rcItem.top+2, dis->rcItem.right-4, dis->rcItem.bottom-4};
1058 
1059 	if (dis->itemState & ODS_SELECTED) {
1060 		style |= DFCS_PUSHED;
1061 		++textRect.left;	++textRect.top;
1062 		++textRect.right;	++textRect.bottom;
1063 	}
1064 
1065 	FillRect(dis->hDC, &dis->rcItem, GetSysColorBrush(COLOR_BTNFACE));
1066 
1067 	 // highlight the button?
1068 	if (_active)
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);
1072 
1073 	TCHAR txt[BUFFER_LEN];
1074 	int txt_len = GetWindowText(_hwnd, txt, BUFFER_LEN);
1075 
1076 	if (dis->itemState & (ODS_DISABLED|ODS_GRAYED)) {
1077 		COLORREF gray = GetSysColor(COLOR_GRAYTEXT);
1078 
1079 		if (gray) {
1080 			{
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);
1084 			}
1085 
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);
1089 		} else {
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);
1100 		}
1101 	} else {
1102 		TextColor lcColor(dis->hDC, _active? _activeColor: _textColor);
1103 		DrawText(dis->hDC, txt, txt_len, &textRect, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
1104 	}
1105 
1106 	if (dis->itemState & ODS_FOCUS) {
1107 		RECT rect = {
1108 			dis->rcItem.left+3, dis->rcItem.top+3,
1109 			dis->rcItem.right-dis->rcItem.left-4, dis->rcItem.bottom-dis->rcItem.top-4
1110 		};
1111 		if (dis->itemState & ODS_SELECTED) {
1112 			++rect.left;	++rect.top;
1113 			++rect.right;	++rect.bottom;
1114 		}
1115 		DrawFocusRect(dis->hDC, &rect);
1116 	}
1117 }
1118 
WndProc(UINT nmsg,WPARAM wparam,LPARAM lparam)1119 LRESULT	FlatButton::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
1120 {
1121 	switch(nmsg) {
1122 	  case WM_MOUSEMOVE: {
1123 		bool active = false;
1124 
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);
1129 
1130 			if (GetCurrentProcessId() == pid_foreground) {
1131 				POINT pt = {GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam)};
1132 				ClientRect clntRect(_hwnd);
1133 
1134 				 // highlight the button?
1135 				if (pt.x>=clntRect.left && pt.x<clntRect.right && pt.y>=clntRect.top && pt.y<clntRect.bottom)
1136 					active = true;
1137 			}
1138 		}
1139 
1140 		if (active != _active) {
1141 			_active = active;
1142 
1143 			if (active) {
1144 				TRACKMOUSEEVENT tme = {sizeof(tme), /*TME_HOVER|*/TME_LEAVE, _hwnd/*, HOVER_DEFAULT*/};
1145 				_TrackMouseEvent(&tme);
1146 			}
1147 
1148 			InvalidateRect(_hwnd, NULL, TRUE);
1149 		}
1150 
1151 		return 0;}
1152 
1153 	  case WM_LBUTTONUP: {
1154 		POINT pt = {GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam)};
1155 		ClientRect clntRect(_hwnd);
1156 
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)
1159 			goto cancel_press;
1160 
1161 		goto def;}
1162 
1163 	  case WM_CANCELMODE:
1164 	  cancel_press: {
1165 		TRACKMOUSEEVENT tme = {sizeof(tme), /*TME_HOVER|*/TME_LEAVE|TME_CANCEL, _hwnd/*, HOVER_DEFAULT*/};
1166 		_TrackMouseEvent(&tme);
1167 		_active = false;
1168 		ReleaseCapture();}
1169 		// fall through
1170 
1171 	  case WM_MOUSELEAVE:
1172 		if (_active) {
1173 			_active = false;
1174 
1175 			InvalidateRect(_hwnd, NULL, TRUE);
1176 		}
1177 
1178 		return 0;
1179 
1180 	  default: def:
1181 		return super::WndProc(nmsg, wparam, lparam);
1182 	}
1183 }
1184 
1185 
HyperlinkCtrl(HWND hwnd,COLORREF colorLink,COLORREF colorVisited)1186 HyperlinkCtrl::HyperlinkCtrl(HWND hwnd, COLORREF colorLink, COLORREF colorVisited)
1187  :	super(hwnd),
1188 	_cmd(ResString(GetDlgCtrlID(hwnd))),
1189 	_textColor(colorLink),
1190 	_colorVisited(colorVisited),
1191 	_hfont(0),
1192 	_crsr_link(0)
1193 {
1194 	init();
1195 }
1196 
HyperlinkCtrl(HWND owner,int id,COLORREF colorLink,COLORREF 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),
1202 	_hfont(0),
1203 	_crsr_link(0)
1204 {
1205 	init();
1206 }
1207 
init()1208 void HyperlinkCtrl::init()
1209 {
1210 	if (_cmd.empty()) {
1211 		TCHAR txt[BUFFER_LEN];
1212 		_cmd.assign(txt, GetWindowText(_hwnd, txt, BUFFER_LEN));
1213 	}
1214 }
1215 
~HyperlinkCtrl()1216 HyperlinkCtrl::~HyperlinkCtrl()
1217 {
1218 	if (_hfont)
1219 		DeleteObject(_hfont);
1220 }
1221 
WndProc(UINT nmsg,WPARAM wparam,LPARAM lparam)1222 LRESULT HyperlinkCtrl::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
1223 {
1224 	switch(nmsg) {
1225 	  case PM_DISPATCH_CTLCOLOR: {
1226 		if (!_hfont) {
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);
1231 		}
1232 
1233 		HDC hdc = (HDC) wparam;
1234 		SetTextColor(hdc, _textColor);	//@@
1235 		SelectFont(hdc, _hfont);
1236 		SetBkMode(hdc, TRANSPARENT);
1237 		return (LRESULT)GetStockObject(HOLLOW_BRUSH);
1238 	  }
1239 
1240 	  case WM_SETCURSOR:
1241 		if (!_crsr_link)
1242 			_crsr_link = LoadCursor(0, IDC_HAND);
1243 
1244 		if (_crsr_link)
1245 			SetCursor(_crsr_link);
1246 		return 0;
1247 
1248 	  case WM_NCHITTEST:
1249 		return HTCLIENT;	// Aktivierung von Maus-Botschaften
1250 
1251 	  case WM_LBUTTONDOWN:
1252 		if (LaunchLink()) {
1253 			_textColor = _colorVisited;
1254 			InvalidateRect(_hwnd, NULL, FALSE);
1255 		} else
1256 			MessageBeep(0);
1257 		return 0;
1258 
1259 	  default:
1260 		return super::WndProc(nmsg, wparam, lparam);
1261 	}
1262 }
1263 
1264 
ToolTip(HWND owner)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))
1269 {
1270 	activate();
1271 }
1272 
1273 
ListSort(HWND hwndListview,PFNLVCOMPARE compare_fct)1274 ListSort::ListSort(HWND hwndListview, PFNLVCOMPARE compare_fct)
1275  :	WindowHandle(hwndListview),
1276 	_compare_fct(compare_fct)
1277 {
1278 	_sort_crit = 0;
1279 	_direction = false;
1280 }
1281 
toggle_sort(int idx)1282 void ListSort::toggle_sort(int idx)
1283 {
1284 	if (_sort_crit == idx)
1285 		_direction = !_direction;
1286 	else {
1287 		_sort_crit = idx;
1288 		_direction = false;
1289 	}
1290 }
1291 
sort()1292 void ListSort::sort()
1293 {
1294 	int idx = ListView_GetSelectionMark(_hwnd);
1295 	LPARAM param = ListView_GetItemData(_hwnd, idx);
1296 
1297 	ListView_SortItems(_hwnd, _compare_fct, (LPARAM)this);
1298 
1299 	if (idx >= 0) {
1300 		idx = ListView_FindItemPara(_hwnd, param);
1301 		ListView_EnsureVisible(_hwnd, idx, FALSE);
1302 	}
1303 }
1304 
1305 
PropSheetPage(UINT nid,Window::CREATORFUNC dlg_creator)1306 PropSheetPage::PropSheetPage(UINT nid, Window::CREATORFUNC dlg_creator)
1307  :	_dlg_creator(dlg_creator)
1308 {
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;
1315 }
1316 
1317 
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)
1321 #endif
1322 
1323 
PropertySheetDialog(HWND owner)1324 PropertySheetDialog::PropertySheetDialog(HWND owner)
1325  :	_hwnd(0)
1326 {
1327 	PROPSHEETHEADER::dwSize = sizeof(PROPSHEETHEADER);
1328 	PROPSHEETHEADER::dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS;
1329 	PROPSHEETHEADER::hwndParent = owner;
1330 	PROPSHEETHEADER::hInstance = g_Globals._hInstance;
1331 }
1332 
add(PropSheetPage & psp)1333 void PropertySheetDialog::add(PropSheetPage& psp)
1334 {
1335 	_pages.push_back(psp);
1336 }
1337 
DoModal(int start_page)1338 int	PropertySheetDialog::DoModal(int start_page)
1339 {
1340 	PROPSHEETHEADER::ppsp = (LPCPROPSHEETPAGE) &_pages[0];
1341 	PROPSHEETHEADER::nPages = _pages.size();
1342 	PROPSHEETHEADER::nStartPage = start_page;
1343 /*
1344 	Window* pwnd = Window::create_property_sheet(this, WINDOW_CREATOR(PropertySheetDlg), NULL);
1345 	if (!pwnd)
1346 		return -1;
1347 
1348 	HWND hwndPropSheet = *pwnd;
1349 */
1350 	int ret = PropertySheet(this);
1351 	if (ret == -1)
1352 		return -1;
1353 
1354 	HWND hwndPropSheet = (HWND) ret;
1355 	HWND hwndparent = GetParent(hwndPropSheet);
1356 
1357 	if (hwndparent)
1358 		EnableWindow(hwndparent, FALSE);
1359 
1360 	ret = 0;
1361 	MSG msg;
1362 
1363 	while(GetMessage(&msg, 0, 0, 0)) {
1364 		try {
1365 			if (Window::pretranslate_msg(&msg))
1366 				continue;
1367 
1368 			if (PropSheet_IsDialogMessage(hwndPropSheet, &msg))
1369 				continue;
1370 
1371 			if (Window::dispatch_dialog_msg(&msg))
1372 				continue;
1373 
1374 			TranslateMessage(&msg);
1375 
1376 			try {
1377 				DispatchMessage(&msg);
1378 			} catch(COMException& e) {
1379 				HandleException(e, 0);
1380 			}
1381 
1382 			if (!PropSheet_GetCurrentPageHwnd(hwndPropSheet)) {
1383 				ret = PropSheet_GetResult(hwndPropSheet);
1384 				break;
1385 			}
1386 		} catch(COMException& e) {
1387 			HandleException(e, 0);
1388 		}
1389 	}
1390 
1391 	if (hwndparent)
1392 		EnableWindow(hwndparent, TRUE);
1393 
1394 	DestroyWindow(hwndPropSheet);
1395 
1396 	return ret;
1397 }
1398 
GetCurrentPage()1399 HWND PropertySheetDialog::GetCurrentPage()
1400 {
1401 	HWND hdlg = PropSheet_GetCurrentPageHwnd(_hwnd);
1402 	return hdlg;
1403 }
1404 
1405 
PropSheetPageDlg(HWND hwnd)1406 PropSheetPageDlg::PropSheetPageDlg(HWND hwnd)
1407  :	super(hwnd)
1408 {
1409 }
1410 
DialogProc(HWND hwnd,UINT nmsg,WPARAM wparam,LPARAM lparam)1411 INT_PTR CALLBACK PropSheetPageDlg::DialogProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
1412 {
1413 	PropSheetPageDlg* pThis = GET_WINDOW(PropSheetPageDlg, hwnd);
1414 
1415 	if (pThis) {
1416 		switch(nmsg) {
1417 		  case WM_COMMAND:
1418 			pThis->Command(LOWORD(wparam), HIWORD(wparam));
1419 			return TRUE;	// message has been processed
1420 
1421 		  case WM_NOTIFY:
1422 			pThis->Notify(wparam, (NMHDR*)lparam);
1423 			return TRUE;	// message has been processed
1424 
1425 		  case WM_NOTIFYFORMAT:
1426 			SetWindowLongPtr(hwnd, DWLP_MSGRESULT, NFR_CURRENT);	// set return value NFR_CURRENT
1427 			return TRUE;	// message has been processed
1428 
1429 		  case WM_NCDESTROY:
1430 			delete pThis;
1431 			return TRUE;	// message has been processed
1432 
1433 		  default:
1434 			return pThis->WndProc(nmsg, wparam, lparam);
1435 		}
1436 	} else if (nmsg == WM_INITDIALOG) {
1437 		PROPSHEETPAGE* psp = (PROPSHEETPAGE*) lparam;
1438 		PropSheetPage* ppsp = (PropSheetPage*) psp->lParam;
1439 
1440 		if (ppsp->_dlg_creator) {
1441 			pThis = static_cast<PropSheetPageDlg*>(ppsp->_dlg_creator(hwnd));
1442 
1443 			if (pThis)
1444 				return pThis->Init(NULL);
1445 		}
1446 	}
1447 
1448 	return FALSE;	// message has not been processed
1449 }
1450 
Command(int id,int code)1451 int PropSheetPageDlg::Command(int id, int code)
1452 {
1453 	// override call to EndDialog in Dialog::Command();
1454 
1455 	return FALSE;
1456 }
1457