1 #include "CUIWindow.h"
2 #include "CUIScaler.h"
3 #include "CUIThemes.h"
4 #include "CUIWindowResizer.h"
5 #include <assert.h>
6 #include <commctrl.h>
7 #include <TCFoundation/mystring.h>
8 #include <TCFoundation/TCUserDefaults.h>
9 #include <TCFoundation/TCImage.h>
10 #include <stdio.h>
11 
12 static LONG g_checkBoxWidth = 0;
13 
14 #if defined(_MSC_VER) && _MSC_VER >= 1400 && defined(_DEBUG)
15 #define new DEBUG_CLIENTBLOCK
16 #endif
17 
18 CUIExport int			CUIWindow::systemMaxWidth = -1;
19 CUIExport int			CUIWindow::systemMaxHeight = -1;
20 CUIExport int			CUIWindow::systemMinTrackWidth = -1;
21 CUIExport int			CUIWindow::systemMinTrackHeight = -1;
22 CUIExport int			CUIWindow::systemMaxTrackWidth = -1;
23 CUIExport int			CUIWindow::systemMaxTrackHeight = -1;
24 CUIExport HCURSOR		CUIWindow::hArrowCursor = NULL;
25 CUIExport HCURSOR		CUIWindow::hWaitCursor = NULL;
26 CUIExport HINSTANCE		CUIWindow::hLanguageModule = NULL;
27 CUIExport bool			CUIWindow::appVersionPopulated = false;
28 CUIExport DWORD			CUIWindow::appVersionMS;
29 CUIExport DWORD			CUIWindow::appVersionLS;
30 CUIExport UIntUIntMap	CUIWindow::ucMessages;
31 
CUIWindow(void)32 CUIWindow::CUIWindow(void)
33 		  :windowTitle(copyString(_UC(""))),
34 		   hInstance(NULL),
35 		   x(0),
36 		   y(0),
37 		   width(0),
38 		   height(0),
39 		   maxWidth(-1),
40 		   maxHeight(-1),
41 		   minWidth(-1),
42 		   minHeight(-1),
43 		   hdc(NULL),
44 		   windowStyle(0),
45 		   windowClassStyle(0),
46 		   exWindowStyle(0),
47 		   hWindow(NULL),
48 		   hWindowMenu(NULL),
49 		   parentWindow(NULL),
50 		   hParentWindow(NULL),
51 		   initialized(FALSE),
52 		   created(FALSE),
53 		   numChildren(0),
54 		   hBackgroundBrush(NULL),
55 		   paintStruct(NULL),
56 		   autosaveName(NULL),
57 		   scaler(NULL)
58 {
59 	init();
60 }
61 
CUIWindow(CUCSTR windowTitle,HINSTANCE hInstance,int x,int y,int width,int height)62 CUIWindow::CUIWindow(CUCSTR windowTitle, HINSTANCE hInstance, int x, int y,
63 					 int width, int height)
64 		  :windowTitle(copyString(windowTitle)),
65 		   hInstance(hInstance),
66 		   x(x),
67 		   y(y),
68 		   width(width),
69 		   height(height),
70 		   maxWidth(-1),
71 		   maxHeight(-1),
72 		   minWidth(-1),
73 		   minHeight(-1),
74 		   hdc(NULL),
75 		   windowStyle(WS_OVERLAPPED | WS_MINIMIZEBOX | WS_MAXIMIZEBOX |
76 		    WS_SYSMENU | WS_THICKFRAME),
77 		   windowClassStyle(CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS),
78 		   exWindowStyle(WS_EX_CONTROLPARENT),
79 		   hWindow(NULL),
80 		   hWindowMenu(NULL),
81 		   parentWindow(NULL),
82 		   hParentWindow(NULL),
83 		   initialized(FALSE),
84 		   created(FALSE),
85 		   numChildren(0),
86 		   hBackgroundBrush(NULL),
87 		   paintStruct(NULL),
88 		   autosaveName(NULL),
89 		   scaler(NULL)
90 {
91 	init();
92 }
93 
CUIWindow(CUIWindow * parentWindow,int x,int y,int width,int height)94 CUIWindow::CUIWindow(CUIWindow* parentWindow, int x, int y, int width,
95 					 int height)
96 		  :windowTitle(copyString(_UC(""))),
97 		   hInstance(parentWindow->getHInstance()),
98 		   x(x),
99 		   y(y),
100 		   width(width),
101 		   height(height),
102 		   maxWidth(-1),
103 		   maxHeight(-1),
104 		   minWidth(-1),
105 		   minHeight(-1),
106 		   hdc(NULL),
107 		   windowStyle(WS_CHILD | WS_VISIBLE/* | WS_CLIPSIBLINGS*/),
108 		   windowClassStyle(CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS),
109 		   exWindowStyle(WS_EX_CONTROLPARENT),
110 		   hWindow(NULL),
111 		   hWindowMenu(NULL),
112 		   parentWindow(parentWindow),
113 		   hParentWindow(parentWindow->getHWindow()),
114 		   initialized(FALSE),
115 		   created(FALSE),
116 		   numChildren(0),
117 		   hBackgroundBrush(NULL),
118 		   paintStruct(NULL),
119 		   autosaveName(NULL),
120 		   scaler(NULL)
121 {
122 	parentWindow->addChild(this);
123 	init();
124 }
125 
CUIWindow(HWND hParentWindow,HINSTANCE hInstance,int x,int y,int width,int height)126 CUIWindow::CUIWindow(HWND hParentWindow, HINSTANCE hInstance, int x, int y,
127 					 int width, int height)
128 		  :windowTitle(copyString(_UC(""))),
129 		   x(x),
130 		   y(y),
131 		   width(width),
132 		   height(height),
133 		   maxWidth(-1),
134 		   maxHeight(-1),
135 		   minWidth(-1),
136 		   minHeight(-1),
137 		   hdc(NULL),
138 		   windowStyle(WS_CHILD | WS_VISIBLE/* | WS_CLIPSIBLINGS*/),
139 		   windowClassStyle(CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS),
140 		   exWindowStyle(WS_EX_CONTROLPARENT),
141 		   hInstance(hInstance),
142 		   hWindow(NULL),
143 		   hWindowMenu(NULL),
144 		   parentWindow(NULL),
145 		   hParentWindow(hParentWindow),
146 		   initialized(FALSE),
147 		   created(FALSE),
148 		   numChildren(0),
149 		   hBackgroundBrush(NULL),
150 		   paintStruct(NULL),
151 		   autosaveName(NULL),
152 		   scaler(NULL)
153 {
154 //	parentWindow->addChild(this);
155 	init();
156 }
157 
initWindow(void)158 BOOL CUIWindow::initWindow(void)
159 {
160 	registerWindowClass();
161 	if (createWindow())
162 	{
163 		initialized = TRUE;
164 		return TRUE;
165 	}
166 	else
167 	{
168 		return FALSE;
169 	}
170 }
171 
windowClassName(void)172 const UCCHAR* CUIWindow::windowClassName(void)
173 {
174 	if (parentWindow || hParentWindow)
175 	{
176 		return _UC("CUISubWindow");
177 	}
178 	else
179 	{
180 		return _UC("CUIMainWindow");
181 	}
182 }
183 
~CUIWindow(void)184 CUIWindow::~CUIWindow(void)
185 {
186 }
187 
dealloc(void)188 void CUIWindow::dealloc(void)
189 {
190 	if (hWindow)
191 	{
192 		DestroyWindow(hWindow);
193 		hWindow = NULL;
194 	}
195 	if (hWindowMenu)
196 	{
197 		DestroyMenu(hWindowMenu);
198 		hWindowMenu = NULL;
199 	}
200 	delete windowTitle;
201 	windowTitle = NULL;
202 	if (!parentWindow)
203 	{
204 		deleteSystemColorPens();
205 		delete systemColors;
206 		systemColors = NULL;
207 		delete systemColorPens;
208 		systemColorPens = NULL;
209 		if (hBackgroundBrush)
210 		{
211  			DeleteObject(hBackgroundBrush);
212 		}
213 	}
214 	delete autosaveName;
215 	TCObject::release(scaler);
216 	TCObject::dealloc();
217 }
218 
closeWindow(void)219 void CUIWindow::closeWindow(void)
220 {
221 	DestroyWindow(hWindow);
222 }
223 
setArrowCursor(void)224 void CUIWindow::setArrowCursor(void)
225 {
226 	if (!hArrowCursor)
227 	{
228 		hArrowCursor = LoadCursor(NULL, IDC_ARROW);
229 	}
230 	SetCursor(hArrowCursor);
231 }
232 
setWaitCursor(void)233 void CUIWindow::setWaitCursor(void)
234 {
235 	if (!hWaitCursor)
236 	{
237 		hWaitCursor = LoadCursor(NULL, IDC_WAIT);
238 	}
239 	SetCursor(hWaitCursor);
240 }
241 
deleteSystemColorPens(void)242 void CUIWindow::deleteSystemColorPens(void)
243 {
244 	if (!parentWindow)
245 	{
246 		int i;
247 
248 		for (i = 0; i < NUM_SYSTEM_COLORS; i++)
249 		{
250 			if (systemColorPens[i])
251 			{
252 				DeleteObject(systemColorPens[i]);
253 				systemColorPens[i] = 0;
254 			}
255 		}
256 	}
257 }
258 
init(void)259 void CUIWindow::init(void)
260 {
261 #ifdef _LEAK_DEBUG
262 	strcpy(className, "CUIWindow");
263 #endif
264 	initUcMessages();
265 	initSystemColors();
266 }
267 
setRBGFillColor(BYTE r,BYTE g,BYTE b)268 void CUIWindow::setRBGFillColor(BYTE r, BYTE g, BYTE b)
269 {
270 	setFillColor(RGB(r, g, b));
271 }
272 
setFillColor(DWORD newColor)273 void CUIWindow::setFillColor(DWORD newColor)
274 {
275 	fillColor = newColor;
276 }
277 
updateSystemColors(void)278 void CUIWindow::updateSystemColors(void)
279 {
280 	if (!parentWindow)
281 	{
282 		int i;
283 
284 		deleteSystemColorPens();
285 		for (i = 0; i < NUM_SYSTEM_COLORS; i++)
286 		{
287 			systemColors[i] = GetSysColor(i);
288 			systemColorPens[i] = CreatePen(PS_SOLID, 0, systemColors[i]);
289 		}
290 	}
291 }
292 
initUcMessages(void)293 void CUIWindow::initUcMessages(void)
294 {
295 	ucMessages[WM_SETTEXT] = WM_SETTEXT;
296 	ucMessages[WM_GETTEXT] = WM_GETTEXT;
297 	ucMessages[CB_DELETESTRING] = CB_DELETESTRING;
298 	ucMessages[CB_ADDSTRING] = CB_ADDSTRING;
299 	ucMessages[LB_ADDSTRING] = LB_ADDSTRING;
300 	ucMessages[CB_SELECTSTRING] = CB_SELECTSTRING;
301 #ifdef TC_NO_UNICODE
302 	ucMessages[SB_SETTIPTEXT] = SB_SETTIPTEXTA;
303 	ucMessages[SB_GETTIPTEXT] = SB_GETTIPTEXTA;
304 	ucMessages[SB_SETTEXT] = SB_SETTEXTA;
305 	ucMessages[SB_GETTEXT] = SB_GETTEXTA;
306 	ucMessages[TTM_ADDTOOL] = TTM_ADDTOOLA;
307 #else // TC_NO_UNICODE
308 	ucMessages[SB_SETTIPTEXT] = SB_SETTIPTEXTW;
309 	ucMessages[SB_GETTIPTEXT] = SB_GETTIPTEXTW;
310 	ucMessages[SB_SETTEXT] = SB_SETTEXTW;
311 	ucMessages[SB_GETTEXT] = SB_GETTEXTW;
312 	ucMessages[TTM_ADDTOOL] = TTM_ADDTOOLW;
313 #endif // TC_NO_UNICODE
314 }
315 
initSystemColors(void)316 void CUIWindow::initSystemColors(void)
317 {
318 	if (parentWindow)
319 	{
320 		systemColors = parentWindow->systemColors;
321 		systemColorPens = parentWindow->systemColorPens;
322 	}
323 	else
324 	{
325 		systemColors = new DWORD[NUM_SYSTEM_COLORS];
326 		systemColorPens = new HPEN[NUM_SYSTEM_COLORS];
327 		memset(systemColorPens, 0, sizeof(HPEN) * NUM_SYSTEM_COLORS);
328 		updateSystemColors();
329 	}
330 }
331 
resize(int newWidth,int newHeight)332 void CUIWindow::resize(int newWidth, int newHeight)
333 {
334 	if (initialized)
335 	{
336 		SIZE decorationSize = {0, 0};
337 
338 		if (parentWindow)
339 		{
340 			decorationSize = getDecorationSize();
341 		}
342 		MoveWindow(hWindow, x - decorationSize.cx / 2, y - decorationSize.cy / 2,
343 			newWidth, newHeight, TRUE);
344 	}
345 	else
346 	{
347 		width = newWidth;
348 		height = newHeight;
349 	}
350 }
351 
setTimer(UINT timerID,UINT elapse)352 UINT_PTR CUIWindow::setTimer(UINT timerID, UINT elapse)
353 {
354 	return SetTimer(hWindow, timerID, elapse, NULL);
355 }
356 
killTimer(UINT timerID)357 BOOL CUIWindow::killTimer(UINT timerID)
358 {
359 	return KillTimer(hWindow, timerID);
360 }
361 
doCommand(int,int,HWND)362 LRESULT CUIWindow::doCommand(int, int, HWND)
363 {
364 	return 1;
365 }
366 
doTimer(UINT_PTR)367 LRESULT CUIWindow::doTimer(UINT_PTR)
368 {
369 	return 1;
370 }
371 
doHelp(LPHELPINFO)372 LRESULT CUIWindow::doHelp(LPHELPINFO)
373 {
374 	return 0;
375 }
376 
doMenuSelect(UINT,UINT,HMENU)377 LRESULT CUIWindow::doMenuSelect(UINT, UINT, HMENU)
378 {
379 	return 1;
380 }
381 
doThemeChanged(void)382 LRESULT CUIWindow::doThemeChanged(void)
383 {
384 	return 1;
385 }
386 
doEnterMenuLoop(bool)387 LRESULT CUIWindow::doEnterMenuLoop(bool /*isTrackPopupMenu*/)
388 {
389 	return 1;
390 }
391 
doExitMenuLoop(bool)392 LRESULT CUIWindow::doExitMenuLoop(bool /*isTrackPopupMenu*/)
393 {
394 	return 1;
395 }
396 
doInitMenuPopup(HMENU,UINT,BOOL)397 LRESULT CUIWindow::doInitMenuPopup(HMENU /*hPopupMenu*/, UINT /*uPos*/,
398 								   BOOL /*fSystemMenu*/)
399 {
400 	return 0;
401 }
402 
doDrawItem(HWND,LPDRAWITEMSTRUCT)403 LRESULT CUIWindow::doDrawItem(HWND /*hControlWnd*/,
404 							  LPDRAWITEMSTRUCT /*drawItemStruct*/)
405 {
406 	return FALSE;
407 }
408 
doSize(WPARAM sizeType,int newWidth,int newHeight)409 LRESULT CUIWindow::doSize(WPARAM sizeType, int newWidth, int newHeight)
410 {
411 	if (sizeType == SIZE_MINIMIZED)
412 	{
413 		return 1;
414 	}
415 	else
416 	{
417 		int deltaWidth = newWidth - width;
418 		int deltaHeight = newHeight - height;
419 		int i;
420 
421 		for (i = 0; i < numChildren; i++)
422 		{
423 			CUIWindow* child = children[i];
424 			SIZE decorationSize = child->getDecorationSize();
425 
426 			child->resize(child->width + decorationSize.cx + deltaWidth,
427 				child->height + decorationSize.cy + deltaHeight);
428 		}
429 		width = newWidth;
430 		height = newHeight;
431 		if (autosaveName != NULL)
432 		{
433 			int saveX, saveY, saveWidth, saveHeight, saveMaximized;
434 
435 			if (sizeType != SIZE_MAXIMIZED || !readAutosaveInfo(saveX, saveY,
436 				saveWidth, saveHeight, saveMaximized))
437 			{
438 				RECT rect;
439 
440 				GetWindowRect(hWindow, &rect);
441 				saveX = rect.left;
442 				saveY = rect.top;
443 				saveWidth = rect.right - rect.left;
444 				saveHeight = rect.bottom - rect.top;
445 			}
446 			saveMaximized = sizeType == SIZE_MAXIMIZED;
447 			writeAutosaveInfo(saveX, saveY, saveWidth, saveHeight,
448 				saveMaximized);
449 		}
450 		return 0;
451 	}
452 }
453 
doMove(int newX,int newY)454 LRESULT CUIWindow::doMove(int newX, int newY)
455 {
456 	x = newX;
457 	y = newY;
458 	if (autosaveName != NULL)
459 	{
460 		if ((GetWindowLong(hWindow, GWL_STYLE) & WS_MAXIMIZE) == 0)
461 		{
462 			RECT rect;
463 			GetWindowRect(hWindow, &rect);
464 
465 			writeAutosaveInfo(rect.left, rect.top, rect.right - rect.left,
466 				rect.bottom - rect.top, 0);
467 		}
468 	}
469 	return 1;
470 }
471 
doEraseBackground(RECT *)472 LRESULT CUIWindow::doEraseBackground(RECT *)
473 {
474 	created = TRUE;
475 	return 0;
476 }
477 
getDecorationSize(HMONITOR hMonitor)478 SIZE CUIWindow::getDecorationSize(HMONITOR hMonitor /*= NULL*/)
479 {
480 	RECT windowRect = { 0, 0, 100, 100 };
481 	WNDCLASSEX windowClass = getWindowClass();
482 	SIZE size;
483 
484 	CUIScaler::adjustWindowRectEx(hMonitor, &windowRect, windowStyle,
485 		windowClass.lpszMenuName != NULL || hWindowMenu, exWindowStyle);
486 	size.cx = windowRect.right - windowRect.left - 100;
487 	size.cy = windowRect.bottom - windowRect.top - 100;
488 	if (!(windowStyle & WS_POPUP) && !(windowStyle & WS_CHILD))
489 	{
490 		size.cx += 2;
491 		size.cy += GetSystemMetrics(SM_CYCAPTION) + 2;
492 	}
493 	return size;
494 }
495 
doCreate(HWND hWnd,LPCREATESTRUCT createStruct)496 LRESULT CUIWindow::doCreate(HWND hWnd, LPCREATESTRUCT createStruct)
497 {
498 	SIZE decorationSize = getDecorationSize();
499 	int dx = decorationSize.cx;
500 	int dy = decorationSize.cy;
501 	RECT windowRect;
502 	int windowWidth;
503 	int windowHeight;
504 
505 	hWindow = hWnd;
506 	GetWindowRect(hWnd, &windowRect);
507 	windowWidth = windowRect.right - windowRect.left;
508 	windowHeight = windowRect.bottom - windowRect.top;
509 	if (windowStyle & WS_CHILD)
510 	{
511 		return 0;
512 	}
513 //	if (windowStyle & WS_MAXIMIZE)
514 //	{
515 //		doSize(SIZE_MAXIMIZED, windowWidth - dx, windowHeight - dy);
516 //	}
517 	if (windowWidth == createStruct->cx && windowHeight == createStruct->cy)
518 	{
519 		doSize(SIZE_RESTORED, createStruct->cx - dx, createStruct->cy - dy);
520 	}
521 	else if (windowWidth > createStruct->cx || windowHeight > createStruct->cy)
522 	{
523 		doSize(SIZE_MAXIMIZED, windowWidth - dx, windowHeight - dy);
524 	}
525 	else
526 	{
527 		doSize(SIZE_MINIMIZED, windowWidth - dx, windowHeight - dy);
528 	}
529 //	x = createStruct->x;
530 //	y = createStruct->y;
531 	return 0;
532 }
533 
doClose(void)534 LRESULT CUIWindow::doClose(void)
535 {
536 	return 1;
537 }
538 
doDestroy(void)539 LRESULT CUIWindow::doDestroy(void)
540 {
541 	return 1;
542 }
543 
doNCDestroy(void)544 LRESULT CUIWindow::doNCDestroy(void)
545 {
546 	// Clean up.
547 	SetWindowLongPtrUC(hWindow, GWLP_USERDATA, (LONG_PTR)NULL);
548 	hWindow = NULL;
549 	hdc = NULL;
550 	hParentWindow = NULL;
551 	initialized = FALSE;
552 	created = FALSE;
553 	return 1;
554 }
555 
doPaint(void)556 void CUIWindow::doPaint(void)
557 {
558 }
559 
doPostPaint(void)560 void CUIWindow::doPostPaint(void)
561 {
562 }
563 
doLButtonDown(WPARAM,int,int)564 LRESULT CUIWindow::doLButtonDown(WPARAM, int, int)
565 {
566 	return 1;
567 }
568 
doLButtonUp(WPARAM,int,int)569 LRESULT CUIWindow::doLButtonUp(WPARAM, int, int)
570 {
571 	return 1;
572 }
573 
doLButtonDoubleClick(WPARAM,int,int)574 LRESULT CUIWindow::doLButtonDoubleClick(WPARAM, int, int)
575 {
576 	return 1;
577 }
578 
doRButtonDown(WPARAM,int,int)579 LRESULT CUIWindow::doRButtonDown(WPARAM, int, int)
580 {
581 	return 1;
582 }
583 
doRButtonUp(WPARAM,int,int)584 LRESULT CUIWindow::doRButtonUp(WPARAM, int, int)
585 {
586 	return 1;
587 }
588 
doRButtonDoubleClick(WPARAM,int,int)589 LRESULT CUIWindow::doRButtonDoubleClick(WPARAM, int, int)
590 {
591 	return 1;
592 }
593 
doMButtonDown(WPARAM,int,int)594 LRESULT CUIWindow::doMButtonDown(WPARAM, int, int)
595 {
596 	return 1;
597 }
598 
doMButtonUp(WPARAM,int,int)599 LRESULT CUIWindow::doMButtonUp(WPARAM, int, int)
600 {
601 	return 1;
602 }
603 
doMButtonDoubleClick(WPARAM,int,int)604 LRESULT CUIWindow::doMButtonDoubleClick(WPARAM, int, int)
605 {
606 	return 1;
607 }
608 
doMouseMove(WPARAM,int,int)609 LRESULT CUIWindow::doMouseMove(WPARAM, int, int)
610 {
611 	return 1;
612 }
613 
doMouseWheel(short,short,int,int)614 LRESULT CUIWindow::doMouseWheel(short, short, int, int)
615 {
616 	return 1;
617 }
618 
doCaptureChanged(HWND)619 LRESULT CUIWindow::doCaptureChanged(HWND)
620 {
621 	return 1;
622 }
623 
doKeyDown(int,LPARAM)624 LRESULT CUIWindow::doKeyDown(int, LPARAM)
625 {
626 	return 1;
627 }
628 
doKeyUp(int,LPARAM)629 LRESULT CUIWindow::doKeyUp(int, LPARAM)
630 {
631 	return 1;
632 }
633 
doDropFiles(HDROP)634 LRESULT CUIWindow::doDropFiles(HDROP)
635 {
636 	return 1;
637 }
638 
doChar(UCCHAR,LPARAM)639 LRESULT CUIWindow::doChar(UCCHAR, LPARAM)
640 {
641 	return 1;
642 }
643 
doShowWindow(BOOL,LPARAM)644 LRESULT CUIWindow::doShowWindow(BOOL, LPARAM)
645 {
646 	return 1;
647 }
648 
doActivateApp(BOOL,DWORD)649 LRESULT CUIWindow::doActivateApp(BOOL, DWORD)
650 {
651 	return 1;
652 }
653 
doActivate(int,BOOL,HWND)654 LRESULT CUIWindow::doActivate(int, BOOL, HWND)
655 {
656 	return 1;
657 }
658 
redrawChildren(BOOL recurse)659 void CUIWindow::redrawChildren(BOOL recurse)
660 {
661 	int i;
662 
663 	for (i = 0; i < numChildren; i++)
664 	{
665 		children[i]->doPaint();
666 		if (recurse)
667 		{
668 			children[i]->redrawChildren(TRUE);
669 		}
670 	}
671 }
672 
doSystemColorChange(void)673 void CUIWindow::doSystemColorChange(void)
674 {
675 	updateSystemColors();
676 	redrawChildren(TRUE);
677 }
678 
calcSystemSizes(void)679 void CUIWindow::calcSystemSizes(void)
680 {
681 	if (systemMaxWidth == -1)
682 	{
683 		systemMaxWidth = GetSystemMetrics(SM_CXMAXIMIZED);
684 		systemMaxHeight = GetSystemMetrics(SM_CYMAXIMIZED);
685 		systemMinTrackWidth = GetSystemMetrics(SM_CXMINTRACK);
686 		systemMinTrackHeight = GetSystemMetrics(SM_CYMINTRACK);
687 		systemMaxTrackWidth = GetSystemMetrics(SM_CXMAXTRACK);
688 		systemMaxTrackHeight = GetSystemMetrics(SM_CYMAXTRACK);
689 	}
690 }
691 
doNotify(int,LPNMHDR)692 LRESULT CUIWindow::doNotify(int /*controlId*/, LPNMHDR /*notification*/)
693 {
694 	return 0;
695 }
696 
doGetMinMaxInfo(HWND hWnd,LPMINMAXINFO minMaxInfo)697 LRESULT CUIWindow::doGetMinMaxInfo(HWND hWnd, LPMINMAXINFO minMaxInfo)
698 {
699 	if (initialized && (windowStyle & WS_CHILD) == 0)
700 	{
701 		if (minWidth >= 0 || minHeight >= 0)
702 		{
703 			int realMaxWidth;
704 			int realMaxHeight;
705 			int minTrackWidth;
706 			int minTrackHeight;
707 			int maxTrackWidth;
708 			int maxTrackHeight;
709 			int decorationWidth;
710 			int decorationHeight;
711 			RECT clientRect;
712 			RECT windowRect;
713 
714 			GetClientRect(hWnd, &clientRect);
715 			GetWindowRect(hWnd, &windowRect);
716 			decorationWidth = (windowRect.right - windowRect.left) -
717 				(clientRect.right - clientRect.left);
718 			decorationHeight = (windowRect.bottom - windowRect.top) -
719 				(clientRect.bottom - clientRect.top);
720 			calcSystemSizes();
721 			int realMinWidth = scalePoints(minWidth);
722 			int realMinHeight = scalePoints(minHeight);
723 			if (maxWidth == -1)
724 			{
725 				realMaxWidth = systemMaxWidth;
726 			}
727 			else
728 			{
729 				realMaxWidth = maxWidth;
730 			}
731 			if (maxHeight == -1)
732 			{
733 				realMaxHeight = systemMaxHeight;
734 			}
735 			else
736 			{
737 				realMaxHeight = maxHeight;
738 			}
739 			if (minWidth == -1)
740 			{
741 				minTrackWidth = systemMinTrackWidth;
742 			}
743 			else if (realMinWidth + decorationWidth > systemMaxTrackWidth)
744 			{
745 				minTrackWidth = systemMaxTrackWidth;
746 			}
747 			else
748 			{
749 				minTrackWidth = realMinWidth + decorationWidth;
750 			}
751 			if (minHeight == -1)
752 			{
753 				minTrackHeight = systemMinTrackHeight;
754 			}
755 			else if (realMinHeight + decorationHeight > systemMaxTrackHeight)
756 			{
757 				minTrackHeight = systemMaxTrackHeight;
758 			}
759 			else
760 			{
761 				minTrackHeight = realMinHeight + decorationHeight;
762 			}
763 			if (maxWidth == -1)
764 			{
765 				maxTrackWidth = systemMaxTrackWidth;
766 			}
767 			else
768 			{
769 				maxTrackWidth = maxWidth;
770 			}
771 			if (maxHeight == -1)
772 			{
773 				maxTrackHeight = systemMaxTrackHeight;
774 			}
775 			else
776 			{
777 				maxTrackHeight = maxHeight;
778 			}
779 			minMaxInfo->ptMaxSize.x = realMaxWidth;
780 			minMaxInfo->ptMaxSize.y = realMaxHeight;
781 			minMaxInfo->ptMinTrackSize.x = minTrackWidth;
782 			minMaxInfo->ptMinTrackSize.y = minTrackHeight;
783 			minMaxInfo->ptMaxTrackSize.x = maxTrackWidth;
784 			minMaxInfo->ptMaxTrackSize.y = maxTrackHeight;
785 			return 0;
786 		}
787 	}
788 	return 1;
789 }
790 
printMessageName(UINT message)791 void CUIWindow::printMessageName(UINT message)
792 {
793 	printf("message: %s\n", getMessageName(message).c_str());
794 }
795 
getMessageName(UINT message)796 std::string CUIWindow::getMessageName(UINT message)
797 {
798 	switch (message)
799 	{
800 	case WM_NULL:
801 		return "WM_NULL";
802 	case WM_CREATE:
803 		return "WM_CREATE";
804 	case WM_DESTROY:
805 		return "WM_DESTROY";
806 	case WM_MOVE:
807 		return "WM_MOVE";
808 	case WM_SIZE:
809 		return "WM_SIZE";
810 	case WM_ACTIVATE:
811 		return "WM_ACTIVATE";
812 	case WM_SETFOCUS:
813 		return "WM_SETFOCUS";
814 	case WM_KILLFOCUS:
815 		return "WM_KILLFOCUS";
816 	case WM_ENABLE:
817 		return "WM_ENABLE";
818 	case WM_SETREDRAW:
819 		return "WM_SETREDRAW";
820 	case WM_SETTEXT:
821 		return "WM_SETTEXT";
822 	case WM_GETTEXT:
823 		return "WM_GETTEXT";
824 	case WM_GETTEXTLENGTH:
825 		return "WM_GETTEXTLENGTH";
826 	case WM_PAINT:
827 		return "WM_PAINT";
828 	case WM_CLOSE:
829 		return "WM_CLOSE";
830 	case WM_QUERYENDSESSION:
831 		return "WM_QUERYENDSESSION";
832 	case WM_QUIT:
833 		return "WM_QUIT";
834 	case WM_QUERYOPEN:
835 		return "WM_QUERYOPEN";
836 	case WM_ERASEBKGND:
837 		return "WM_ERASEBKGND";
838 	case WM_SYSCOLORCHANGE:
839 		return "WM_SYSCOLORCHANGE";
840 	case WM_ENDSESSION:
841 		return "WM_ENDSESSION";
842 	case WM_SHOWWINDOW:
843 		return "WM_SHOWWINDOW";
844 	case WM_SETTINGCHANGE:
845 		return "WM_SETTINGCHANGE";
846 	case WM_DEVMODECHANGE:
847 		return "WM_DEVMODECHANGE";
848 	case WM_ACTIVATEAPP:
849 		return "WM_ACTIVATEAPP";
850 	case WM_FONTCHANGE:
851 		return "WM_FONTCHANGE";
852 	case WM_TIMECHANGE:
853 		return "WM_TIMECHANGE";
854 	case WM_CANCELMODE:
855 		return "WM_CANCELMODE";
856 	case WM_SETCURSOR:
857 		return "WM_SETCURSOR";
858 	case WM_MOUSEACTIVATE:
859 		return "WM_MOUSEACTIVATE";
860 	case WM_CHILDACTIVATE:
861 		return "WM_CHILDACTIVATE";
862 	case WM_QUEUESYNC:
863 		return "WM_QUEUESYNC";
864 	case WM_GETMINMAXINFO:
865 		return "WM_GETMINMAXINFO";
866 	case WM_PAINTICON:
867 		return "WM_PAINTICON";
868 	case WM_ICONERASEBKGND:
869 		return "WM_ICONERASEBKGND";
870 	case WM_NEXTDLGCTL:
871 		return "WM_NEXTDLGCTL";
872 	case WM_SPOOLERSTATUS:
873 		return "WM_SPOOLERSTATUS";
874 	case WM_DRAWITEM:
875 		return "WM_DRAWITEM";
876 	case WM_MEASUREITEM:
877 		return "WM_MEASUREITEM";
878 	case WM_DELETEITEM:
879 		return "WM_DELETEITEM";
880 	case WM_VKEYTOITEM:
881 		return "WM_VKEYTOITEM";
882 	case WM_CHARTOITEM:
883 		return "WM_CHARTOITEM";
884 	case WM_SETFONT:
885 		return "WM_SETFONT";
886 	case WM_GETFONT:
887 		return "WM_GETFONT";
888 	case WM_SETHOTKEY:
889 		return "WM_SETHOTKEY";
890 	case WM_GETHOTKEY:
891 		return "WM_GETHOTKEY";
892 	case WM_QUERYDRAGICON:
893 		return "WM_QUERYDRAGICON";
894 	case WM_COMPAREITEM:
895 		return "WM_COMPAREITEM";
896 	case WM_COMPACTING:
897 		return "WM_COMPACTING";
898 	case WM_COMMNOTIFY:
899 		return "WM_COMMNOTIFY";
900 	case WM_WINDOWPOSCHANGING:
901 		return "WM_WINDOWPOSCHANGING";
902 	case WM_WINDOWPOSCHANGED:
903 		return "WM_WINDOWPOSCHANGED";
904 	case WM_POWER:
905 		return "WM_POWER";
906 	case WM_COPYDATA:
907 		return "WM_COPYDATA";
908 	case WM_CANCELJOURNAL:
909 		return "WM_CANCELJOURNAL";
910 	case WM_NOTIFY:
911 		return "WM_NOTIFY";
912 	case WM_INPUTLANGCHANGEREQUEST:
913 		return "WM_INPUTLANGCHANGEREQUEST";
914 	case WM_INPUTLANGCHANGE:
915 		return "WM_INPUTLANGCHANGE";
916 	case WM_TCARD:
917 		return "WM_TCARD";
918 	case WM_HELP:
919 		return "WM_HELP";
920 	case WM_USERCHANGED:
921 		return "WM_USERCHANGED";
922 	case WM_NOTIFYFORMAT:
923 		return "WM_NOTIFYFORMAT";
924 	case WM_CONTEXTMENU:
925 		return "WM_CONTEXTMENU";
926 	case WM_STYLECHANGING:
927 		return "WM_STYLECHANGING";
928 	case WM_STYLECHANGED:
929 		return "WM_STYLECHANGED";
930 	case WM_DISPLAYCHANGE:
931 		return "WM_DISPLAYCHANGE";
932 	case WM_GETICON:
933 		return "WM_GETICON";
934 	case WM_SETICON:
935 		return "WM_SETICON";
936 	case WM_NCCREATE:
937 		return "WM_NCCREATE";
938 	case WM_NCDESTROY:
939 		return "WM_NCDESTROY";
940 	case WM_NCCALCSIZE:
941 		return "WM_NCCALCSIZE";
942 	case WM_NCHITTEST:
943 		return "WM_NCHITTEST";
944 	case WM_NCPAINT:
945 		return "WM_NCPAINT";
946 	case WM_NCACTIVATE:
947 		return "WM_NCACTIVATE";
948 	case WM_GETDLGCODE:
949 		return "WM_GETDLGCODE";
950 	case WM_SYNCPAINT:
951 		return "WM_SYNCPAINT";
952 	case WM_NCMOUSEMOVE:
953 		return "WM_NCMOUSEMOVE";
954 	case WM_NCLBUTTONDOWN:
955 		return "WM_NCLBUTTONDOWN";
956 	case WM_NCLBUTTONUP:
957 		return "WM_NCLBUTTONUP";
958 	case WM_NCLBUTTONDBLCLK:
959 		return "WM_NCLBUTTONDBLCLK";
960 	case WM_NCRBUTTONDOWN:
961 		return "WM_NCRBUTTONDOWN";
962 	case WM_NCRBUTTONUP:
963 		return "WM_NCRBUTTONUP";
964 	case WM_NCRBUTTONDBLCLK:
965 		return "WM_NCRBUTTONDBLCLK";
966 	case WM_NCMBUTTONDOWN:
967 		return "WM_NCMBUTTONDOWN";
968 	case WM_NCMBUTTONUP:
969 		return "WM_NCMBUTTONUP";
970 	case WM_NCMBUTTONDBLCLK:
971 		return "WM_NCMBUTTONDBLCLK";
972 	case WM_KEYDOWN:
973 		return "WM_KEYDOWN";
974 	case WM_KEYUP:
975 		return "WM_KEYUP";
976 	case WM_CHAR:
977 		return "WM_CHAR";
978 	case WM_DEADCHAR:
979 		return "WM_DEADCHAR";
980 	case WM_SYSKEYDOWN:
981 		return "WM_SYSKEYDOWN";
982 	case WM_SYSKEYUP:
983 		return "WM_SYSKEYUP";
984 	case WM_SYSCHAR:
985 		return "WM_SYSCHAR";
986 	case WM_SYSDEADCHAR:
987 		return "WM_SYSDEADCHAR";
988 	case WM_KEYLAST:
989 		return "WM_KEYLAST";
990 	case WM_IME_STARTCOMPOSITION:
991 		return "WM_IME_STARTCOMPOSITION";
992 	case WM_IME_ENDCOMPOSITION:
993 		return "WM_IME_ENDCOMPOSITION";
994 	case WM_IME_COMPOSITION:
995 		return "WM_IME_COMPOSITION";
996 	case WM_INITDIALOG:
997 		return "WM_INITDIALOG";
998 	case WM_COMMAND:
999 		return "WM_COMMAND";
1000 	case WM_SYSCOMMAND:
1001 		return "WM_SYSCOMMAND";
1002 	case WM_TIMER:
1003 		return "WM_TIMER";
1004 	case WM_HSCROLL:
1005 		return "WM_HSCROLL";
1006 	case WM_VSCROLL:
1007 		return "WM_VSCROLL";
1008 	case WM_INITMENU:
1009 		return "WM_INITMENU";
1010 	case WM_INITMENUPOPUP:
1011 		return "WM_INITMENUPOPUP";
1012 	case WM_MENUSELECT:
1013 		return "WM_MENUSELECT";
1014 	case WM_MENUCHAR:
1015 		return "WM_MENUCHAR";
1016 	case WM_ENTERIDLE:
1017 		return "WM_ENTERIDLE";
1018 	case WM_CTLCOLORMSGBOX:
1019 		return "WM_CTLCOLORMSGBOX";
1020 	case WM_CTLCOLOREDIT:
1021 		return "WM_CTLCOLOREDIT";
1022 	case WM_CTLCOLORLISTBOX:
1023 		return "WM_CTLCOLORLISTBOX";
1024 	case WM_CTLCOLORBTN:
1025 		return "WM_CTLCOLORBTN";
1026 	case WM_CTLCOLORDLG:
1027 		return "WM_CTLCOLORDLG";
1028 	case WM_CTLCOLORSCROLLBAR:
1029 		return "WM_CTLCOLORSCROLLBAR";
1030 	case WM_CTLCOLORSTATIC:
1031 		return "WM_CTLCOLORSTATIC";
1032 	case WM_MOUSEMOVE:
1033 		return "WM_MOUSEMOVE";
1034 	case WM_LBUTTONDOWN:
1035 		return "WM_LBUTTONDOWN";
1036 	case WM_LBUTTONUP:
1037 		return "WM_LBUTTONUP";
1038 	case WM_LBUTTONDBLCLK:
1039 		return "WM_LBUTTONDBLCLK";
1040 	case WM_RBUTTONDOWN:
1041 		return "WM_RBUTTONDOWN";
1042 	case WM_RBUTTONUP:
1043 		return "WM_RBUTTONUP";
1044 	case WM_RBUTTONDBLCLK:
1045 		return "WM_RBUTTONDBLCLK";
1046 	case WM_MBUTTONDOWN:
1047 		return "WM_MBUTTONDOWN";
1048 	case WM_MBUTTONUP:
1049 		return "WM_MBUTTONUP";
1050 	case WM_MBUTTONDBLCLK:
1051 		return "WM_MBUTTONDBLCLK";
1052 	case WM_MOUSEWHEEL:
1053 		return "WM_MOUSEWHEEL";
1054 	case WM_PARENTNOTIFY:
1055 		return "WM_PARENTNOTIFY";
1056 	case WM_ENTERMENULOOP:
1057 		return "WM_ENTERMENULOOP";
1058 	case WM_EXITMENULOOP:
1059 		return "WM_EXITMENULOOP";
1060 	case WM_SIZING:
1061 		return "WM_SIZING";
1062 	case WM_CAPTURECHANGED:
1063 		return "WM_CAPTURECHANGED";
1064 	case WM_MOVING:
1065 		return "WM_MOVING";
1066 	case WM_POWERBROADCAST:
1067 		return "WM_POWERBROADCAST";
1068 	case WM_DEVICECHANGE:
1069 		return "WM_DEVICECHANGE";
1070 	case WM_MDICREATE:
1071 		return "WM_MDICREATE";
1072 	case WM_MDIDESTROY:
1073 		return "WM_MDIDESTROY";
1074 	case WM_MDIACTIVATE:
1075 		return "WM_MDIACTIVATE";
1076 	case WM_MDIRESTORE:
1077 		return "WM_MDIRESTORE";
1078 	case WM_MDINEXT:
1079 		return "WM_MDINEXT";
1080 	case WM_MDIMAXIMIZE:
1081 		return "WM_MDIMAXIMIZE";
1082 	case WM_MDITILE:
1083 		return "WM_MDITILE";
1084 	case WM_MDICASCADE:
1085 		return "WM_MDICASCADE";
1086 	case WM_MDIICONARRANGE:
1087 		return "WM_MDIICONARRANGE";
1088 	case WM_MDIGETACTIVE:
1089 		return "WM_MDIGETACTIVE";
1090 	case WM_MDISETMENU:
1091 		return "WM_MDISETMENU";
1092 	case WM_ENTERSIZEMOVE:
1093 		return "WM_ENTERSIZEMOVE";
1094 	case WM_EXITSIZEMOVE:
1095 		return "WM_EXITSIZEMOVE";
1096 	case WM_DROPFILES:
1097 		return "WM_DROPFILES";
1098 	case WM_MDIREFRESHMENU:
1099 		return "WM_MDIREFRESHMENU";
1100 	case WM_IME_SETCONTEXT:
1101 		return "WM_IME_SETCONTEXT";
1102 	case WM_IME_NOTIFY:
1103 		return "WM_IME_NOTIFY";
1104 	case WM_IME_CONTROL:
1105 		return "WM_IME_CONTROL";
1106 	case WM_IME_COMPOSITIONFULL:
1107 		return "WM_IME_COMPOSITIONFULL";
1108 	case WM_IME_SELECT:
1109 		return "WM_IME_SELECT";
1110 	case WM_IME_CHAR:
1111 		return "WM_IME_CHAR";
1112 	case WM_IME_KEYDOWN:
1113 		return "WM_IME_KEYDOWN";
1114 	case WM_IME_KEYUP:
1115 		return "WM_IME_KEYUP";
1116 	case WM_MOUSEHOVER:
1117 		return "WM_MOUSEHOVER";
1118 	case WM_MOUSELEAVE:
1119 		return "WM_MOUSELEAVE";
1120 	case WM_CUT:
1121 		return "WM_CUT";
1122 	case WM_COPY:
1123 		return "WM_COPY";
1124 	case WM_PASTE:
1125 		return "WM_PASTE";
1126 	case WM_CLEAR:
1127 		return "WM_CLEAR";
1128 	case WM_UNDO:
1129 		return "WM_UNDO";
1130 	case WM_RENDERFORMAT:
1131 		return "WM_RENDERFORMAT";
1132 	case WM_RENDERALLFORMATS:
1133 		return "WM_RENDERALLFORMATS";
1134 	case WM_DESTROYCLIPBOARD:
1135 		return "WM_DESTROYCLIPBOARD";
1136 	case WM_DRAWCLIPBOARD:
1137 		return "WM_DRAWCLIPBOARD";
1138 	case WM_PAINTCLIPBOARD:
1139 		return "WM_PAINTCLIPBOARD";
1140 	case WM_VSCROLLCLIPBOARD:
1141 		return "WM_VSCROLLCLIPBOARD";
1142 	case WM_SIZECLIPBOARD:
1143 		return "WM_SIZECLIPBOARD";
1144 	case WM_ASKCBFORMATNAME:
1145 		return "WM_ASKCBFORMATNAME";
1146 	case WM_CHANGECBCHAIN:
1147 		return "WM_CHANGECBCHAIN";
1148 	case WM_HSCROLLCLIPBOARD:
1149 		return "WM_HSCROLLCLIPBOARD";
1150 	case WM_QUERYNEWPALETTE:
1151 		return "WM_QUERYNEWPALETTE";
1152 	case WM_PALETTEISCHANGING:
1153 		return "WM_PALETTEISCHANGING";
1154 	case WM_PALETTECHANGED:
1155 		return "WM_PALETTECHANGED";
1156 	case WM_HOTKEY:
1157 		return "WM_HOTKEY";
1158 	case WM_PRINT:
1159 		return "WM_PRINT";
1160 	case WM_PRINTCLIENT:
1161 		return "WM_PRINTCLIENT";
1162 	case BM_GETCHECK:
1163 		return "BM_GETCHECK";
1164 	case BM_SETCHECK:
1165 		return "BM_SETCHECK";
1166 	case BM_GETSTATE:
1167 		return "BM_GETSTATE";
1168 	case BM_SETSTATE:
1169 		return "BM_SETSTATE";
1170 	case BM_SETSTYLE:
1171 		return "BM_SETSTYLE";
1172 	case BM_CLICK:
1173 		return "BM_CLICK";
1174 	case BM_GETIMAGE:
1175 		return "BM_GETIMAGE";
1176 	case BM_SETIMAGE:
1177 		return "BM_SETIMAGE";
1178 	default:
1179 		{
1180 			char string[128];
1181 
1182 			sprintf(string, "0x%04X", message);
1183 			return string;
1184 		}
1185 	}
1186 }
1187 
windowProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)1188 LRESULT CUIWindow::windowProc(HWND hWnd, UINT message, WPARAM wParam,
1189 							  LPARAM lParam)
1190 {
1191 	LRESULT rval;
1192 	RECT updateRect;
1193 
1194 	if ((windowClassStyle & CS_OWNDC) && !hdc)
1195 	{
1196 		hdc = GetDC(hWnd);
1197 	}
1198 //	printf("%s\n", windowClassName());
1199 //	printf("0x%08X 0x%08X 0x%08X ", hWnd, wParam, lParam);
1200 //	printMessageName(message);
1201 #ifdef _DEBUG
1202 //	_CrtDbgReport(_CRT_WARN, NULL, 0, NULL, "wMsg: 0x%X\n", message);
1203 #endif // _DEBUG
1204 	switch (message)
1205 	{
1206 		case WM_CREATE:
1207 			return doCreate(hWnd, (LPCREATESTRUCT)lParam);
1208 			break;
1209 		case WM_GETMINMAXINFO:
1210 			if (!doGetMinMaxInfo(hWnd, (LPMINMAXINFO)lParam))
1211 			{
1212 				return 0;
1213 			}
1214 			break;
1215 		case WM_SHOWWINDOW:
1216 			if (!doShowWindow((BOOL)wParam, lParam))
1217 			{
1218 				return 0;
1219 			}
1220 			break;
1221 		case WM_ACTIVATEAPP:
1222 			if (!doActivateApp((BOOL)wParam, (DWORD)lParam))
1223 			{
1224 				return 0;
1225 			}
1226 			break;
1227 		case WM_ACTIVATE:
1228 			if (!doActivate((int)(unsigned short)LOWORD(wParam),
1229 				(BOOL)(unsigned short)HIWORD(wParam), (HWND)lParam))
1230 			{
1231 				return 0;
1232 			}
1233 			break;
1234 		case WM_SIZE:
1235 			if (!doSize(wParam, (int)(short)LOWORD(lParam),
1236 				(int)(short)HIWORD(lParam)))
1237 			{
1238 				return 0;
1239 			}
1240 			break;
1241 		case WM_MOVE:
1242 			if (!doMove((int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam)))
1243 			{
1244 				return 0;
1245 			}
1246 			break;
1247 		case WM_ERASEBKGND:
1248 			{
1249 				BOOL hadHdc = hdc != NULL;
1250 
1251 				if (!hadHdc)
1252 				{
1253 					hdc = (HDC)wParam;
1254 				}
1255 				if ((rval = doEraseBackground()) != 0)
1256 				{
1257 					if (!hadHdc)
1258 					{
1259 						hdc = NULL;
1260 					}
1261 					return rval;
1262 				}
1263 				if (!hadHdc)
1264 				{
1265 					hdc = NULL;
1266 				}
1267 			}
1268 			break;
1269 		case WM_CLOSE:
1270 			if (!doClose())
1271 			{
1272 				return 0;
1273 			}
1274 			break;
1275 		case WM_DESTROY:
1276 			if (!doDestroy())
1277 			{
1278 				return 0;
1279 			}
1280 			break;
1281 		case WM_NCDESTROY:
1282 			if (!doNCDestroy())
1283 			{
1284 				return 0;
1285 			}
1286 			break;
1287 		case WM_COMMAND:
1288 			if (!doCommand((int)(unsigned short)LOWORD(wParam),
1289 				(int)(unsigned short)HIWORD(wParam), (HWND)lParam))
1290 			{
1291 				return 0;
1292 			}
1293 			break;
1294 		case WM_PAINT:
1295 			if (GetUpdateRect(hWnd, &updateRect, FALSE))
1296 			{
1297 				bool paintStructAllocated = false;
1298 
1299 				if (!paintStruct)
1300 				{
1301 					paintStruct = new PAINTSTRUCT;
1302 					paintStructAllocated = true;
1303 				}
1304 				if (windowClassStyle & CS_OWNDC)
1305 				{
1306 					if (BeginPaint(hWnd, paintStruct))
1307 					{
1308 						doPaint();
1309 						EndPaint(hWnd, paintStruct);
1310 					}
1311 				}
1312 				else
1313 				{
1314 					hdc = BeginPaint(hWnd, paintStruct);
1315 					if (hdc)
1316 					{
1317 						if (paintStruct->fErase)
1318 						{
1319 							doEraseBackground(&updateRect);
1320 						}
1321 						doPaint();
1322 						hdc = NULL;
1323 						EndPaint(hWnd, paintStruct);
1324 					}
1325 				}
1326 				if (paintStructAllocated)
1327 				{
1328 					delete paintStruct;
1329 					paintStruct = NULL;
1330 				}
1331 				doPostPaint();
1332 				return 0;
1333 			}
1334 			break;
1335 		case WM_LBUTTONDOWN:
1336 			if (!doLButtonDown(wParam, (int)(short)LOWORD(lParam),
1337 				(int)(short)HIWORD(lParam)))
1338 			{
1339 				return 0;
1340 			}
1341 			break;
1342 		case WM_LBUTTONUP:
1343 			if (!doLButtonUp(wParam, (int)(short)LOWORD(lParam),
1344 				(int)(short)HIWORD(lParam)))
1345 			{
1346 				return 0;
1347 			}
1348 			break;
1349 		case WM_LBUTTONDBLCLK:
1350 			if (!doLButtonDoubleClick(wParam, (int)(short)LOWORD(lParam),
1351 				(int)(short)HIWORD(lParam)))
1352 			{
1353 				return 0;
1354 			}
1355 			break;
1356 		case WM_RBUTTONDOWN:
1357 			if (!doRButtonDown(wParam, (int)(short)LOWORD(lParam),
1358 				(int)(short)HIWORD(lParam)))
1359 			{
1360 				return 0;
1361 			}
1362 			break;
1363 		case WM_RBUTTONUP:
1364 			if (!doRButtonUp(wParam, (int)(short)LOWORD(lParam),
1365 				(int)(short)HIWORD(lParam)))
1366 			{
1367 				return 0;
1368 			}
1369 			break;
1370 		case WM_RBUTTONDBLCLK:
1371 			if (!doRButtonDoubleClick(wParam, (int)(short)LOWORD(lParam),
1372 				(int)(short)HIWORD(lParam)))
1373 			{
1374 				return 0;
1375 			}
1376 			break;
1377 		case WM_MBUTTONDOWN:
1378 			if (!doMButtonDown(wParam, (int)(short)LOWORD(lParam),
1379 				(int)(short)HIWORD(lParam)))
1380 			{
1381 				return 0;
1382 			}
1383 			break;
1384 		case WM_MBUTTONUP:
1385 			if (!doMButtonUp(wParam, (int)(short)LOWORD(lParam),
1386 				(int)(short)HIWORD(lParam)))
1387 			{
1388 				return 0;
1389 			}
1390 			break;
1391 		case WM_MBUTTONDBLCLK:
1392 			if (!doMButtonDoubleClick(wParam, (int)(short)LOWORD(lParam),
1393 				(int)(short)HIWORD(lParam)))
1394 			{
1395 				return 0;
1396 			}
1397 			break;
1398 		case WM_MOUSEMOVE:
1399 			if (!doMouseMove(wParam, (int)(short)LOWORD(lParam),
1400 				(int)(short)HIWORD(lParam)))
1401 			{
1402 				return 0;
1403 			}
1404 			break;
1405 		case WM_MOUSEWHEEL:
1406 			if (!doMouseWheel(LOWORD(wParam), HIWORD(wParam),
1407 				(int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam)))
1408 			{
1409 				return 0;
1410 			}
1411 			break;
1412 		case WM_CAPTURECHANGED:
1413 			if (!doCaptureChanged((HWND)lParam))
1414 			{
1415 				return 0;
1416 			}
1417 			break;
1418 		case WM_KEYDOWN:
1419 			if (!doKeyDown((int)wParam, lParam))
1420 			{
1421 				return 0;
1422 			}
1423 			break;
1424 		case WM_KEYUP:
1425 			if (!doKeyUp((int)wParam, lParam))
1426 			{
1427 				return 0;
1428 			}
1429 			break;
1430 		case WM_DROPFILES:
1431 			if (!doDropFiles((HDROP)wParam))
1432 			{
1433 				return 0;
1434 			}
1435 			break;
1436 		case WM_SYSCOLORCHANGE:
1437 			doSystemColorChange();
1438 			break;
1439 		case WM_CHAR:
1440 			if (!doChar((UCCHAR)wParam, lParam))
1441 			{
1442 				return 0;
1443 			}
1444 			break;
1445 		case WM_TIMER:
1446 			if (!lParam && !doTimer((UINT_PTR)wParam))
1447 			{
1448 				return 0;
1449 			}
1450 			break;
1451 		case WM_HELP:
1452 			if (doHelp((LPHELPINFO)lParam))
1453 			{
1454 				return TRUE;
1455 			}
1456 			break;
1457 		case WM_MENUSELECT:
1458 			if (!doMenuSelect(LOWORD(wParam), HIWORD(wParam), (HMENU)lParam))
1459 			{
1460 				return 0;
1461 			}
1462 			break;
1463 		case WM_ENTERMENULOOP:
1464 			if (!doEnterMenuLoop(wParam ? true : false))
1465 			{
1466 				return 0;
1467 			}
1468 			break;
1469 		case WM_EXITMENULOOP:
1470 			if (!doExitMenuLoop(wParam ? true : false))
1471 			{
1472 				return 0;
1473 			}
1474 			break;
1475 		case WM_INITMENUPOPUP:
1476 			if (!doInitMenuPopup((HMENU)wParam, (UINT)LOWORD(lParam),
1477 				(BOOL)HIWORD(lParam)))
1478 			{
1479 				return 0;
1480 			}
1481 			break;
1482 		case WM_DRAWITEM:
1483 			if (doDrawItem((HWND)wParam, (LPDRAWITEMSTRUCT)lParam))
1484 			{
1485 				return TRUE;
1486 			}
1487 			break;
1488 		case WM_THEMECHANGED:
1489 			if (!doThemeChanged())
1490 			{
1491 				return 0;
1492 			}
1493 			break;
1494 		case WM_NOTIFY:
1495 			return doNotify((int)(short)LOWORD(wParam), (LPNMHDR)lParam);
1496 			break;
1497 		case WM_DPICHANGED:
1498 			return doDpiChanged((int)(short)LOWORD(wParam), (int)(short)HIWORD(wParam),
1499 				(RECT*)lParam);
1500 			break;
1501 		default:
1502 			break;
1503 	}
1504 	return DefWindowProc(hWnd, message, wParam, lParam);
1505 }
1506 
doDpiChanged(int dpiX,int dpiY,RECT * proposedRect)1507 LRESULT CUIWindow::doDpiChanged(int dpiX, int dpiY, RECT* proposedRect)
1508 {
1509 	initScaler();
1510 	scaler->setDpi(dpiX, dpiY);
1511 	if (handleDpiChange())
1512 	{
1513 		SetWindowPos(hWindow, NULL,
1514 			proposedRect->left,
1515 			proposedRect->top,
1516 			proposedRect->right - proposedRect->left,
1517 			proposedRect->bottom - proposedRect->top,
1518 			SWP_NOZORDER | SWP_NOACTIVATE);
1519 	}
1520 	return 0;
1521 }
1522 
staticWindowProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)1523 LRESULT CALLBACK CUIWindow::staticWindowProc(HWND hWnd, UINT message,
1524 											WPARAM wParam, LPARAM lParam)
1525 {
1526 	CUIWindow* cuiWindow = (CUIWindow*)GetWindowLongPtrUC(hWnd, GWLP_USERDATA);
1527 
1528 	if (!cuiWindow)
1529 	{
1530 		if (message == WM_CREATE || message == WM_NCCREATE)
1531 		{
1532 			CREATESTRUCT* createStruct = (LPCREATESTRUCT)lParam;
1533 
1534 			cuiWindow = (CUIWindow*)(createStruct->lpCreateParams);
1535 			if (cuiWindow)
1536 			{
1537 				SetWindowLongPtrUC(hWnd, GWLP_USERDATA, (LONG_PTR)cuiWindow);
1538 			}
1539 		}
1540 		else
1541 		{
1542 			return DefWindowProc(hWnd, message, wParam, lParam);
1543 		}
1544 	}
1545 	if (cuiWindow)
1546 	{
1547 		return cuiWindow->windowProc(hWnd, message, wParam, lParam);
1548 	}
1549 	else
1550 	{
1551 		return DefWindowProc(hWnd, message, wParam, lParam);
1552 	}
1553 }
1554 
disableNonModalWindow(HWND hWnd,LPARAM hModalDialog)1555 BOOL CALLBACK CUIWindow::disableNonModalWindow(HWND hWnd, LPARAM hModalDialog)
1556 {
1557 	if (hWnd != (HWND)hModalDialog)
1558 	{
1559 		EnableWindow(hWnd, FALSE);
1560 	}
1561 	return TRUE;
1562 }
1563 
enableNonModalWindow(HWND hWnd,LPARAM hModalDialog)1564 BOOL CALLBACK CUIWindow::enableNonModalWindow(HWND hWnd, LPARAM hModalDialog)
1565 {
1566 	if (hWnd != (HWND)hModalDialog)
1567 	{
1568 		EnableWindow(hWnd, TRUE);
1569 	}
1570 	return TRUE;
1571 }
1572 
runDialogModal(HWND hDlg,bool allowMessages)1573 void CUIWindow::runDialogModal(HWND hDlg, bool allowMessages)
1574 {
1575 	DWORD processId = GetCurrentProcessId();
1576 	DWORD dlgProcessId;
1577 
1578 	if (hDlg == NULL || GetWindowThreadProcessId(hDlg, &dlgProcessId) == 0 ||
1579 		processId != dlgProcessId)
1580 	{
1581 		// If we get garbage input to this function, we end up disabling
1582 		// ALL windows on the whole screen, instead of just the LDView ones.
1583 		// That makes life difficult on the user.
1584 		return;
1585 	}
1586 	ShowWindow(hDlg, SW_SHOWNORMAL);
1587 	EnumThreadWindows(GetWindowThreadProcessId(hDlg, NULL),
1588 		disableNonModalWindow, (LPARAM)hDlg);
1589 	while (1)
1590 	{
1591 		MSG msg;
1592 
1593 		if (!GetMessage(&msg, NULL, 0, 0))
1594 		{
1595 			doDialogClose(hDlg);
1596 		}
1597 		if (allowMessages || msg.hwnd == hDlg || IsChild(hDlg, msg.hwnd))
1598 		{
1599 			if (!IsDialogMessage(hDlg, &msg))
1600 			{
1601 				TranslateMessage(&msg);
1602 				DispatchMessage(&msg);
1603 			}
1604 			else
1605 			{
1606 			}
1607 		}
1608 		else
1609 		{
1610 			if (msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST &&
1611 				msg.message != WM_MOUSEMOVE && msg.message != WM_ACTIVATE)
1612 			{
1613 				MessageBeep(MB_OK);
1614 			}
1615 			else
1616 			{
1617 				TranslateMessage(&msg);
1618 				DispatchMessage(&msg);
1619 			}
1620 		}
1621 		if (!IsWindow(hDlg) || !IsWindowVisible(hDlg))
1622 		{
1623 			break;
1624 		}
1625 	}
1626 }
1627 
flushDialogModal(HWND hDlg)1628 bool CUIWindow::flushDialogModal(HWND hDlg)
1629 {
1630 	return flushModal(hDlg, true);
1631 }
1632 
processModalMessage(MSG msg)1633 void CUIWindow::processModalMessage(MSG msg)
1634 {
1635 	TranslateMessage(&msg);
1636 	DispatchMessage(&msg);
1637 }
1638 
flushModal(HWND hWnd,bool isDialog,int maxFlush)1639 bool CUIWindow::flushModal(HWND hWnd, bool isDialog, int maxFlush)
1640 {
1641 	int i = maxFlush;
1642 	MSG lastMsg = {0};
1643 	bool firstMessage = true;
1644 
1645 	if (!IsWindowVisible(hWnd))
1646 	{
1647 		ShowWindow(hWnd, SW_SHOWNORMAL);
1648 	}
1649 	EnumThreadWindows(GetWindowThreadProcessId(hWnd, NULL),
1650 		disableNonModalWindow, (LPARAM)hWnd);
1651 	while (1)
1652 	{
1653 		MSG msg;
1654 
1655 		if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
1656 		{
1657 			break;
1658 		}
1659 		if (msg.message == WM_QUIT)
1660 		{
1661 			return false;
1662 		}
1663 //		printf("0x%08x\n", msg.hwnd);
1664 //		printMessageName(msg.message);
1665 		if (msg.hwnd == hWnd || IsChild(hWnd, msg.hwnd))
1666 		{
1667 			if (!isDialog || !IsDialogMessage(hWnd, &msg))
1668 			{
1669 				// This message checking code is a hack, but for some reason
1670 				// the toolbar goes into an infinite paint loop if I don't do
1671 				// it.
1672 				if (firstMessage || lastMsg.hwnd != msg.hwnd ||
1673 					lastMsg.message != msg.message)
1674 				{
1675 					processModalMessage(msg);
1676 				}
1677 				else
1678 				{
1679 					if (msg.message == WM_PAINT)
1680 					{
1681 						// More of the hack: break the infinite paint loop by
1682 						// claiming it's no longer needed.
1683 						ValidateRect(msg.hwnd, NULL);
1684 					}
1685 				}
1686 			}
1687 			else
1688 			{
1689 			}
1690 		}
1691 		else
1692 		{
1693 			if (msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST &&
1694 				msg.message != WM_MOUSEMOVE && msg.message != WM_ACTIVATE)
1695 			{
1696 				MessageBeep(MB_OK);
1697 			}
1698 			else
1699 			{
1700 				TranslateMessage(&msg);
1701 				DispatchMessage(&msg);
1702 			}
1703 		}
1704 		if (!IsWindow(hWnd) || !IsWindowVisible(hWnd))
1705 		{
1706 			break;
1707 		}
1708 		if (i-- == 0)
1709 		{
1710 			break;
1711 		}
1712 		firstMessage = false;
1713 		lastMsg = msg;
1714 	}
1715 	return true;
1716 }
1717 
doDialogClose(HWND hDlg)1718 void CUIWindow::doDialogClose(HWND hDlg)
1719 {
1720 	EnumThreadWindows(GetWindowThreadProcessId(hDlg, NULL),
1721 		enableNonModalWindow, (LPARAM)hDlg);
1722 	ShowWindow(hDlg, SW_HIDE);
1723 }
1724 
doDialogThemeChanged(void)1725 BOOL CUIWindow::doDialogThemeChanged(void)
1726 {
1727 	return TRUE;
1728 }
1729 
doDialogCommand(HWND,int,int,HWND)1730 BOOL CUIWindow::doDialogCommand(HWND, int, int, HWND)
1731 {
1732 	return FALSE;
1733 }
1734 
doDialogVScroll(HWND,int,int,HWND)1735 BOOL CUIWindow::doDialogVScroll(HWND, int, int, HWND)
1736 {
1737 	return FALSE;
1738 }
1739 
doDialogHScroll(HWND,int,int,HWND)1740 BOOL CUIWindow::doDialogHScroll(HWND, int, int, HWND)
1741 {
1742 	return FALSE;
1743 }
1744 
doDialogInit(HWND,HWND,LPARAM)1745 BOOL CUIWindow::doDialogInit(HWND, HWND, LPARAM)
1746 {
1747 	return TRUE;
1748 }
1749 
doDialogNotify(HWND,int,LPNMHDR)1750 BOOL CUIWindow::doDialogNotify(HWND, int, LPNMHDR)
1751 {
1752 	return FALSE;
1753 }
1754 
doDialogSize(HWND,WPARAM,int,int)1755 BOOL CUIWindow::doDialogSize(HWND, WPARAM, int, int)
1756 {
1757 	return FALSE;
1758 }
1759 
doDialogGetMinMaxInfo(HWND,LPMINMAXINFO)1760 BOOL CUIWindow::doDialogGetMinMaxInfo(HWND, LPMINMAXINFO)
1761 {
1762 	return FALSE;
1763 }
1764 
doDialogChar(HWND,UCCHAR,LPARAM)1765 BOOL CUIWindow::doDialogChar(HWND, UCCHAR, LPARAM)
1766 {
1767 	return FALSE;
1768 }
1769 
doDialogHelp(HWND,LPHELPINFO)1770 BOOL CUIWindow::doDialogHelp(HWND, LPHELPINFO)
1771 {
1772 	return FALSE;
1773 }
1774 
doDialogCtlColorStatic(HDC,HWND)1775 BOOL CUIWindow::doDialogCtlColorStatic(HDC /*hdcStatic*/, HWND)
1776 {
1777 	return FALSE;
1778 }
1779 
doDialogCtlColorBtn(HDC,HWND)1780 BOOL CUIWindow::doDialogCtlColorBtn(HDC /*hdcStatic*/, HWND)
1781 {
1782 	return FALSE;
1783 }
1784 
dialogProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)1785 INT_PTR CUIWindow::dialogProc(
1786 	HWND hDlg,
1787 	UINT message,
1788 	WPARAM wParam,
1789 	LPARAM lParam)
1790 {
1791 //	printf("CUIWindow::dialogProc(0x%04X, 0x%04X, 0x%08X, 0x%08X)\n", hDlg,
1792 //		message, wParam, lParam);
1793 	BOOL retValue;
1794 
1795 	switch (message)
1796 	{
1797 		case WM_INITDIALOG:
1798 			return doDialogInit(hDlg, (HWND)wParam, lParam);
1799 			break;
1800 		case WM_CLOSE:
1801 			doDialogClose(hDlg);
1802 			break;
1803 		case WM_COMMAND:
1804 			return doDialogCommand(hDlg, (int)(short)LOWORD(wParam),
1805 				(int)(short)HIWORD(wParam), (HWND)lParam);
1806 			break;
1807 		case WM_VSCROLL:
1808 			return doDialogVScroll(hDlg, (int)(short)LOWORD(wParam),
1809 				(int)(short)HIWORD(wParam), (HWND)lParam);
1810 			break;
1811 		case WM_HSCROLL:
1812 			return doDialogHScroll(hDlg, (int)(short)LOWORD(wParam),
1813 				(int)(short)HIWORD(wParam), (HWND)lParam);
1814 			break;
1815 		case WM_NOTIFY:
1816 			return doDialogNotify(hDlg, (int)(short)LOWORD(wParam),
1817 				(LPNMHDR)lParam);
1818 			break;
1819 		case WM_SIZE:
1820 			return doDialogSize(hDlg, wParam, (int)(short)LOWORD(lParam),
1821 				(int)(short)HIWORD(lParam));
1822 			break;
1823 		case WM_GETMINMAXINFO:
1824 			return doDialogGetMinMaxInfo(hDlg, (LPMINMAXINFO)lParam);
1825 			break;
1826 		case WM_CHAR:
1827 			return doDialogChar(hDlg, (UCCHAR)wParam, lParam);
1828 			break;
1829 		case WM_HELP:
1830 			return doDialogHelp(hDlg, (LPHELPINFO)lParam);
1831 			break;
1832 		case WM_THEMECHANGED:
1833 			return doDialogThemeChanged();
1834 			break;
1835 		case WM_CTLCOLORSTATIC:
1836 			retValue = doDialogCtlColorStatic((HDC)wParam, (HWND)lParam);
1837 			if (retValue)
1838 			{
1839 				return retValue;
1840 			}
1841 			break;
1842 		case WM_CTLCOLORBTN:
1843 			retValue = doDialogCtlColorBtn((HDC)wParam, (HWND)lParam);
1844 			if (retValue)
1845 			{
1846 				return retValue;
1847 			}
1848 			break;
1849 		default:
1850 			return FALSE;
1851 			break;
1852 	}
1853 	return FALSE;
1854 }
1855 
staticDialogProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)1856 INT_PTR CALLBACK CUIWindow::staticDialogProc(
1857 	HWND hDlg,
1858 	UINT message,
1859 	WPARAM wParam,
1860 	LPARAM lParam)
1861 {
1862 	CUIWindow* cuiWindow;
1863 
1864 //	debugPrintf("CUIWindow::staticDialogProc\n");
1865 //	printMessageName(message);
1866 	if (message == WM_INITDIALOG)
1867 	{
1868 		cuiWindow = (CUIWindow*)lParam;
1869 		SetWindowLongPtrUC(hDlg, DWLP_USER, lParam);
1870 	}
1871 	else
1872 	{
1873 		cuiWindow = (CUIWindow*)GetWindowLongPtrUC(hDlg, DWLP_USER);
1874 	}
1875 	if (cuiWindow)
1876 	{
1877 		return cuiWindow->dialogProc(hDlg, message, wParam, lParam);
1878 	}
1879 	else
1880 	{
1881 		return FALSE;
1882 	}
1883 }
1884 
populateAppVersion(void)1885 void CUIWindow::populateAppVersion(void)
1886 {
1887 	if (!appVersionPopulated)
1888 	{
1889 		UCCHAR appFilename[1024];
1890 
1891 		if (GetModuleFileName(NULL, appFilename, COUNT_OF(appFilename)) > 0)
1892 		{
1893 			DWORD zero;
1894 			DWORD versionInfoSize = GetFileVersionInfoSize(appFilename, &zero);
1895 
1896 			if (versionInfoSize > 0)
1897 			{
1898 				BYTE *versionInfo = new BYTE[versionInfoSize];
1899 
1900 				if (GetFileVersionInfo(appFilename, NULL, versionInfoSize,
1901 					versionInfo))
1902 				{
1903 					VS_FIXEDFILEINFO *fixedVersionInfo;
1904 					UINT versionLength;
1905 
1906 					if (VerQueryValue(versionInfo, _UC("\\"),
1907 						(void**)&fixedVersionInfo, &versionLength))
1908 					{
1909 						appVersionMS = fixedVersionInfo->dwProductVersionMS;
1910 						appVersionLS = fixedVersionInfo->dwProductVersionLS;
1911 						appVersionPopulated = true;
1912 					}
1913 				}
1914 				delete[] versionInfo;
1915 			}
1916 		}
1917 	}
1918 }
1919 
loadLanguageModule(LCID lcid,bool includeSub)1920 bool CUIWindow::loadLanguageModule(LCID lcid, bool includeSub)
1921 {
1922 	UCCHAR localeInfo[1024];
1923 	LCTYPE lcType = LOCALE_SENGLANGUAGE;
1924 
1925 	if (includeSub)
1926 	{
1927 		lcType = LOCALE_SLANGUAGE;
1928 	}
1929 	if (GetLocaleInfo(lcid, lcType, localeInfo, COUNT_OF(localeInfo)) > 0)
1930 	{
1931 		const char *appName = TCUserDefaults::getAppName();
1932 		UCCHAR languageModuleName[1024];
1933 		UCSTR nameOverride =
1934 			TCUserDefaults::stringForKeyUC("LanguageModuleName", NULL, false);
1935 
1936 		if (strchr(appName, '/'))
1937 		{
1938 			appName = strrchr(appName, '/') + 1;
1939 		}
1940 		if (strchr(appName, '\\'))
1941 		{
1942 			appName = strrchr(appName, '\\') + 1;
1943 		}
1944 		if (nameOverride)
1945 		{
1946 			ucstrcpy(languageModuleName, nameOverride);
1947 			delete[] nameOverride;
1948 		}
1949 		else
1950 		{
1951 			ucstring ucAppName;
1952 			utf8toucstring(ucAppName, appName);
1953 			sucprintf(languageModuleName, COUNT_OF(languageModuleName),
1954 				_UC("%s-%s.dll"), ucAppName.c_str(), localeInfo);
1955 		}
1956 		hLanguageModule = LoadLibrary(languageModuleName);
1957 		if (hLanguageModule)
1958 		{
1959 			DWORD (*getCUIAppLanguageModuleVersion)(const char *, int) =
1960 				(DWORD (*)(const char *, int))GetProcAddress(hLanguageModule,
1961 				"getCUIAppLanguageModuleVersion");
1962 
1963 			if (getCUIAppLanguageModuleVersion)
1964 			{
1965 				DWORD dllVersionMS;
1966 				DWORD dllVersionLS;
1967 
1968 				dllVersionMS = getCUIAppLanguageModuleVersion(appName, 0);
1969 				dllVersionLS = getCUIAppLanguageModuleVersion(appName, 1);
1970 				// Note that we don't care about the least significant version
1971 				// part, so we mask that part out of our comparison.
1972 				if (dllVersionMS != appVersionMS ||
1973 					(dllVersionLS & 0xFFFF0000) != (appVersionLS & 0xFFFF0000))
1974 				{
1975 					UCCHAR message[1024];
1976 
1977 					sucprintf(message, COUNT_OF(message),
1978 						_UC("Language module %s found.\n")
1979 						_UC("This language module was created for a different ")
1980 						_UC("version of LDView, and therefore cannot be used."),
1981 						languageModuleName);
1982 					MessageBox(NULL, message, _UC("Wrong Language Module"),
1983 						MB_ICONWARNING | MB_OK);
1984 					FreeLibrary(hLanguageModule);
1985 					hLanguageModule = NULL;
1986 				}
1987 			}
1988 			else
1989 			{
1990 				FreeLibrary(hLanguageModule);
1991 				hLanguageModule = NULL;
1992 			}
1993 		}
1994 	}
1995 	if (includeSub && hLanguageModule == NULL)
1996 	{
1997 		return loadLanguageModule(lcid, false);
1998 	}
1999 	else
2000 	{
2001 		return hLanguageModule != NULL;
2002 	}
2003 }
2004 
populateLanguageModule(HINSTANCE hDefaultModule)2005 void CUIWindow::populateLanguageModule(HINSTANCE hDefaultModule)
2006 {
2007 	if (!hLanguageModule)
2008 	{
2009 		populateAppVersion();
2010 		if (!loadLanguageModule(LOCALE_USER_DEFAULT))
2011 		{
2012 			hLanguageModule = hDefaultModule;
2013 		}
2014 	}
2015 }
2016 
getLanguageModule(void)2017 HINSTANCE CUIWindow::getLanguageModule(void)
2018 {
2019 	if (!hLanguageModule)
2020 	{
2021 		populateLanguageModule(GetModuleHandle(NULL));
2022 	}
2023 	return hLanguageModule;
2024 }
2025 
createDialog(UCSTR templateName,BOOL asChildWindow,DLGPROC dialogProc,LPARAM lParam)2026 HWND CUIWindow::createDialog(UCSTR templateName, BOOL asChildWindow,
2027 							 DLGPROC dialogProc, LPARAM lParam)
2028 {
2029 	HWND hWnd;
2030 
2031 	if (asChildWindow)
2032 	{
2033 		hWnd = hWindow;
2034 	}
2035 	else
2036 	{
2037 		hWnd = NULL;
2038 	}
2039 	if (!lParam)
2040 	{
2041 		lParam = (LPARAM)this;
2042 	}
2043 	HWND hDlg = CreateDialogParamUC(getLanguageModule(), templateName, hWnd,
2044 		dialogProc, lParam);
2045 	fixDialogSizes(hDlg);
2046 	return hDlg;
2047 }
2048 
createDialog(int templateNumber,BOOL asChildWindow,DLGPROC dialogProc,LPARAM lParam)2049 HWND CUIWindow::createDialog(int templateNumber, BOOL asChildWindow,
2050 							 DLGPROC dialogProc, LPARAM lParam)
2051 {
2052 	return createDialog(MAKEINTRESOURCEUC(templateNumber), asChildWindow,
2053 		dialogProc, lParam);
2054 }
2055 
getBackgroundBrush(void)2056 HBRUSH CUIWindow::getBackgroundBrush(void)
2057 {
2058 	if (!hBackgroundBrush)
2059 	{
2060  		hBackgroundBrush = CreateSolidBrush(RGB(0, 0, 0));
2061 	}
2062  	return hBackgroundBrush;
2063 //	return (HBRUSH)(COLOR_WINDOW + 1);
2064 }
2065 
getWindowClass(void)2066 WNDCLASSEX CUIWindow::getWindowClass(void)
2067 {
2068 	WNDCLASSEX windowClass;
2069 
2070 	// Set up and window class
2071 	windowClass.cbSize = sizeof(windowClass);
2072 	windowClass.style = windowClassStyle;
2073 	windowClass.lpfnWndProc = staticWindowProc;
2074 	windowClass.cbClsExtra = 0;
2075 	windowClass.cbWndExtra = 0;
2076 	windowClass.hInstance = getLanguageModule();
2077 	windowClass.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
2078 	windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
2079 	windowClass.hbrBackground = getBackgroundBrush();
2080 	windowClass.lpszMenuName = NULL;
2081 	windowClass.lpszClassName = windowClassName();
2082 	windowClass.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);
2083 	return windowClass;
2084 }
2085 
registerWindowClass(void)2086 void CUIWindow::registerWindowClass(void)
2087 {
2088 	WNDCLASSEX windowClass;
2089 
2090 	if (!GetClassInfoEx(getLanguageModule(), windowClassName(), &windowClass))
2091 	{
2092 		windowClass = getWindowClass();
2093 		RegisterClassEx(&windowClass);
2094 	}
2095 }
2096 
setTitle(CUCSTR value)2097 void CUIWindow::setTitle(CUCSTR value)
2098 {
2099 	delete windowTitle;
2100 	windowTitle = copyString(value);
2101 	if (hWindow)
2102 	{
2103 		setWindowTextUC(hWindow, windowTitle);
2104 	}
2105 }
2106 
createMainWindow(void)2107 BOOL CUIWindow::createMainWindow(void)
2108 {
2109 	POINT point = { 0, 0 };
2110 	if (x != CW_USEDEFAULT)
2111 	{
2112 		point.x = x;
2113 		point.y = y;
2114 	}
2115 	HMONITOR hMonitor = MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY);
2116 	SIZE decorationSize = getDecorationSize(hMonitor);
2117 	int dx = decorationSize.cx;
2118 	int dy = decorationSize.cy;
2119 	double scaleFactor = CUIScaler::getScaleFactor(hMonitor);
2120 	if (x != CW_USEDEFAULT)
2121 	{
2122 		x = (int)(x * scaleFactor);
2123 		y = (int)(y * scaleFactor);
2124 	}
2125 	int totalWidth = (int)(width * scaleFactor) + dx;
2126 	int totalHeight = (int)(height * scaleFactor) + dy;
2127 	hWindow = CreateWindowEx(exWindowStyle, windowClassName(), windowTitle,
2128 		windowStyle, x, y, totalWidth, totalHeight, NULL, hWindowMenu,
2129 		getLanguageModule(), this);
2130 	if (!hWindow)
2131 	{
2132 		DWORD error = GetLastError();
2133 
2134 		if (error)
2135 		{
2136 			return FALSE;
2137 		}
2138 	}
2139 	SetWindowLongPtrUC(hWindow, GWLP_USERDATA, (LONG_PTR)this);
2140 	return TRUE;
2141 }
2142 
createSubWindow(void)2143 BOOL CUIWindow::createSubWindow(void)
2144 {
2145 	SIZE decorationSize = getDecorationSize();
2146 	int dx = decorationSize.cx;
2147 	int dy = decorationSize.cy;
2148 
2149 	dx = 0;
2150 	dy = 0;
2151 	if (!hParentWindow)
2152 	{
2153 		hParentWindow = parentWindow->hWindow;
2154 	}
2155 	hWindow = CreateWindowEx(exWindowStyle, windowClassName(), windowTitle,
2156 		windowStyle, x - dx / 2, y - dy / 2, width, height, hParentWindow,
2157 		hWindowMenu, getLanguageModule(), this);
2158 	if (!hWindow)
2159 	{
2160 		DWORD error = GetLastError();
2161 
2162 		if (error)
2163 		{
2164 			return FALSE;
2165 		}
2166 	}
2167 	SetWindowLongPtrUC(hWindow, GWLP_USERDATA, (LONG_PTR)this);
2168 	return TRUE;
2169 }
2170 
createWindow(void)2171 BOOL CUIWindow::createWindow(void)
2172 {
2173 	if (parentWindow || hParentWindow)
2174 	{
2175 		return createSubWindow();
2176 	}
2177 	else
2178 	{
2179 		return createMainWindow();
2180 	}
2181 }
2182 
showWindow(int nCmdShow)2183 void CUIWindow::showWindow(int nCmdShow)
2184 {
2185 	ShowWindow(hWindow, nCmdShow);
2186 	UpdateWindow(hWindow);
2187 }
2188 
maximize(void)2189 void CUIWindow::maximize(void)
2190 {
2191 //	printf("About to maximize...\n");
2192 	showWindow(SW_MAXIMIZE);
2193 //	printf("Maximized.\n");
2194 }
2195 
minimize(void)2196 void CUIWindow::minimize(void)
2197 {
2198 	showWindow(SW_MINIMIZE);
2199 }
2200 
restore(void)2201 void CUIWindow::restore(void)
2202 {
2203 	showWindow(SW_RESTORE);
2204 }
2205 
addChild(CUIWindow * childWindow)2206 void CUIWindow::addChild(CUIWindow* childWindow)
2207 {
2208 	if (numChildren < CUI_MAX_CHILDREN)
2209 	{
2210 		children[numChildren] = childWindow;
2211 		numChildren++;
2212 	}
2213 }
2214 
removeChild(CUIWindow * childWindow)2215 void CUIWindow::removeChild(CUIWindow* childWindow)
2216 {
2217 	int i;
2218 
2219 	for (i = 0; i < numChildren && children[i] != childWindow; i++)
2220 	{
2221 	}
2222 	for (i++; i < numChildren; i++)
2223 	{
2224 		children[i-1] = children[i];
2225 	}
2226 	numChildren--;
2227 }
2228 
copyToClipboard(const char * value)2229 bool CUIWindow::copyToClipboard(const char *value)
2230 {
2231 	size_t len = strlen(value) + 1;
2232 	HGLOBAL hBuf = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
2233 
2234 	if (hBuf)
2235 	{
2236 		char *buf = (char*)GlobalLock(hBuf);
2237 
2238 		strcpy(buf, value);
2239 		GlobalUnlock(hBuf);
2240 		if (OpenClipboard(hWindow))
2241 		{
2242 			EmptyClipboard();
2243 			SetClipboardData(CF_OEMTEXT, hBuf);
2244 			CloseClipboard();
2245 			return true;
2246 		}
2247 		else
2248 		{
2249 			GlobalFree(hBuf);
2250 		}
2251 	}
2252 	return false;
2253 }
2254 
2255 #ifndef TC_NO_UNICODE
copyToClipboard(const wchar_t * value)2256 bool CUIWindow::copyToClipboard(const wchar_t *value)
2257 {
2258 	size_t len = wcslen(value) + 1;
2259 	HGLOBAL hBuf = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
2260 		len * sizeof(wchar_t));
2261 
2262 	if (hBuf)
2263 	{
2264 		wchar_t *buf = (wchar_t*)GlobalLock(hBuf);
2265 
2266 		wcscpy(buf, value);
2267 		GlobalUnlock(hBuf);
2268 		if (OpenClipboard(hWindow))
2269 		{
2270 			EmptyClipboard();
2271 			SetClipboardData(CF_UNICODETEXT, hBuf);
2272 			CloseClipboard();
2273 			return true;
2274 		}
2275 		else
2276 		{
2277 			GlobalFree(hBuf);
2278 		}
2279 	}
2280 	return false;
2281 }
2282 #endif // TC_NO_UNICODE
2283 
findSubMenu(HMENU hParentMenu,int subMenuIndex,int * index)2284 HMENU CUIWindow::findSubMenu(HMENU hParentMenu, int subMenuIndex, int *index)
2285 {
2286 	int i;
2287 	int count = GetMenuItemCount(hParentMenu);
2288 	int foundCount = 0;
2289 	MENUITEMINFO itemInfo;
2290 
2291 	memset(&itemInfo, 0, sizeof(MENUITEMINFO));
2292 	itemInfo.cbSize = sizeof(MENUITEMINFO);
2293 	itemInfo.fMask = MIIM_DATA | MIIM_SUBMENU;
2294 	for (i = 0; i < count; i++)
2295 	{
2296 		GetMenuItemInfo(hParentMenu, i, TRUE, &itemInfo);
2297 		if (itemInfo.hSubMenu)
2298 		{
2299 			if (foundCount == subMenuIndex)
2300 			{
2301 				if (index)
2302 				{
2303 					*index = i;
2304 				}
2305 				return itemInfo.hSubMenu;
2306 			}
2307 			foundCount++;
2308 		}
2309 	}
2310 	return NULL;
2311 }
2312 
2313 // Note: static method.
createWindowExUC(DWORD dwExStyle,CUCSTR lpClassName,CUCSTR lpWindowName,DWORD dwStyle,int x,int y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE hInstance,LPVOID lpParam)2314 HWND CUIWindow::createWindowExUC(DWORD dwExStyle, CUCSTR lpClassName,
2315 	CUCSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth,
2316 	int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance,
2317 	LPVOID lpParam)
2318 {
2319 #ifdef TC_NO_UNICODE
2320 	return ::CreateWindowExA(dwExStyle, lpClassName, lpWindowName, dwStyle, x,
2321 		y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
2322 #else // TC_NO_UNICODE
2323 	return ::CreateWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle, x,
2324 		y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
2325 #endif // TC_NO_UNICODE
2326 }
2327 
2328 // Note: static method.
setWindowTextUC(HWND hWnd,CUCSTR text)2329 BOOL CUIWindow::setWindowTextUC(HWND hWnd, CUCSTR text)
2330 {
2331 #ifdef TC_NO_UNICODE
2332 	return ::SetWindowTextA(hWnd, text);
2333 #else // TC_NO_UNICODE
2334 	return ::SetWindowTextW(hWnd, text);
2335 #endif // TC_NO_UNICODE
2336 }
2337 
2338 // Note: static method.
sendMessageUC(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)2339 LRESULT CUIWindow::sendMessageUC(
2340 	HWND hWnd,
2341 	UINT uMsg,
2342 	WPARAM wParam,
2343 	LPARAM lParam)
2344 {
2345 	UINT actualMessage = ucMessages[uMsg];
2346 
2347 	assert(actualMessage);
2348 #ifdef TC_NO_UNICODE
2349 	return ::SendMessageA(hWnd, actualMessage, wParam, lParam);
2350 #else // TC_NO_UNICODE
2351 	return ::SendMessageW(hWnd, actualMessage, wParam, lParam);
2352 #endif // TC_NO_UNICODE
2353 }
2354 
2355 // Note: static method.
sendDlgItemMessageUC(HWND hDlg,int nIDDlgItem,UINT uMsg,WPARAM wParam,LPARAM lParam)2356 LRESULT CUIWindow::sendDlgItemMessageUC(
2357 	HWND hDlg,
2358 	int nIDDlgItem,
2359 	UINT uMsg,
2360 	WPARAM wParam,
2361 	LPARAM lParam)
2362 {
2363 	UINT actualMessage = ucMessages[uMsg];
2364 
2365 	assert(actualMessage);
2366 #ifdef TC_NO_UNICODE
2367 	return ::SendDlgItemMessageA(hDlg, nIDDlgItem, actualMessage, wParam,
2368 		lParam);
2369 #else // TC_NO_UNICODE
2370 	return ::SendDlgItemMessageW(hDlg, nIDDlgItem, actualMessage, wParam,
2371 		lParam);
2372 #endif // TC_NO_UNICODE
2373 }
2374 
2375 // Note: static method.
messageBoxUC(HWND hWnd,CUCSTR lpText,CUCSTR lpCaption,UINT uType)2376 int CUIWindow::messageBoxUC(
2377 	HWND hWnd,
2378 	CUCSTR lpText,
2379 	CUCSTR lpCaption,
2380 	UINT uType)
2381 {
2382 #ifdef TC_NO_UNICODE
2383 	return ::MessageBoxA(hWnd, lpText, lpCaption, uType);
2384 #else // TC_NO_UNICODE
2385 	return ::MessageBoxW(hWnd, lpText, lpCaption, uType);
2386 #endif // TC_NO_UNICODE
2387 }
2388 
2389 // Note: static method.
createStatusWindowUC(LONG style,CUCSTR lpszText,HWND hwndParent,UINT wID)2390 HWND CUIWindow::createStatusWindowUC(
2391 	LONG style,
2392 	CUCSTR lpszText,
2393 	HWND hwndParent,
2394 	UINT wID)
2395 {
2396 #ifdef TC_NO_UNICODE
2397 	return ::CreateStatusWindowA(style, lpszText, hwndParent, wID);
2398 #else // TC_NO_UNICODE
2399 	return ::CreateStatusWindowW(style, lpszText, hwndParent, wID);
2400 #endif // TC_NO_UNICODE
2401 }
2402 
2403 // Note: static method.
insertMenuItemUC(HMENU hmenu,UINT item,BOOL fByPosition,MENUITEMINFOUC * lpmi)2404 BOOL CUIWindow::insertMenuItemUC(
2405 	HMENU hmenu,
2406 	UINT item,
2407 	BOOL fByPosition,
2408 	MENUITEMINFOUC *lpmi)
2409 {
2410 #ifdef TC_NO_UNICODE
2411 	return ::InsertMenuItemA(hmenu, item, fByPosition, lpmi);
2412 #else // TC_NO_UNICODE
2413 	return ::InsertMenuItemW(hmenu, item, fByPosition, lpmi);
2414 #endif // TC_NO_UNICODE
2415 }
2416 
2417 // Note: static method.
getOpenFileNameUC(OPENFILENAMEUC * lpofn)2418 BOOL CUIWindow::getOpenFileNameUC(OPENFILENAMEUC *lpofn)
2419 {
2420 #ifdef TC_NO_UNICODE
2421 	return ::GetOpenFileNameA(lpofn);
2422 #else // TC_NO_UNICODE
2423 	return ::GetOpenFileNameW(lpofn);
2424 #endif // TC_NO_UNICODE
2425 }
2426 
2427 
2428 // Note: static method
getTextExtentPoint32UC(HDC hdc,CUCSTR lpString,int cbString,LPSIZE lpSize)2429 BOOL CUIWindow::getTextExtentPoint32UC(
2430 	HDC hdc,
2431 	CUCSTR lpString,
2432 	int cbString,
2433 	LPSIZE lpSize)
2434 {
2435 #ifdef TC_NO_UNICODE
2436 	return ::GetTextExtentPoint32A(hdc, lpString, cbString, lpSize);
2437 #else // TC_NO_UNICODE
2438 	return ::GetTextExtentPoint32W(hdc, lpString, cbString, lpSize);
2439 #endif // TC_NO_UNICODE
2440 }
2441 
2442 // Note: static method.
screenToClient(HWND hWnd,RECT * rect)2443 BOOL CUIWindow::screenToClient(HWND hWnd, RECT *rect)
2444 {
2445 	POINT tempPoint = {rect->left, rect->top};
2446 	if (::ScreenToClient(hWnd, &tempPoint))
2447 	{
2448 		rect->left = tempPoint.x;
2449 		rect->top = tempPoint.y;
2450 		tempPoint.x = rect->right;
2451 		tempPoint.y = rect->bottom;
2452 		if (::ScreenToClient(hWnd, &tempPoint))
2453 		{
2454 			rect->right = tempPoint.x;
2455 			rect->bottom = tempPoint.y;
2456 			return TRUE;
2457 		}
2458 	}
2459 	return FALSE;
2460 }
2461 
2462 // Note: static method.
clientToScreen(HWND hWnd,RECT * rect)2463 BOOL CUIWindow::clientToScreen(HWND hWnd, RECT *rect)
2464 {
2465 	POINT tempPoint = {rect->left, rect->top};
2466 	if (::ClientToScreen(hWnd, &tempPoint))
2467 	{
2468 		rect->left = tempPoint.x;
2469 		rect->top = tempPoint.y;
2470 		tempPoint.x = rect->right;
2471 		tempPoint.y = rect->bottom;
2472 		if (::ClientToScreen(hWnd, &tempPoint))
2473 		{
2474 			rect->right = tempPoint.x;
2475 			rect->bottom = tempPoint.y;
2476 			return TRUE;
2477 		}
2478 	}
2479 	return FALSE;
2480 }
2481 
2482 // Note: static method
setMenuCheck(HMENU hParentMenu,UINT uItem,bool checked,bool radio)2483 void CUIWindow::setMenuCheck(
2484 	HMENU hParentMenu,
2485 	UINT uItem,
2486 	bool checked,
2487 	bool radio)
2488 {
2489 	MENUITEMINFO itemInfo;
2490 	//char title[256];
2491 
2492 	memset(&itemInfo, 0, sizeof(MENUITEMINFO));
2493 	itemInfo.cbSize = sizeof(MENUITEMINFO);
2494 	itemInfo.fMask = MIIM_STATE;// | MIIM_TYPE;
2495 	//itemInfo.fType = MFT_STRING;
2496 	//itemInfo.dwTypeData = title;
2497 	//itemInfo.cch = 256;
2498 	GetMenuItemInfo(hParentMenu, uItem, FALSE, &itemInfo);
2499 	if (checked)
2500 	{
2501 		itemInfo.fState |= MFS_CHECKED;
2502 		itemInfo.fState &= ~MFS_UNCHECKED;
2503 	}
2504 	else
2505 	{
2506 		itemInfo.fState &= ~MFS_CHECKED;
2507 		itemInfo.fState |= MFS_UNCHECKED;
2508 	}
2509 	itemInfo.fType = MFT_STRING;
2510 	if (radio)
2511 	{
2512 		itemInfo.fType |= MFT_RADIOCHECK;
2513 	}
2514 	SetMenuItemInfo(hParentMenu, uItem, FALSE, &itemInfo);
2515 }
2516 
2517 // Note: static method
setMenuRadioCheck(HMENU hParentMenu,UINT uItem,bool checked)2518 void CUIWindow::setMenuRadioCheck(HMENU hParentMenu, UINT uItem, bool checked)
2519 {
2520 	setMenuCheck(hParentMenu, uItem, checked, true);
2521 }
2522 
2523 // Note: static method
getMenuCheck(HMENU hParentMenu,UINT uItem)2524 bool CUIWindow::getMenuCheck(HMENU hParentMenu, UINT uItem)
2525 {
2526 	MENUITEMINFO itemInfo;
2527 
2528 	memset(&itemInfo, 0, sizeof(MENUITEMINFO));
2529 	itemInfo.cbSize = sizeof(MENUITEMINFO);
2530 	itemInfo.fMask = MIIM_STATE;
2531 	GetMenuItemInfo(hParentMenu, uItem, FALSE, &itemInfo);
2532 	return (itemInfo.fState & MFS_CHECKED) != 0;
2533 }
2534 
setMenuItemsEnabled(HMENU hMenu,bool enabled)2535 void CUIWindow::setMenuItemsEnabled(HMENU hMenu, bool enabled)
2536 {
2537 	int i;
2538 	int count = GetMenuItemCount(hMenu);
2539 
2540 	for (i = 0; i < count; i++)
2541 	{
2542 		setMenuEnabled(hMenu, i, enabled, TRUE);
2543 	}
2544 }
2545 
setMenuEnabled(HMENU hParentMenu,int itemID,bool enabled,BOOL byPosition)2546 void CUIWindow::setMenuEnabled(
2547 	HMENU hParentMenu,
2548 	int itemID,
2549 	bool enabled,
2550 	BOOL byPosition)
2551 {
2552 	MENUITEMINFO itemInfo;
2553 	//BYTE tbState = 0;
2554 
2555 	itemInfo.cbSize = sizeof(itemInfo);
2556 	itemInfo.fMask = MIIM_STATE;
2557 	if (GetMenuItemInfo(hParentMenu, itemID, byPosition, &itemInfo))
2558 	{
2559 		if (enabled)
2560 		{
2561 			itemInfo.fState &= ~MFS_DISABLED;
2562 		}
2563 		else
2564 		{
2565 			itemInfo.fState |= MFS_DISABLED;
2566 		}
2567 		itemInfo.fMask = MIIM_STATE;
2568 		SetMenuItemInfo(hParentMenu, itemID, byPosition, &itemInfo);
2569 	}
2570 }
2571 
2572 // Note: static method
listBoxResetContent(HWND hWnd)2573 void CUIWindow::listBoxResetContent(HWND hWnd)
2574 {
2575 	SendMessage(hWnd, LB_RESETCONTENT, 0, 0);
2576 }
2577 
2578 // Note: static method
listBoxGetText(HWND hWnd,int index,ucstring & text)2579 void CUIWindow::listBoxGetText(HWND hWnd, int index, ucstring &text)
2580 {
2581 	LRESULT getLengthResult = SendMessage(hWnd, LB_GETTEXTLEN,
2582 		(WPARAM)index, 0);
2583 	if (getLengthResult > 0 && getLengthResult != LB_ERR)
2584 	{
2585 		text.resize(getLengthResult);
2586 		SendMessage(hWnd, LB_GETTEXT, (WPARAM)index, (LPARAM)&text[0]);
2587 	}
2588 	else
2589 	{
2590 		text.clear();
2591 	}
2592 }
2593 
2594 // Note: static method
listBoxSelectString(HWND hWnd,CUCSTR text)2595 void CUIWindow::listBoxSelectString(HWND hWnd, CUCSTR text)
2596 {
2597 	SendMessage(hWnd, LB_SELECTSTRING, 0, (LPARAM)text);
2598 }
2599 
2600 // Note: static method
listBoxSelectString(HWND hWnd,const ucstring & text)2601 void CUIWindow::listBoxSelectString(HWND hWnd, const ucstring &text)
2602 {
2603 	listBoxSelectString(hWnd, text.c_str());
2604 }
2605 
2606 // Note: static method
listBoxFindStringExact(HWND hWnd,CUCSTR text)2607 int CUIWindow::listBoxFindStringExact(HWND hWnd, CUCSTR text)
2608 {
2609 	return (int)SendMessage(hWnd, LB_FINDSTRINGEXACT, 0, (LPARAM)text);
2610 }
2611 
2612 // Note: static method
listBoxFindStringExact(HWND hWnd,const ucstring & text)2613 int CUIWindow::listBoxFindStringExact(HWND hWnd, const ucstring &text)
2614 {
2615 	return listBoxFindStringExact(hWnd, text.c_str());
2616 }
2617 
2618 // Note: static method
listBoxSetCurSel(HWND hWnd,int index)2619 void CUIWindow::listBoxSetCurSel(HWND hWnd, int index)
2620 {
2621 	SendMessage(hWnd, LB_SETCURSEL, (WPARAM)index, 0);
2622 }
2623 
2624 // Note: static method
listBoxGetCurSel(HWND hWnd)2625 int CUIWindow::listBoxGetCurSel(HWND hWnd)
2626 {
2627 	return (int)SendMessage(hWnd, LB_GETCURSEL, 0, 0);
2628 }
2629 
2630 // Note: static method
listBoxGetCount(HWND hWnd)2631 int CUIWindow::listBoxGetCount(HWND hWnd)
2632 {
2633 	return (int)SendMessage(hWnd, LB_GETCOUNT, 0, 0);
2634 }
2635 
2636 // Note: static method
listBoxAddString(HWND hWnd,CUCSTR text)2637 int CUIWindow::listBoxAddString(HWND hWnd, CUCSTR text)
2638 {
2639 	return (int)SendMessage(hWnd, LB_ADDSTRING, 0, (LPARAM)text);
2640 }
2641 
2642 // Note: static method
listBoxAddString(HWND hWnd,const ucstring & text)2643 int CUIWindow::listBoxAddString(HWND hWnd, const ucstring &text)
2644 {
2645 	return listBoxAddString(hWnd, text.c_str());
2646 }
2647 
2648 // Note: static method
buttonSetCheck(HWND hWnd,int state)2649 void CUIWindow::buttonSetCheck(HWND hWnd, int state)
2650 {
2651 	SendMessage(hWnd, BM_SETCHECK, (WPARAM)state, 0);
2652 }
2653 
2654 // Note: static method
buttonSetChecked(HWND hWnd,bool checked)2655 void CUIWindow::buttonSetChecked(HWND hWnd, bool checked)
2656 {
2657 	buttonSetCheck(hWnd, checked ? BST_CHECKED : BST_UNCHECKED);
2658 }
2659 
2660 // Note: static method
buttonGetCheck(HWND hWnd)2661 int CUIWindow::buttonGetCheck(HWND hWnd)
2662 {
2663 	return (int)SendMessage(hWnd, BM_GETCHECK, 0, 0);
2664 }
2665 
2666 // Note: static method
buttonIsChecked(HWND hWnd)2667 bool CUIWindow::buttonIsChecked(HWND hWnd)
2668 {
2669 	return buttonGetCheck(hWnd) == BST_CHECKED;
2670 }
2671 
2672 // Note: static method
buttonSetBitmap(HWND hWnd,HBITMAP hBitmap)2673 HBITMAP CUIWindow::buttonSetBitmap(HWND hWnd, HBITMAP hBitmap)
2674 {
2675 	return (HBITMAP)SendMessage(hWnd, BM_SETIMAGE, IMAGE_BITMAP,
2676 		(LPARAM)hBitmap);
2677 }
2678 
2679 // Note: static method
buttonSetIcon(HWND hWnd,HICON hIcon)2680 HICON CUIWindow::buttonSetIcon(HWND hWnd, HICON hIcon)
2681 {
2682 	return (HICON)SendMessage(hWnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);
2683 }
2684 
2685 // Note: static method
buttonGetBitmap(HWND hWnd)2686 HBITMAP CUIWindow::buttonGetBitmap(HWND hWnd)
2687 {
2688 	return (HBITMAP)SendMessage(hWnd, BM_GETIMAGE, IMAGE_BITMAP, 0);
2689 }
2690 
2691 // Note: static method
buttonGetIcon(HWND hWnd)2692 HICON CUIWindow::buttonGetIcon(HWND hWnd)
2693 {
2694 	return (HICON)SendMessage(hWnd, BM_GETIMAGE, IMAGE_ICON, 0);
2695 }
2696 
2697 // Note: static method
buttonSetStyle(HWND hWnd,DWORD dwStyle,bool redraw)2698 void CUIWindow::buttonSetStyle(HWND hWnd, DWORD dwStyle, bool redraw)
2699 {
2700 	SendMessage(hWnd, BM_SETSTYLE, LOWORD(dwStyle),
2701 		redraw ? MAKELPARAM(TRUE, 0) : 0);
2702 }
2703 
2704 // Note: static method
progressBarSetPos(HWND hWnd,int pos)2705 int CUIWindow::progressBarSetPos(HWND hWnd, int pos)
2706 {
2707 	return (int)SendMessage(hWnd, PBM_SETPOS, (WPARAM)pos, 0);
2708 }
2709 
2710 // Note: static method
progressBarGetPos(HWND hWnd)2711 int CUIWindow::progressBarGetPos(HWND hWnd)
2712 {
2713 	return (int)SendMessage(hWnd, PBM_GETPOS, 0, 0);
2714 }
2715 
2716 // Note: static method
trackBarGetPos(HWND hWnd)2717 int CUIWindow::trackBarGetPos(HWND hWnd)
2718 {
2719 	return (int)SendMessage(hWnd, TBM_GETPOS, 0, 0);
2720 }
2721 
2722 // Note: static method
listBoxInsertString(HWND hWnd,int index,CUCSTR text)2723 void CUIWindow::listBoxInsertString(HWND hWnd, int index, CUCSTR text)
2724 {
2725 	SendMessage(hWnd, LB_INSERTSTRING, (WPARAM)index, (LPARAM)text);
2726 }
2727 
2728 // Note: static method
listBoxInsertString(HWND hWnd,int index,const ucstring & text)2729 void CUIWindow::listBoxInsertString(HWND hWnd, int index, const ucstring &text)
2730 {
2731 	listBoxInsertString(hWnd, index, text.c_str());
2732 }
2733 
2734 // Note: static method
listBoxDeleteString(HWND hWnd,int index)2735 void CUIWindow::listBoxDeleteString(HWND hWnd, int index)
2736 {
2737 	SendMessage(hWnd, LB_DELETESTRING, (WPARAM)index, 0);
2738 }
2739 
2740 // Note: static method
windowSetText(HWND hWnd,CUCSTR text)2741 void CUIWindow::windowSetText(HWND hWnd, CUCSTR text)
2742 {
2743 	SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM)text);
2744 }
2745 
2746 // Note: static method
windowSetText(HWND hWnd,const ucstring & text)2747 void CUIWindow::windowSetText(HWND hWnd, const ucstring &text)
2748 {
2749 	windowSetText(hWnd, text.c_str());
2750 }
2751 
2752 // Note: static method
windowGetText(HWND hWnd,ucstring & text)2753 void CUIWindow::windowGetText(HWND hWnd, ucstring &text)
2754 {
2755 	text.resize(SendMessage(hWnd, WM_GETTEXTLENGTH, 0, 0));
2756 	sendMessageUC(hWnd, WM_GETTEXT, (WPARAM)text.size() + 1, (LPARAM)&text[0]);
2757 }
2758 
2759 // Note: static method
windowGetValue(HWND hWnd,long & value)2760 bool CUIWindow::windowGetValue(HWND hWnd, long &value)
2761 {
2762 	ucstring text;
2763 
2764 	windowGetText(hWnd, text);
2765 	return sucscanf(text.c_str(), _UC("%ld"), &value) == 1;
2766 }
2767 
2768 // Note: static method
windowGetValue(HWND hWnd,int & value)2769 bool CUIWindow::windowGetValue(HWND hWnd, int &value)
2770 {
2771 	ucstring text;
2772 
2773 	windowGetText(hWnd, text);
2774 	return sucscanf(text.c_str(), _UC("%d"), &value) == 1;
2775 }
2776 
2777 // Note: static method
windowGetValue(HWND hWnd,float & value)2778 bool CUIWindow::windowGetValue(HWND hWnd, float &value)
2779 {
2780 	ucstring text;
2781 
2782 	windowGetText(hWnd, text);
2783 	return sucscanf(text.c_str(), _UC("%f"), &value) == 1;
2784 }
2785 
2786 // Note: static method
windowGetValue(HWND hWnd,double & value)2787 bool CUIWindow::windowGetValue(HWND hWnd, double &value)
2788 {
2789 	ucstring text;
2790 
2791 	windowGetText(hWnd, text);
2792 	return sucscanf(text.c_str(), _UC("%lf"), &value) == 1;
2793 }
2794 
2795 // Note: static method
checkGet(HWND hWnd)2796 bool CUIWindow::checkGet(HWND hWnd)
2797 {
2798 	return SendMessage(hWnd, BM_GETCHECK, 0, 0) != 0;
2799 }
2800 
2801 // Note: static method
checkSet(HWND hWnd,bool value)2802 void CUIWindow::checkSet(HWND hWnd, bool value)
2803 {
2804 	SendMessage(hWnd, BM_SETCHECK, value, 0);
2805 }
2806 
positionResizeGrip(HWND hSizeGrip)2807 void CUIWindow::positionResizeGrip(HWND hSizeGrip)
2808 {
2809 	RECT clientRect;
2810 	GetClientRect(hWindow, &clientRect);
2811 	positionResizeGrip(hSizeGrip, clientRect.right, clientRect.bottom);
2812 	RedrawWindow(hWindow, NULL, NULL, RDW_ERASE | RDW_INVALIDATE);
2813 }
2814 
positionResizeGrip(HWND hSizeGrip,int parentWidth,int parentHeight)2815 void CUIWindow::positionResizeGrip(
2816 	HWND hSizeGrip,
2817 	int parentWidth,
2818 	int parentHeight)
2819 {
2820 	int sbSize = GetSystemMetrics(SM_CXVSCROLL);
2821 
2822 	MoveWindow(hSizeGrip, parentWidth - sbSize, parentHeight - sbSize, sbSize,
2823 		sbSize, FALSE);
2824 }
2825 
writeAutosaveInfo(int saveX,int saveY,int saveWidth,int saveHeight,int saveMaximized)2826 void CUIWindow::writeAutosaveInfo(
2827 	int saveX,
2828 	int saveY,
2829 	int saveWidth,
2830 	int saveHeight,
2831 	int saveMaximized)
2832 {
2833 	if (autosaveName != NULL)
2834 	{
2835 		char info[1024];
2836 		float width, height;
2837 		float scaleFactor = (float)getScaleFactor();
2838 
2839 		width = saveWidth / scaleFactor;
2840 		height = saveHeight / scaleFactor;
2841 		sprintf(info, "%d %d %f %f %d", saveX, saveY, width, height,
2842 			saveMaximized);
2843 		TCUserDefaults::setStringForKey(info, autosaveName, false);
2844 	}
2845 }
2846 
readAutosaveInfo(int & saveX,int & saveY,int & saveWidth,int & saveHeight,int & saveMaximized)2847 bool CUIWindow::readAutosaveInfo(
2848 	int &saveX,
2849 	int &saveY,
2850 	int &saveWidth,
2851 	int &saveHeight,
2852 	int &saveMaximized)
2853 {
2854 	bool retValue = false;
2855 
2856 	if (autosaveName != NULL)
2857 	{
2858 		char *info = TCUserDefaults::stringForKey(autosaveName, NULL, false);
2859 
2860 		if (info != NULL)
2861 		{
2862 			float width, height;
2863 			if (sscanf(info, "%d %d %f %f %d", &saveX, &saveY, &width, &height,
2864 				&saveMaximized) == 5)
2865 			{
2866 				saveWidth = scalePoints(width);
2867 				saveHeight = scalePoints(height);
2868 				retValue = true;
2869 			}
2870 			delete info;
2871 		}
2872 	}
2873 	return retValue;
2874 }
2875 
setAutosaveName(const char * value)2876 void CUIWindow::setAutosaveName(const char *value)
2877 {
2878 	int saveX, saveY, saveWidth, saveHeight, saveMaximized;
2879 
2880 	autosaveName = new char[strlen(value) + 32];
2881 	sprintf(autosaveName, "WindowAutosave/%s", value);
2882 	if (readAutosaveInfo(saveX, saveY, saveWidth, saveHeight,
2883 		saveMaximized))
2884 	{
2885 		RECT testRect = { 0, 0, 10, 10 };
2886 		int adjustWidth;
2887 		int adjustHeight;
2888 		bool resizable = (GetWindowLong(hWindow, GWL_STYLE) &
2889 			(WS_THICKFRAME | WS_MAXIMIZEBOX)) != 0;
2890 
2891 		AdjustWindowRectEx(&testRect, GetWindowLong(hWindow, GWL_STYLE), FALSE,
2892 			GetWindowLong(hWindow, GWL_EXSTYLE));
2893 		adjustWidth = testRect.right - testRect.left - 10;
2894 		adjustHeight = testRect.bottom - testRect.top - 10;
2895 		if (!resizable)
2896 		{
2897 			// If the window isn't resizable, don't try to restore its last size, in
2898 			// case the size in the .rc file changes in a future version.
2899 			RECT oldRect;
2900 			GetWindowRect(hWindow, &oldRect);
2901 			saveWidth = oldRect.right - oldRect.left;
2902 			saveHeight = oldRect.bottom - oldRect.top;
2903 		}
2904 		if (saveWidth < minWidth + adjustWidth)
2905 		{
2906 			saveWidth = minWidth + adjustWidth;
2907 		}
2908 		if (saveHeight < minHeight + adjustHeight)
2909 		{
2910 			saveHeight = minHeight + adjustHeight;
2911 		}
2912 		RECT newRect = { saveX, saveY, saveX + saveWidth, saveY + saveHeight };
2913 		HMONITOR hMonitor = MonitorFromRect(&newRect, MONITOR_DEFAULTTONULL);
2914 		bool okRect = true;
2915 		if (hMonitor == NULL)
2916 		{
2917 			// There is no longer a monitor where the window was last displayed.
2918 			okRect = false;
2919 		}
2920 		else
2921 		{
2922 			MONITORINFO monitorInfo;
2923 			memset(&monitorInfo, 0, sizeof(monitorInfo));
2924 			monitorInfo.cbSize = sizeof(MONITORINFO);
2925 			if (GetMonitorInfo(hMonitor, &monitorInfo))
2926 			{
2927 				RECT visibleRect;
2928 				IntersectRect(&visibleRect, &newRect, &monitorInfo.rcWork);
2929 				int totalArea = (newRect.right - newRect.left) *
2930 					(newRect.bottom - newRect.top);
2931 				int visibleArea = (visibleRect.right - visibleRect.left) *
2932 					(visibleRect.bottom - visibleRect.top);
2933 				if (visibleArea * 2 < totalArea)
2934 				{
2935 					// Less than half the window is visible.
2936 					okRect = false;
2937 				}
2938 			}
2939 			else
2940 			{
2941 				// We shouldn't get here; I think it means that the monitor that
2942 				// was originally found for the rect went away between when we
2943 				// asked for the rect's monitor and when we asked for info about
2944 				// that monitor.
2945 				okRect = false;
2946 			}
2947 		}
2948 		if (!okRect)
2949 		{
2950 			// The saved window rect is less than half visible.
2951 			// Use the saved window size, but use the default location.
2952 			GetWindowRect(hWindow, &newRect);
2953 			saveX = newRect.left;
2954 			saveY = newRect.top;
2955 		}
2956 		MoveWindow(hWindow, saveX, saveY, saveWidth, saveHeight,
2957 			saveMaximized == 0);
2958 		if (saveMaximized)
2959 		{
2960 			ShowWindow(hWindow, SW_MAXIMIZE);
2961 		}
2962 	}
2963 }
2964 
2965 #ifndef TC_NO_UNICODE
2966 // Note: static method
addFileType(char * fileTypes,const char * description,const char * filter)2967 void CUIWindow::addFileType(
2968 	char *fileTypes,
2969 	const char *description,
2970 	const char *filter)
2971 {
2972 	char* spot = fileTypes;
2973 
2974 	for (spot = fileTypes; spot[0] != 0 || spot[1] != 0; spot++)
2975 		;
2976 	if (spot != fileTypes)
2977 	{
2978 		spot++;
2979 	}
2980 	strcpy(spot, description);
2981 	spot += strlen(description) + 1;
2982 	strcpy(spot, filter);
2983 	spot += strlen(filter) + 1;
2984 	*spot = 0;
2985 }
2986 #endif // TC_NO_UNICODE
2987 
2988 // Note: static method
addFileType(UCSTR fileTypes,CUCSTR description,CUCSTR filter)2989 void CUIWindow::addFileType(
2990 	UCSTR fileTypes,
2991 	CUCSTR description,
2992 	CUCSTR filter)
2993 {
2994 	UCSTR spot = fileTypes;
2995 
2996 	for (spot = fileTypes; spot[0] != 0 || spot[1] != 0; spot++)
2997 		;
2998 	if (spot != fileTypes)
2999 	{
3000 		spot++;
3001 	}
3002 	ucstrcpy(spot, description);
3003 	spot += ucstrlen(description) + 1;
3004 	ucstrcpy(spot, filter);
3005 	spot += ucstrlen(filter) + 1;
3006 	*spot = 0;
3007 }
3008 
3009 // Note: static method
getOpenFilenameSize(bool uc)3010 int CUIWindow::getOpenFilenameSize(bool uc)
3011 {
3012 	OSVERSIONINFO osvi;
3013 
3014 	osvi.dwOSVersionInfoSize = sizeof(osvi);
3015 #pragma warning(push)
3016 #pragma warning(disable:4996)
3017 	GetVersionEx(&osvi);
3018 #pragma warning(pop)
3019 	if (osvi.dwMajorVersion < 5)
3020 	{
3021 		if (uc)
3022 		{
3023 			return sizeof(OPENFILENAME_NT4UC);
3024 		}
3025 		else
3026 		{
3027 			return sizeof(OPENFILENAME_NT4A);
3028 		}
3029 	}
3030 	else
3031 	{
3032 		if (uc)
3033 		{
3034 			return sizeof(OPENFILENAMEUC);
3035 		}
3036 		else
3037 		{
3038 			return sizeof(OPENFILENAMEA);
3039 		}
3040 	}
3041 }
3042 
3043 // Note: static method
comboAddString(HWND hWnd,CUCSTR string)3044 int CUIWindow::comboAddString(HWND hWnd, CUCSTR string)
3045 {
3046 	return (int)SendMessage(hWnd, CB_ADDSTRING, 0, (LPARAM)string);
3047 }
3048 
3049 // Note: static method
comboAddString(HWND hWnd,const ucstring & string)3050 int CUIWindow::comboAddString(HWND hWnd, const ucstring &string)
3051 {
3052 	return comboAddString(hWnd, string.c_str());
3053 }
3054 
3055 // Note: static method
comboDeleteString(HWND hWnd,int index)3056 int CUIWindow::comboDeleteString(HWND hWnd, int index)
3057 {
3058 	return (int)SendMessage(hWnd, CB_DELETESTRING, (WPARAM)index, 0);
3059 }
3060 
3061 // Note: static method
comboSelectString(HWND hWnd,int startIndex,CUCSTR string)3062 int CUIWindow::comboSelectString(HWND hWnd, int startIndex, CUCSTR string)
3063 {
3064 	return (int)SendMessage(hWnd, CB_SELECTSTRING, (WPARAM)startIndex,
3065 		(LPARAM)string);
3066 }
3067 
3068 // Note: static method
comboSelectString(HWND hWnd,int startIndex,const ucstring & string)3069 int CUIWindow::comboSelectString(
3070 	HWND hWnd,
3071 	int startIndex,
3072 	const ucstring &string)
3073 {
3074 	return comboSelectString(hWnd, startIndex, string.c_str());
3075 }
3076 
3077 // Note: static method
comboResetContent(HWND hWnd)3078 void CUIWindow::comboResetContent(HWND hWnd)
3079 {
3080 	SendMessage(hWnd, CB_RESETCONTENT, 0, 0);
3081 }
3082 
3083 // Note: static method
comboSetCurSel(HWND hWnd,int index)3084 int CUIWindow::comboSetCurSel(HWND hWnd, int index)
3085 {
3086 	return (int)SendMessage(hWnd, CB_SETCURSEL, (WPARAM)index, 0);
3087 }
3088 
3089 // Note: static method
comboGetCurSel(HWND hWnd)3090 int CUIWindow::comboGetCurSel(HWND hWnd)
3091 {
3092 	return (int)SendMessage(hWnd, CB_GETCURSEL, 0, 0);
3093 }
3094 
3095 // Note: static method
comboGetCount(HWND hWnd)3096 int CUIWindow::comboGetCount(HWND hWnd)
3097 {
3098 	return (int)SendMessage(hWnd, CB_GETCOUNT, 0, 0);
3099 }
3100 
3101 // Note: static method
notificationName(UINT code)3102 const std::string CUIWindow::notificationName(UINT code)
3103 {
3104 	static char buf[128];
3105 
3106 	switch (code)
3107 	{
3108 	case TBN_GETBUTTONINFOA:
3109 		return "TBN_GETBUTTONINFOA";
3110 	case TBN_BEGINDRAG:
3111 		return "TBN_BEGINDRAG";
3112 	case TBN_ENDDRAG:
3113 		return "TBN_ENDDRAG";
3114 	case TBN_BEGINADJUST:
3115 		return "TBN_BEGINADJUST";
3116 	case TBN_ENDADJUST:
3117 		return "TBN_ENDADJUST";
3118 	case TBN_RESET:
3119 		return "TBN_RESET";
3120 	case TBN_QUERYINSERT:
3121 		return "TBN_QUERYINSERT";
3122 	case TBN_QUERYDELETE:
3123 		return "TBN_QUERYDELETE";
3124 	case TBN_TOOLBARCHANGE:
3125 		return "TBN_TOOLBARCHANGE";
3126 	case TBN_CUSTHELP:
3127 		return "TBN_CUSTHELP";
3128 	case TBN_DROPDOWN:
3129 		return "TBN_DROPDOWN";
3130 	case TBN_GETOBJECT:
3131 		return "TBN_GETOBJECT";
3132 	case TBN_HOTITEMCHANGE:
3133 		return "TBN_HOTITEMCHANGE";
3134 	case TBN_DRAGOUT:
3135 		return "TBN_DRAGOUT";
3136 	case TBN_DELETINGBUTTON:
3137 		return "TBN_DELETINGBUTTON";
3138 	case TBN_GETDISPINFOA:
3139 		return "TBN_GETDISPINFOA";
3140 	case TBN_GETDISPINFOW:
3141 		return "TBN_GETDISPINFOW";
3142 	case TBN_GETINFOTIPA:
3143 		return "TBN_GETINFOTIPA";
3144 	case TBN_GETINFOTIPW:
3145 		return "TBN_GETINFOTIPW";
3146 	case TBN_GETBUTTONINFOW:
3147 		return "TBN_GETBUTTONINFOW";
3148 	case TBN_RESTORE:
3149 		return "TBN_RESTORE";
3150 	case TBN_SAVE:
3151 		return "TBN_SAVE";
3152 	case TBN_INITCUSTOMIZE:
3153 		return "TBN_INITCUSTOMIZE";
3154 
3155 	case TTN_GETDISPINFOA:
3156 		return "TTN_GETDISPINFOA";
3157 	case TTN_GETDISPINFOW:
3158 		return "TTN_GETDISPINFOW";
3159 	case TTN_SHOW:
3160 		return "TTN_SHOW";
3161 	case TTN_POP:
3162 		return "TTN_POP";
3163 	case TTN_LINKCLICK:
3164 		return "TTN_LINKCLICK";
3165 
3166 	case NM_OUTOFMEMORY:
3167 		return "NM_OUTOFMEMORY";
3168 	case NM_CLICK:
3169 		return "NM_CLICK";
3170 	case NM_DBLCLK:
3171 		return "NM_DBLCLK";
3172 	case NM_RETURN:
3173 		return "NM_RETURN";
3174 	case NM_RCLICK:
3175 		return "NM_RCLICK";
3176 	case NM_RDBLCLK:
3177 		return "NM_RDBLCLK";
3178 	case NM_SETFOCUS:
3179 		return "NM_SETFOCUS";
3180 	case NM_KILLFOCUS:
3181 		return "NM_KILLFOCUS";
3182 	case NM_CUSTOMDRAW:
3183 		return "NM_CUSTOMDRAW";
3184 	case NM_HOVER:
3185 		return "NM_HOVER";
3186 	case NM_NCHITTEST:
3187 		return "NM_NCHITTEST";
3188 	case NM_KEYDOWN:
3189 		return "NM_KEYDOWN";
3190 	case NM_RELEASEDCAPTURE:
3191 		return "NM_RELEASEDCAPTURE";
3192 	case NM_SETCURSOR:
3193 		return "NM_SETCURSOR";
3194 	case NM_CHAR:
3195 		return "NM_CHAR";
3196 	case NM_TOOLTIPSCREATED:
3197 		return "NM_TOOLTIPSCREATED";
3198 	case NM_LDOWN:
3199 		return "NM_LDOWN";
3200 	case NM_RDOWN:
3201 		return "NM_RDOWN";
3202 	case NM_THEMECHANGED:
3203 		return "NM_THEMECHANGED";
3204 	default:
3205 		sprintf(buf, "0x%08X", code);
3206 		return buf;
3207 	}
3208 }
3209 
createDIBSection(HDC hBitmapDC,int bitmapWidth,int bitmapHeight,BYTE ** bmBuffer,bool force32)3210 HBITMAP CUIWindow::createDIBSection(
3211 	HDC hBitmapDC,
3212 	int bitmapWidth,
3213 	int bitmapHeight,
3214 	BYTE **bmBuffer,
3215 	bool force32 /*= false*/)
3216 {
3217 	return TCImage::createDIBSection(hBitmapDC, bitmapWidth, bitmapHeight, bmBuffer, force32);
3218 }
3219 
getScaleFactor(bool recalculate,UINT * dpiX,UINT * dpiY)3220 double CUIWindow::getScaleFactor(
3221 	bool recalculate /*= false*/,
3222 	UINT *dpiX /*= NULL*/,
3223 	UINT *dpiY /*= NULL*/)
3224 {
3225 	initScaler();
3226 	return scaler->getScaleFactor(recalculate, dpiX, dpiY);
3227 }
3228 
getBitmapSize(HBITMAP hBitmap,SIZE & size)3229 bool CUIWindow::getBitmapSize(HBITMAP hBitmap, SIZE& size)
3230 {
3231 	BITMAP bm;
3232 	if (GetObject(hBitmap, sizeof(BITMAP), &bm) != 0)
3233 	{
3234 		size.cx = bm.bmWidth;
3235 		size.cy = bm.bmHeight;
3236 		return true;
3237 	}
3238 	return false;
3239 }
3240 
initScaler(void)3241 void CUIWindow::initScaler(void)
3242 {
3243 	if (scaler == NULL)
3244 	{
3245 		scaler = new CUIScaler(this);
3246 	}
3247 }
3248 
scalePoints(int points)3249 int CUIWindow::scalePoints(int points)
3250 {
3251 	initScaler();
3252 	return scaler->scale(points);
3253 }
3254 
unscalePixels(int pixels)3255 int CUIWindow::unscalePixels(int pixels)
3256 {
3257 	initScaler();
3258 	return scaler->unscale(pixels);
3259 }
3260 
statusBarSetParts(HWND hStatusBar,WPARAM numParts,int * parts,bool scale)3261 bool CUIWindow::statusBarSetParts(
3262 	HWND hStatusBar,
3263 	WPARAM numParts,
3264 	int *parts,
3265 	bool scale /*= true*/)
3266 {
3267 	if (scale)
3268 	{
3269 		for (WPARAM i = 0; i < numParts; ++i)
3270 		{
3271 			if (parts[i] != -1)
3272 			{
3273 				parts[i] = scalePoints(parts[i]);
3274 			}
3275 		}
3276 	}
3277 	return SendMessage(hStatusBar, SB_SETPARTS, numParts, (LPARAM)parts) !=
3278 		FALSE;
3279 }
3280 
3281 // Note: static method
statusBarGetText(HWND hWnd,TCByte part,ucstring & text)3282 WORD CUIWindow::statusBarGetText(HWND hWnd, TCByte part, ucstring &text)
3283 {
3284 	LRESULT getLengthResult = SendMessage(hWnd, SB_GETTEXTLENGTH, part, 0);
3285 	WORD length = LOWORD(getLengthResult);
3286 	if (length > 0)
3287 	{
3288 		text.resize(length);
3289 		return HIWORD(SendMessage(hWnd, SB_GETTEXT, part, (LPARAM)&text[0]));
3290 	}
3291 	else
3292 	{
3293 		text.clear();
3294 		return HIWORD(getLengthResult);
3295 	}
3296 }
3297 
3298 // Note: static method
statusBarSetText(HWND hWnd,TCByte part,CUCSTR text,WORD flags)3299 bool CUIWindow::statusBarSetText(
3300 	HWND hWnd,
3301 	TCByte part,
3302 	CUCSTR text,
3303 	WORD flags)
3304 {
3305 	return SendMessage(hWnd, SB_SETTEXT, part | flags, (LPARAM)text) != FALSE;
3306 }
3307 
3308 // Note: static method
statusBarSetText(HWND hWnd,TCByte part,const ucstring & text,WORD flags)3309 bool CUIWindow::statusBarSetText(
3310 	HWND hWnd,
3311 	TCByte part,
3312 	const ucstring &text,
3313 	WORD flags)
3314 {
3315 	return statusBarSetText(hWnd, part, text.c_str(), flags);
3316 }
3317 
3318 // Note: static method
statusBarSetTipText(HWND hWnd,TCByte part,CUCSTR text)3319 void CUIWindow::statusBarSetTipText(
3320 	HWND hWnd,
3321 	TCByte part,
3322 	CUCSTR text)
3323 {
3324 	SendMessage(hWnd, SB_SETTIPTEXT, part, (LPARAM)text);
3325 }
3326 
3327 // Note: static method
statusBarSetTipText(HWND hWnd,TCByte part,const ucstring & text)3328 void CUIWindow::statusBarSetTipText(
3329 	HWND hWnd,
3330 	TCByte part,
3331 	const ucstring &text)
3332 {
3333 	statusBarSetTipText(hWnd, part, text.c_str());
3334 }
3335 
3336 // Note: static method
statusBarSetIcon(HWND hWnd,TCByte part,HICON hIcon)3337 bool CUIWindow::statusBarSetIcon(
3338 	HWND hWnd,
3339 	TCByte part,
3340 	HICON hIcon)
3341 {
3342 	return SendMessage(hWnd, SB_SETICON, part, (LPARAM)hIcon) != FALSE;
3343 }
3344 
addImageToImageList(HIMAGELIST hImageList,int resourceId,const SIZE & size,double scaleFactor)3345 int CUIWindow::addImageToImageList(
3346 	HIMAGELIST hImageList,
3347 	int resourceId,
3348 	const SIZE& size,
3349 	double scaleFactor /*= 1.0*/)
3350 {
3351 	TCImage *image = TCImage::createFromResource(NULL, resourceId, 4, true, scaleFactor);
3352 	int retValue = addImageToImageList(hImageList, image, size);
3353 	TCObject::release(image);
3354 	return retValue;
3355 }
3356 
addImageToImageList(HIMAGELIST hImageList,TCImage * image,const SIZE & size)3357 int CUIWindow::addImageToImageList(HIMAGELIST hImageList, TCImage *image, const SIZE& size)
3358 {
3359 	if (image == NULL)
3360 	{
3361 		return -1;
3362 	}
3363 	int imageIndex = -1;
3364 	HBITMAP hBitmap;
3365 	HBITMAP hMask;
3366 	bool stretched = false;
3367 
3368 	image->getBmpAndMask(hBitmap, hMask, false, CUIScaler::use32bit());
3369 	if (image->getWidth() != size.cx || image->getHeight() != size.cy)
3370 	{
3371 		HBITMAP hScaleBitmap = NULL;
3372 		HBITMAP hScaleMask = NULL;
3373 		if (scaler->scaleBitmap(hBitmap, hScaleBitmap,
3374 			(double)size.cx / (double)image->getWidth()) &&
3375 			(hMask == NULL || scaler->scaleBitmap(hMask, hScaleMask)))
3376 		{
3377 			imageIndex = ImageList_Add(hImageList, hScaleBitmap, hScaleMask);
3378 			stretched = true;
3379 		}
3380 		if (hScaleBitmap != NULL)
3381 		{
3382 			DeleteObject(hScaleBitmap);
3383 		}
3384 		if (hScaleMask != NULL)
3385 		{
3386 			DeleteObject(hScaleMask);
3387 		}
3388 	}
3389 	if (!stretched)
3390 	{
3391 		imageIndex = ImageList_Add(hImageList, hBitmap, hMask);
3392 	}
3393 	if (hBitmap != NULL)
3394 	{
3395 		DeleteObject(hBitmap);
3396 	}
3397 	if (hMask != NULL)
3398 	{
3399 		DeleteObject(hMask);
3400 	}
3401 	return imageIndex;
3402 }
3403 
setMinSize(int width,int height,bool unscale)3404 void CUIWindow::setMinSize(int width, int height, bool unscale)
3405 {
3406 	if (unscale && width != -1)
3407 	{
3408 		minWidth = unscalePixels(width);
3409 	}
3410 	else
3411 	{
3412 		minWidth = width;
3413 	}
3414 	if (unscale && height != -1)
3415 	{
3416 		minHeight = unscalePixels(height);
3417 	}
3418 	else
3419 	{
3420 		minHeight = height;
3421 	}
3422 }
3423 
3424 // This calculates the height necessary in order to display a string of text in
3425 // a check button of a given width.  If the button has a theme, the theme system
3426 // is used for the calculation.  Otherwise, it's done manually.
calcCheckHeight(HWND hCheck,HDC hdc,int checkBoxWidth,int width,int & optimalWidth)3427 int CUIWindow::calcCheckHeight(
3428 	HWND hCheck,
3429 	HDC hdc,
3430 	int checkBoxWidth,
3431 	int width,
3432 	int &optimalWidth)
3433 {
3434 	HTHEME hTheme = CUIThemes::getWindowTheme(hCheck);
3435 	ucstring text;
3436 	int height;
3437 	int newWidth = 0;
3438 
3439 	CUIWindow::windowGetText(hCheck, text);
3440 	if (hTheme == NULL)
3441 	{
3442 		// Do the calculation manually using the width available in the check
3443 		// button for the text.
3444 		height = calcTextHeight(hdc, text, width - checkBoxWidth, newWidth);
3445 		// The actual total width of the button is the width of the text plus
3446 		// the width of the check box.
3447 		newWidth += checkBoxWidth;
3448 	}
3449 	else
3450 	{
3451 		// Give it plenty of vertical space for the text.
3452 		RECT boundingRect = { 0, 0, width, 1024 };
3453 		RECT textRect;
3454 		SIZE boxSize;
3455 		int state = CBS_CHECKEDNORMAL;
3456 #ifdef TC_NO_UNICODE
3457 		std::wstring wText;
3458 
3459 		stringtowstring(wText, text);
3460 #else // TC_NO_UNICODE
3461 		std::wstring &wText = text;
3462 #endif // TC_NO_UNICODE
3463 		// Get the size of the check box.
3464 		CUIThemes::getThemePartSize(hTheme, hdc, BP_CHECKBOX, state, NULL,
3465 			TS_TRUE, &boxSize);
3466 		HMONITOR hMonitor = MonitorFromWindow(hCheck, MONITOR_DEFAULTTOPRIMARY);
3467 		double scaleFactor = CUIScaler::getScaleFactor(hMonitor);
3468 		// The + 3 is for the space between the check box and the text.  (This
3469 		// was determined empirically, but works at both the standard font DPI
3470 		// of 96 and the "large fonts" DPI of 120.
3471 		boundingRect.left += boxSize.cx + (LONG)(3 * scaleFactor);
3472 		// The following basically does exactly what we are trying to do in this
3473 		// method.  It calculates the width and height needed for the text
3474 		// string to fit into the given bounding box, wrapping as needed.
3475 		CUIThemes::getThemeTextExtent(hTheme, hdc, BP_CHECKBOX, state,
3476 			wText.c_str(), -1, DT_LEFT | DT_WORDBREAK | DT_CALCRECT,
3477 			&boundingRect, &textRect);
3478 		height = textRect.bottom - textRect.top;
3479 		newWidth = textRect.right;
3480 	}
3481 	if (newWidth > optimalWidth)
3482 	{
3483 		optimalWidth = newWidth;
3484 	}
3485 	return height;
3486 }
3487 
3488 // This calculates the height necessary in order to display a string of text in
3489 // a given width.  It also calculate the actual width needed, and if that is
3490 // greater than optimalWidth, it updates optimalWidth to match.  If the text has
3491 // to be wrapped to multiple lines, this does that at spaces.  If a word in the
3492 // text is too long to fit on one line, it wraps at whatever location is
3493 // necessary.
calcTextHeight(HDC hdc,const ucstring & text,int width,int & optimalWidth)3494 int CUIWindow::calcTextHeight(
3495 	HDC hdc,
3496 	const ucstring &text,
3497 	int width,
3498 	int &optimalWidth)
3499 {
3500 	// remaining keeps track of all the text that hasn't yet been accounted for.
3501 	ucstring remaining = text;
3502 	int height = 0;
3503 
3504 	for (int i = 0; remaining.size() > 0; i++)
3505 	{
3506 		SIZE size;
3507 		ucstring line = remaining;
3508 
3509 		// Start out with the size needed for the whole string.
3510 		CUIWindow::getTextExtentPoint32UC(hdc, line.c_str(), (int)line.size(),
3511 			&size);
3512 		while (size.cx > width)
3513 		{
3514 			// If we get here, the string didn't fit in the given width.  Pull
3515 			// a word off the right and try again.
3516 			size_t index = line.rfind(' ');
3517 
3518 			if (line.size() == 0)
3519 			{
3520 				// Nothing fit at all, so just bail to avoid an infinite loop.
3521 				break;
3522 			}
3523 			if (index >= line.size())
3524 			{
3525 				// No spaces for split: chop off one character.
3526 				index = line.size() - 1;
3527 			}
3528 			line = line.substr(0, index);
3529 			// At this point, line has had one word removed from it (if it
3530 			// contains any spaces, otherwise one character removed).  See what
3531 			// size is neccessary for that.
3532 			CUIWindow::getTextExtentPoint32UC(hdc, line.c_str(),
3533 				(int)line.size(), &size);
3534 		}
3535 		// When we get here, whatever is in line fits in the given width.
3536 		if (line.size() > 0)
3537 		{
3538 			size_t j;
3539 
3540 			// Pull the contents of line out of remaining.
3541 			remaining = remaining.substr(line.size());
3542 			// Find the first non-space character in remaining.
3543 			for (j = 0; isspace(remaining[j]); j++)
3544 			{
3545 				// Don't do anything.
3546 			}
3547 			if (j > 0)
3548 			{
3549 				// If there were spaces on the beginning of remaining, trim them
3550 				// off.
3551 				remaining = remaining.substr(j);
3552 			}
3553 		}
3554 		else
3555 		{
3556 			// Nothing in remaining fit in the given width, so bail.
3557 			remaining.resize(0);
3558 		}
3559 		// Increment height by the height of this line of text.
3560 		height += size.cy;
3561 		if (size.cx > optimalWidth)
3562 		{
3563 			// This line of text is wider than optimalWidth, so update
3564 			// optimalWidth to match this width.
3565 			optimalWidth = size.cx;
3566 		}
3567 	}
3568 	// Return the calculated height for the text string.
3569 	return height;
3570 }
3571 
staticFixSize(HWND hChild,LPARAM lParam)3572 static BOOL CALLBACK staticFixSize(HWND hChild, LPARAM lParam)
3573 {
3574 	CUIWindow::fixControlSize(hChild, (HDC)lParam);
3575 	return TRUE;
3576 }
3577 
fixControlSize(HWND hChild,HDC hdc,bool force)3578 void CUIWindow::fixControlSize(HWND hChild, HDC hdc, bool force)
3579 {
3580 	bool skip = !force;
3581 	if (skip)
3582 	{
3583 		UCCHAR className[1024];
3584 		GetClassName(hChild, className, COUNT_OF(className));
3585 		if (ucstrcmp(className, WC_BUTTON) == 0)
3586 		{
3587 			long buttonStyle = GetWindowLong(hChild, GWL_STYLE) & BS_TYPEMASK;
3588 			if (buttonStyle == BS_AUTOCHECKBOX || buttonStyle == BS_CHECKBOX ||
3589 				buttonStyle == BS_AUTORADIOBUTTON || buttonStyle == BS_RADIOBUTTON)
3590 			{
3591 				// Check box or radio button.
3592 				skip = false;
3593 			}
3594 		}
3595 	}
3596 	if (!skip)
3597 	{
3598 		RECT rect;
3599 		ucstring title;
3600 		CUIWindow::windowGetText(hChild, title);
3601 		POINT point = { 0, 0 };
3602 		ClientToScreen(GetParent(hChild), &point);
3603 		GetWindowRect(hChild, &rect);
3604 		rect.left -= point.x;
3605 		rect.right -= point.x;
3606 		rect.top -= point.y;
3607 		rect.bottom -= point.y;
3608 		int width = rect.right - rect.left;
3609 		int optimalWidth = 0;
3610 		int height = CUIWindow::calcCheckHeight(hChild, hdc,
3611 			g_checkBoxWidth, width * 2, optimalWidth);
3612 		MoveWindow(hChild, rect.left, rect.top, optimalWidth,
3613 			rect.bottom - rect.top, TRUE);
3614 	}
3615 }
3616 
fixControlSize(HWND hWnd)3617 void CUIWindow::fixControlSize(HWND hWnd)
3618 {
3619 	HWND hDlg = GetParent(hWnd);
3620 	HDC hdc = GetDC(hDlg);
3621 	HFONT hNewFont = (HFONT)SendMessage(hDlg, WM_GETFONT, 0, 0);
3622 	HFONT hOldFont = (HFONT)SelectObject(hdc, hNewFont);
3623 	fixControlSize(hWnd, hdc, true);
3624 	SelectObject(hdc, hOldFont);
3625 	ReleaseDC(hDlg, hdc);
3626 }
3627 
fixDialogSizes(HWND hDlg)3628 void CUIWindow::fixDialogSizes(HWND hDlg)
3629 {
3630 	HDC hdc = GetDC(hDlg);
3631 	HFONT hNewFont = (HFONT)SendMessage(hDlg, WM_GETFONT, 0, 0);
3632 	HFONT hOldFont = (HFONT)SelectObject(hdc, hNewFont);
3633 	SIZE size;
3634 	GetTextExtentPoint32A(hdc, "X", 1, &size);
3635 	HMONITOR hMonitor = MonitorFromWindow(hDlg, MONITOR_DEFAULTTOPRIMARY);
3636 	double scaleFactor = CUIScaler::getScaleFactor(hMonitor);
3637 	// The check box size is calculated based on the font height.  The + 4 is
3638 	// for the space between the box and the text.
3639 	g_checkBoxWidth = size.cy + (LONG)(scaleFactor * 4);
3640 	EnumChildWindows(hDlg, staticFixSize, (LPARAM)hdc);
3641 	SelectObject(hdc, hOldFont);
3642 	ReleaseDC(hDlg, hdc);
3643 }
3644 
haveWindowsVersionOrLater(WORD wMajorVersion,WORD wMinorVersion)3645 static bool haveWindowsVersionOrLater(WORD wMajorVersion, WORD wMinorVersion)
3646 {
3647 	OSVERSIONINFOEX osvi;
3648 	DWORDLONG dwlConditionMask = 0;
3649 	int op = VER_GREATER_EQUAL;
3650 
3651 	// Initialize the OSVERSIONINFOEX structure.
3652 	ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
3653 	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
3654 	osvi.dwMajorVersion = wMajorVersion;
3655 	osvi.dwMinorVersion = wMinorVersion;
3656 	osvi.wServicePackMajor = 0;
3657 	osvi.wServicePackMinor = 0;
3658 
3659 	// Initialize the condition mask.
3660 	VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, op);
3661 	VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, op);
3662 	VER_SET_CONDITION(dwlConditionMask, VER_SERVICEPACKMAJOR, op);
3663 	VER_SET_CONDITION(dwlConditionMask, VER_SERVICEPACKMINOR, op);
3664 
3665 	// Perform the test.
3666 	return VerifyVersionInfo(
3667 		&osvi,
3668 		VER_MAJORVERSION | VER_MINORVERSION |
3669 		VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
3670 		dwlConditionMask) != FALSE;
3671 }
3672 
haveWindowsXPOrLater(void)3673 bool haveWindowsXPOrLater(void)
3674 {
3675 	return haveWindowsVersionOrLater(5, 1);
3676 }
3677 
haveWindowsVistaOrLater(void)3678 bool haveWindowsVistaOrLater(void)
3679 {
3680 	return haveWindowsVersionOrLater(6, 0);
3681 }
3682 
haveWindows7OrLater(void)3683 bool haveWindows7OrLater(void)
3684 {
3685 	// Yes, "Windows 7" is Windows Version 6.1.
3686 	return haveWindowsVersionOrLater(6, 1);
3687 }
3688