|
|
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: addctrl.c
14: *
15: * Contains routines for adding (creating) and deleting controls.
16: *
17: * Functions:
18: *
19: * AddNewDialog()
20: * DropControl()
21: * AddControl()
22: * CreateControl()
23: * CreateDlgFont()
24: * MyGetCharDimensions()
25: * AdjustDefaultSizes()
26: * DeleteControl()
27: * DeleteDialog()
28: * DeleteControl2()
29: * FreeCTYPE()
30: *
31: * Comments:
32: *
33: ****************************************************************************/
34:
35: #include "dlgedit.h"
36: #include "dlgfuncs.h"
37: #include "dlgextrn.h"
38: #include "dialogs.h"
39:
40: #include <stdlib.h>
41: #include <string.h>
42:
43: STATICFN HFONT CreateDlgFont(HWND hwnd, LPTSTR pszFontName,
44: INT nPointSize);
45: STATICFN INT MyGetCharDimensions(HWND hwnd, HFONT hFont,
46: PTEXTMETRIC ptm);
47: STATICFN VOID AdjustDefaultSizes(VOID);
48: STATICFN VOID DeleteControl2(NPCTYPE npcDel);
49: STATICFN VOID FreeCTYPE(NPCTYPE npc);
50:
51:
52:
53: /************************************************************************
54: * AddNewDialog
55: *
56: * High level function to add a new dialog to the current resource.
57: * Any existing dialog will be saved away in the resource buffer.
58: * The dialog is created at a default position and size with default
59: * styles.
60: *
61: ************************************************************************/
62:
63: VOID AddNewDialog(VOID)
64: {
65: RECT rc;
66:
67: if (gfEditingDlg) {
68: if (!SynchDialogResource())
69: return;
70:
71: DeleteDialog(FALSE);
72: }
73:
74: /*
75: * Now drop a new dialog window.
76: */
77: SetRect(&rc, DEFDIALOGXPOS, DEFDIALOGYPOS,
78: DEFDIALOGXPOS + awcd[W_DIALOG].cxDefault,
79: DEFDIALOGYPOS + awcd[W_DIALOG].cyDefault);
80: DropControl(&awcd[W_DIALOG], &rc);
81: }
82:
83:
84:
85: /************************************************************************
86: * DropControl
87: *
88: * This function drops a new control of Type at the specified
89: * location. The default style and text of the control is
90: * determined from the awcd table based on its type. The control
91: * is selected after being dropped. This function changes the status
92: * window to reflect the selected control.
93: *
94: * Arguments:
95: * PWINDOWCLASSDESC pwcd - Describes the type of new control.
96: * PRECT prc - Rectangle of the new control (in dialog units).
97: *
98: ************************************************************************/
99:
100: VOID DropControl(
101: PWINDOWCLASSDESC pwcd,
102: PRECT prc)
103: {
104: ORDINAL ordIcon;
105: ORDINAL ordDlg;
106: LPTSTR pszText;
107: NPCTYPE npcNew;
108: INT idCtrl;
109: DIALOGINFO di;
110:
111: /*
112: * Get the next available id to use for the new control.
113: */
114: idCtrl = NextID((pwcd->iType == W_DIALOG) ? NEXTID_DIALOG : NEXTID_CONTROL,
115: plInclude, 0);
116:
117: if (pwcd->iType == W_ICON) {
118: /*
119: * For icon controls, the text is really an ordinal or name
120: * of the icon resource to display. We get the next available
121: * id (skipping the id we just got for the control itself) to
122: * use as an ordinal.
123: */
124: WriteOrd(&ordIcon, NextID(NEXTID_CONTROL, plInclude, idCtrl));
125: pszText = (LPTSTR)&ordIcon;
126: }
127: else {
128: pszText = pwcd->pszTextDefault;
129: }
130:
131: /*
132: * Make the control.
133: */
134: if (pwcd->iType == W_DIALOG) {
135: /*
136: * Pick a default name for the dialog.
137: */
138: WriteOrd(&ordDlg, NextID(NEXTID_DIALOG, plInclude, 0));
139:
140: di.fResFlags = DEFDLGMEMFLAGS;
141: di.wLanguage = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
142: di.pszClass = NULL;
143: di.pszMenu = NULL;
144: di.DataVersion = 0;
145: di.Version = 0;
146: di.Characteristics = 0;
147: di.nPointSize = DEFPOINTSIZE;
148: lstrcpy(di.szFontName, ids(IDS_DEFFONTNAME));
149:
150: npcNew = AddControl(pwcd, pszText,
151: pwcd->flStyles, pwcd->flExtStyle, idCtrl,
152: prc->left, prc->top,
153: prc->right - prc->left, prc->bottom - prc->top,
154: (LPTSTR)&ordDlg, &di);
155: }
156: else {
157: npcNew = AddControl(pwcd, pszText,
158: pwcd->flStyles, pwcd->flExtStyle, idCtrl,
159: prc->left, prc->top,
160: prc->right - prc->left, prc->bottom - prc->top,
161: NULL, NULL);
162: }
163:
164: if (!npcNew)
165: return;
166:
167: /*
168: * If we just dropped a dialog, we need to now show it.
169: * It it was some other control, mark the dialog as having
170: * been changed.
171: */
172: if (pwcd->iType == W_DIALOG) {
173: ShowWindow(npcNew->hwnd, SW_SHOWNA);
174: ToolboxOnTop();
175: }
176: else {
177: gfDlgChanged = TRUE;
178: }
179:
180: SelectControl(npcNew, FALSE);
181:
182: gfResChged = TRUE;
183: ShowFileStatus(FALSE);
184:
185: /*
186: * Now we determine if one of the fields in the status ribbon
187: * should be given the focus initially. The assumption is that
188: * there are some things that a user will always want to change
189: * when dropping a new control, such as the text in a push
190: * button, for example.
191: */
192: idCtrl = 0;
193: switch (pwcd->iType) {
194: case W_ICON:
195: /*
196: * For icons, the first thing the user will
197: * probably want to do is to change the name.
198: */
199: idCtrl = DID_STATUSNAME;
200: break;
201:
202: default:
203: /*
204: * If this control has text, they will probably want
205: * to change it. This includes the caption if the
206: * control is a dialog.
207: */
208: if (pwcd->fHasText)
209: idCtrl = DID_STATUSTEXT;
210:
211: break;
212: }
213:
214: if (idCtrl) {
215: SendDlgItemMessage(hwndStatus, idCtrl,
216: EM_SETSEL, (WPARAM)(0), (LONG)(-1));
217: SetFocus(GetDlgItem(hwndStatus, idCtrl));
218: }
219: }
220:
221:
222:
223: /************************************************************************
224: * AddControl
225: *
226: * This function is used to add a new control. CreateControl() does
227: * half the work.
228: *
229: * Arguments:
230: * PWINDOWCLASSDESC pwcd - Window class structure. Describes the
231: * type of control to add.
232: * LPTSTR pszText - Text for the new control.
233: * DWORD style - Style of the new control.
234: * DWORD flExtStyle - Extended style of the new control.
235: * INT id - ID for the new control.
236: * INT x - X location of the new control.
237: * INT y - Y location of the new control.
238: * INT cx - Width of the new control.
239: * INT cy - Height of the new control.
240: * LPTSTR pszDlgName - For dialogs, has dialog name.
241: * PDIALOGINFO pdi - Ptr to additional dialog info (NULL for controls).
242: *
243: * Returns:
244: * A pointer to the CTYPE structure for the new control.
245: * NULL if it couldn't create the control.
246: *
247: ************************************************************************/
248:
249: NPCTYPE AddControl(
250: PWINDOWCLASSDESC pwcd,
251: LPTSTR pszText,
252: DWORD style,
253: DWORD flExtStyle,
254: INT id,
255: INT x,
256: INT y,
257: INT cx,
258: INT cy,
259: LPTSTR pszDlgName,
260: PDIALOGINFO pdi)
261: {
262: NPCTYPE npcNew;
263: NPCTYPE npcT;
264: NPCTYPE *npnpcLast;
265: HWND hwndBehind;
266:
267: if (!(npcNew = (NPCTYPE)MyAlloc(sizeof(CTYPE))))
268: return NULL;
269:
270: /*
271: * These are checked later if a failure occurs,
272: * so we null them out now.
273: */
274: npcNew->hwnd = NULL;
275: npcNew->hwndDrag = NULL;
276: npcNew->text = NULL;
277:
278: /*
279: * Set up some fields and create the control.
280: */
281: npcNew->npcNext = NULL;
282: npcNew->pwcd = pwcd;
283: npcNew->fSelected = FALSE;
284: SetRect(&npcNew->rc, x, y, x + cx, y + cy);
285:
286: if (pwcd->iType == W_DIALOG)
287: hwndBehind = (HWND)NULL;
288: else
289: hwndBehind = (HWND)1;
290:
291: if (!CreateControl(npcNew, pszText, style, flExtStyle, id, &npcNew->rc,
292: hwndBehind, pdi))
293: goto CreateFailed;
294:
295: /*
296: * Create the drag window, unless this is the dialog.
297: */
298: if (pwcd->iType != W_DIALOG) {
299: npcNew->hwndDrag = CreateWindow(
300: szDragClass,
301: NULL,
302: WS_CHILD,
303: 0, 0, 0, 0,
304: gcd.npc->hwnd,
305: NULL,
306: ghInst,
307: NULL);
308:
309: /*
310: * Store the CTYPE pointer into the control's drag window.
311: * This will be used by PCFROMHWND later.
312: */
313: SETPCINTOHWND(npcNew->hwndDrag, npcNew);
314:
315: /*
316: * Move the drag window to the top of the Z-Order.
317: */
318: SetWindowPos(npcNew->hwndDrag, NULL, 0, 0, 0, 0,
319: SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
320:
321: SizeDragToControl(npcNew);
322: }
323:
324: /*
325: * Did we just create a dialog?
326: */
327: if (pwcd->iType == W_DIALOG) {
328: /*
329: * First, copy the new name (it can be an ordinal!).
330: */
331: if (!(gcd.pszDlgName = MyAlloc(NameOrdLen(pszDlgName))))
332: goto CreateFailed;
333:
334: NameOrdCpy(gcd.pszDlgName, pszDlgName);
335:
336: /*
337: * Now, setup some other globals. We clear the gcd.prl pointer,
338: * because we are assuming that this dialog was not created
339: * from a res link (it was dropped instead). The routines
340: * that call AddControl when creating a dialog from a res
341: * link are responsible for setting this global later.
342: */
343: gcd.prl = NULL;
344: gcd.npc = npcNew;
345: gfEditingDlg = TRUE;
346: }
347: else {
348: /*
349: * Search for the last control in the list.
350: */
351: npnpcLast = &npcHead;
352: for (npcT = npcHead; npcT; npcT = npcT->npcNext)
353: npnpcLast = &npcT->npcNext;
354:
355: /*
356: * Link in the new control at the end of the list.
357: */
358: *npnpcLast = npcNew;
359: cWindows++;
360: }
361:
362: return npcNew;
363:
364: CreateFailed:
365: FreeCTYPE(npcNew);
366: return NULL;
367: }
368:
369:
370:
371: /************************************************************************
372: * CreateControl
373: *
374: * Creates a control. Some styles may be masked off of the actual
375: * control created. This function can also create the dialog box.
376: *
377: * If the control created is the dialog box, it will not be made visible.
378: * This must be done by the caller. This allows the caller to first add
379: * all the controls to the dialog before showing it.
380: *
381: * The x, y, cx and cy coordinates are all in dialog units. For a
382: * type of W_DIALOG, this will be relative to the apps client. For a
383: * control, this will be relative to the "client" area of the dialog.
384: *
385: * Arguments:
386: * NPCTYPE npc - The CTYPE pointer to the new control. The hwnd
387: * fields of the npc will be set.
388: * LPTSTR pszText - The window text.
389: * DWORD flStyle - The style to use.
390: * DWORD flExtStyle - Extended style of the new control.
391: * INT id - ID for the control.
392: * PRECT prc - The size and location of the new control.
393: * HWND hwndBehind - Put new control behind this hwnd in Z-order.
394: * PDIALOGINFO pdi - Pointer to additional dialog info (NULL for controls).
395: *
396: * Returns:
397: * Handle of the control created.
398: * NULL if control was not created.
399: *
400: ************************************************************************/
401:
402: HWND CreateControl(
403: NPCTYPE npc,
404: LPTSTR pszText,
405: DWORD flStyle,
406: DWORD flExtStyle,
407: INT id,
408: PRECT prc,
409: HWND hwndBehind,
410: PDIALOGINFO pdi)
411: {
412: HWND hwnd;
413: HWND hwndChild;
414: WNDPROC lpfnChild;
415: RECT rcT;
416: TEXTMETRIC tm;
417: LPTSTR pszCreateClass;
418: LPTSTR pszTextOld;
419: INT iType = npc->pwcd->iType;
420:
421: /*
422: * Set the text field. Remember that it can be an ordinal
423: * (for icon controls).
424: */
425: pszTextOld = npc->text;
426: if (pszText && *pszText) {
427: if (!(npc->text = MyAlloc(NameOrdLen(pszText))))
428: return NULL;
429:
430: NameOrdCpy(npc->text, pszText);
431: }
432: else {
433: npc->text = NULL;
434: }
435:
436: /*
437: * If there was text before on this control, free it now.
438: * This should be done after the new text is allocated and
439: * copied, because it is common to pass this routine the same
440: * pointer, and we don't want to free the text before we have
441: * copied it!
442: */
443: if (pszTextOld)
444: MyFree(pszTextOld);
445:
446: /*
447: * Also set some other values in the CTYPE structure.
448: */
449: npc->id = id;
450: npc->flStyle = flStyle;
451: npc->flExtStyle = flExtStyle;
452:
453: /*
454: * If this is a dialog and it has the WS_CHILD style, remove
455: * it and make it WS_POPUP instead. This prevents some problems
456: * when editing the dialog.
457: */
458: if (iType == W_DIALOG && (flStyle & WS_CHILD)) {
459: flStyle &= ~WS_CHILD;
460: flStyle |= WS_POPUP;
461: }
462:
463: /*
464: * If this is an emulated custom control, we always make it with the
465: * default styles no matter what the user has specified. If not,
466: * remove any styles that can cause problems for a control of this
467: * type, such as OWNERDRAW styles.
468: */
469: if (npc->pwcd->fEmulated)
470: flStyle = awcd[W_CUSTOM].flStyles;
471: else
472: flStyle &= ~npc->pwcd->flStylesBad;
473:
474: if (iType == W_DIALOG) {
475: /*
476: * If the style includes the DS_MODALFRAME bit, set the appropriate
477: * extended style bit.
478: */
479: if (flStyle & DS_MODALFRAME)
480: flExtStyle |= WS_EX_DLGMODALFRAME;
481:
482: /*
483: * Create the dialog, but don't show it yet.
484: */
485: hwnd = CreateWindowEx(
486: flExtStyle,
487: MAKEINTRESOURCE(DIALOGCLASS),
488: npc->text,
489: flStyle & ~WS_VISIBLE,
490: 0, 0, 0, 0,
491: ghwndSubClient,
492: 0,
493: ghInst,
494: NULL);
495: }
496: else {
497: /*
498: * Get the size of the control.
499: */
500: rcT = *prc;
501:
502: /*
503: * Map the dialog unit rectangle to window coords.
504: */
505: DUToWinRect(&rcT);
506:
507: /*
508: * If this is an icon, the text field is actually going
509: * to be an ordinal that has the resource id. We must map this to
510: * an id of our own or when we create the control it will cause a
511: * "Resource not found" error.
512: */
513: if (iType == W_ICON)
514: pszText = (LPTSTR)&gordIcon;
515: else
516: pszText = npc->text;
517:
518: /*
519: * Get the class name to use. In the case of custom controls,
520: * if the control is emulated, use the special emulator class.
521: * Otherwise, it is an installed custom control, and we can use
522: * it's real class string.
523: */
524: if (iType == W_CUSTOM) {
525: if (npc->pwcd->fEmulated)
526: pszCreateClass = szCustomClass;
527: else
528: pszCreateClass = npc->pwcd->pszClass;
529: }
530: else {
531: pszCreateClass = ids(acsd[awcd[iType].iClass].idsClass);
532: }
533:
534: /*
535: * Create the control. We always create it visible in work mode,
536: * even if the style says it isn't.
537: */
538: hwnd = CreateWindowEx(
539: flExtStyle,
540: pszCreateClass,
541: pszText,
542: flStyle | WS_VISIBLE,
543: rcT.left, rcT.top,
544: rcT.right - rcT.left,
545: rcT.bottom - rcT.top,
546: gcd.npc->hwnd,
547: 0,
548: ghInst,
549: NULL);
550: }
551:
552: if (!hwnd) {
553: Message(MSG_CREATECTRLERROR, pszCreateClass);
554: return NULL;
555: }
556:
557: if (iType == W_DIALOG) {
558: /*
559: * Did they specify a font?
560: */
561: if (*pdi->szFontName) {
562: gcd.hFont = CreateDlgFont(hwnd, pdi->szFontName, pdi->nPointSize);
563: lstrcpy(gcd.di.szFontName, pdi->szFontName);
564: gcd.di.nPointSize = pdi->nPointSize;
565: gcd.fFontSpecified = TRUE;
566: }
567: else {
568: gcd.hFont = NULL;
569: *gcd.di.szFontName = CHAR_NULL;
570: gcd.di.nPointSize = 0;
571: gcd.fFontSpecified = FALSE;
572: }
573:
574: /*
575: * Get the dimensions of the font. It is a possible case that
576: * they specified a font but it could not be created, so in
577: * that case we use the system font as well as if they didn't
578: * specify a font at all.
579: */
580: if (gcd.hFont) {
581: gcd.cxChar = MyGetCharDimensions(hwnd, gcd.hFont, &tm);
582: gcd.cyChar = tm.tmHeight;
583: }
584: else {
585: gcd.cxChar = gcxSysChar;
586: gcd.cyChar = gcySysChar;
587: }
588:
589: /*
590: * Now that we know what font we are using, adjust some entries
591: * in the awcd (array of window class data) table for default
592: * sizing of controls.
593: */
594: AdjustDefaultSizes();
595: }
596:
597: /*
598: * If there is a valid user specified font, inform the control
599: * of it. Once the font has been set into the dialog, it
600: * must not be destroyed, because the dialog window will
601: * clean it up when it is destroyed.
602: */
603: if (gcd.hFont)
604: SendMessage(hwnd, WM_SETFONT, (WPARAM)gcd.hFont, 0L);
605:
606: /*
607: * Move the window into the requested Z-Order.
608: */
609: SetWindowPos(hwnd, hwndBehind, 0, 0, 0, 0,
610: SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
611:
612: /*
613: * Store the CTYPE pointer into the control's hwnd.
614: * This will be used by PCFROMHWND later.
615: */
616: SETPCINTOHWND(hwnd, npc);
617:
618: /*
619: * Subclass the control.
620: */
621: npc->pwcd->pfnOldWndProc =
622: (WNDPROC)SetWindowLong(hwnd, GWL_WNDPROC,
623: (iType == W_DIALOG) ? (DWORD)DialogCtrlWndProc :
624: (DWORD)CtrlWndProc);
625:
626: /*
627: * Be sure double-clicks are enabled for this control.
628: */
629: (UINT)SetClassLong((hwnd), GCL_STYLE, (LONG)((UINT)GetClassLong((hwnd), GCL_STYLE) | CS_DBLCLKS));
630:
631: /*
632: * Subclass any children this control may have.
633: */
634: for (hwndChild = GetTopWindow(hwnd); hwndChild;
635: hwndChild = GetNextWindow(hwndChild, GW_HWNDNEXT)) {
636: lpfnChild = (WNDPROC)SetWindowLong(hwndChild,
637: GWL_WNDPROC, (DWORD)ChildWndProc);
638: SETCHILDPROC(hwndChild, lpfnChild);
639: }
640:
641: /*
642: * Did we just create a dialog?
643: */
644: if (iType == W_DIALOG) {
645: /*
646: * Now that the dialog is created, we can figure out how to
647: * size it. We start by mapping the dialog units to window
648: * coordinates,
649: */
650: rcT = *prc;
651: DUToWinRect(&rcT);
652:
653: /*
654: * We now have the rectangle for the client area. Expand it
655: * to account for the frame controls.
656: */
657: AdjustWindowRectEx(&rcT, flStyle, FALSE, flExtStyle);
658:
659: /*
660: * Now we can map the rect from the apps client area
661: * to the desktop, then we set the dialogs position.
662: */
663: ClientToScreenRect(ghwndSubClient, &rcT);
664: SetWindowPos(hwnd, NULL,
665: rcT.left, rcT.top,
666: rcT.right - rcT.left, rcT.bottom - rcT.top,
667: SWP_NOZORDER | SWP_NOACTIVATE);
668:
669: SaveDlgClientRect(hwnd);
670:
671: /*
672: * Save the class name, if any.
673: */
674: if (pdi->pszClass && *pdi->pszClass) {
675: if (!(gcd.di.pszClass = MyAlloc(NameOrdLen(pdi->pszClass)))) {
676: DestroyWindow(hwnd);
677: return (HWND)NULL;
678: }
679:
680: NameOrdCpy(gcd.di.pszClass, pdi->pszClass);
681: }
682: else {
683: gcd.di.pszClass = NULL;
684: }
685:
686: /*
687: * Save the menu name, if any.
688: */
689: if (pdi->pszMenu && *pdi->pszMenu) {
690: if (!(gcd.di.pszMenu = MyAlloc(NameOrdLen(pdi->pszMenu)))) {
691: DestroyWindow(hwnd);
692: return (HWND)NULL;
693: }
694:
695: NameOrdCpy(gcd.di.pszMenu, pdi->pszMenu);
696: }
697: else {
698: gcd.di.pszMenu = NULL;
699: }
700:
701: /*
702: * Set some other fields in the additional dialog info structure.
703: */
704: gcd.di.fResFlags = pdi->fResFlags;
705: gcd.di.wLanguage = pdi->wLanguage;
706: gcd.di.DataVersion = pdi->DataVersion;
707: gcd.di.Version = pdi->Version;
708: gcd.di.Characteristics = pdi->Characteristics;
709: }
710:
711: npc->hwnd = hwnd;
712: return hwnd;
713: }
714:
715:
716:
717: /************************************************************************
718: * CreateDlgFont
719: *
720: * This function creates a font with the given face name and point size
721: * and returns a handle to it.
722: *
723: * Arguments:
724: * HWND hwnd - Dialog window handle.
725: * LPTSTR pszFontName - Name of the font (for example: "Helv").
726: * INT nPointSize - Point size of the font (for example: 8 or 12).
727: *
728: * Returns:
729: * A handle to the created font, or NULL if it could not be created.
730: *
731: ************************************************************************/
732:
733: STATICFN HFONT CreateDlgFont(
734: HWND hwnd,
735: LPTSTR pszFontName,
736: INT nPointSize)
737: {
738: HFONT hFont;
739: HFONT hFontOld;
740: HDC hDC;
741: LOGFONT lf;
742: TCHAR szFaceName[LF_FACESIZE];
743:
744: /*
745: * Initialize the logical font structure. Note that filling the
746: * structure with zeros gives it all the default settings.
747: */
748: memset(&lf, 0, sizeof(LOGFONT));
749: lf.lfHeight = (SHORT)-PointSizeToPixels(nPointSize);
750: lf.lfWeight = FW_BOLD;
751: lstrcpy(lf.lfFaceName, pszFontName);
752:
753: if (!(hFont = CreateFontIndirect(&lf)))
754: return NULL;
755:
756: /*
757: * If we didn't get the face name that was requested, delete the
758: * new font and return NULL. This will effectively select the
759: * system font for this dialog.
760: */
761: hDC = GetDC(hwnd);
762: if (hFontOld = SelectObject(hDC, hFont)) {
763: GetTextFace(hDC, LF_FACESIZE, szFaceName);
764: SelectObject(hDC, hFontOld);
765:
766: if (lstrcmpi(szFaceName, pszFontName) != 0) {
767: DeleteObject(hFont);
768: hFont = NULL;
769: }
770: }
771: else {
772: DeleteObject(hFont);
773: hFont = NULL;
774: }
775:
776: ReleaseDC(hwnd, hDC);
777:
778: return hFont;
779: }
780:
781:
782:
783: /************************************************************************
784: * MyGetCharDimensions
785: *
786: * This function calculates the average character width of the given
787: * font for the given window. This must be used instead of
788: * simply using the tmAveCharWidth field of the text metrics, because
789: * this value is not correct for proportional fonts.
790: *
791: * Arguments:
792: * HWND hwnd - The window handle.
793: * HFONT hFont - The font handle.
794: * PTEXTMETRIC ptm - Where to return the text metrics.
795: *
796: * Returns:
797: * The average character width. The text metrics are returned in
798: * the TEXTMETRIC structure pointed to by ptm.
799: *
800: ************************************************************************/
801:
802: STATICFN INT MyGetCharDimensions(
803: HWND hwnd,
804: HFONT hFont,
805: PTEXTMETRIC ptm)
806: {
807: register INT i;
808: HDC hDC;
809: SIZE size;
810: INT iWidth;
811: TCHAR szAveCharWidth[52];
812: HFONT hFontOld;
813:
814: hDC = GetDC(hwnd);
815: hFontOld = SelectObject(hDC, hFont);
816:
817: GetTextMetrics(hDC, ptm);
818:
819: /*
820: * Is this a variable pitch font?
821: */
822: if (ptm->tmPitchAndFamily & 0x01) {
823: for (i = 0; i < 26; i++)
824: szAveCharWidth[i] = (TCHAR)(i + CHAR_A);
825:
826: for (i = 0; i < 26; i++)
827: szAveCharWidth[i + 26] = (TCHAR)(i + CHAR_CAP_A);
828:
829: GetTextExtentPoint(hDC, szAveCharWidth, 52, &size);
830: iWidth = (INT)size.cx / 26;
831:
832: //
833: // Round it up.
834: //
835: iWidth = (iWidth + 1) / 2;
836: }
837: else {
838: iWidth = ptm->tmAveCharWidth;
839: }
840:
841: SelectObject(hDC, hFontOld);
842: ReleaseDC(hwnd, hDC);
843:
844: return iWidth;
845: }
846:
847:
848:
849: /************************************************************************
850: * AdjustDefaultSizes
851: *
852: * This functions adjusts some default size entries in the awcd (array of
853: * window class data) table.
854: * This must be done at run time, because the actual values depend on the
855: * system that dlgedit is being run on and the font of the current dialog.
856: *
857: * This function should be called any time that a dialog is created,
858: * or its font is changed.
859: *
860: ************************************************************************/
861:
862: STATICFN VOID AdjustDefaultSizes(VOID)
863: {
864: awcd[W_ICON].cxDefault =
865: (((GetSystemMetrics(SM_CXICON) * 4) * 2) + gcd.cxChar)
866: / (gcd.cxChar * 2);
867:
868: awcd[W_ICON].cyDefault =
869: (((GetSystemMetrics(SM_CYICON) * 8) * 2) + gcd.cyChar)
870: / (gcd.cyChar * 2);
871:
872: awcd[W_VERTSCROLL].cxDefault =
873: (((GetSystemMetrics(SM_CXVSCROLL) * 4) * 2) + gcd.cxChar)
874: / (gcd.cxChar * 2);
875:
876: awcd[W_HORZSCROLL].cyDefault =
877: (((GetSystemMetrics(SM_CYHSCROLL) * 8) * 2) + gcd.cyChar)
878: / (gcd.cyChar * 2);
879: }
880:
881:
882:
883: /************************************************************************
884: * DeleteControl
885: *
886: * This deletes all selected controls from the dialog being edited
887: * (or the dialog itself, if it is selected).
888: *
889: ************************************************************************/
890:
891: VOID DeleteControl(VOID)
892: {
893: if (gfDlgSelected) {
894: if (Message(MSG_DELETEDIALOG) == IDYES)
895: /*
896: * Delete the dialog, including the resource for it.
897: */
898: DeleteDialog(TRUE);
899: }
900: else {
901: while (gnpcSel)
902: DeleteControl2(gnpcSel);
903:
904: gfDlgChanged = TRUE;
905: }
906:
907: gfResChged = TRUE;
908: ShowFileStatus(FALSE);
909: StatusUpdate();
910: StatusSetEnable();
911: }
912:
913:
914:
915: /************************************************************************
916: * DeleteControl2
917: *
918: * This deletes a control by destroying its window and removing it
919: * from the linked list of controls associated with the dialog box.
920: * The control is destroyed and the window is unlinked and the CTYPE free'd.
921: *
922: ************************************************************************/
923:
924: STATICFN VOID DeleteControl2(
925: NPCTYPE npcDel)
926: {
927: register NPCTYPE npcT;
928: register NPCTYPE *npnpcLast;
929:
930: UnSelectControl(npcDel);
931:
932: /*
933: * Search for the control, unlink it from the list and free it.
934: */
935: npcT = npcHead;
936: npnpcLast = &npcHead;
937: while (npcT) {
938: if (npcT == npcDel) {
939: *npnpcLast = npcT->npcNext;
940: FreeCTYPE(npcT);
941: cWindows--;
942: break;
943: }
944:
945: npnpcLast = &npcT->npcNext;
946: npcT = npcT->npcNext;
947: }
948: }
949:
950:
951:
952: /************************************************************************
953: * DeleteDialog
954: *
955: * This deletes the dialog box being worked on and sets globals
956: * and the Status Window appropriately. All CTYPEs are freed, the
957: * status window is updated and the dialog window is destroyed.
958: *
959: * Arguments:
960: * BOOL fResAlso - If TRUE, delete the dialog resource also.
961: *
962: ************************************************************************/
963:
964: VOID DeleteDialog(
965: BOOL fResAlso)
966: {
967: register NPCTYPE npcT;
968: register NPCTYPE npcNext;
969:
970: CancelSelection(FALSE);
971:
972: /*
973: * If they requested that the dialog resource be deleted also,
974: * do it first while some globals are still set.
975: */
976: if (fResAlso)
977: DeleteDialogResource();
978:
979: /*
980: * Hide the window for better painting speed.
981: */
982: ShowWindow(gcd.npc->hwnd, SW_HIDE);
983:
984: /*
985: * Free all the controls.
986: */
987: npcT = npcHead;
988: while (npcT) {
989: npcNext = npcT->npcNext;
990: FreeCTYPE(npcT);
991: npcT = npcNext;
992: }
993: npcHead = NULL;
994: cWindows = 0;
995:
996: /*
997: * Free the dialog itself.
998: */
999: FreeCTYPE(gcd.npc);
1000:
1001: if (gcd.pszDlgName) {
1002: MyFree(gcd.pszDlgName);
1003: gcd.pszDlgName = NULL;
1004: }
1005:
1006: if (gcd.di.pszClass) {
1007: MyFree(gcd.di.pszClass);
1008: gcd.di.pszClass = NULL;
1009: }
1010:
1011: if (gcd.di.pszMenu) {
1012: MyFree(gcd.di.pszMenu);
1013: gcd.di.pszMenu = NULL;
1014: }
1015:
1016: if (gcd.hFont) {
1017: DeleteObject(gcd.hFont);
1018: gcd.hFont = NULL;
1019: }
1020:
1021: gcd.fFontSpecified = FALSE;
1022: *gcd.di.szFontName = CHAR_NULL;
1023:
1024: /*
1025: * Set these globals back to the system font values so that
1026: * workers like WinToDUPoint will still work.
1027: */
1028: gcd.cxChar = gcxSysChar;
1029: gcd.cyChar = gcySysChar;
1030:
1031: gcd.prl = NULL;
1032:
1033: gcd.npc = NULL;
1034: gfEditingDlg = FALSE;
1035: gfDlgChanged = FALSE;
1036:
1037: ToolboxSelectTool(W_NOTHING, FALSE);
1038: StatusUpdate();
1039: StatusSetEnable();
1040: }
1041:
1042:
1043:
1044: /************************************************************************
1045: * FreeCTYPE
1046: *
1047: * This function frees an allocated CTYPE. The associated control or
1048: * dialog window is destroyed, and memory for the text and/or class
1049: * is freed, followed by freeing the actual CTYPE structure itself.
1050: *
1051: * If the hwnd in the CTYPE is NULL, only the text (if not NULL) is
1052: * assumed to be valid and will be freed, followed by the CTYPE structure
1053: * itself. This allows FreeCTYPE to be called when the CTYPE is only
1054: * partially initialized. This is a little dependant on the order that
1055: * a CTYPE is allocated and initialized in AddControl().
1056: *
1057: * Arguments:
1058: * NPCTYPE npc = The CTYPE to free.
1059: *
1060: ************************************************************************/
1061:
1062: STATICFN VOID FreeCTYPE(
1063: NPCTYPE npc)
1064: {
1065: if (npc->hwnd)
1066: DestroyWindow(npc->hwnd);
1067:
1068: if (npc->hwndDrag)
1069: DestroyWindow(npc->hwndDrag);
1070:
1071: if (npc->text)
1072: MyFree(npc->text);
1073:
1074: MyFree(npc);
1075: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.