Metatarget for copying of testfile fixed.
[AROS.git] / workbench / libs / gadtools / createmenusa.c
blobae3d2f08c4c0c138bae506d5ac9d3a211efcf6e0
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
4 */
5 #include "gadtools_intern.h"
6 #include <exec/memory.h>
7 #include <exec/types.h>
8 #define DEBUG 0
10 #include <intuition/intuition.h>
11 #include <libraries/gadtools.h>
12 #include <utility/tagitem.h>
14 #include <aros/debug.h>
16 #include <proto/gadtools.h>
18 /*********************************************************************
20 NAME */
22 AROS_LH2(struct Menu *, CreateMenusA,
24 /* SYNOPSIS */
25 AROS_LHA(struct NewMenu *, newmenu, A0),
26 AROS_LHA(struct TagItem *, tagList, A1),
28 /* LOCATION */
29 struct Library *, GadToolsBase, 8, GadTools)
31 /* FUNCTION
32 CreateMenusA() creates a complete menu or parts of a menu.
34 INPUTS
35 newmenu - pointer to struct NewMenu
36 taglist - additional tags
38 RESULT
39 A pointer to a menu structure.
41 NOTES
42 CreateMenusA() stores no position information in the menu structure.
43 You need to call LayoutMenusA() to retrieve them.
44 The strings supplied for the menu are not copied into a private
45 buffer. Therefore they must be preserved, until FreeMenus() was
46 called.
48 EXAMPLE
50 BUGS
52 SEE ALSO
53 FreeMenus(), LayoutMenusA()
55 INTERNALS
57 HISTORY
59 ***************************************************************************/
60 #if NEWMENUCODE
63 * We need to allocate the whole menu in one block as we can't just
64 * go through the menustructure in freemenus as programs may do dynamic
65 * menu links which would be illegally freeed that way.
66 * As barlabels are dynamic Boopsi image objects we need to store them
67 * in a menu pregap so we can free them through DisposeObject() before
68 * we free the whole menublock.
70 * Menu Memory structure:
71 * void *BarLabelTable[BarLabelCount];
72 * ULONG BarLabelCount;
73 * Menu(returned Ptr):
74 * MenuStructure
75 * .
76 * .
80 AROS_LIBFUNC_INIT
82 struct Menu * firstmenu = NULL, * curmenu = NULL;
83 struct MenuItem * newitem, * firstitem = NULL, * curitem = NULL;
84 struct MenuItem * newsubitem, * firstsubitem = NULL, * cursubitem = NULL;
85 struct TagItem * ti;
86 ULONG menu_ctr = 0;
87 ULONG item_ctr = 0;
88 ULONG subitem_ctr = 0;
89 BOOL end;
90 BOOL fullmenu = GetTagData(GTMN_FullMenu, FALSE, tagList);
91 UBYTE prevtype = (UBYTE)-1;
92 ULONG BarLabels;
93 ULONG MenuMemSize;
94 struct NewMenu *menuentry;
95 UBYTE *MyMenuMemory;
96 UBYTE *MyMenuMemPtr;
97 struct Image **MyBarTablePtr;
98 ULONG err = 0;
100 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NewMenu %p TagList %p full %d\n",
101 newmenu, tagList, fullmenu));
103 D(bug("Entering %s\n",__FUNCTION__));
105 BarLabels = 0;
106 MenuMemSize = 0;
107 menuentry = newmenu;
109 end = FALSE;
110 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: count elements\n"));
111 while (!end)
113 BOOL is_image = FALSE;
114 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: Type %d\n", menuentry->nm_Type));
115 switch (menuentry->nm_Type)
117 case NM_TITLE:
118 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NW_TITLE\n"));
119 MenuMemSize += getmenutitlesize(newmenu,tagList);
120 break;
122 case IM_ITEM:
123 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: IM_ITEM\n"));
124 is_image = TRUE;
125 /* Fall through */
127 case NM_ITEM: /* also the BARLABEL */
129 ** There has to be a menu structure available
130 ** to create an item, unless GTMN_FullMenu is FALSE.
132 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NM_ITEM\n"));
133 if (menuentry->nm_Label == NM_BARLABEL)
135 BarLabels++;
137 MenuMemSize += getmenuitemsize(newmenu,
138 is_image,
139 tagList,
140 GTB(GadToolsBase));
142 break;
144 case IM_SUB:
145 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: IM_SUB\n"));
146 is_image = TRUE;
147 /* Fall through */
149 case NM_SUB:
151 ** There has to be an item menu structure available
152 ** to create a sub item, unless GTMN_FullMenu == FALSE.
154 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NM_SUB\n"));
155 if (menuentry->nm_Label == NM_BARLABEL)
157 BarLabels++;
159 MenuMemSize += getmenuitemsize(newmenu,
160 is_image,
161 tagList,
162 GTB(GadToolsBase));
163 break;
165 case NM_IGNORE:
167 ** Nothing to do in this case
169 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NM_IGNORE\n"));
170 break;
172 case NM_END:
174 ** The end.
176 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NM_END\n"));
177 end = TRUE;
178 break;
180 } /* switch (menuentry->nm_Type) */
181 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: Current MenuMemSize %ld\n",MenuMemSize));
182 menuentry++;
183 } /* while (!end) */
186 * Add space for barlabel count+area which must come at the beginning.
188 MenuMemSize += sizeof(ULONG) + (BarLabels * sizeof(void*));
190 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: MenuMemSize %ld BarLabels %ld\n",MenuMemSize,BarLabels));
192 if (!(MyMenuMemory=AllocVec(MenuMemSize,MEMF_ANY | MEMF_CLEAR)))
194 ULONG *Ptr;
196 ** Set the secondary error value if requested.
198 if ((Ptr =(ULONG*) GetTagData(GTMN_SecondaryError, (IPTR) NULL, tagList)))
200 *Ptr = GTMENU_NOMEM;
202 return(NULL);
204 MyBarTablePtr =(struct Image**) MyMenuMemory;
205 MyMenuMemPtr =(UBYTE*) &MyBarTablePtr[BarLabels];
206 *((ULONG*) MyMenuMemPtr) = BarLabels;
207 MyMenuMemPtr += sizeof(ULONG);
209 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: MyMenuMemory 0x%lx MyBarTablePtr 0x%lx MyMenuMemPtr 0x%lx\n",MyMenuMemory,MyBarTablePtr,MyMenuMemPtr));
211 end = FALSE;
212 while (!end)
214 BOOL is_image = FALSE;
216 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: Type %d\n", newmenu->nm_Type));
217 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: Current MyMenuMemory 0x%lx MyBarTablePtr 0x%lx MyMenuMemPtr 0x%lx\n",MyMenuMemory,MyBarTablePtr,MyMenuMemPtr));
219 switch (newmenu->nm_Type)
221 case NM_TITLE:
222 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NW_TITLE\n"));
223 curmenu = makemenutitle(newmenu,
224 &MyMenuMemPtr,
225 tagList);
227 if (NULL == curmenu)
229 err = GTMENU_NOMEM;
230 goto failexit;
234 ** Append it to the list of menus or make it the
235 ** first entry.
237 if (NULL == firstmenu)
238 firstmenu = curmenu;
239 else
240 appendmenu(firstmenu, curmenu);
242 menu_ctr ++;
243 item_ctr = 0;
244 curitem = firstitem = cursubitem = firstsubitem = NULL;
245 break;
247 case IM_ITEM:
248 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: IM_ITEM\n"));
249 is_image = TRUE;
250 /* Fall through */
252 case NM_ITEM: /* also the BARLABEL */
254 ** There has to be a menu structure available
255 ** to create an item, unless GTMN_FullMenu is FALSE.
257 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NM_ITEM\n"));
259 if (fullmenu && (NULL == curmenu))
261 err = GTMENU_INVALID;
262 goto failexit;
265 if (item_ctr >= 64)
267 /* CreateMenusA must still return success here, only that the
268 menus will be trimmed */
269 err = GTMENU_TRIMMED;
270 break;
273 newitem = makemenuitem(newmenu,
274 &MyMenuMemPtr,
275 &MyBarTablePtr,
276 is_image,
277 tagList,
278 GTB(GadToolsBase));
280 if (NULL == newitem)
282 err = GTMENU_NOMEM;
283 goto failexit;
287 ** Append this item to the current menu title
290 if (curitem)
292 curitem->NextItem = newitem;
294 else
296 firstitem = newitem;
297 if (curmenu)
299 curmenu->FirstItem = newitem;
300 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: set FirstItem 0x%lx\n", newitem));
304 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NextItem 0x%lx\n", newitem));
306 item_ctr ++;
307 subitem_ctr = 0;
308 cursubitem = firstsubitem = NULL;
310 curitem = newitem;
311 break;
313 case IM_SUB:
314 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: IM_SUB\n"));
315 is_image = TRUE;
316 /* Fall through */
318 case NM_SUB:
320 ** There has to be an item menu structure available
321 ** to create a sub item, unless GTMN_FullMenu == FALSE.
323 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NM_SUB\n"));
324 if ( (fullmenu && (NULL == curitem)) ||
325 (prevtype == NM_TITLE) )
327 err = GTMENU_INVALID;
328 goto failexit;
331 if (subitem_ctr >= 32)
333 err = GTMENU_TRIMMED;
334 /* CreateMenusA must still return success here, only that the
335 menus will be trimmed */
336 break;
339 newsubitem = makemenuitem(newmenu,
340 &MyMenuMemPtr,
341 &MyBarTablePtr,
342 is_image,
343 tagList,
344 GTB(GadToolsBase));
346 if (NULL == newsubitem)
348 err = GTMENU_NOMEM;
349 goto failexit;
352 if (curitem)
354 if (!curitem->SubItem)
360 ** Append this item to the current sub menu item
363 if (cursubitem)
365 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: CurSubItem 0x%lx NextItem 0x%lx\n", cursubitem,newsubitem));
366 cursubitem->NextItem = newsubitem;
368 else
370 firstsubitem = newsubitem;
371 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: FirstSubItem 0x%lx\n", firstsubitem));
372 if (curitem)
374 curitem->SubItem = newsubitem;
376 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: CurItem 0x%lx SubItem 0x%lx\n", curitem,newsubitem));
378 /* Add the ">>" mark. Hmm ... maybe if would be better if this
379 was done in LayoutMenus() ??? */
381 curitem->Flags &= ~COMMSEQ;
382 if (curitem->Flags & ITEMTEXT)
384 struct IntuiText *it = (struct IntuiText *)curitem->ItemFill;
386 if (!it->NextText)
388 struct IntuiText *it2 = it + 1;
390 it->NextText = it2;
391 it2->IText = "»";
398 cursubitem = newsubitem;
399 subitem_ctr ++;
400 break;
402 case NM_IGNORE:
404 ** Nothing to do in this case
406 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NM_IGNORE\n"));
407 break;
409 case NM_END:
411 ** The end.
413 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NM_END\n"));
414 end = TRUE;
415 break;
417 } /* switch (newmenu->nm_Type) */
419 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: firstmenu %p curmenu %p firstitem %p curitem %p firstsub %p cursub %p\n",
420 firstmenu, curmenu, firstitem, curitem, firstsubitem, cursubitem));
422 prevtype = newmenu->nm_Type;
425 ** Advance to the next item in the array
427 newmenu = &newmenu[1];
429 } /* while (FALSE == end) */
432 ** Set the secondary error value if requested.
434 ti = FindTagItem(GTMN_SecondaryError, tagList);
436 if (NULL != ti)
437 ti->ti_Data = err;
439 if (!firstmenu)
441 firstmenu = (struct Menu *)firstitem;
442 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: No FirstMenu..use firstitem 0x%lx\n", firstitem));
444 if (!firstmenu)
446 firstmenu = (struct Menu *)firstsubitem;
447 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: No FirstMenu..use firstsubitem 0x%lx\n", firstsubitem));
450 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: return %p\n", firstmenu));
452 // DumpMenu(firstmenu);
454 return firstmenu;
457 failexit:
459 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: failed\n"));
462 ** Free all memory
464 FreeMenus(firstmenu);
467 ** Set the secondary error value if requested.
469 ti = FindTagItem(GTMN_SecondaryError, tagList);
471 if (NULL != ti)
472 ti->ti_Data = err;
474 return NULL;
476 AROS_LIBFUNC_EXIT
478 } /* CreateMenusA */
480 #else
482 AROS_LIBFUNC_INIT
484 struct Menu * firstmenu = NULL, * curmenu = NULL;
485 struct MenuItem * newitem, * firstitem = NULL, * curitem = NULL;
486 struct MenuItem * newsubitem, * firstsubitem = NULL, * cursubitem = NULL;
487 struct TagItem * ti;
488 ULONG menu_ctr = 0;
489 ULONG item_ctr = 0;
490 ULONG subitem_ctr = 0;
491 BOOL end = FALSE;
492 BOOL fullmenu = GetTagData(GTMN_FullMenu, FALSE, tagList);
493 UBYTE prevtype = (UBYTE)-1;
495 ULONG err = 0;
497 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NewMenu %p TagList %p full %d\n",
498 newmenu, tagList, fullmenu));
500 D(bug("Entering %s\n",__FUNCTION__));
502 while (FALSE == end)
504 BOOL is_image = FALSE;
506 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: Type %d\n", newmenu->nm_Type));
508 switch (newmenu->nm_Type)
510 case NM_TITLE:
511 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NW_TITLE\n"));
512 curmenu = makemenutitle(newmenu,
513 tagList);
515 if (NULL == curmenu)
517 err = GTMENU_NOMEM;
518 goto failexit;
522 ** Append it to the list of menus or make it the
523 ** first entry.
525 if (NULL == firstmenu)
526 firstmenu = curmenu;
527 else
528 appendmenu(firstmenu, curmenu);
530 menu_ctr ++;
531 item_ctr = 0;
532 curitem = firstitem = cursubitem = firstsubitem = NULL;
533 break;
535 case IM_ITEM:
536 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: IM_ITEM\n"));
537 is_image = TRUE;
538 /* Fall through */
540 case NM_ITEM: /* also the BARLABEL */
542 ** There has to be a menu structure available
543 ** to create an item, unless GTMN_FullMenu is FALSE.
545 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NM_ITEM\n"));
547 if (fullmenu && (NULL == curmenu))
549 err = GTMENU_INVALID;
550 goto failexit;
553 if (item_ctr >= 64)
555 /* CreateMenusA must still return success here, only that the
556 menus will be trimmed */
557 err = GTMENU_TRIMMED;
558 break;
561 newitem = makemenuitem(newmenu,
562 is_image,
563 tagList,
564 GTB(GadToolsBase));
566 if (NULL == newitem)
568 err = GTMENU_NOMEM;
569 goto failexit;
573 ** Append this item to the current menu title
576 if (curitem)
578 curitem->NextItem = newitem;
580 else
582 firstitem = newitem;
583 if (curmenu)
585 curmenu->FirstItem = newitem;
586 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: set FirstItem 0x%lx\n", newitem));
590 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NextItem 0x%lx\n", newitem));
592 item_ctr ++;
593 subitem_ctr = 0;
594 cursubitem = firstsubitem = NULL;
596 curitem = newitem;
597 break;
599 case IM_SUB:
600 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: IM_SUB\n"));
601 is_image = TRUE;
602 /* Fall through */
604 case NM_SUB:
606 ** There has to be an item menu structure available
607 ** to create a sub item, unless GTMN_FullMenu == FALSE.
609 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NM_SUB\n"));
610 if ( (fullmenu && (NULL == curitem)) ||
611 (prevtype == NM_TITLE) )
613 err = GTMENU_INVALID;
614 goto failexit;
617 if (subitem_ctr >= 32)
619 err = GTMENU_TRIMMED;
620 /* CreateMenusA must still return success here, only that the
621 menus will be trimmed */
622 break;
625 newsubitem = makemenuitem(newmenu,
626 is_image,
627 tagList,
628 GTB(GadToolsBase));
630 if (NULL == newsubitem)
632 err = GTMENU_NOMEM;
633 goto failexit;
636 if (curitem)
638 if (!curitem->SubItem)
644 ** Append this item to the current sub menu item
647 if (cursubitem)
649 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: CurSubItem 0x%lx NextItem 0x%lx\n", cursubitem,newsubitem));
650 cursubitem->NextItem = newsubitem;
652 else
654 firstsubitem = newsubitem;
655 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: FirstSubItem 0x%lx\n", firstsubitem));
656 if (curitem)
658 curitem->SubItem = newsubitem;
660 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: CurItem 0x%lx SubItem 0x%lx\n", curitem,newsubitem));
662 /* Add the ">>" mark. Hmm ... maybe if would be better if this
663 was done in LayoutMenus() ??? */
665 curitem->Flags &= ~COMMSEQ;
666 if (curitem->Flags & ITEMTEXT)
668 struct IntuiText *it = (struct IntuiText *)curitem->ItemFill;
670 if (!it->NextText)
672 struct IntuiText *it2 = it + 1;
674 it->NextText = it2;
675 it2->IText = "»";
682 cursubitem = newsubitem;
683 subitem_ctr ++;
684 break;
686 case NM_IGNORE:
688 ** Nothing to do in this case
690 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NM_IGNORE\n"));
691 break;
693 case NM_END:
695 ** The end.
697 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NM_END\n"));
698 end = TRUE;
699 break;
701 } /* switch (newmenu->nm_Type) */
703 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: firstmenu %p curmenu %p firstitem %p curitem %p firstsub %p cursub %p\n",
704 firstmenu, curmenu, firstitem, curitem, firstsubitem, cursubitem));
706 prevtype = newmenu->nm_Type;
709 ** Advance to the next item in the array
711 newmenu = &newmenu[1];
713 } /* while (FALSE == end) */
716 ** Set the secondary error value if requested.
718 ti = FindTagItem(GTMN_SecondaryError, tagList);
720 if (NULL != ti)
721 ti->ti_Data = err;
723 if (!firstmenu)
725 firstmenu = (struct Menu *)firstitem;
726 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: No FirstMenu..use firstitem 0x%lx\n", firstitem));
728 if (!firstmenu)
730 firstmenu = (struct Menu *)firstsubitem;
731 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: No FirstMenu..use firstsubitem 0x%lx\n", firstsubitem));
734 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: return %p\n", firstmenu));
736 DumpMenu(firstmenu);
738 return firstmenu;
741 failexit:
743 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: failed\n"));
746 ** Free all memory
748 FreeMenus(firstmenu);
751 ** Set the secondary error value if requested.
753 ti = FindTagItem(GTMN_SecondaryError, tagList);
755 if (NULL != ti)
756 ti->ti_Data = err;
758 return NULL;
760 AROS_LIBFUNC_EXIT
762 } /* CreateMenusA */
763 #endif
765 #if 0
766 void DumpMenuItem(struct MenuItem *item)
768 if (!item) return;
769 while (item)
771 DEBUG_DUMPMENUS(bug("DumpMenus: Item 0x%lx NextItem 0x%lx SubItem 0x%lx\n", item,item->NextItem,item->SubItem));
772 if (item->Flags & ITEMTEXT)
774 struct IntuiText *MyText=(struct IntuiText*) item->ItemFill;
775 DEBUG_DUMPMENUS(bug("DumpMenus: <%s>\n",MyText->IText));
777 else
779 DEBUG_DUMPMENUS(bug("DumpMenus: Image 0x%lx\n", item->ItemFill));
781 DumpMenuItem(item->SubItem);
782 item = item->NextItem;
786 void DumpMenu(struct Menu *menu)
788 ULONG *p = (ULONG *)menu - 1;
790 if (!menu) return;
791 if (*p)
793 DumpMenuItem((struct MenuItem*) menu);
795 else
797 while (menu)
799 DEBUG_DUMPMENUS(bug("DumpMenus: Menu 0x%lx <%s> NextMenu 0x%lx FirstItem 0x%lx\n", menu, menu->MenuName, menu->NextMenu, menu->FirstItem));
800 DumpMenuItem(menu->FirstItem);
801 menu = menu->NextMenu;
805 #endif