1: /*
2: ============================================================================
3: xoblite™ -> an advanced "extended shell" for Microsoft® Windows® 11
4: Copyright © 2002-2026 Karl Henrik Henriksson [qwilk/@xoblite]
5: Copyright © 2001-2004 The Blackbox for Windows Development Team
6: http://xoblite.net/ + https://github.com/xoblite/
7: ============================================================================
8:
9: Blackbox for Windows is free software, released under the
10: GNU General Public License (GPL version 2 or later), with an extension
11: that allows linking of proprietary modules under a controlled interface.
12: What this means is that plugins etc. are allowed to be released
13: under any license the author wishes. Please note, however, that the
14: original Blackbox gradient math code used in Blackbox for Windows
15: is available under the BSD license.
16:
17: http://www.fsf.org/licenses/gpl.html
18: http://www.fsf.org/licenses/gpl-faq.html#LinkingOverControlledInterface
19: http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
20:
21: This program is distributed in the hope that it will be useful,
22: but WITHOUT ANY WARRANTY; without even the implied warranty of
23: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24: GNU General Public License for more details.
25:
26: For additional license information, please read the included license.html.
27:
28: ============================================================================
29: */
30:
31: #include "PopupDialog.h"
32:
33: const char szPopupDialogName[] = "BBPopupDialog"; // Window class etc.
34:
35: extern PopupDialog* pPopupDialog;
36: extern Settings* pSettings;
37: extern BImage* pBImage;
38:
39: int popupDialogMessageSubscription[] = { BB_RECONFIGURE, BB_POPUPMESSAGE, 0 };
40:
41: //===========================================================================
42:
43: PopupDialog::PopupDialog(HINSTANCE hInstance)
44: {
45: hPopupDialogWnd = NULL;
46: hBlackboxWnd = GetBBWnd();
47: hPopupDialogInstance = hInstance;
48: cachedBackground = CreateCompatibleDC(NULL);
49: message.title[0] = message.body[0] = '\0';
50: PopupDialogHidden = true;
51: PopupTypeYesNo = false;
52: dynamicFontHeight = 15;
53:
54: //====================
55:
56: // Get size and position for our window...
57: GetDimensions();
58:
59: //====================
60:
61: // Register window class...
62: WNDCLASS wc;
63: ZeroMemory(&wc, sizeof(wc));
64: wc.hInstance = hPopupDialogInstance; // hInstance
65: wc.lpfnWndProc = PopupDialogProc; // Window procedure
66: wc.lpszClassName = szPopupDialogName; // Window class name
67: wc.hbrBackground = NULL; // No class background brush
68: wc.style = CS_DBLCLKS; // Class styles (e.g. accept doubleclicks)
69: wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Always display the regular arrow cursor
70:
71: if (!RegisterClass(&wc))
72: {
73: MessageBox(0, "Error registering popup dialog window class!", szPopupDialogName, MB_OK | MB_ICONERROR | MB_TOPMOST);
74: Log("PopupDialog: Error registering window class!", NULL);
75: return;
76: }
77:
78: // Create popup dialog window...
79: hPopupDialogWnd = CreateWindowEx(
80: WS_EX_TOOLWINDOW | WS_EX_ACCEPTFILES | WS_EX_NOACTIVATE | WS_EX_LAYERED, // window style
81: szPopupDialogName, // window class
82: NULL, // window name
83: WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, // window parameters
84: PopupDialogX, // x position
85: PopupDialogY, // y position
86: PopupDialogWidth, // window width
87: PopupDialogHeight, // window height
88: NULL, //pDesktop->hDesktopWnd, // owner window
89: NULL, // no menu
90: hPopupDialogInstance, // hInstance
91: NULL // no window creation data
92: );
93:
94: if (!hPopupDialogWnd)
95: {
96: UnregisterClass(szPopupDialogName, hPopupDialogInstance); // Unregister window class
97: MessageBox(0, "Error creating popup dialog window!", szPopupDialogName, MB_OK | MB_ICONERROR | MB_TOPMOST);
98: Log("PopupDialog: Error creating window!", NULL);
99: return;
100: }
101:
102: ShowWindow(hPopupDialogWnd, SW_HIDE);
103: MakeSticky(hPopupDialogWnd); // Make the popup dialog window sticky... (i.e. shown regardless of the current workspace)
104:
105: //====================
106:
107: // Subscribe to Blackbox messages applicable to popup dialogs...
108: SendMessage(hBlackboxWnd, BB_REGISTERMESSAGE, (WPARAM)hPopupDialogWnd, (LPARAM)popupDialogMessageSubscription);
109: }
110:
111: //===========================================================================
112:
113: PopupDialog::~PopupDialog()
114: {
115: // Unsubscribe to previously subscribed Blackbox messages...
116: SendMessage(hBlackboxWnd, BB_UNREGISTERMESSAGE, (WPARAM)hPopupDialogWnd, (LPARAM)popupDialogMessageSubscription);
117:
118: if (hPopupDialogWnd) DestroyWindow(hPopupDialogWnd); // Destroy window....
119: UnregisterClass(szPopupDialogName, hPopupDialogInstance); // Unregister window class...
120: if (cachedBackground) DeleteDC(cachedBackground); // Delete the cached gradient...
121: }
122:
123: //===========================================================================
124:
125: LRESULT CALLBACK PopupDialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
126: {
127:
128: switch (message)
129: {
130: //====================
131:
132: case BB_POPUPMESSAGE:
133: {
134: if ((wParam == NULL) && (lParam == NULL))
135: {
136: ShowWindow(pPopupDialog->hPopupDialogWnd, SW_HIDE);
137: pPopupDialog->PopupDialogHidden = true;
138: }
139: else
140: {
141: // strncpy(pPopupDialog->message.title, (LPCSTR)wParam, sizeof(pPopupDialog->message.title));
142: // strncpy(pPopupDialog->message.body, (LPCSTR)lParam, sizeof(pPopupDialog->message.body));
143: strncpy_s(pPopupDialog->message.title, sizeofArray(pPopupDialog->message.title), (LPCSTR)wParam, _TRUNCATE);
144: strncpy_s(pPopupDialog->message.body, sizeofArray(pPopupDialog->message.body), (LPCSTR)lParam, _TRUNCATE);
145: pPopupDialog->message.title[sizeof(pPopupDialog->message.title)-1] = '\0';
146: pPopupDialog->message.body[sizeof(pPopupDialog->message.body)-1] = '\0';
147:
148: if (!_strnicmp(pPopupDialog->message.body, "@xoblite", 8) || !_strnicmp(pPopupDialog->message.body, "@GoToURL", 8)) pPopupDialog->PopupTypeYesNo = true;
149: else pPopupDialog->PopupTypeYesNo = false;
150:
151: pPopupDialog->PopupDialogHidden = false;
152: pPopupDialog->UpdatePopupDialog();
153:
154: ShowWindow(pPopupDialog->hPopupDialogWnd, SW_SHOWNOACTIVATE);
155: // if (pPopupDialog->PopupTypeYesNo) SetWindowPos(pPopupDialog->hPopupDialogWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER);
156: // else
157: // {
158: // SetWindowPos(pPopupDialog->hPopupDialogWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER);
159: // SetWindowPos(pPopupDialog->hPopupDialogWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER);
160: // }
161: SetWindowPos(pPopupDialog->hPopupDialogWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER);
162:
163: if (pPopupDialog->PopupTypeYesNo) SetForegroundWindow(pPopupDialog->hPopupDialogWnd); // Move the focus to the popup dialog window to allow Yes/No selection via the keyboard... (see WM_KEYDOWN below)
164: }
165: }
166: break;
167:
168: //===========================================================================
169:
170: case BB_RECONFIGURE:
171: case WM_DISPLAYCHANGE:
172: {
173: if (!pPopupDialog->PopupDialogHidden) pPopupDialog->UpdatePopupDialog();
174: }
175: break;
176:
177: case WM_SETTINGCHANGE:
178: {
179: if (!pPopupDialog->PopupDialogHidden)
180: {
181: // Update the [centered] popup dialog window's position if the work area changes...
182: // (e.g. if the Explorer taskbar is moved to another screen edge)
183: if (wParam == SPI_SETWORKAREA) pPopupDialog->UpdatePopupDialog();
184: }
185: return 0;
186: }
187:
188: //====================
189:
190: case WM_CLOSE:
191: return 0;
192:
193: //====================
194:
195: case WM_NCHITTEST:
196: {
197: RECT r;
198: GetWindowRect(hwnd, &r);
199: int relativeY = HIWORD(lParam) - r.top; // Get y position relative to the window... (nb. lParam x/y position is relative to the *screen*)
200: if (relativeY <= pPopupDialog->PopupDialogTitleHeight) return HTCAPTION;
201: else return HTCLIENT;
202: }
203: break;
204:
205: //====================
206:
207: case WM_LBUTTONUP:
208: {
209: if (pPopupDialog->PopupTypeYesNo)
210: {
211: POINT pt;
212: pt.x = LOWORD(lParam);
213: pt.y = HIWORD(lParam);
214:
215: // Did the user click the "Yes" button?
216: if (PtInRect(&pPopupDialog->popupYesRect, pt))
217: {
218: ShowWindow(pPopupDialog->hPopupDialogWnd, SW_HIDE);
219: pPopupDialog->PopupDialogHidden = true;
220: // PlaySoundFX(SFX_TASKBAR_MINIMIZE);
221: BBSmartExecute(pPopupDialog->message.body);
222: break;
223: }
224: else if (PtInRect(&pPopupDialog->popupNoRect, pt))
225: {
226: ShowWindow(pPopupDialog->hPopupDialogWnd, SW_HIDE);
227: pPopupDialog->PopupDialogHidden = true;
228: // PlaySoundFX(SFX_TASKBAR_MINIMIZE);
229: break;
230: }
231: }
232: else
233: {
234: ShowWindow(pPopupDialog->hPopupDialogWnd, SW_HIDE);
235: pPopupDialog->PopupDialogHidden = true;
236: PlaySoundFX(SFX_TASKBAR_MINIMIZE);
237: }
238: }
239: break;
240:
241: //====================
242:
243: case WM_KEYDOWN:
244: {
245: if (pPopupDialog->PopupTypeYesNo)
246: {
247: if (wParam == VK_RETURN) // Return key -> Equivalent to clicking the "Yes" button...
248: {
249: ShowWindow(pPopupDialog->hPopupDialogWnd, SW_HIDE);
250: pPopupDialog->PopupDialogHidden = true;
251: // PlaySoundFX(SFX_TASKBAR_MINIMIZE);
252: BBSmartExecute(pPopupDialog->message.body);
253: }
254: else if ((wParam == VK_ESCAPE) || (wParam == VK_DELETE)) // Escape of Delete key -> Equivalent to clicking the "No" button...
255: {
256: ShowWindow(pPopupDialog->hPopupDialogWnd, SW_HIDE);
257: pPopupDialog->PopupDialogHidden = true;
258: // PlaySoundFX(SFX_TASKBAR_MINIMIZE);
259: }
260: }
261:
262: return 0;
263: }
264: break;
265:
266: //====================
267:
268: default:
269: return DefWindowProc(hwnd, message, wParam, lParam);
270:
271: //====================
272: }
273: return 0;
274: }
275:
276: //===========================================================================
277: // Function: UpdatePopupDialog
278: // Purpose: ...
279: //===========================================================================
280:
281: void PopupDialog::UpdatePopupDialog()
282: {
283: if (PopupDialogHidden) return;
284:
285: // Fetch the new size and position parameters for our window...
286: GetDimensions();
287:
288: RECT r;
289: SetRect(&r, 0, 0, PopupDialogWidth, PopupDialogHeight);
290:
291: HDC hdc = GetWindowDC(hPopupDialogWnd);
292: HBITMAP bufbmp = CreateCompatibleBitmap(hdc, PopupDialogWidth, PopupDialogHeight);
293: DeleteObject(SelectObject(cachedBackground, bufbmp));
294: ReleaseDC(hPopupDialogWnd, hdc);
295:
296: //====================
297:
298: // Draw popup dialog window background... (title + body as applicable)
299: if (PopupTypeYesNo)
300: {
301: SetRect(&r, 0, 0, PopupDialogWidth, PopupDialogHeight);
302: HBRUSH brush = CreateSolidBrush(0x000000);
303: FillRect(cachedBackground, &r, brush);
304: DeleteObject(brush);
305: }
306: else
307: {
308: SetRect(&r, 0, 0, PopupDialogWidth, PopupDialogHeight);
309: HBRUSH brush = CreateSolidBrush(0xffffff);
310: FillRect(cachedBackground, &r, brush);
311: DeleteObject(brush);
312:
313: SetRect(&r, 0, 0, PopupDialogWidth, PopupDialogTitleHeight);
314: brush = CreateSolidBrush(0x000000);
315: FillRect(cachedBackground, &r, brush);
316: DeleteObject(brush);
317: }
318:
319: //====================
320:
321: // Create the popup dialog window font... (nb. always using "Segoe UI" for consistency)
322: HFONT font = CreateFont(dynamicFontHeight*pSettings->scalingFactorHiDPI, 0, 0, 0, FW_NORMAL, false, false, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Segoe UI");
323: HGDIOBJ oldfont = SelectObject(cachedBackground, font);
324: SetBkMode(cachedBackground, TRANSPARENT);
325:
326: if (PopupTypeYesNo) // -> Popup dialog window with a question + yes/no buttons; executing a specified bro@m upon answering yes, abort on answering no...
327: {
328: // Draw message...
329: // DrawTextWithEffects(cachedBackground, popupTitleTextRect, message.title, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS, 0xffffff, false, 0, false, 0, 0, 0);
330: DrawTextWithEffects(cachedBackground, popupTitleTextRect, message.title, DT_CENTER | DT_TOP | DT_NOPREFIX | DT_WORD_ELLIPSIS, 0xffffff, false, 0, false, 0, 0, 0);
331:
332: // Draw yes/no butttons...
333: int buttonBorderWidth = 2;
334: if (pSettings->scalingFactorHiDPI > 1) buttonBorderWidth = 5 * (pSettings->scalingFactorHiDPI - 1);
335: MakeGradient(cachedBackground, popupYesRect, B_SOLID, 0x000000, 0, false, 0, 0, 0, 0x008800, buttonBorderWidth);
336: DrawTextWithEffects(cachedBackground, popupYesRect, "Yes", DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE, 0xffffff, false, 0, false, 0, 0, 0);
337: MakeGradient(cachedBackground, popupNoRect, B_SOLID, 0x000000, 0, false, 0, 0, 0, 0x000088, buttonBorderWidth);
338: DrawTextWithEffects(cachedBackground, popupNoRect, "No", DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE, 0xffffff, false, 0, false, 0, 0, 0);
339:
340: }
341: else // -> Popup dialog window showing information in a regular black text on white background message body... (e.g. About xoblite, About the current style, etc)
342: {
343: // Draw message title...
344: DrawTextWithEffects(cachedBackground, popupTitleTextRect, message.title, DT_LEFT | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS, 0xffffff, false, 0, false, 0, 0, 0);
345: // Draw message body...
346: DrawTextWithEffects(cachedBackground, popupBodyTextRect, message.body, DT_LEFT | DT_TOP | DT_NOPREFIX | DT_WORD_ELLIPSIS, 0x000000, false, 0, false, 0, 0, 0);
347: }
348:
349: DeleteObject(SelectObject(cachedBackground, oldfont));
350:
351: //====================
352:
353: // Are we showing the "About xoblite..." popup dialog window?
354: if (IsInString(message.title, "About xoblite..."))
355: {
356: // Draw xoblite icon rightmost on the window title bar...
357: HICON popupIcon;
358: RECT iconRect;
359: int titleVerticalCenter = PopupDialogTitleHeight / 2;
360:
361: iconRect.left = PopupDialogWidth - popupIconSize - (5*pSettings->scalingFactorHiDPI);
362: iconRect.top = titleVerticalCenter - (popupIconSize / 2);
363: iconRect.bottom = iconRect.top + popupIconSize;
364: iconRect.right = iconRect.left + popupIconSize;
365:
366: popupIcon = LoadIcon(hPopupDialogInstance, MAKEINTRESOURCE(IDI_XOBLITE));
367: DrawSatHueIcon(cachedBackground, iconRect, popupIcon, popupIconSize, 255, 0);
368: DeleteObject(popupIcon);
369: }
370:
371: //====================
372:
373: // Apply per pixel alpha, creating e.g. nice rounded corners... 8)
374: SetRect(&r, 0, 0, PopupDialogWidth, PopupDialogHeight);
375: AlphaRect(cachedBackground, r, 255); // 210?
376: AlphaCorner(cachedBackground, r, CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT, 0, 0, 0, 0, 0, 255); // 210?
377: SetRect(&r, 0, 0, PopupDialogWidth, PopupDialogTitleHeight);
378: AlphaRect(cachedBackground, r, 255);
379: AlphaCorner(cachedBackground, r, CORNER_TOPLEFT | CORNER_TOPRIGHT, 0, 0, 0, 0, 0, 255);
380: SetRect(&r, 0, 0, PopupDialogWidth, PopupDialogHeight);
381: AlphaApply(cachedBackground, r);
382:
383: //====================
384:
385: if (bufbmp) DeleteObject(bufbmp);
386:
387: POINT pt;
388: pt.x = PopupDialogX, pt.y = PopupDialogY;
389: POINT ptSrc;
390: ptSrc.x = 0, ptSrc.y = 0;
391:
392: BLENDFUNCTION bf;
393: bf.BlendOp = AC_SRC_OVER;
394: bf.BlendFlags = 0;
395: bf.AlphaFormat = AC_SRC_ALPHA;
396: bf.SourceConstantAlpha = (unsigned char)255;
397:
398: SIZE windowSize = { PopupDialogWidth, PopupDialogHeight };
399: BOOL result = UpdateLayeredWindow(hPopupDialogWnd, NULL, &pt, &windowSize, cachedBackground, &ptSrc, 0, &bf, ULW_ALPHA);
400: /*
401: if (!cachedBackground) SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)"xoblite -> PopupDialog -> Invalid cachedBackground!");
402:
403: if (result == 0)
404: {
405: int error = GetLastError();
406: char msg[255];
407: sprintf_s(msg, sizeofArray(msg), "xoblite -> PopupDialog -> UpdateLayeredWindow failed! [error code %d]", error);
408: SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_ERROR_MESSAGE, (LPARAM)msg);
409: }
410: */
411: }
412:
413: //===========================================================================
414: // Function: GetDimensions
415: // Purpose: ...
416: //===========================================================================
417:
418: void PopupDialog::GetDimensions()
419: {
420: RECT workArea;
421: SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&workArea, SPIF_SENDCHANGE);
422: ScreenWidth = workArea.right - workArea.left;
423: ScreenHeight = workArea.bottom - workArea.top;
424:
425: //====================
426:
427: // Count the number of row of text in the message body...
428: int numberOfRowsOfText = 1;
429: if (PopupTypeYesNo)
430: {
431: for (unsigned int n=0; n < strnlen_s(message.title, sizeofArray(message.title)); n++)
432: {
433: if (message.title[n] == '\n') numberOfRowsOfText++;
434: }
435: }
436: else
437: {
438: for (unsigned int n=0; n< strnlen_s(message.body, sizeofArray(message.body)); n++)
439: {
440: if (message.body[n] == '\n') numberOfRowsOfText++;
441: }
442: }
443:
444: // char msg[255];
445: // sprintf_s(msg, sizeofArray(msg), "PopupDialog -> DEBUG -> numberOfRowsOfText: %d", numberOfRowsOfText);
446: // SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
447:
448: //====================
449:
450: dynamicFontHeight = 15; // Default font size (before being multiplied by HiDPI scaling factor)
451: if (!PopupTypeYesNo)
452: {
453: // Adjust the font size dynamically based on a rough approximation (read: not an exact science here) of the resulting window size...
454: while (((1+numberOfRowsOfText) * (dynamicFontHeight*pSettings->scalingFactorHiDPI)) > ((ScreenHeight*80)/100)) dynamicFontHeight -= 1;
455: if (dynamicFontHeight < 5) dynamicFontHeight = 5; // Safeguard :)
456: }
457:
458: //====================
459:
460: // Calculate the window title height...
461: SIZE size;
462: HDC fonthdc = CreateDC("DISPLAY", NULL, NULL, NULL);
463: HFONT tempFont = CreateFont(dynamicFontHeight*pSettings->scalingFactorHiDPI, 0, 0, 0, FW_NORMAL, false, false, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Segoe UI");
464: HGDIOBJ oldFont = SelectObject(fonthdc, tempFont);
465:
466: GetTextExtentPoint32(fonthdc, "TQkgfp/", 8, &size);
467: PopupDialogTitleHeight = size.cy + (5*pSettings->scalingFactorHiDPI);
468:
469: // Choose the window title icon size depending on the height of the window title...
470: // if (PopupDialogTitleHeight >= 36) popupIconSize = 32;
471: // else popupIconSize = 16;
472:
473: // Set the window title icon size depending on the height of the window title...
474: popupIconSize = size.cy;
475:
476: //====================
477:
478: // Calculate window height...
479: if (PopupTypeYesNo)
480: {
481: PopupDialogYesNoHeight = (PopupDialogTitleHeight * 2);
482: // PopupDialogHeight = (size.cy * numberOfRowsOfText) + PopupDialogYesNoHeight + 30; // 30 pixels -> 10 pixels of padding at the top, bottom and in between message and yes/no buttons
483: PopupDialogHeight = (size.cy * numberOfRowsOfText) + PopupDialogYesNoHeight + (15*pSettings->scalingFactorHiDPI); // -> Extra pixels of padding at the top, bottom and in between message and yes/no buttons
484: }
485: // else PopupDialogHeight = (size.cy * (numberOfRowsOfText+1)) + 25; // Message title 1 row + body N rows + misc padding
486: else PopupDialogHeight = (size.cy * (1+numberOfRowsOfText)) + (15*pSettings->scalingFactorHiDPI); // Message title 1 row + Body N rows + Padding around them
487:
488: //====================
489:
490: // Calculate window width...
491: char* ptr = NULL;
492: char* ptr2 = NULL;
493: int maxWidth;
494:
495: if (PopupTypeYesNo)
496: {
497: ptr = message.title;
498: maxWidth = 0;
499: }
500: else
501: {
502: ptr = message.body;
503: GetTextExtentPoint32(fonthdc, message.title, strnlen_s(message.title, sizeofArray(message.title)), &size);
504: maxWidth = size.cx;
505: }
506:
507: char oneRowOfText[MAX_LINE_LENGTH];
508: while (numberOfRowsOfText > 0)
509: {
510: if (ptr[0] == '\0') break;
511: else if (ptr[0] != '\n')
512: {
513: ptr2 = strchr(ptr, '\n');
514: if (ptr2 == NULL)
515: {
516: strcpy_s(oneRowOfText, sizeofArray(oneRowOfText), ptr);
517: // SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)oneRowOfText);
518: GetTextExtentPoint32(fonthdc, oneRowOfText, strnlen_s(oneRowOfText, sizeofArray(oneRowOfText)), &size);
519: if (size.cx > maxWidth) maxWidth = size.cx;
520: break;
521: }
522: else
523: {
524: // strncpy(oneRowOfText, ptr, ptr2 - ptr);
525: strncpy_s(oneRowOfText, sizeofArray(oneRowOfText), ptr, ptr2-ptr);
526: oneRowOfText[ptr2-ptr] = '\0';
527: // SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)oneRowOfText);
528: GetTextExtentPoint32(fonthdc, oneRowOfText, strnlen_s(oneRowOfText, sizeofArray(oneRowOfText)), &size);
529: if (size.cx > maxWidth) maxWidth = size.cx;
530: numberOfRowsOfText--;
531: ptr = ptr2++;
532: }
533: }
534: else ptr++;
535: }
536:
537: // PopupDialogWidth = maxWidth + 30 + popupIconSize; // Max width (of title or body) + 10 pixels padding on each side + 16 or 32 pixels wide icon + 10 pixels padding to the right of the icon
538: PopupDialogWidth = maxWidth + (15*pSettings->scalingFactorHiDPI) + popupIconSize; // Padding + Max width of title or body text + Padding + 16 or 32 pixels wide icon + Padding
539: if ((pSettings->scalingFactorHiDPI > 1) && (PopupDialogWidth < (200* pSettings->scalingFactorHiDPI))) PopupDialogWidth = (200 * pSettings->scalingFactorHiDPI); // Simple failsafe
540: else if (PopupDialogWidth < 300) PopupDialogWidth = 300; // Simple failsafe
541:
542: //====================
543:
544: // Update the popup dialog window RECTs for later use...
545: int padding = 5 * pSettings->scalingFactorHiDPI;
546: if (PopupTypeYesNo)
547: {
548: int xcenter = PopupDialogWidth / 2;
549: // SetRect(&popupYesRect, 10, PopupDialogHeight - PopupDialogYesNoHeight - 10, xcenter - 5, PopupDialogHeight - 10);
550: // SetRect(&popupNoRect, xcenter + 5, PopupDialogHeight - PopupDialogYesNoHeight - 10, PopupDialogWidth - 10, PopupDialogHeight - 10);
551: // SetRect(&popupTitleTextRect, 10, 10, PopupDialogWidth - 10, popupYesRect.top - 10);
552: SetRect(&popupYesRect, padding, PopupDialogHeight - PopupDialogYesNoHeight - padding, xcenter - (padding/2), PopupDialogHeight - padding);
553: SetRect(&popupNoRect, xcenter + (padding/2), PopupDialogHeight - PopupDialogYesNoHeight - padding, PopupDialogWidth - padding, PopupDialogHeight - padding);
554: SetRect(&popupTitleTextRect, padding, padding, PopupDialogWidth - padding, popupYesRect.top - padding);
555: }
556: else
557: {
558: // SetRect(&popupTitleTextRect, 10, 0, PopupDialogWidth - 10, PopupDialogTitleHeight);
559: // SetRect(&popupBodyTextRect, 10, PopupDialogTitleHeight + 5, PopupDialogWidth - 10, PopupDialogHeight);
560: SetRect(&popupTitleTextRect, padding, 0, PopupDialogWidth-padding, PopupDialogTitleHeight);
561: SetRect(&popupBodyTextRect, padding, PopupDialogTitleHeight+(padding/2), PopupDialogWidth-padding, PopupDialogHeight);
562: }
563:
564: DeleteObject(SelectObject(fonthdc, oldFont));
565: DeleteDC(fonthdc);
566:
567: //====================
568:
569: PopupDialogX = workArea.left + (ScreenWidth / 2) - (PopupDialogWidth / 2);
570: PopupDialogY = workArea.top + (ScreenHeight / 2) - (PopupDialogHeight / 2);
571: }
572:
573: //===========================================================================
574: