2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
5 #include "gadtools_intern.h"
6 #include <exec/memory.h>
7 #include <exec/types.h>
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 /*********************************************************************
22 AROS_LH2(struct Menu
*, CreateMenusA
,
25 AROS_LHA(struct NewMenu
*, newmenu
, A0
),
26 AROS_LHA(struct TagItem
*, tagList
, A1
),
29 struct Library
*, GadToolsBase
, 8, GadTools
)
32 CreateMenusA() creates a complete menu or parts of a menu.
35 newmenu - pointer to struct NewMenu
36 taglist - additional tags
39 A pointer to a menu structure.
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
53 FreeMenus(), LayoutMenusA()
59 ***************************************************************************/
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;
82 struct Menu
* firstmenu
= NULL
, * curmenu
= NULL
;
83 struct MenuItem
* newitem
, * firstitem
= NULL
, * curitem
= NULL
;
84 struct MenuItem
* newsubitem
, * firstsubitem
= NULL
, * cursubitem
= NULL
;
88 ULONG subitem_ctr
= 0;
90 BOOL fullmenu
= GetTagData(GTMN_FullMenu
, FALSE
, tagList
);
91 UBYTE prevtype
= (UBYTE
)-1;
94 struct NewMenu
*menuentry
;
97 struct Image
**MyBarTablePtr
;
100 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NewMenu %p TagList %p full %d\n",
101 newmenu
, tagList
, fullmenu
));
103 D(bug("Entering %s\n",__FUNCTION__
));
110 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: count elements\n"));
113 BOOL is_image
= FALSE
;
114 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: Type %d\n", menuentry
->nm_Type
));
115 switch (menuentry
->nm_Type
)
118 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NW_TITLE\n"));
119 MenuMemSize
+= getmenutitlesize(newmenu
,tagList
);
123 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: IM_ITEM\n"));
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
)
137 MenuMemSize
+= getmenuitemsize(newmenu
,
145 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: IM_SUB\n"));
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
)
159 MenuMemSize
+= getmenuitemsize(newmenu
,
167 ** Nothing to do in this case
169 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NM_IGNORE\n"));
176 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NM_END\n"));
180 } /* switch (menuentry->nm_Type) */
181 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: Current MenuMemSize %ld\n",MenuMemSize
));
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
)))
196 ** Set the secondary error value if requested.
198 if ((Ptr
=(ULONG
*) GetTagData(GTMN_SecondaryError
, (IPTR
) NULL
, tagList
)))
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
));
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
)
222 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NW_TITLE\n"));
223 curmenu
= makemenutitle(newmenu
,
234 ** Append it to the list of menus or make it the
237 if (NULL
== firstmenu
)
240 appendmenu(firstmenu
, curmenu
);
244 curitem
= firstitem
= cursubitem
= firstsubitem
= NULL
;
248 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: IM_ITEM\n"));
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
;
267 /* CreateMenusA must still return success here, only that the
268 menus will be trimmed */
269 err
= GTMENU_TRIMMED
;
273 newitem
= makemenuitem(newmenu
,
287 ** Append this item to the current menu title
292 curitem
->NextItem
= newitem
;
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
));
308 cursubitem
= firstsubitem
= NULL
;
314 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: IM_SUB\n"));
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
;
331 if (subitem_ctr
>= 32)
333 err
= GTMENU_TRIMMED
;
334 /* CreateMenusA must still return success here, only that the
335 menus will be trimmed */
339 newsubitem
= makemenuitem(newmenu
,
346 if (NULL
== newsubitem
)
354 if (!curitem
->SubItem
)
360 ** Append this item to the current sub menu item
365 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: CurSubItem 0x%lx NextItem 0x%lx\n", cursubitem
,newsubitem
));
366 cursubitem
->NextItem
= newsubitem
;
370 firstsubitem
= newsubitem
;
371 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: FirstSubItem 0x%lx\n", firstsubitem
));
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
;
388 struct IntuiText
*it2
= it
+ 1;
398 cursubitem
= newsubitem
;
404 ** Nothing to do in this case
406 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NM_IGNORE\n"));
413 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NM_END\n"));
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
);
441 firstmenu
= (struct Menu
*)firstitem
;
442 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: No FirstMenu..use firstitem 0x%lx\n", firstitem
));
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);
459 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: failed\n"));
464 FreeMenus(firstmenu
);
467 ** Set the secondary error value if requested.
469 ti
= FindTagItem(GTMN_SecondaryError
, tagList
);
484 struct Menu
* firstmenu
= NULL
, * curmenu
= NULL
;
485 struct MenuItem
* newitem
, * firstitem
= NULL
, * curitem
= NULL
;
486 struct MenuItem
* newsubitem
, * firstsubitem
= NULL
, * cursubitem
= NULL
;
490 ULONG subitem_ctr
= 0;
492 BOOL fullmenu
= GetTagData(GTMN_FullMenu
, FALSE
, tagList
);
493 UBYTE prevtype
= (UBYTE
)-1;
497 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NewMenu %p TagList %p full %d\n",
498 newmenu
, tagList
, fullmenu
));
500 D(bug("Entering %s\n",__FUNCTION__
));
504 BOOL is_image
= FALSE
;
506 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: Type %d\n", newmenu
->nm_Type
));
508 switch (newmenu
->nm_Type
)
511 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NW_TITLE\n"));
512 curmenu
= makemenutitle(newmenu
,
522 ** Append it to the list of menus or make it the
525 if (NULL
== firstmenu
)
528 appendmenu(firstmenu
, curmenu
);
532 curitem
= firstitem
= cursubitem
= firstsubitem
= NULL
;
536 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: IM_ITEM\n"));
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
;
555 /* CreateMenusA must still return success here, only that the
556 menus will be trimmed */
557 err
= GTMENU_TRIMMED
;
561 newitem
= makemenuitem(newmenu
,
573 ** Append this item to the current menu title
578 curitem
->NextItem
= newitem
;
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
));
594 cursubitem
= firstsubitem
= NULL
;
600 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: IM_SUB\n"));
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
;
617 if (subitem_ctr
>= 32)
619 err
= GTMENU_TRIMMED
;
620 /* CreateMenusA must still return success here, only that the
621 menus will be trimmed */
625 newsubitem
= makemenuitem(newmenu
,
630 if (NULL
== newsubitem
)
638 if (!curitem
->SubItem
)
644 ** Append this item to the current sub menu item
649 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: CurSubItem 0x%lx NextItem 0x%lx\n", cursubitem
,newsubitem
));
650 cursubitem
->NextItem
= newsubitem
;
654 firstsubitem
= newsubitem
;
655 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: FirstSubItem 0x%lx\n", firstsubitem
));
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
;
672 struct IntuiText
*it2
= it
+ 1;
682 cursubitem
= newsubitem
;
688 ** Nothing to do in this case
690 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NM_IGNORE\n"));
697 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: NM_END\n"));
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
);
725 firstmenu
= (struct Menu
*)firstitem
;
726 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: No FirstMenu..use firstitem 0x%lx\n", firstitem
));
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
));
743 DEBUG_CREATEMENUSA(dprintf("CreateMenusA: failed\n"));
748 FreeMenus(firstmenu
);
751 ** Set the secondary error value if requested.
753 ti
= FindTagItem(GTMN_SecondaryError
, tagList
);
766 void DumpMenuItem(struct MenuItem
*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
));
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;
793 DumpMenuItem((struct MenuItem
*) 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
;