|
|
1.1 root 1:
2: /******************************************************************************\
3: * This is a part of the Microsoft Source Code Samples.
4: * Copyright (C) 1993 Microsoft Corporation.
5: * All rights reserved.
6: * This source code is only intended as a supplement to
7: * Microsoft Development Tools and/or WinHelp documentation.
8: * See these sources for detailed information regarding the
9: * Microsoft samples programs.
10: \******************************************************************************/
11:
12: /****************************** Module Header *******************************
13: * Module Name: dlgedit.c
14: *
15: * Main function and window procedure for the Dialog Box Editor.
16: *
17: * Functions:
18: *
19: * MainWndProc()
20: * ReadWindowPos()
21: * WriteWindowPos()
22: * InitApplication()
23: * InitInstance()
24: * PenWinRegister()
25: * GetSystemValues()
26: * ReadEnv()
27: * WriteEnv()
28: * LoadSysColorBitmaps()
29: * LoadAlterBitmap()
30: * RGBInvertRGB()
31: * SizeRibbons()
32: * DialogTerminate()
33: *
34: * Comments:
35: *
36: * Because of the need for a dialog in both work and test mode to be
37: * shown relative to the client area of its parent, and because the
38: * editor has a ribbon control along the top of its client area, there
39: * needed to be another window created that will be the actual parent
40: * of the dialog being edited. This window, called the ghwndSubClient
41: * window, is sized to be the size of the editors client area minus
42: * the height of the ribbon window at the top. This makes it so that
43: * a dialog that has an origin of 0,0 will have the top edge of its
44: * client area just below the bottom of the ribbon window in the
45: * editor. This window does not need any special processing. It simply
46: * paints its background with the app workspace color, and is used as
47: * the basis for coordinate conversion for the dialog.
48: *
49: ****************************************************************************/
50:
51: #include "dlgedit.h"
52: #include "dlgfuncs.h"
53: #include "dlgextrn.h"
54: #include "dialogs.h"
55:
56: #include <commdlg.h>
57:
58: #include <stdlib.h>
59: #include <string.h>
60:
61: STATICFN BOOL InitApplication(HANDLE hInstance);
62: STATICFN BOOL InitInstance(HANDLE hInstance, INT nCmdShow);
63: STATICFN VOID PenWinRegister(VOID);
64: STATICFN VOID GetSystemValues(VOID);
65: STATICFN VOID ReadEnv(VOID);
66: STATICFN VOID WriteEnv(VOID);
67: STATICFN VOID LoadSysColorBitmaps(VOID);
68: STATICFN HBITMAP LoadAlterBitmap(INT idbm, DWORD rgbNew, DWORD rgbNew2);
69: STATICFN DWORD RGBInvertRGB(DWORD rgb);
70: STATICFN VOID SizeRibbons(HWND hwnd);
71: STATICFN VOID DialogTerminate(VOID);
72:
73: static RECT grcAppPos; // Saves the app's window pos.
74: static UINT gmsgHelp; // Registered help message from commdlg.
75: static BOOL fStartAsIcon = FALSE; // TRUE if app is started minimized.
76:
77: /*
78: * Contains the address of the Pen Windows callback.
79: */
80: typedef VOID ( APIENTRY *LPFNPENWIN)(WORD, BOOL);
81: static LPFNPENWIN lpfnRegisterPenApp;
82:
83:
84:
85: /************************************************************************
86: * WinMain
87: *
88: * This is the main function for the dialog editor.
89: *
90: ************************************************************************/
91:
92: INT WINAPI WinMain(
93: HINSTANCE hInstance,
94: HINSTANCE hPrevInstance,
95: LPSTR lpCmdLine,
96: INT nCmdShow)
97: {
98: MSG msg;
99:
100: if (!hPrevInstance) {
101: if (!InitApplication(hInstance)) {
102: Message(MSG_NOINIT);
103: return FALSE;
104: }
105: }
106:
107: if (!InitInstance(hInstance, nCmdShow)) {
108: Message(MSG_NOINIT);
109: return FALSE;
110: }
111:
112: while (GetMessage(&msg, NULL, 0, 0)) {
113: if (!ghwndTestDlg || !IsDialogMessage(ghwndTestDlg, &msg)) {
114: if (!hwndStatus || !IsDialogMessage(hwndStatus, &msg)) {
115: if (!TranslateAccelerator(ghwndMain, ghAccTable, &msg)) {
116: TranslateMessage(&msg);
117: DispatchMessage(&msg);
118: }
119: }
120: }
121: }
122:
123: DialogTerminate();
124:
125: /*
126: * Return the value from PostQuitMessage.
127: */
128: return msg.wParam;
129: }
130:
131:
132:
133: /************************************************************************
134: * InitApplication
135: *
136: * Registers the window classes.
137: *
138: * Arguments:
139: * HANDLE hInstance - Instance handle from WinMain.
140: *
141: * Returns:
142: * TRUE if all of the window classes were created; otherwise, FALSE.
143: *
144: ************************************************************************/
145:
146: STATICFN BOOL InitApplication(
147: HANDLE hInstance)
148: {
149: WNDCLASS wc;
150:
151: wc.style = CS_DBLCLKS;
152: wc.lpfnWndProc = MainWndProc;
153: wc.cbClsExtra = 0;
154: wc.cbWndExtra = sizeof(DWORD);
155: wc.hInstance = hInstance;
156: wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDICON_DLGEDIT));
157: wc.hCursor = LoadCursor(NULL, IDC_ARROW);
158: wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
159: wc.lpszMenuName = MAKEINTRESOURCE(IDMENU_MAIN);
160: wc.lpszClassName = szMainClass;
161: if (!RegisterClass(&wc))
162: return FALSE;
163:
164: wc.style = 0;
165: wc.lpfnWndProc = DefWindowProc;
166: wc.cbClsExtra = 0;
167: wc.cbWndExtra = 0;
168: wc.hInstance = hInstance;
169: wc.hIcon = NULL;
170: wc.hCursor = LoadCursor(NULL, IDC_ARROW);
171: wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
172: wc.lpszMenuName = NULL;
173: wc.lpszClassName = szSubClientClass;
174: if (!RegisterClass(&wc))
175: return FALSE;
176:
177: wc.style = CS_DBLCLKS;
178: wc.lpfnWndProc = DragWndProc;
179: wc.cbClsExtra = 0;
180: wc.cbWndExtra = sizeof(DWORD);
181: wc.hInstance = hInstance;
182: wc.hIcon = NULL;
183: wc.hCursor = LoadCursor(NULL, IDC_ARROW);
184: wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
185: wc.lpszMenuName = NULL;
186: wc.lpszClassName = szDragClass;
187: if (!RegisterClass(&wc))
188: return FALSE;
189:
190: wc.style = 0;
191: wc.lpfnWndProc = ToolboxWndProc;
192: wc.cbClsExtra = 0;
193: wc.cbWndExtra = 0;
194: wc.hInstance = hInstance;
195: wc.hIcon = NULL;
196: wc.hCursor = LoadCursor(NULL, IDC_ARROW);
197: wc.hbrBackground = GetStockObject(LTGRAY_BRUSH);
198: wc.lpszMenuName = NULL;
199: wc.lpszClassName = szToolboxClass;
200: if (!RegisterClass(&wc))
201: return FALSE;
202:
203: wc.style = 0;
204: wc.lpfnWndProc = ToolBtnWndProc;
205: wc.cbClsExtra = 0;
206: wc.cbWndExtra = 0;
207: wc.hInstance = hInstance;
208: wc.hIcon = NULL;
209: wc.hCursor = LoadCursor(NULL, IDC_ARROW);
210: wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
211: wc.lpszMenuName = NULL;
212: wc.lpszClassName = szToolBtnClass;
213: if (!RegisterClass(&wc))
214: return FALSE;
215:
216: wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
217: wc.lpfnWndProc = CustomWndProc;
218: wc.cbClsExtra = 0;
219: wc.cbWndExtra = 0;
220: wc.hInstance = hInstance;
221: wc.hIcon = NULL;
222: wc.hCursor = LoadCursor(NULL, IDC_ARROW);
223: wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
224: wc.lpszMenuName = NULL;
225: wc.lpszClassName = szCustomClass;
226: if (!RegisterClass(&wc))
227: return FALSE;
228:
229: return TRUE;
230: }
231:
232:
233:
234: /************************************************************************
235: * InitInstance
236: *
237: * Initializes the dialog editor by loading resources, etc.
238: *
239: * Arguments:
240: * HANDLE hInstance - Instance handle from WinMain.
241: * int nCmdShow - Show command from WinMain.
242: *
243: * Returns:
244: * FALSE if any errors occurred during initialization
245: *
246: ************************************************************************/
247:
248: STATICFN BOOL InitInstance(
249: HANDLE hInstance,
250: INT nCmdShow)
251: {
252: HDC hDC;
253: TEXTMETRIC tm;
254: INT x;
255: INT y;
256: INT cx;
257: INT cy;
258: BOOL fMaximized;
259: INT i;
260: TCHAR szArg1[CCHTEXTMAX];
261:
262: ghInst = hInstance;
263:
264: /*
265: * We need a mouse - make sure we have one.
266: */
267: if (!GetSystemMetrics(SM_MOUSEPRESENT)) {
268: Message(MSG_NOMOUSE);
269: return FALSE;
270: }
271:
272: /*
273: * Register for Pen Windows, if it is present.
274: */
275: PenWinRegister();
276:
277: ghAccTable = LoadAccelerators(ghInst, MAKEINTRESOURCE(IDACCEL_MAIN));
278:
279: /*
280: * Create a dark gray pen for use in borders later.
281: */
282: if (!(hpenDarkGray = CreatePen(PS_SOLID, 1, DARKGRAY)))
283: return FALSE;
284:
285: /*
286: * Get some system constants.
287: */
288: GetSystemValues();
289:
290: /*
291: * Note that this must be done instead of using the text metrics,
292: * because Windows internally generates a better average value for
293: * proportional fonts, and we must match it or our dialogs will
294: * be out of proportion.
295: */
296: gcxSysChar = LOWORD(GetDialogBaseUnits());
297: gcySysChar = HIWORD(GetDialogBaseUnits());
298:
299: /*
300: * Because some useful worker routines like WinToDUPoint use
301: * the values in gcd.c*Char, set them to be the default font right
302: * away. When a dialog is loaded with a different font, they
303: * will be modified.
304: */
305: gcd.cxChar = gcxSysChar;
306: gcd.cyChar = gcySysChar;
307:
308: /*
309: * Build the help file name path. Assume the help file is in the
310: * same directory as the executable.
311: */
312: GetModuleFileName(ghInst, gszHelpFile, CCHMAXPATH);
313: *FileInPath(gszHelpFile) = CHAR_NULL;
314: lstrcat(gszHelpFile, ids(IDS_HELPFILE));
315:
316: /*
317: * Register the message for help from the common dialogs.
318: */
319: gmsgHelp = RegisterWindowMessage(HELPMSGSTRING);
320:
321: /*
322: * Hook the message filter stream so that we can detect F1 keystrokes.
323: */
324: ghhkMsgFilter = SetWindowsHook(WH_MSGFILTER, (HOOKPROC)MsgFilterHookFunc);
325:
326: /*
327: * Read the last position for the app.
328: */
329: if (!ReadWindowPos(szAppPos, &x, &y, &cx, &cy, &fMaximized)) {
330: x = CW_USEDEFAULT;
331: y = CW_USEDEFAULT;
332: cx = CW_USEDEFAULT;
333: cy = CW_USEDEFAULT;
334: fMaximized = FALSE;
335: }
336:
337: /*
338: * Create the main window.
339: */
340: if (!(ghwndMain = CreateWindow(szMainClass, NULL,
341: WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
342: x, y, cx, cy, NULL, NULL, hInstance, NULL)))
343: return FALSE;
344:
345: ShowFileStatus(TRUE);
346:
347: /*
348: * Read the Preferences data.
349: */
350: ReadEnv();
351:
352: /*
353: * If the app was saved when maximized (and they didn't start it up
354: * with some kind of an option to have it minimized or in some
355: * other funny initial state from the shell), then cause it to
356: * be maximized when shown.
357: */
358: if (fMaximized && (nCmdShow == SW_SHOWNORMAL || nCmdShow == SW_SHOW))
359: nCmdShow = SW_SHOWMAXIMIZED;
360:
361: ShowWindow(ghwndMain, nCmdShow);
362: UpdateWindow(ghwndMain);
363:
364: /*
365: * Did the user start this app minimized from the program manager?
366: */
367: if (IsIconic(ghwndMain)) {
368: /*
369: * Set a flag. The showing of the toolbox will be deferred
370: * until the app is restored.
371: */
372: fStartAsIcon = TRUE;
373: }
374: else {
375: /*
376: * If they had the Toolbox before, show it now.
377: */
378: if (gfShowToolbox)
379: ToolboxShow(TRUE);
380: }
381:
382: hcurArrow = LoadCursor(NULL, IDC_ARROW);
383: hcurWait = LoadCursor(NULL, IDC_WAIT);
384: hcurOutSel = LoadCursor(ghInst, MAKEINTRESOURCE(IDCUR_OUTSEL));
385: hcurMove = LoadCursor(ghInst, MAKEINTRESOURCE(IDCUR_MOVE));
386: hcurInsert = LoadCursor(ghInst, MAKEINTRESOURCE(IDCUR_INSERT));
387: hcurDropTool = LoadCursor(ghInst, MAKEINTRESOURCE(IDCUR_DROPTOOL));
388: hcurSizeNESW = LoadCursor(NULL, IDC_SIZENESW);
389: hcurSizeNS = LoadCursor(NULL, IDC_SIZENS);
390: hcurSizeNWSE = LoadCursor(NULL, IDC_SIZENWSE);
391: hcurSizeWE = LoadCursor(NULL, IDC_SIZEWE);
392:
393: if (!hcurArrow ||
394: !hcurWait ||
395: !hcurOutSel ||
396: !hcurMove ||
397: !hcurDropTool ||
398: !hcurInsert)
399: return FALSE;
400:
401: if ((hDC = GetDC(ghwndMain)) == NULL)
402: return FALSE;
403:
404: GetTextMetrics(hDC, &tm);
405:
406: gcyPixelsPerInch = GetDeviceCaps(hDC, LOGPIXELSY);
407:
408: /*
409: * Create a memory DC for drawing bitmaps.
410: */
411: ghDCMem = CreateCompatibleDC(hDC);
412:
413: ReleaseDC(ghwndMain, hDC);
414:
415: /*
416: * Load the bitmaps that depend on system colors.
417: */
418: LoadSysColorBitmaps();
419:
420: fmtDlg = RegisterClipboardFormat(L"DIALOG");
421:
422: /*
423: * Initialize the icon control ordinal to the icon id from our exe
424: * that we will use to show these kind of controls.
425: */
426: WriteOrd(&gordIcon, IDICON_ICON);
427:
428: /*
429: * Initialize the default text fields in the awcd array. Because
430: * CCONTROLS does not include the dialog type, it has to be done
431: * separately.
432: */
433: awcd[W_DIALOG].pszTextDefault = ids(awcd[W_DIALOG].idsTextDefault);
434: for (i = 0; i < CCONTROLS; i++)
435: awcd[i].pszTextDefault = ids(awcd[i].idsTextDefault);
436:
437: /*
438: * If there was a command line argument specified, try and open
439: * it as the initial file.
440: */
441: if (__argc > 1) {
442: MultiByteToWideChar(CP_ACP, 0, __argv[1], -1, szArg1, CCHTEXTMAX);
443: OpenCmdLineFile(szArg1);
444: }
445:
446: /*
447: * Be sure the focus is on the main window. This corrects a
448: * problem where the accelerators don't initially work because
449: * the focus gets placed on the Properties Bar.
450: */
451: SetFocus(ghwndMain);
452:
453: return TRUE;
454: }
455:
456:
457:
458: /************************************************************************
459: * PenWinRegister
460: *
461: * This function will register for Pen Windows, if it is present.
462: *
463: ************************************************************************/
464:
465: STATICFN VOID PenWinRegister(VOID)
466: {
467: HANDLE hmod;
468:
469: if (!(hmod = (HANDLE)GetSystemMetrics(SM_PENWINDOWS)))
470: return;
471:
472: if (lpfnRegisterPenApp =
473: (LPFNPENWIN)GetProcAddress(hmod, "RegisterPenApp"))
474: (*lpfnRegisterPenApp)(1, TRUE); // Be Pen-Enhanced!
475: }
476:
477:
478:
479: /************************************************************************
480: * GetSystemValues
481: *
482: * This function reads various system values. It is called at init time,
483: * as well as if we are informed by a WM_SYSVALUECHANGED message that
484: * some of these values have been changed.
485: *
486: ************************************************************************/
487:
488: STATICFN VOID GetSystemValues(VOID)
489: {
490: gcyBorder = GetSystemMetrics(SM_CYBORDER);
491:
492: /*
493: * The distance that the mouse can move during a pre-drag operation
494: * before starting to drag the control anyways is based on the
495: * mouse double-click movement distances in the system.
496: */
497: gcxPreDragMax = GetSystemMetrics(SM_CXDOUBLECLK);
498: gcyPreDragMax = GetSystemMetrics(SM_CYDOUBLECLK);
499:
500: /*
501: * The number of milliseconds that the pre-drag debounce time lasts.
502: */
503: gmsecPreDrag = 250;
504: }
505:
506:
507:
508: /************************************************************************
509: * ReadWindowPos
510: *
511: * This function retrieves the saved window position for a window and
512: * returns it in the specified variables. It is used between sessions
513: * to restore the application windows to the position they had when
514: * the editor was last exited.
515: *
516: * Arguments:
517: * LPTSTR pszKeyName - KeyName the position was saved under.
518: * PINT px - Saved x position.
519: * PINT py - Saved y position.
520: * PINT pcx - Saved width.
521: * PINT pcy - Saved height.
522: * BOOL *pfMaximized - Set to TRUE if window was maximized when saved.
523: *
524: * Returns:
525: * TRUE if the position could be read, or FALSE otherwise.
526: * If FALSE is returned, the values in the specified variables are
527: * not valid! The caller must be able to handle a FALSE return and
528: * supply a default position for the window.
529: *
530: ************************************************************************/
531:
532: BOOL ReadWindowPos(
533: LPTSTR pszKeyName,
534: PINT px,
535: PINT py,
536: PINT pcx,
537: PINT pcy,
538: BOOL *pfMaximized)
539: {
540: static CHAR szSep[] = " ,";
541: TCHAR szBuf[CCHTEXTMAX];
542: CHAR szBufAnsi[CCHTEXTMAX];
543: PSTR psz;
544: BOOL fDefCharUsed;
545:
546: if (!GetPrivateProfileString(ids(IDS_APPNAME),
547: pszKeyName, szEmpty, szBuf, CCHTEXTMAX, ids(IDS_DLGEDITINI)))
548: return FALSE;
549:
550: WideCharToMultiByte(CP_ACP, 0, szBuf, -1, szBufAnsi, CCHTEXTMAX,
551: NULL, &fDefCharUsed);
552:
553: if (!(psz = strtok(szBufAnsi, szSep)))
554: return FALSE;
555:
556: *px = atoi(psz);
557:
558: if (!(psz = strtok(NULL, szSep)))
559: return FALSE;
560:
561: *py = atoi(psz);
562:
563: if (!(psz = strtok(NULL, szSep)))
564: return FALSE;
565:
566: *pcx = atoi(psz);
567:
568: if (!(psz = strtok(NULL, szSep)))
569: return FALSE;
570:
571: *pcy = atoi(psz);
572:
573: /*
574: * If there is a "1" following the coordinates, the window was
575: * maximized when it was saved.
576: */
577: *pfMaximized = FALSE;
578: if ((psz = strtok(NULL, szSep)) && atoi(psz) == 1)
579: *pfMaximized = TRUE;
580:
581: /*
582: * Don't allow a zero sized window.
583: */
584: if (*pcx == 0 || *pcy == 0)
585: return FALSE;
586:
587: /*
588: * Return success.
589: */
590: return TRUE;
591:
592: }
593:
594:
595:
596: /************************************************************************
597: * WriteWindowPos
598: *
599: * This function writes the position of a window to the
600: * editor's profile file under the specified keyname.
601: * The ReadWindowPos function is the counterpart of this
602: * function.
603: *
604: * Arguments:
605: * PRECT prc - Rectangle for the "restored" window size.
606: * BOOL fMaximized - TRUE if the window is maximized.
607: * LPTSTR pszKeyName - KeyName to save the position under.
608: *
609: ************************************************************************/
610:
611: VOID WriteWindowPos(
612: PRECT prc,
613: BOOL fMaximized,
614: LPTSTR pszKeyName)
615: {
616: TCHAR szBuf[CCHTEXTMAX];
617:
618: wsprintf(szBuf, L"%d %d %d %d", prc->left, prc->top,
619: prc->right - prc->left, prc->bottom - prc->top);
620:
621: if (fMaximized)
622: lstrcat(szBuf, L" 1");
623:
624: WritePrivateProfileString(ids(IDS_APPNAME),
625: pszKeyName, szBuf, ids(IDS_DLGEDITINI));
626: }
627:
628:
629:
630: /*************************************************************************
631: * ReadEnv
632: *
633: * This function initializes variables from their counterparts
634: * in the private profile file for DlgEdit. The application
635: * merely needs to construct an array of INIENTRY structures
636: * to describe the variables that must be initialized.
637: *
638: * Note that the original value read from the profile is saved when
639: * it is read. This allows us to optimize what needs to be written
640: * out with WriteEnv.
641: *
642: *************************************************************************/
643:
644: STATICFN VOID ReadEnv(VOID)
645: {
646: register INT i;
647:
648: for (i = 0; gaie[i].pszKeyName; i++) {
649: *gaie[i].pnVar = gaie[i].nSave =
650: GetPrivateProfileInt(ids(IDS_APPNAME),
651: gaie[i].pszKeyName, gaie[i].nDefault,
652: ids(IDS_DLGEDITINI));
653: }
654:
655: ReadCustomProfile();
656: }
657:
658:
659:
660: /*************************************************************************
661: * WriteEnv
662: *
663: * This function is the counterpart to ReadEnv. It saves values
664: * in the profile file.
665: *
666: *************************************************************************/
667:
668: STATICFN VOID WriteEnv(VOID)
669: {
670: register INT i;
671: TCHAR szBuf[17];
672:
673: for (i = 0; gaie[i].pszKeyName; i++) {
674: /*
675: * Has the user changed the value since it was read?
676: */
677: if (gaie[i].nSave != *gaie[i].pnVar) {
678: /*
679: * If the new value is the same as the default value,
680: * erase the entry from the ini file. Otherwise,
681: * write the user-specified value out.
682: */
683: if (*gaie[i].pnVar == gaie[i].nDefault) {
684: WritePrivateProfileString(ids(IDS_APPNAME),
685: gaie[i].pszKeyName, NULL, ids(IDS_DLGEDITINI));
686: }
687: else {
688: itoaw(*gaie[i].pnVar, szBuf, 10);
689: WritePrivateProfileString(ids(IDS_APPNAME),
690: gaie[i].pszKeyName, szBuf, ids(IDS_DLGEDITINI));
691: }
692: }
693: }
694:
695: WriteCustomProfile();
696: }
697:
698:
699:
700: /************************************************************************
701: * MainWndProc
702: *
703: * This is the window procedure for the "dlgedit" class. This is the
704: * class of the main dialog editor "client" window.
705: *
706: ************************************************************************/
707:
708: WINDOWPROC MainWndProc(
709: HWND hwnd,
710: UINT msg,
711: WPARAM wParam,
712: LPARAM lParam)
713: {
714: switch (msg) {
715: case WM_CREATE:
716: {
717: RECT rc;
718:
719: /*
720: * Create the status window.
721: */
722: CreateDialog(ghInst, MAKEINTRESOURCE(DID_STATUS),
723: hwnd, StatusDlgProc);
724:
725: /*
726: * Save away its height for sizing later (like when
727: * the app is minimized then restored).
728: */
729: GetWindowRect(hwndStatus, &rc);
730: gcyStatus = rc.bottom - rc.top;
731:
732: ghwndSubClient = CreateWindow(szSubClientClass, NULL,
733: WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
734: hwnd, NULL, ghInst, NULL);
735:
736: ghMenuMain = GetMenu(hwnd);
737: LoadMenuBitmaps(ghMenuMain);
738: }
739:
740: break;
741:
742: case WM_ACTIVATE:
743: /*
744: * If the main window is getting activated, there is no
745: * currently active dialog.
746: */
747: if (LOWORD(wParam))
748: gidCurrentDlg = 0;
749:
750: goto DoDefault;
751:
752: case WM_INITMENU:
753: if (GetMenu(ghwndMain) == (HMENU)wParam)
754: InitMenu((HMENU)wParam);
755:
756: break;
757:
758: case WM_MENUSELECT:
759: if (HIWORD(wParam) &
760: (MF_POPUP | MF_SYSMENU))
761: gMenuSelected = 0;
762: else
763: gMenuSelected = LOWORD(wParam);
764:
765: break;
766:
767: case WM_COMMAND:
768: DialogMenu(LOWORD(wParam));
769: break;
770:
771: case WM_KEYDOWN:
772: switch (wParam) {
773: case VK_UP:
774: case VK_DOWN:
775: case VK_LEFT:
776: case VK_RIGHT:
777: if ((GetKeyState(VK_SHIFT) & 0x8000) ||
778: (GetKeyState(VK_CONTROL) & 0x8000))
779: break;
780:
781: /*
782: * Ignore it if we are not in a normal state
783: * (don't allow when dragging).
784: */
785: if (gState != STATE_NORMAL)
786: break;
787:
788: /*
789: * Be sure any outstanding changes get applied
790: * without errors.
791: */
792: if (!StatusApplyChanges())
793: break;
794:
795: /*
796: * Move the control in the specified direction.
797: */
798: MoveControl(wParam);
799: break;
800:
801: case VK_TAB:
802: if (GetKeyState(VK_CONTROL) & 0x8000)
803: break;
804:
805: /*
806: * Ignore it if we are not in a normal state
807: * (don't allow when dragging).
808: */
809: if (gState != STATE_NORMAL)
810: break;
811:
812: /*
813: * Be sure any outstanding changes get applied
814: * without errors.
815: */
816: if (!StatusApplyChanges())
817: break;
818:
819: /*
820: * Is the shift key pressed also?
821: */
822: if (GetKeyState(VK_SHIFT) & 0x8000)
823: SelectPrevious();
824: else
825: SelectNext();
826:
827: break;
828:
829: case VK_ESCAPE:
830: if ((GetKeyState(VK_SHIFT) & 0x8000) ||
831: (GetKeyState(VK_CONTROL) & 0x8000))
832: break;
833:
834: /*
835: * Be sure any outstanding changes get applied
836: * without errors.
837: */
838: if (!StatusApplyChanges())
839: break;
840:
841: if (gState == STATE_SELECTING)
842: OutlineSelectCancel();
843:
844: /*
845: * Cancel any drag operation they might have been doing.
846: */
847: if (gState != STATE_NORMAL)
848: DragCancel();
849:
850: break;
851:
852: case VK_RETURN:
853: if ((GetKeyState(VK_SHIFT) & 0x8000) ||
854: (GetKeyState(VK_CONTROL) & 0x8000))
855: break;
856:
857: /*
858: * Be sure any outstanding changes get applied
859: * without errors.
860: */
861: if (!StatusApplyChanges())
862: break;
863:
864: switch (gState) {
865: POINTS mpt;
866: POINT pt;
867: DWORD dwPos;
868:
869: case STATE_SELECTING:
870: /*
871: * In outline selection mode. Map the
872: * location of the mouse at the time that
873: * the user pressed Enter into a point
874: * relative to the dialog client and complete
875: * the selection operation.
876: */
877: dwPos = GetMessagePos();
878: mpt = (*((POINTS *)&(dwPos)));
879: ((pt).x = (mpt).x, (pt).y = (mpt).y);
880: ScreenToClient(gcd.npc->hwnd, &pt);
881: OutlineSelectEnd(pt.x, pt.y);
882:
883: break;
884:
885: case STATE_DRAGGING:
886: case STATE_DRAGGINGNEW:
887: /*
888: * We are dragging something. Map the
889: * location of the mouse at the time
890: * that the user pressed Enter into a
891: * point relative to the proper window
892: * and complete the drag operation.
893: */
894: dwPos = GetMessagePos();
895: mpt = (*((POINTS *)&(dwPos)));
896: ((pt).x = (mpt).x, (pt).y = (mpt).y);
897:
898: /*
899: * The point must be changed to be relative to
900: * the window that the ending mouse up message
901: * would have come through, which will be the
902: * capture window for the drag. This will be
903: * the dialog if we are adding a new control,
904: * or it will be the selected control if we are
905: * dragging an existing control.
906: */
907: ScreenToClient((gState == STATE_DRAGGING) ?
908: gnpcSel->hwnd : gcd.npc->hwnd, &pt);
909:
910: /*
911: * If the dialog is selected, map the points from
912: * the client area to the window.
913: */
914: if (gfDlgSelected)
915: MapDlgClientPoint(&pt, TRUE);
916:
917: DragEnd(pt.x, pt.y);
918:
919: break;
920: }
921:
922: break;
923: }
924:
925: break;
926:
927: case WM_NCCALCSIZE:
928: /*
929: * Save away what is going to be the new window position.
930: */
931: if (!IsIconic(hwnd) && !IsZoomed(hwnd))
932: grcAppPos = *((LPRECT)lParam);
933:
934: /*
935: * Now let the DefWindowProc calculate the client area normally.
936: */
937: goto DoDefault;
938:
939: case WM_MOVE:
940: if (gfEditingDlg)
941: RepositionDialog();
942:
943: break;
944:
945: case WM_SIZE:
946: SizeRibbons(hwnd);
947:
948: /*
949: * Did the app start minimized and is it being restored
950: * for the first time? If so, show the toolbox if
951: * the user has requested it.
952: */
953: if (fStartAsIcon && !IsIconic(hwnd)) {
954: if (gfShowToolbox)
955: ToolboxShow(TRUE);
956:
957: fStartAsIcon = FALSE;
958: }
959:
960: break;
961:
962: case WM_SYSCOLORCHANGE:
963: LoadSysColorBitmaps();
964: break;
965:
966: case WM_CLOSE:
967: if (ghwndTestDlg)
968: DestroyTestDialog();
969:
970: if (DoWeSave(FILE_INCLUDE) == IDCANCEL ||
971: DoWeSave(FILE_RESOURCE) == IDCANCEL)
972: break;
973:
974: /*
975: * First destroy the Properties Bar.
976: */
977: DestroyWindow(hwndStatus);
978: hwndStatus = NULL;
979:
980: DestroyWindow(hwnd);
981: break;
982:
983: case WM_QUERYENDSESSION:
984: if (ghwndTestDlg)
985: DestroyTestDialog();
986:
987: if (DoWeSave(FILE_INCLUDE) == IDCANCEL ||
988: DoWeSave(FILE_RESOURCE) == IDCANCEL)
989: return FALSE;
990: else
991: return TRUE;
992:
993: case WM_DESTROY:
994: /*
995: * Save the position of the app's window.
996: */
997: WriteWindowPos(&grcAppPos, IsZoomed(hwnd), szAppPos);
998:
999: WinHelp(hwnd, gszHelpFile, HELP_QUIT, 0L);
1000: FreeMenuBitmaps();
1001: PostQuitMessage(0);
1002: break;
1003:
1004: default:
1005: /*
1006: * Is this the registered help message from one of the common
1007: * dialogs? If so, show the help for it.
1008: *
1009: * The check to be sure gmsgHelp is non-zero is just in
1010: * case the call to register the help message failed
1011: * (it will return zero) and there happens to be a zero
1012: * message that gets sent to this window somehow.
1013: */
1014: if (msg == gmsgHelp && gmsgHelp) {
1015: ShowHelp(FALSE);
1016: return 0;
1017: }
1018:
1019: DoDefault:
1020: return DefWindowProc(hwnd, msg, wParam, lParam);
1021: }
1022:
1023: return 0;
1024: }
1025:
1026:
1027:
1028: /************************************************************************
1029: * LoadSysColorBitmaps
1030: *
1031: * This function loads bitmaps that depend on the system window and
1032: * highlight colors. As it loads them, it replaces two special colors
1033: * in them with some system colors.
1034: * This is used for the control type bitmaps that appear in lines
1035: * in the listbox in the Order/Group dialog.
1036: *
1037: ************************************************************************/
1038:
1039: STATICFN VOID LoadSysColorBitmaps(VOID)
1040: {
1041: DWORD rgbWindow;
1042: DWORD rgbWindowText;
1043: DWORD rgbHighlight;
1044: DWORD rgbHighlightText;
1045: INT i;
1046:
1047: rgbWindow = GetSysColor(COLOR_WINDOW);
1048: rgbWindowText = GetSysColor(COLOR_WINDOWTEXT);
1049: rgbHighlight = GetSysColor(COLOR_HIGHLIGHT);
1050: rgbHighlightText = GetSysColor(COLOR_HIGHLIGHTTEXT);
1051:
1052: if (hbmTabStop)
1053: DeleteObject(hbmTabStop);
1054:
1055: hbmTabStop = LoadAlterBitmap(IDBM_TABSTOP, rgbWindow, rgbWindowText);
1056:
1057: if (hbmTabStopSel)
1058: DeleteObject(hbmTabStopSel);
1059:
1060: hbmTabStopSel = LoadAlterBitmap(IDBM_TABSTOP,
1061: rgbHighlight, rgbHighlightText);
1062:
1063: for (i = 0; i < CCONTROLS; i++) {
1064: if (awcd[i].hbmCtrlType)
1065: DeleteObject(awcd[i].hbmCtrlType);
1066:
1067: awcd[i].hbmCtrlType = LoadAlterBitmap(
1068: awcd[i].idbmCtrlType, rgbWindow, rgbWindowText);
1069:
1070: if (awcd[i].hbmCtrlTypeSel)
1071: DeleteObject(awcd[i].hbmCtrlTypeSel);
1072:
1073: awcd[i].hbmCtrlTypeSel = LoadAlterBitmap(
1074: awcd[i].idbmCtrlType, rgbHighlight, rgbHighlightText);
1075: }
1076:
1077: if (ghbmDragHandle)
1078: DeleteObject(ghbmDragHandle);
1079:
1080: ghbmDragHandle = LoadAlterBitmap(IDBM_DRAGHANDLE,
1081: rgbWindow, rgbHighlight);
1082:
1083: if (ghbmDragHandle2)
1084: DeleteObject(ghbmDragHandle2);
1085:
1086: ghbmDragHandle2 = LoadAlterBitmap(IDBM_DRAGHANDLE2,
1087: rgbWindow, rgbHighlight);
1088: }
1089:
1090:
1091:
1092: /************************************************************************
1093: * LoadAlterBitmap
1094: *
1095: * This function loads a single bitmap. As it does, it replaces a
1096: * couple special RGB colors (REPLACECOLOR1 and REPLACECOLOR2) with
1097: * the passed in RGB colors.
1098: *
1099: * Arguments:
1100: * INT idbm - Integer ID of the bitmap to load.
1101: * DWORD rgbNew - Color to replace the special color with.
1102: * DWORD rgbNew2 - A second color to replace the second special color with.
1103: *
1104: * Returns:
1105: * The handle to the bitmap, or NULL if an error occurs.
1106: *
1107: ************************************************************************/
1108:
1109: STATICFN HBITMAP LoadAlterBitmap(
1110: INT idbm,
1111: DWORD rgbNew,
1112: DWORD rgbNew2)
1113: {
1114: register INT i;
1115: LPBITMAPINFOHEADER lpbihInfo;
1116: HDC hdcScreen;
1117: HANDLE hresLoad;
1118: HANDLE hres;
1119: DWORD FAR *qlng;
1120: LPBYTE lpbBits;
1121: HANDLE hbmp;
1122: DWORD rgbReplace1;
1123: DWORD rgbReplace2;
1124:
1125: hresLoad = FindResource(ghInst, MAKEINTRESOURCE(idbm), RT_BITMAP);
1126: if (!hresLoad)
1127: return NULL;
1128:
1129: hres = LoadResource(ghInst, hresLoad);
1130: if (!hresLoad)
1131: return NULL;
1132:
1133: rgbNew = RGBInvertRGB(rgbNew);
1134: rgbNew2 = RGBInvertRGB(rgbNew2);
1135: rgbReplace1 = RGBInvertRGB(REPLACECOLOR1);
1136: rgbReplace2 = RGBInvertRGB(REPLACECOLOR2);
1137: lpbihInfo = (LPBITMAPINFOHEADER)LockResource(hres);
1138: qlng = (LPDWORD)((PBYTE)(lpbihInfo) + lpbihInfo->biSize);
1139:
1140: for (i = 0; i < (1 << lpbihInfo->biBitCount); i++, qlng++) {
1141: if (*qlng == rgbReplace1)
1142: *qlng = rgbNew;
1143: else if (*qlng == rgbReplace2)
1144: *qlng = rgbNew2;
1145: }
1146:
1147: /*
1148: * First skip over the header structure.
1149: */
1150: lpbBits = (LPBYTE)(lpbihInfo + 1);
1151:
1152: /*
1153: * Skip the color table entries, if any.
1154: */
1155: lpbBits += (1 << (lpbihInfo->biBitCount)) * sizeof(RGBQUAD);
1156:
1157: /*
1158: * Create a color bitmap compatible with the display device.
1159: */
1160: if (hdcScreen = GetDC(NULL)) {
1161: hbmp = CreateDIBitmap(hdcScreen, lpbihInfo, (LONG)CBM_INIT,
1162: lpbBits, (LPBITMAPINFO)lpbihInfo, DIB_RGB_COLORS);
1163: ReleaseDC(NULL, hdcScreen);
1164: }
1165:
1166: UnlockResource(hres);
1167: FreeResource(hres);
1168:
1169: return hbmp;
1170: }
1171:
1172:
1173:
1174: /************************************************************************
1175: * RGBInvertRGB
1176: *
1177: * Reverses the RGB order of a color. This needs to be done to match
1178: * the resource file format of the color table.
1179: *
1180: ************************************************************************/
1181:
1182: STATICFN DWORD RGBInvertRGB(
1183: DWORD rgb)
1184: {
1185: return (DWORD)RGB(GetBValue(rgb), GetGValue(rgb), GetRValue(rgb));
1186: }
1187:
1188:
1189:
1190: /************************************************************************
1191: * SizeRibbons
1192: *
1193: * This function positions and sizes the child ribbon and subclient
1194: * windows in the dialog editor. It needs to be called any time the
1195: * size of the main windows changes.
1196: *
1197: * Arguments:
1198: * HWND hwnd - Parent window handle.
1199: *
1200: ************************************************************************/
1201:
1202: STATICFN VOID SizeRibbons(
1203: HWND hwnd)
1204: {
1205: RECT rcClient;
1206:
1207: if (hwndStatus && !IsIconic(hwnd)) {
1208: /*
1209: * Get the client area.
1210: */
1211: GetClientRect(hwnd, &rcClient);
1212:
1213: /*
1214: * Size/move the status and subclient window to fit
1215: * the new client area.
1216: */
1217: SetWindowPos(hwndStatus, NULL,
1218: 0, 0,
1219: rcClient.right - rcClient.left,
1220: min(rcClient.bottom - rcClient.top, gcyStatus),
1221: SWP_NOACTIVATE | SWP_NOZORDER);
1222:
1223: SetWindowPos(ghwndSubClient, NULL,
1224: 0, gcyStatus,
1225: rcClient.right - rcClient.left,
1226: max((rcClient.bottom - rcClient.top) - gcyStatus, 0),
1227: SWP_NOACTIVATE | SWP_NOZORDER);
1228: }
1229: }
1230:
1231:
1232:
1233: /****************************************************************************
1234: * DialogTerminate
1235: *
1236: * This undoes what DialogInit does. It should be called before terminating
1237: * and after a DialogInit.
1238: *
1239: ****************************************************************************/
1240:
1241: STATICFN VOID DialogTerminate(VOID)
1242: {
1243: register INT i;
1244:
1245: /*
1246: * Save the Preferences data.
1247: */
1248: WriteEnv();
1249:
1250: if (hbmTabStop)
1251: DeleteObject(hbmTabStop);
1252:
1253: if (hbmTabStopSel)
1254: DeleteObject(hbmTabStopSel);
1255:
1256: if (ghbmDragHandle)
1257: DeleteObject(ghbmDragHandle);
1258:
1259: if (ghbmDragHandle2)
1260: DeleteObject(ghbmDragHandle2);
1261:
1262: if (ghDCMem)
1263: DeleteDC(ghDCMem);
1264:
1265: /*
1266: * Free the control type bitmaps.
1267: */
1268: for (i = 0; i < CCONTROLS; i++) {
1269: if (awcd[i].hbmCtrlType)
1270: DeleteObject(awcd[i].hbmCtrlType);
1271:
1272: if (awcd[i].hbmCtrlTypeSel)
1273: DeleteObject(awcd[i].hbmCtrlTypeSel);
1274: }
1275:
1276: /*
1277: * Free all the custom control links. This must be done before the
1278: * app exits so that any loaded DLL's get unloaded!
1279: */
1280: while (gpclHead)
1281: RemoveCustomLink(gpclHead);
1282:
1283: if (hpenDarkGray)
1284: DeleteObject(hpenDarkGray);
1285:
1286: if (ghhkMsgFilter)
1287: UnhookWindowsHookEx(ghhkMsgFilter);
1288:
1289: if (lpfnRegisterPenApp)
1290: (*lpfnRegisterPenApp)((WORD)1, FALSE);
1291: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.