|
|
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: restodlg.c
14: *
15: * Routines that take a dialog resource and create the dialog to edit, or
16: * the other way around.
17: *
18: * Fucntions:
19: * SynchDialogResource()
20: * AllocDialogResource()
21: * ResLinkToDialog()
22: * ResToDialog()
23: * GetiClass()
24: * Duplicate()
25: * MakeCopyFromRes()
26: * TypeFromClassStyle()
27: *
28: * Comments:
29: *
30: ****************************************************************************/
31:
32: #include "dlgedit.h"
33: #include "dlgfuncs.h"
34: #include "dlgextrn.h"
35:
36: STATICFN INT TypeFromClassStyle(INT iClass, DWORD flStyle);
37:
38:
39:
40: /************************************************************************
41: * SynchDialogResource
42: *
43: * This routine synchronizes the resource buffer with the contents of
44: * the current dialog being edited. This may involve deleting the old
45: * contents of the current dialog prior to adding the new data.
46: *
47: * It is ok to call this routine even if there is not an existing dialog
48: * being edited (it will just return) and it should be called before any
49: * operation that needs the in memory copy of the dialog to accurately
50: * reflect the contents of the current dialog, such as just before a
51: * save to disk.
52: *
53: * Returns:
54: * TRUE if all goes well (includes the case where nothing was done).
55: * FALSE if an error occurs updating the resource.
56: *
57: ************************************************************************/
58:
59: BOOL SynchDialogResource(VOID)
60: {
61: PRES pRes;
62: PRESLINK prl;
63: PRESLINK prlNew;
64: PRESLINK prlPrev;
65:
66: if (!gfEditingDlg)
67: return TRUE;
68:
69: /*
70: * Allocate a resource for the current dialog.
71: */
72: if (!(pRes = AllocDialogResource(FALSE, FALSE)))
73: return FALSE;
74:
75: /*
76: * Allocate a new link for it.
77: */
78: if (!(prlNew = AllocResLink(pRes)))
79: return FALSE;
80:
81: /*
82: * Free the local copy of the dialog resource now that the
83: * link has been created (and the resource copied to global
84: * memory).
85: */
86: MyFree(pRes);
87:
88: /*
89: * Does a link for the dialog already exist?
90: */
91: if (gcd.prl) {
92: /*
93: * Find the existing link and get it's previous link.
94: */
95: for (prl = gprlHead, prlPrev = NULL; prl && prl != gcd.prl;
96: prlPrev = prl, prl = prl->prlNext)
97: ;
98:
99: /*
100: * Start linking it in.
101: */
102: prlNew->prlNext = gcd.prl->prlNext;
103:
104: if (prlPrev)
105: prlPrev->prlNext = prlNew;
106: else
107: gprlHead = prlNew;
108:
109: /*
110: * Delete the old link now that it is replaced.
111: */
112: FreeResLink(gcd.prl);
113: }
114: else {
115: /*
116: * Search for the end of the list. Get a pointer to the last link.
117: */
118: for (prl = gprlHead, prlPrev = NULL; prl;
119: prlPrev = prl, prl = prl->prlNext)
120: ;
121:
122: /*
123: * Add the new link to the end of the list.
124: */
125: if (prlPrev)
126: prlPrev->prlNext = prlNew;
127: else
128: gprlHead = prlNew;
129: }
130:
131: /*
132: * Update our global with the new link. Clear the "dialog changed"
133: * flag.
134: */
135: gcd.prl = prlNew;
136: gfDlgChanged = FALSE;
137:
138: return TRUE;
139: }
140:
141:
142:
143: /************************************************************************
144: * AllocDialogResource
145: *
146: * This function allocates memory and builds a resource file format
147: * image in it of the current dialog.
148: *
149: * Arguments:
150: * BOOL fTestMode - TRUE if a special test mode version of the current
151: * dialog should be created.
152: * BOOL fClipboard - If TRUE, only the selected control(s) will be
153: * placed in the resource. This is used when putting
154: * controls or groups of controls into the clipboard.
155: * If the dialog is selected, this flag is ignored,
156: * because selecting the dialog implies all the
157: * controls will be written out also.
158: *
159: * Returns:
160: * Pointer to the resource buffer.
161: * NULL if unable to create the resource.
162: *
163: ************************************************************************/
164:
165: PRES AllocDialogResource(
166: BOOL fTestMode,
167: BOOL fClipboard)
168: {
169: NPCTYPE npc;
170: INT cControls;
171: BOOL fSelectedOnly = FALSE;
172: INT cbDlgName;
173: INT cbCaption;
174: INT cbPointSize;
175: INT cbFontName;
176: INT cbCD;
177: INT cbResHeader;
178: INT cbResData;
179: INT cbResSize;
180: INT cbMenuName;
181: INT cbClass;
182: INT cbText;
183: INT cbAlloc;
184: PBYTE pb;
185: PRES pResBegin;
186: PRES pResBegin2;
187: LPTSTR pszClass;
188: LPTSTR pszMenu;
189: LPTSTR pszText;
190: DWORD flStyle;
191: PDIALOGBOXHEADER pdbh;
192: PCONTROLDATA pcd;
193: ORDINAL ordClass;
194:
195: cControls = cWindows;
196: if (fClipboard && !gfDlgSelected) {
197: fSelectedOnly = TRUE;
198: for (cControls = 0, npc = npcHead; npc; npc = npc->npcNext)
199: if (npc->fSelected)
200: cControls++;
201: }
202:
203: /*
204: * If testing, don't allow a dialog to be created with any
205: * special class, or with the real menu.
206: */
207: if (fTestMode) {
208: pszClass = NULL;
209: pszMenu = NULL;
210: }
211: else {
212: pszClass = gcd.di.pszClass;
213: pszMenu = gcd.di.pszMenu;
214: }
215:
216: cbDlgName = NameOrdLen(gcd.pszDlgName);
217: cbCaption = (gcd.npc->text) ?
218: (lstrlen(gcd.npc->text) + 1) * sizeof(TCHAR) : sizeof(TCHAR);
219: cbClass = pszClass ? NameOrdLen(pszClass) : sizeof(TCHAR);
220: cbMenuName = pszMenu ? NameOrdLen(pszMenu) : sizeof(TCHAR);
221:
222: if (gcd.fFontSpecified) {
223: cbPointSize = sizeof(WORD);
224: cbFontName = (lstrlen(gcd.di.szFontName) + 1) * sizeof(TCHAR);
225: }
226: else {
227: cbPointSize = cbFontName = 0;
228: }
229:
230: /*
231: * Calculate the size of the resource header.
232: */
233: cbResHeader = sizeof(RES) + // The first fixed part.
234: sizeof(ORDINAL) + // The RT_DIALOG ordinal.
235: cbDlgName; // The dialog's name.
236: DWordAlign((PBYTE *)&cbResHeader); // Pad for the dialog's name.
237: cbResHeader += sizeof(RES2); // The last fixed part.
238:
239: /*
240: * Calculate the size of the resource data. This will just include
241: * the dialog box header right now.
242: */
243: cbResData = SIZEOF_DIALOGBOXHEADER + // The first fixed part.
244: cbMenuName + // The menu.
245: cbClass + // The class.
246: cbCaption + // The caption.
247: cbPointSize + // The point size.
248: cbFontName; // The font name.
249:
250: /*
251: * Allocate some buffer space. Be sure to round this up to a DWORD
252: * boundary to allow space for padding if necessary, but don't round
253: * cbResData field because it will need to be written into the header
254: * later, and the value that is written is an exact size (not rounded
255: * up).
256: */
257: cbAlloc = cbResSize = cbResHeader + cbResData;
258: DWordAlign((PBYTE *)&cbAlloc);
259: if (!(pResBegin = (PRES)MyAlloc(cbAlloc)))
260: return NULL;
261:
262: /*
263: * Write the resource header.
264: */
265: pdbh = (PDIALOGBOXHEADER)WriteResHeader(pResBegin, 0, ORDID_RT_DIALOG,
266: gcd.pszDlgName, gcd.di.fResFlags, gcd.di.wLanguage,
267: gcd.di.DataVersion, gcd.di.Version, gcd.di.Characteristics);
268:
269: /*
270: * Write out the style.
271: */
272: flStyle = gcd.npc->flStyle;
273: if (fTestMode) {
274: flStyle &= ~awcd[W_DIALOG].flStylesTestBad;
275: flStyle |= WS_VISIBLE;
276: }
277:
278: pdbh->lStyle = flStyle;
279: pdbh->lExtendedStyle = gcd.npc->flExtStyle;
280: pdbh->NumberOfItems = (WORD)cControls;
281:
282: /*
283: * Write the coordinates.
284: *
285: * If we are allocating a template that only has the selected controls
286: * in it, we put the value of CONTROLS_ONLY in the "cx" field of the
287: * dialog header. This is what we will check when the user pastes
288: * something from the clipboard into a dialog to determine whether
289: * to paste the entire dialog, or only the controls within the dialog
290: * item array.
291: */
292: pdbh->x = (WORD)gcd.npc->rc.left;
293: pdbh->y = (WORD)gcd.npc->rc.top;
294:
295: if (fSelectedOnly)
296: pdbh->cx = CONTROLS_ONLY;
297: else
298: pdbh->cx = (WORD)(gcd.npc->rc.right - gcd.npc->rc.left);
299:
300: pdbh->cy = (WORD)(gcd.npc->rc.bottom - gcd.npc->rc.top);
301:
302: pb = (PBYTE)pdbh + SIZEOF_DIALOGBOXHEADER;
303:
304: /*
305: * Write the menu name if there is one (we always write at least a null.
306: */
307: pb = NameOrdCpy((LPTSTR)pb, pszMenu ? pszMenu : szEmpty);
308:
309: /*
310: * Write the class if there is one (we always write at least a null.
311: */
312: pb = NameOrdCpy((LPTSTR)pb, pszClass ? pszClass : szEmpty);
313:
314: /*
315: * Write the caption if there is one (we always write at least a null).
316: */
317: pb = WriteSz((LPTSTR)pb, gcd.npc->text ? gcd.npc->text : szEmpty);
318:
319: /*
320: * Write out the font, if there is one specified.
321: */
322: if (gcd.fFontSpecified) {
323: *(PWORD)pb = (WORD)gcd.di.nPointSize;
324: pb += sizeof(WORD);
325:
326: pb = WriteSz((LPTSTR)pb, gcd.di.szFontName);
327: }
328:
329: /*
330: * Pad to a DWORD boundary. This is ok even if there are no controls
331: * that follow, because we were sure to allocate on an even dword
332: * boundary above.
333: */
334: DWordPad(&pb);
335:
336: /*
337: * Now do dialog items.
338: */
339: for (npc = npcHead; npc; npc = npc->npcNext) {
340: /*
341: * Skip the control if it is NOT selected and we only want the
342: * selected controls.
343: */
344: if (fSelectedOnly && !npc->fSelected)
345: continue;
346:
347: /*
348: * If we are testing, we don't want to really create a control
349: * with some funny class because it probably won't be found.
350: * We will substitute our custom class emulator instead.
351: */
352: if (fTestMode && npc->pwcd->fEmulated)
353: pszClass = szCustomClass;
354: else
355: pszClass = npc->pwcd->pszClass;
356:
357: /*
358: * Get a pointer to the text. If this is an icon control and
359: * we are going into test mode, change the text field so that
360: * it points to an ordinal for DlgEdit's icon to display, or
361: * the icon resource will probably not be found when the dialog
362: * is created.
363: */
364: pszText = npc->text;
365: if (npc->pwcd->iType == W_ICON && fTestMode)
366: pszText = (LPTSTR)&gordIcon;
367:
368: cbText = pszText ? NameOrdLen(pszText) : sizeof(TCHAR);
369: cbClass = pszClass ? NameOrdLen(pszClass) : sizeof(ORDINAL);
370:
371: cbCD = SIZEOF_CONTROLDATA + // The fixed portion.
372: cbClass + // The class.
373: cbText + // The text.
374: sizeof(WORD); // nExtraStuff field.
375:
376: /*
377: * Since we are adding a new control, we dword align the
378: * previous size of the resource data to ensure the new
379: * control starts on a dword boundary.
380: */
381: DWordAlign((PBYTE *)&cbResSize);
382:
383: /*
384: * Allocate room for this control. This includes room for the
385: * template structure, class, text and a byte for the cb field
386: * for the create struct data.
387: */
388: cbAlloc = cbResSize + cbCD;
389: DWordAlign((PBYTE *)&cbAlloc);
390: pResBegin2 = (PRES)MyRealloc((PBYTE)pResBegin, cbAlloc);
391: if (!pResBegin2) {
392: MyFree(pResBegin);
393: return NULL;
394: }
395:
396: pResBegin = pResBegin2;
397: pcd = (PCONTROLDATA)((PBYTE)pResBegin + cbResSize);
398: cbResSize += cbCD;
399:
400: /*
401: * Write the style. If testing, remove any styles that can
402: * cause problems, such as ownerdraw styles. If testing and
403: * this is an emulated custom control, always make it with
404: * the default styles no matter what the user has specified.
405: */
406: flStyle = npc->flStyle;
407: if (fTestMode) {
408: if (npc->pwcd->fEmulated)
409: flStyle = awcd[W_CUSTOM].flStyles;
410: else
411: flStyle &= ~npc->pwcd->flStylesTestBad;
412: }
413:
414: pcd->lStyle = flStyle;
415: pcd->lExtendedStyle = npc->flExtStyle;
416:
417: /*
418: * Write the coordinates.
419: */
420: pcd->x = (WORD)npc->rc.left;
421: pcd->y = (WORD)npc->rc.top;
422: pcd->cx = (WORD)(npc->rc.right - npc->rc.left);
423: pcd->cy = (WORD)(npc->rc.bottom - npc->rc.top);
424:
425: /*
426: * Write the id.
427: */
428: pcd->wId = (WORD)npc->id;
429:
430: pb = (PBYTE)pcd + SIZEOF_CONTROLDATA;
431:
432: /*
433: * Write the class. This will be a string, except for the
434: * predefined control classes, which all have an ordinal
435: * value defined for them.
436: */
437: if (pszClass) {
438: pb = NameOrdCpy((LPTSTR)pb, pszClass);
439: }
440: else {
441: WriteOrd(&ordClass, acsd[awcd[npc->pwcd->iType].iClass].idOrd);
442: pb = NameOrdCpy((LPTSTR)pb, (LPTSTR)&ordClass);
443: }
444:
445: /*
446: * Write the text.
447: */
448: pb = NameOrdCpy((LPTSTR)pb, pszText ? pszText : szEmpty);
449:
450: /*
451: * Write out a zero because there are no additional bytes
452: * of create struct data.
453: */
454: *(PWORD)pb = 0;
455: pb += sizeof(WORD);
456:
457: /*
458: * Pad to a DWORD boundary. This is ok even if there are no more
459: * controls, because we were sure to allocate on an even dword
460: * boundary above.
461: */
462: DWordPad(&pb);
463: }
464:
465: /*
466: * Now go back and fill in the resource data size field.
467: */
468: pResBegin->DataSize = cbResSize - cbResHeader;
469:
470: return pResBegin;
471: }
472:
473:
474:
475: /************************************************************************
476: * ResLinkToDialog
477: *
478: * This function is used to create a dialog out of a dialog resource
479: * that has been stored in the resource linked list.
480: *
481: * Arguments:
482: * PRESLINK prl - Points to the link that describes the dialog to
483: * create. It is assumed that the resource is a
484: * dialog resource.
485: *
486: ************************************************************************/
487:
488: VOID ResLinkToDialog(
489: PRESLINK prl)
490: {
491: PRES pRes;
492:
493: pRes = (PRES)GlobalLock(prl->hRes);
494: ResToDialog(pRes, TRUE);
495: GlobalUnlock(prl->hRes);
496:
497: /*
498: * If the dialog was successfully created, remember which res link
499: * it was created from.
500: */
501: if (gfEditingDlg)
502: gcd.prl = prl;
503: }
504:
505:
506:
507: /************************************************************************
508: * ResToDialog
509: *
510: * This function creates a dialog box, complete with controls,
511: * from a dialog resource template.
512: *
513: * Arguments:
514: * PRES pRes - Pointer to the dialog resource to use.
515: * BOOL fDoDialog - TRUE if a new dialog should be created, followed
516: * by the controls. If this is FALSE, just the
517: * controls will be created and added to the current
518: * dialog.
519: *
520: * Returns:
521: * TRUE on success, FALSE if an error occured.
522: *
523: ************************************************************************/
524:
525: BOOL ResToDialog(
526: PRES pRes,
527: BOOL fDoDialog)
528: {
529: LPTSTR pszText;
530: LPTSTR pszClass;
531: INT x;
532: INT y;
533: INT cx;
534: INT cy;
535: INT id;
536: INT iClass;
537: INT cdit;
538: INT Type;
539: DWORD flStyle;
540: DWORD flExtStyle;
541: NPCTYPE npc;
542: LPTSTR pszMenuName;
543: LPTSTR pszFontName;
544: INT nPointSize;
545: LPTSTR pszDlgName;
546: LPTSTR pszCaption;
547: PDIALOGBOXHEADER pdbh;
548: PCONTROLDATA pcd;
549: PWINDOWCLASSDESC pwcd;
550: PCUSTLINK pcl;
551: PRES2 pRes2;
552: DIALOGINFO di;
553: CCINFO cci;
554:
555: /*
556: * First check that the pointer is ok.
557: */
558: if (!pRes)
559: return FALSE;
560:
561: pRes2 = ResourcePart2(pRes);
562: pdbh = (PDIALOGBOXHEADER)SkipResHeader(pRes);
563:
564: /*
565: * Parse out the dialog box header.
566: * After this point, pcd is pointing to the first dialog control item.
567: */
568: pcd = ParseDialogBoxHeader(pdbh,
569: &flStyle, &flExtStyle, &cdit, &x, &y, &cx, &cy,
570: &pszMenuName, &pszClass, &pszCaption,
571: &nPointSize, &pszFontName);
572:
573: /*
574: * Are we pasting the entire dialog?
575: */
576: if (fDoDialog) {
577: pszDlgName = ResourceName(pRes);
578:
579: /*
580: * Determine the best base id for the dialog.
581: */
582: if (IsOrd(pszDlgName))
583: id = OrdID(pszDlgName);
584: else
585: id = NextID(NEXTID_DIALOG, plInclude, 0);
586:
587: di.fResFlags = pRes2->MemoryFlags;
588: di.wLanguage = pRes2->LanguageId;
589: di.pszClass = pszClass;
590: di.pszMenu = pszMenuName;
591: di.DataVersion = pRes2->DataVersion;
592: di.Version = pRes2->Version;
593: di.Characteristics = pRes2->Characteristics;
594: di.nPointSize = nPointSize;
595: lstrcpy(di.szFontName, pszFontName ? pszFontName : szEmpty);
596:
597: /*
598: * Create the dialog.
599: */
600: if (!AddControl(&awcd[W_DIALOG], pszCaption, flStyle, flExtStyle, id,
601: x, y, cx, cy, pszDlgName, &di))
602: return FALSE;
603: }
604:
605: while (cdit--) {
606: pcd = ParseControlData(pcd, &flStyle, &flExtStyle, &x, &y, &cx, &cy,
607: &id, &pszClass, &pszText);
608:
609: /*
610: * If we are not creating a new dialog, and the id in
611: * the resource is already in use, we will use the next
612: * available one instead.
613: */
614: if (!fDoDialog && !IsUniqueID(id))
615: id = NextID(NEXTID_CONTROL, plInclude, 0);
616:
617: /*
618: * Fix up the class. If the class is a predefined ordinal type,
619: * we will null out pszClass so it doesn't confuse AddControl
620: * into thinking that there is a string class for this control.
621: */
622: iClass = GetiClass(pszClass);
623: Type = TypeFromClassStyle(iClass, flStyle);
624: if (IsOrd(pszClass))
625: pszClass = NULL;
626:
627: if (Type == W_CUSTOM) {
628: /*
629: * Search the list of installed custom controls for one
630: * that matches the class.
631: */
632: for (pcl = gpclHead;
633: pcl && lstrcmpi(pcl->pwcd->pszClass, pszClass) != 0;
634: pcl = pcl->pclNext)
635: ;
636:
637: /*
638: * Was a match found?
639: */
640: if (pcl) {
641: pwcd = pcl->pwcd;
642: }
643: else {
644: /*
645: * An existing custom control link for this class was
646: * not found. We will add an emulated custom control
647: * to support it. We assume the default style and size
648: * should be what this control has.
649: */
650: lstrcpy(cci.szClass, pszClass);
651: cci.flOptions = 0;
652: *cci.szDesc = TEXT('\0');
653: cci.cxDefault = cx;
654: cci.cyDefault = cy;
655: cci.flStyleDefault = flStyle;
656: cci.flExtStyleDefault = flExtStyle;
657: *cci.szTextDefault = TEXT('\0');
658: cci.cStyleFlags = 0;
659: cci.aStyleFlags = NULL;
660: cci.lpfnStyle = NULL;
661: cci.lpfnSizeToText = NULL;
662: cci.dwReserved1 = 0;
663: cci.dwReserved2 = 0;
664:
665: if (pcl = AddCustomLink(&cci, TRUE, FALSE, NULL, NULL))
666: pwcd = pcl->pwcd;
667: else
668: /*
669: * Skip this control and continue creating the
670: * rest of the dialog.
671: */
672: continue;
673: }
674: }
675: else {
676: pwcd = &awcd[Type];
677: }
678:
679: /*
680: * If we are not creating the entire dialog (we allow existing
681: * resource files to be a little messed up), and this control
682: * is a default pushbutton, we will then loop through all the
683: * existing controls checking for another default pushbutton.
684: * If one is found, we convert the default pushbutton being
685: * created into a normal pushbutton instead. It is not allowed
686: * to have more than one default pushbuttons in the same dialog.
687: */
688: if (!fDoDialog && Type == W_PUSHBUTTON &&
689: (flStyle & BS_ALL) == BS_DEFPUSHBUTTON) {
690: for (npc = npcHead; npc; npc = npc->npcNext) {
691: if (npc->pwcd->iType == W_PUSHBUTTON &&
692: (npc->flStyle & BS_ALL) == BS_DEFPUSHBUTTON) {
693: flStyle = (flStyle & ~BS_ALL) | BS_PUSHBUTTON;
694: break;
695: }
696: }
697: }
698:
699: npc = AddControl(pwcd, pszText, flStyle, flExtStyle, id,
700: x, y, cx, cy, NULL, NULL);
701:
702: /*
703: * If the control creation succeeded, and we are just adding
704: * controls (not creating a whole new dialog), select the
705: * controls as they are added, but don't do any drawing yet.
706: */
707: if (!fDoDialog && npc)
708: SelectControl2(npc, TRUE);
709: }
710:
711: /*
712: * Update the selected rectangle. This is normally done by
713: * SelectControl2 but we told it not to so that the selection
714: * could be done faster. We also select the first control here.
715: */
716: if (!fDoDialog) {
717: SetAnchorToFirstSel(TRUE);
718: CalcSelectedRect();
719: }
720:
721: ShowWindow(gcd.npc->hwnd, SW_SHOWNA);
722: ToolboxOnTop();
723:
724: return TRUE;
725: }
726:
727:
728:
729: /************************************************************************
730: * TypeFromClassStyle
731: *
732: * This function returns the type of a control (one of the W_ constants)
733: * based on the class in iClass and the style in flStyle.
734: *
735: * Arguments:
736: * INT iClass = The class of the control, as an IC_* defined constant.
737: * DWORD flStyle = The style of the control.
738: *
739: * Returns:
740: * The type of the control (W_* constant).
741: * W_NOTHING is the error return.
742: *
743: ************************************************************************/
744:
745: STATICFN INT TypeFromClassStyle(
746: INT iClass,
747: DWORD flStyle)
748: {
749: switch (iClass) {
750: case IC_BUTTON:
751: return rgmpiClsBtnType[flStyle & BS_ALL];
752:
753: case IC_EDIT:
754: return W_EDIT;
755:
756: case IC_SCROLLBAR:
757: return (flStyle & SBS_VERT) ? W_VERTSCROLL : W_HORZSCROLL;
758:
759: case IC_STATIC:
760: return rgmpiClsStcType[flStyle & SS_ALL];
761:
762: case IC_LISTBOX:
763: return W_LISTBOX;
764:
765: case IC_COMBOBOX:
766: return W_COMBOBOX;
767:
768: case IC_CUSTOM:
769: return W_CUSTOM;
770:
771: case IC_DIALOG:
772: return W_DIALOG;
773:
774: default:
775: return W_NOTHING;
776: }
777: }
778:
779:
780:
781: /************************************************************************
782: * GetiClass
783: *
784: * This function returns the class identifier number for the
785: * window class of the control, given the class string from the
786: * dialog template.
787: *
788: * An ordinal class is a special ordinal that is used to identify
789: * each of the standard control classes. It is used in the
790: * dialog template to save space. The class string passed in
791: * can be an ordinal and if so, it will be checked against these
792: * predefined ordinal class values for a match.
793: *
794: * Arguments:
795: * LPTSTR pszClass - The class string or ordinal.
796: *
797: * Returns:
798: * The class identifier, one of the IC_* symbols in dlgedit.h.
799: * If the class cannot be determined, it assumes it is a custom
800: * class and returns IC_CUSTOM.
801: *
802: ************************************************************************/
803:
804: INT GetiClass(
805: LPTSTR pszClass)
806: {
807: INT i;
808: WORD idOrd;
809:
810: if (IsOrd(pszClass)) {
811: idOrd = OrdID(pszClass);
812: for (i = 0; i < IC_DIALOG; i++) {
813: if (acsd[i].idOrd == idOrd)
814: return i;
815: }
816: }
817: else {
818: for (i = 0; i < IC_DIALOG; i++) {
819: if (lstrcmpi(ids(acsd[i].idsClass), pszClass) == 0)
820: return i;
821: }
822: }
823:
824: /*
825: * Not found. Assume it is a user defined class.
826: */
827: return IC_CUSTOM;
828: }
829:
830:
831:
832: /************************************************************************
833: * Duplicate
834: *
835: * This routine duplicates the current selection.
836: *
837: ************************************************************************/
838:
839: VOID Duplicate(VOID)
840: {
841: PRES pRes;
842:
843: if (gcSelected) {
844: /*
845: * Store the current selection in a dialog resource.
846: */
847: if (!(pRes = AllocDialogResource(FALSE, TRUE)))
848: return;
849:
850: MakeCopyFromRes(pRes);
851: }
852: }
853:
854:
855:
856: /************************************************************************
857: * MakeCopyFromRes
858: *
859: * This function uses the given dialog template to either add a new
860: * dialog to the current resource file, or drop controls from the
861: * template into the current dialog. If copying a dialog, it is created
862: * right away. If copying controls, an operation is begun to start
863: * tracking them to their final destination in the current dialog.
864: *
865: * The caller of this function should NOT free pRes. This will
866: * be done either before the function returns, or after the drag
867: * operation is complete.
868: *
869: * Arguments:
870: * PRES pRes - Points to the dialog resource that contains
871: * the dialog or controls to make a copy of.
872: *
873: ************************************************************************/
874:
875: VOID MakeCopyFromRes(
876: PRES pRes)
877: {
878: PDIALOGBOXHEADER pdbh;
879: PCONTROLDATA pcd;
880: INT cControls;
881: INT i;
882: BOOL fFreeData = TRUE;
883: INT iType;
884: INT iClass;
885: INT nBottom;
886: INT nBottomLowest;
887:
888: gpResCopy = pRes;
889: pdbh = (PDIALOGBOXHEADER)SkipResHeader(gpResCopy);
890:
891: /*
892: * If cx is CONTROLS_ONLY, then we know that we only
893: * want to copy the controls in the template, not
894: * the entire dialog plus controls.
895: */
896: if (pdbh->cx == CONTROLS_ONLY) {
897: /*
898: * Begin copying in new controls into the current dialog.
899: */
900: cControls = pdbh->NumberOfItems;
901: if (cControls) {
902: /*
903: * Seed the rectangle with impossible values.
904: */
905: SetRect(&grcCopy, 32000, 32000, -32000, -32000);
906: nBottomLowest = 0;
907:
908: /*
909: * Loop through all the controls, expanding the rectangle
910: * to fit around all of them.
911: */
912: pcd = SkipDialogBoxHeader(pdbh);
913: for (i = 0; i < cControls; i++) {
914: iClass = GetiClass((LPTSTR)((PBYTE)pcd + SIZEOF_CONTROLDATA));
915: iType = TypeFromClassStyle(iClass, pcd->lStyle);
916:
917: if (grcCopy.left > (INT)pcd->x)
918: grcCopy.left = (INT)pcd->x;
919:
920: if (grcCopy.top > (INT)pcd->y)
921: grcCopy.top = (INT)pcd->y;
922:
923: if (grcCopy.right < (INT)pcd->x + (INT)pcd->cx)
924: grcCopy.right = (INT)pcd->x + (INT)pcd->cx;
925:
926: nBottom = ((INT)pcd->y + (INT)pcd->cy) -
927: GetOverHang(iType, (INT)pcd->cy);
928: if (nBottom > nBottomLowest)
929: nBottomLowest = nBottom;
930:
931: if (grcCopy.bottom < (INT)pcd->y + (INT)pcd->cy)
932: grcCopy.bottom = (INT)pcd->y + (INT)pcd->cy;
933:
934: pcd = SkipControlData(pcd);
935: }
936:
937: /*
938: * Begin dragging the new control(s). Set a flag so that
939: * the resource data is NOT free'd until after the drag
940: * is finished.
941: */
942: DragNewBegin(grcCopy.right - grcCopy.left,
943: grcCopy.bottom - grcCopy.top,
944: grcCopy.bottom - nBottomLowest);
945: fFreeData = FALSE;
946: }
947: }
948: else {
949: /*
950: * Begin copying in a new dialog, complete with controls.
951: */
952: if (SynchDialogResource()) {
953: /*
954: * Remove any existing dialog.
955: */
956: if (gfEditingDlg)
957: DeleteDialog(FALSE);
958:
959: if (ResToDialog(gpResCopy, TRUE)) {
960: SelectControl(gcd.npc, FALSE);
961: gfResChged = TRUE;
962: ShowFileStatus(FALSE);
963: }
964: }
965: }
966:
967: if (fFreeData) {
968: MyFree(gpResCopy);
969: gpResCopy = NULL;
970: }
971: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.