/* Public domain */ #ifndef _AGAR_GUI_MENU_H_ #define _AGAR_GUI_MENU_H_ #include #include #include #include struct ag_menu; struct ag_menu_view; struct ag_button; typedef struct ag_menu_item { Uint32 tag; /* Tagged Non-Object */ char *_Nonnull text; /* Label text */ int lblMenu[2]; /* Cached surfaces of AG_Menu(3) */ /* 0=Disabled, 1=Enabled */ int lblView[3]; /* Cached surfaces of AG_MenuView(3) */ /* 0=Disabled, 1=Enabled, 2=Selected */ int value; /* Default bool value binding */ AG_Surface *_Nullable icon; /* Icon surface */ AG_Function *_Nullable stateFn; /* State function (overrides flag) */ int state; /* State flag */ AG_KeySym key_equiv; /* Key shortcut */ AG_KeyMod key_mod; int x, y; /* Position in parent view */ Uint flags; #define AG_MENU_ITEM_ICONS 0x01 /* At least one item has an icon */ #define AG_MENU_ITEM_NOSELECT 0x02 /* Non-selectable regardless of state */ #define AG_MENU_ITEM_SEPARATOR 0x04 /* Item is a cosmetic separator */ #define AG_MENU_ITEM_INVERTED 0x08 /* Invert the binding state */ AG_Event *_Nullable clickFn; /* Raised on click */ AG_Event *_Nullable poll; /* Raised before the item is drawn */ enum ag_menu_binding { /* Boolean binding */ AG_MENU_NO_BINDING, AG_MENU_INT_BOOL, AG_MENU_INT8_BOOL, AG_MENU_INT_FLAGS, AG_MENU_INT8_FLAGS, AG_MENU_INT16_FLAGS, AG_MENU_INT32_FLAGS } bind_type; Uint32 bind_flags; /* Bitmask (for FLAGS) */ void *_Nullable bind_p; /* Pointer to data */ #ifdef AG_THREADS _Nullable_Mutex AG_Mutex *_Nullable bind_lock; /* Lock on data */ #endif struct ag_menu_view *_Nullable view; /* Parent view (subitems) */ struct ag_menu *_Nullable pmenu; /* Parent menu */ struct ag_menu_item *_Nullable sel_subitem; /* Selected subitem */ struct ag_button *_Nullable tbButton; /* Related toolbar button */ struct ag_menu_item *_Nullable parent; /* Parent MenuItem if any */ AG_TAILQ_HEAD_(ag_menu_item) subItems; /* Child items */ Uint nSubItems; Uint32 _pad; AG_TAILQ_ENTRY(ag_menu_item) items; /* In parent */ } AG_MenuItem; /* Tagged Non-Object */ #define AGMENUITEM(p) ((AG_MenuItem *)(p)) #define AGcMENUITEM(p) ((const AG_MenuItem *)(p)) #ifdef AG_TYPE_SAFETY # define AG_MENUITEM_VALID(p) (AGMENUITEM(p)->tag == agNonObjectSignature) # define AG_MENUITEM_IS_VALID(p) if (!AG_MENUITEM_VALID(p)) { AG_FatalError("Illegal AG_MenuItem access"); } # define AG_MENUITEM_PTR(v) AG_MenuGetItemPtr(event,(v),0) # define AG_cMENUITEM_PTR(v) AG_MenuGetItemPtr(event,(v),1) #else # define AG_MENUITEM_VALID(p) 1 # define AG_MENUITEM_IS_VALID(p) # define AG_MENUITEM_PTR(v) event->argv[v].data.p # define AG_cMENUITEM_PTR(v) event->argv[v].data.p #endif enum ag_menu_style { AG_MENU_DROPDOWN, /* Drop-down menu */ AG_MENU_POPUP, /* Contextual popup */ AG_MENU_GLOBAL /* Global application menu */ }; typedef struct ag_menu { struct ag_widget wid; /* AG_Widget -> AG_Menu */ Uint flags; #define AG_MENU_HFILL 0x01 #define AG_MENU_VFILL 0x02 #define AG_MENU_NO_COLOR_BG 0x04 /* Don't use parent MenuView's "color" as the "background-color" of menu-expansion windows. */ #define AG_MENU_NO_BOOL_MSG 0x08 /* Don't notify the user when a boolean has been toggled by a keyboard shortcut. */ #define AG_MENU_FAST_BOOL_MSG 0x10 /* Display the notification message only for 400ms (default = 1s). */ #define AG_MENU_EXPAND (AG_MENU_HFILL | AG_MENU_VFILL) enum ag_menu_style style; /* Menu style */ AG_MenuItem *_Nonnull root; /* Root menu item */ int selecting; /* Selection in progress */ int lPadLbl, rPadLbl; /* Item label padding in pixels */ int tPadLbl, bPadLbl; int itemh; /* Item height (optimization) */ int curState; /* For MenuState() */ Uint32 _pad; AG_MenuItem *_Nullable itemSel; /* Selected top-level item */ AG_Toolbar *_Nullable curToolbar; /* For MenuToolbar() */ AG_Rect r; /* View area */ } AG_Menu; #define AGMENU(o) ((AG_Menu *)(o)) #define AGcMENU(o) ((const AG_Menu *)(o)) #define AG_MENU_ISA(o) (((AGOBJECT(o)->cid & 0xff000000) >> 24) == 0x18) #define AG_MENU_SELF() AGMENU( AG_OBJECT(0, "AG_Widget:AG_Menu:*") ) #define AG_MENU_PTR(n) AGMENU( AG_OBJECT((n), "AG_Widget:AG_Menu:*") ) #define AG_MENU_NAMED(n) AGMENU( AG_OBJECT_NAMED((n),"AG_Widget:AG_Menu:*") ) #define AG_cMENU_SELF() AGcMENU( AG_cOBJECT(0, "AG_Widget:AG_Menu:*") ) #define AG_cMENU_PTR(n) AGcMENU( AG_cOBJECT((n), "AG_Widget:AG_Menu:*") ) #define AG_cMENU_NAMED(n) AGcMENU( AG_cOBJECT_NAMED((n),"AG_Widget:AG_Menu:*") ) typedef struct ag_popup_menu { AG_Widget *_Nonnull widget; /* Parent widget */ AG_Menu *_Nonnull menu; /* Menu (allocated) */ AG_MenuItem *_Nonnull root; /* Alias for menu->root */ AG_Window *_Nullable win; /* Expanded window */ } AG_PopupMenu; typedef struct ag_menu_view { struct ag_widget wid; /* AG_Widget -> AG_MenuView */ AG_Menu *_Nullable pmenu; /* Associated menu */ AG_MenuItem *_Nullable pitem; /* Associated menu item */ int spLblArrow; /* Label and submenu arrow spacing */ int arrowRight; /* Right arrow surface handle */ } AG_MenuView; #define AGMENUVIEW(o) ((AG_MenuView *)(o)) #define AGcMENUVIEW(o) ((const AG_MenuView *)(o)) #define AG_MENUVIEW_ISA(o) (((AGOBJECT(o)->cid & 0xff000000) >> 24) == 0x19) #define AG_MENUVIEW_SELF() AGMENUVIEW( AG_OBJECT(0, "AG_Widget:AG_MenuView:*") ) #define AG_MENUVIEW_PTR(n) AGMENUVIEW( AG_OBJECT((n), "AG_Widget:AG_MenuView:*") ) #define AG_MENUVIEW_NAMED(n) AGMENUVIEW( AG_OBJECT_NAMED((n), "AG_Widget:AG_MenuView:*") ) #define AG_cMENUVIEW_SELF() AGcMENUVIEW( AG_cOBJECT(0, "AG_Widget:AG_MenuView:*") ) #define AG_cMENUVIEW_PTR(n) AGcMENUVIEW( AG_cOBJECT((n), "AG_Widget:AG_MenuView:*") ) #define AG_cMENUVIEW_NAMED(n) AGcMENUVIEW( AG_cOBJECT_NAMED((n), "AG_Widget:AG_MenuView:*") ) __BEGIN_DECLS extern AG_WidgetClass agMenuClass; extern AG_WidgetClass agMenuViewClass; extern AG_Menu *_Nullable agAppMenu; extern AG_Window *_Nullable agAppMenuWin; AG_Menu *_Nonnull AG_MenuNew(void *_Nullable, Uint); AG_Menu *_Nullable AG_MenuNewGlobal(Uint); void AG_MenuDraw(void *_Nonnull); AG_PopupMenu *_Nonnull AG_PopupNew(void *_Nonnull); void AG_PopupShow(AG_PopupMenu *_Nonnull); void AG_PopupShowAt(AG_PopupMenu *_Nonnull, int,int); void AG_PopupHide(AG_PopupMenu *_Nonnull); void AG_PopupDestroy(AG_PopupMenu *_Nonnull); void AG_MenuDel(AG_MenuItem *_Nonnull); void AG_MenuItemFree(AG_MenuItem *_Nonnull); AG_Window *_Nullable AG_MenuExpand(void *_Nullable, AG_MenuItem *_Nonnull, int,int); void AG_MenuCollapse(AG_MenuItem *_Nullable); void AG_MenuCollapseAll(AG_Menu *_Nonnull); void AG_MenuSetLabelPadding(AG_Menu *_Nonnull, int,int,int,int); #define AG_MenuSetLabelPaddingLeft(m,v) \ AG_MenuSetLabelPadding((m),(v),-1,-1,-1) #define AG_MenuSetLabelPaddingRight(m,v) \ AG_MenuSetLabelPadding((m),-1,(v),-1,-1) #define AG_MenuSetLabelPaddingTop(m,v) \ AG_MenuSetLabelPadding((m),-1,-1,(v),-1) #define AG_MenuSetLabelPaddingBottom(m,v) \ AG_MenuSetLabelPadding((m),-1,-1,-1,(v)) void AG_MenuSetIcon(AG_MenuItem *_Nonnull, const AG_Surface *_Nullable); void AG_MenuSetLabel(AG_MenuItem *_Nonnull, const char *_Nonnull, ...) FORMAT_ATTRIBUTE(printf,2,3); void AG_MenuSetLabelS(AG_MenuItem *_Nonnull, const char *_Nonnull); void AG_MenuSetPollFn(AG_MenuItem *_Nonnull, _Nonnull AG_EventFn, const char *_Nullable, ...); void AG_MenuInvalidateLabels(AG_MenuItem *_Nonnull); void AG_MenuFreeSubitems(AG_MenuItem *_Nonnull); void AG_MenuState(AG_MenuItem *_Nonnull, int); #define AG_MenuDisable(m) AG_MenuState((m),0) #define AG_MenuEnable(m) AG_MenuState((m),1) int AG_MenuBoolGet(AG_MenuItem *_Nonnull); void AG_MenuBoolToggle(AG_MenuItem *_Nonnull); void AG_MenuToolbar(AG_MenuItem *_Nonnull, AG_Toolbar *_Nullable); AG_MenuItem *_Nonnull AG_MenuNode(AG_MenuItem *_Nonnull, const char *_Nullable, const AG_Surface *_Nullable); AG_MenuItem *_Nonnull AG_MenuSeparator(AG_MenuItem *_Nonnull); AG_MenuItem *_Nonnull AG_MenuSectionS(AG_MenuItem *_Nonnull, const char *_Nullable); AG_MenuItem *_Nonnull AG_MenuSection(AG_MenuItem *_Nonnull, const char *_Nonnull, ...) FORMAT_ATTRIBUTE(printf,2,3); AG_MenuItem *_Nonnull AG_MenuAction(AG_MenuItem *_Nonnull, const char *_Nullable, const AG_Surface *_Nullable, _Nonnull AG_EventFn, const char *_Nullable, ...); AG_MenuItem *_Nonnull AG_MenuActionKb(AG_MenuItem *_Nonnull, const char *_Nullable, const AG_Surface *_Nullable, AG_KeySym, AG_KeyMod, _Nonnull AG_EventFn, const char *_Nullable, ...); AG_MenuItem *_Nonnull AG_MenuTool(AG_MenuItem *_Nonnull, AG_Toolbar *_Nonnull, const char *_Nullable, const AG_Surface *_Nullable, AG_KeySym, AG_KeyMod, _Nonnull AG_EventFn, const char *_Nullable, ...); AG_MenuItem *_Nonnull AG_MenuDynamicItem(AG_MenuItem *_Nonnull, const char *_Nullable, const AG_Surface *_Nullable, _Nonnull AG_EventFn, const char *_Nullable, ...); AG_MenuItem *_Nonnull AG_MenuDynamicItemKb(AG_MenuItem *_Nonnull, const char *_Nullable, const AG_Surface *_Nullable, AG_KeySym, AG_KeyMod, _Nonnull AG_EventFn, const char *_Nullable, ...); AG_MenuItem *_Nonnull AG_MenuIntBoolMp(AG_MenuItem *_Nonnull, const char *_Nullable, const AG_Surface *_Nullable, int *_Nonnull, int, _Nonnull_Mutex AG_Mutex *_Nullable); AG_MenuItem *_Nonnull AG_MenuInt8BoolMp(AG_MenuItem *_Nonnull, const char *_Nullable, const AG_Surface *_Nullable, Uint8 *_Nonnull, int, _Nonnull_Mutex AG_Mutex *_Nullable); AG_MenuItem *_Nonnull AG_MenuIntFlagsMp(AG_MenuItem *_Nonnull, const char *_Nullable, const AG_Surface *_Nullable, int *_Nonnull, int, int, _Nonnull_Mutex AG_Mutex *_Nullable); AG_MenuItem *_Nonnull AG_MenuInt8FlagsMp(AG_MenuItem *_Nonnull, const char *_Nullable, const AG_Surface *_Nullable, Uint8 *_Nonnull, Uint8, int, _Nonnull_Mutex AG_Mutex *_Nullable); AG_MenuItem *_Nonnull AG_MenuInt16FlagsMp(AG_MenuItem *_Nonnull, const char *_Nullable, const AG_Surface *_Nullable, Uint16 *_Nonnull, Uint16, int, _Nonnull_Mutex AG_Mutex *_Nullable); AG_MenuItem *_Nonnull AG_MenuInt32FlagsMp(AG_MenuItem *_Nonnull, const char *_Nullable, const AG_Surface *_Nullable, Uint32 *_Nonnull, Uint32, int, _Nonnull_Mutex AG_Mutex *_Nullable); #define AG_MenuIntBool(mi,t,i,p,inv) \ AG_MenuIntBoolMp((mi),(t),(i),(p),(inv),NULL) #define AG_MenuInt8Bool(mi,t,i,p,inv) \ AG_MenuInt8BoolMp((mi),(t),(i),(p),(inv),NULL) #define AG_MenuBool(mi,t,i,p,inv) \ AG_MenuIntBoolMp((mi),(t),(i),(p),(inv),NULL) #define AG_MenuBoolMp(mi,t,i,p,inv,mu) \ AG_MenuIntBoolMp((mi),(t),(i),(p),(inv),(mu)) #define AG_MenuIntFlags(mi,t,i,fp,fl,inv) \ AG_MenuIntFlagsMp((mi),(t),(i),(fp),(fl),(inv),NULL) #define AG_MenuInt8Flags(mi,t,i,fp,fl,inv) \ AG_MenuInt8FlagsMp((mi),(t),(i),(fp),(fl),(inv),NULL) #define AG_MenuInt16Flags(mi,t,i,fp,fl,inv) \ AG_MenuInt16FlagsMp((mi),(t),(i),(fp),(fl),(inv),NULL) #define AG_MenuInt32Flags(mi,t,i,fp,fl,inv) \ AG_MenuInt32FlagsMp((mi),(t),(i),(fp),(fl),(inv),NULL) #define AG_MenuUintFlagsMp(mi,t,i,fp,fl,inv,mtx) \ AG_MenuIntFlagsMp((mi),(t),(i),(int *)(fp),(int)(fl),(inv),(mtx)) #define AG_MenuUintFlags(mi,t,i,fp,fl,inv) \ AG_MenuIntFlagsMp((mi),(t),(i),(int *)(fp),(int)(fl),(inv),NULL) #define AG_MenuFlagsMp(mi,t,i,fp,fl,inv,mtx) \ AG_MenuIntFlagsMp((mi),(t),(i),(int *)(fp),(int)(fl),(inv),(mtx)) #define AG_MenuFlags(mi,t,i,fp,fl,inv) \ AG_MenuIntFlagsMp((mi),(t),(i),(int *)(fp),(int)(fl),(inv),NULL) void AG_MenuSetIntBoolMp(AG_MenuItem *_Nonnull, int *_Nonnull, int, _Nonnull_Mutex AG_Mutex *_Nonnull); #define AG_MenuSetIntBool(mi,p,fl,inv,mtx) \ AG_MenuSetIntBoolMp((mi),(p),(fl),(inv),(mtx)) void AG_MenuSetIntFlagsMp(AG_MenuItem *_Nonnull, int *_Nonnull, int, int, _Nonnull_Mutex AG_Mutex *_Nonnull); #ifdef AG_TYPE_SAFETY AG_MenuItem *_Nullable AG_MenuGetItemPtr(const AG_Event *_Nonnull, int, int); #endif #ifdef AG_LEGACY # define AG_MENU_ITEM_PTR(v) AG_MENUITEM_PTR(v) # define AG_CONST_MENU_ITEM_PTR(v) AG_cMENUITEM_PTR(v) # define AG_MenuAddItem(m,lbl) AG_MenuNode((m)->root,(lbl),NULL) # define AG_MenuSetPaddingLeft(m,v) AG_MenuSetPadding((m),(v),-1,-1,-1) # define AG_MenuSetPaddingRight(m,v) AG_MenuSetPadding((m),-1,(v),-1,-1) # define AG_MenuSetPaddingTop(m,v) AG_MenuSetPadding((m),-1,-1,(v),-1) # define AG_MenuSetPaddingBottom(m,v) AG_MenuSetPadding((m),-1,-1,-1,(v)) void AG_MenuSetPadding(AG_Menu *_Nonnull, int,int,int,int) DEPRECATED_ATTRIBUTE; #endif /* AG_LEGACY */ __END_DECLS #include #endif /* _AGAR_GUI_MENU_H_ */