.\" Copyright (c) 2005-2022 Julien Nadeau Carriere .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, .\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES .\" (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR .\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, .\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING .\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 21, 2022 .Dt AG_MENU 3 .Os Agar 1.7 .Sh NAME .Nm AG_Menu .Nd agar menu system .Sh SYNOPSIS .Bd -literal #include #include .Ed .Sh DESCRIPTION .\" IMAGE(/widgets/AG_Menu.png, "An expanded AG_Menu") The .Nm widget displays a hierarchical menu composed of items of the following types: .Bl -tag -width "Dynamic items " .It Action items Selecting the item causes a specified function to be invoked, with the specified arguments. See .Fn AG_MenuAction . .It Boolean items A menu item tied to a variable describing a boolean value (either an integer, or specific bits in an integer). Selecting an active boolean item will toggle the value. See .Fn AG_MenuBool . .It Separators A cosmetic separator, displayed as a horizontal or vertical bar depending on the display mode. See .Fn AG_MenuSeparator . .It Dynamic items A dynamically updated menu item. The item itself (possibly including child items) are expected to be generated by a specified callback routine. The first argument to the callback routine is a pointer to the .Ft AG_MenuItem . An example of a dynamic item would be a submenu displaying the current contents of a folder. See .Fn AG_MenuDynamicItem . .El .Pp Menu elements can be displayed in text format with the .Ft AG_MenuView widget, or in icon format using .Xr AG_Toolbar 3 . .Pp Note: Many functions of .Nm accept .Fa fn and .Fa fnArgs arguments; see .Xr AG_Event 3 for details on event handler functions in Agar. .Sh INHERITANCE HIERARCHY .Xr AG_Object 3 -> .Xr AG_Widget 3 -> .Nm . .Sh INITIALIZATION .nr nS 1 .Ft "AG_Menu *" .Fn AG_MenuNew "AG_Widget *parent" "Uint flags" .Pp .Ft "AG_Menu *" .Fn AG_MenuNewGlobal "Uint flags" .Pp .Ft void .Fn AG_MenuExpand "AG_Widget *parentWidget" "AG_MenuItem *item" "int x" "int y" .Pp .Ft void .Fn AG_MenuCollapse "AG_MenuItem *item" .Pp .Ft void .Fn AG_MenuCollapseAll "AG_Menu *m" .Pp .Ft void .Fn AG_MenuSetPadding "AG_Menu *menu" "int left" "int right" "int top" "int bottom" .Pp .Ft void .Fn AG_MenuSetLabelPadding "AG_Menu *menu" "int left" "int right" "int top" "int bottom" .Pp .nr nS 0 The .Fn AG_MenuNew function allocates, initializes, and attaches a new .Nm widget. See the .Sx FLAGS sections for available .Fa flags options. .Pp The .Fn AG_MenuNewGlobal constructor creates a global "application menu". The manner in which application menus are displayed is dependent on the underlying platform and graphics system. If there is insufficient memory, or an application menu is already defined, .Fn AG_MenuNewGlobal may fail returning NULL. .Pp The .Fn AG_MenuExpand function creates a new window containing an .Ft AG_MenuView widget displaying the menu items under .Fa item . The optional .Fa parentWidget argument should point to some parent widget or window. The new window is created at coordinates .Fa x , .Fa y relative to .Fa parentWidget . The newly created window is also attached to the parent window of .Fa parentWidget . .Pp .Fn AG_MenuCollapse closes the window previously created by .Fn AG_MenuExpand for the given menu item. .Fn AG_MenuCollapseAll closes all windows generated by .Fn AG_MenuExpand for the whole menu .Fa m . .Pp .Fn AG_MenuSetPadding sets the global padding around all menu items, in pixels. .Fn AG_MenuSetLabelPadding sets the padding around the text label of items. If a parameter is -1, its current value is preserved. .Sh MENU ITEMS .nr nS 1 .Ft "AG_MenuItem *" .Fn AG_MenuNode "AG_MenuItem *parent" "const char *text" "const AG_Surface *icon" .Pp .Ft "AG_MenuItem *" .Fn AG_MenuAction "AG_MenuItem *parent" "const char *text" "const AG_Surface *icon" "void (*fn)(AG_Event *)" "const char *fnArgs" "..." .Pp .Ft "AG_MenuItem *" .Fn AG_MenuActionKb "AG_MenuItem *parent" "const char *text" "const AG_Surface *icon" "AG_KeySym keysym" "AG_KeyMod keymod" "void (*fn)(AG_Event *)" "const char *fnArgs" "..." .Pp .Ft "AG_MenuItem *" .Fn AG_MenuDynamicItem "AG_MenuItem *parent" "const char *text" "const AG_Surface *icon" "void (*fn)(AG_Event *)" "const char *fnArgs" "..." .Pp .Ft "AG_MenuItem *" .Fn AG_MenuDynamicItemKb "AG_MenuItem *parent" "const char *text" "const AG_Surface *icon" "AG_KeySym key" "AG_KeyMod kmod" "void (*fn)(AG_Event *)" "const char *fnArgs" "..." .Pp .Ft "AG_MenuItem *" .Fn AG_MenuTool "AG_MenuItem *parent" "AG_Toolbar *toolbar" "const char *text" "const AG_Surface *icon" "AG_KeySym keysym" "AG_KeyMod keymod" "void (*fn)(AG_Event *)" "const char *fnArgs" "..." .Pp .Ft "void" .Fn AG_MenuSetIcon "AG_MenuItem *item" "const AG_Surface *su" .Pp .Ft "void" .Fn AG_MenuSetLabel "AG_MenuItem *item" "const char *format" "..." .Pp .Ft "void" .Fn AG_MenuSetLabelS "AG_MenuItem *item" "const char *label" .Pp .Ft "void" .Fn AG_MenuSetPollFn "AG_MenuItem *item" "void (*fn)(AG_Event *)" "const char *fnArgs" "..." .Pp .Ft "void" .Fn AG_MenuDel "AG_MenuItem *menu" .Pp .Ft "void" .Fn AG_MenuState "AG_MenuItem *item" "int state" .Pp .Ft "void" .Fn AG_MenuEnable "AG_MenuItem *item" .Pp .Ft "void" .Fn AG_MenuDisable "AG_MenuItem *item" .Pp .nr nS 0 The .Fn AG_MenuNode function inserts a new node (no-op) item displaying the given .Fa text and .Fa icon (or NULL if none). Node items are typically only used to attach subitems. .Pp The .Fn AG_MenuAction function inserts a new action item displaying the given .Fa text and .Fa icon (or NULL if none). When selected, the item will invoke the specified event handler function .Fa fn . .Pp The .Fn AG_MenuActionKb variant also associates the action with the given .Xr AG_KeySym 3 and modifier. .Pp The .Fn AG_MenuTool variant also inserts an item into the specified .Xr AG_Toolbar 3 widget. .Pp The .Fn AG_MenuSetIcon function sets the icon associated with a menu item. If an argument of NULL is given, any existing icon is removed. .Pp .Fn AG_MenuSetLabel changes the text associated with an existing menu item. .Fn AG_MenuSetPollFn changes the callback function associated with a given item (previously created with .Fn AG_MenuDynamicItem ) . .Pp The .Fn AG_MenuDynamicItem function creates a dynamic menu item. The specified callback routine .Fa fn will be invoked repeatedly to update the menu item, with the .Nm as receiver object (access with .Fn AG_MENU_SELF ) , and the first Pointer argument a pointer to the .Ft AG_MenuItem . The callback routine is allowed to directly modify the .Va state member of the .Ft AG_MenuItem . This variable defines the boolean state for the specified menu item (0 = disabled, 1 = enabled). If .Va state is -1, the boolean state is determined from any boolean/flag binding associated with the item. The callback can also change the text label and icon using .Fn AG_MenuSetLabel and .Fn AG_MenuSetIcon . .Pp The .Fn AG_MenuDel routine deletes the specified menu item and its sub-items. .Pp The .Fn AG_MenuState (or its variants .Fn AG_MenuEnable and .Fn AG_MenuDisable ) request that all subsequently created menu items are assigned the given state. .Sh BOOLEAN AND BITMASK ITEMS .nr nS 1 .Ft "AG_MenuItem *" .Fn AG_MenuBool "AG_MenuItem *" "const char *text" "const AG_Surface *icon" "int *value" "int invert" .Pp .Ft "AG_MenuItem *" .Fn AG_MenuBoolMp "AG_MenuItem *" "const char *text" "const AG_Surface *icon" "int *value" "int invert" "AG_Mutex *mutex" .Pp .Ft "AG_MenuItem *" .Fn AG_MenuIntBool "AG_MenuItem *" "const char *text" "const AG_Surface *icon" "int *value" "int invert" .Pp .Ft "AG_MenuItem *" .Fn AG_MenuIntBoolMp "AG_MenuItem *" "const char *text" "const AG_Surface *icon" "int *value" "int invert" "AG_Mutex *mutex" .Pp .Ft "AG_MenuItem *" .Fn AG_MenuInt8Bool "AG_MenuItem *" "const char *text" "const AG_Surface *icon" "Uint8 *value" "int invert" .Pp .Ft "AG_MenuItem *" .Fn AG_MenuInt8BoolMp "AG_MenuItem *" "const char *text" "const AG_Surface *icon" "Uint8 *value" "int invert" "AG_Mutex *mutex" .Pp .Ft "AG_MenuItem *" .Fn AG_MenuFlags "AG_MenuItem *" "const char *text" "const AG_Surface *icon" "int *value" "int flags" "int invert" .Pp .Ft "AG_MenuItem *" .Fn AG_MenuFlagsMp "AG_MenuItem *" "const char *text" "const AG_Surface *icon" "int *value" "int flags" "int invert" "AG_Mutex *mutex" .Pp .Ft "AG_MenuItem *" .Fn AG_MenuIntFlags "AG_MenuItem *" "const char *text" "const AG_Surface *icon" "int *value" "int flags" "int invert" .Pp .Ft "AG_MenuItem *" .Fn AG_MenuIntFlagsMp "AG_MenuItem *" "const char *text" "const AG_Surface *icon" "int *value" "int flags" "int invert" "AG_Mutex *mutex" .Pp .Ft "AG_MenuItem *" .Fn AG_MenuInt8Flags "AG_MenuItem *" "const char *text" "const AG_Surface *icon" "Uint8 *value" "Uint8 flags" "int invert" .Pp .Ft "AG_MenuItem *" .Fn AG_MenuInt8FlagsMp "AG_MenuItem *" "const char *text" "const AG_Surface *icon" "Uint8 *value" "Uint8 flags" "int invert" "AG_Mutex *mutex" .Pp .Ft "AG_MenuItem *" .Fn AG_MenuInt16Flags "AG_MenuItem *" "const char *text" "const AG_Surface *icon" "Uint16 *value" "Uint16 flags" "int invert" .Pp .Ft "AG_MenuItem *" .Fn AG_MenuInt16FlagsMp "AG_MenuItem *" "const char *text" "const AG_Surface *icon" "Uint16 *value" "Uint16 flags" "int invert" "AG_Mutex *mutex" .Pp .Ft "AG_MenuItem *" .Fn AG_MenuInt32Flags "AG_MenuItem *" "const char *text" "const AG_Surface *icon" "Uint32 *value" "Uint32 flags" "int invert" .Pp .nr nS 0 The .Fn AG_Menu*Bool functions create a new item that binds to the given boolean variable. If the .Fa invert parameter is non-zero, the actual value is inverted. .Pp The .Fn AG_Menu*Flags functions create a new item controlling one or more bits inside an integer value. The .Fa flags argument specifies the bitmask. If .Fa invert is non-zero, the bits are inverted. .Pp The .Fn AG_Menu*BoolMp and .Fn AG_Menu*FlagsMp variants accept a .Ft "AG_Mutex *" argument specifying a mutex to acquire prior to reading or writing the data. .Sh OTHER ITEMS .nr nS 1 .Ft "void" .Fn AG_MenuSeparator "AG_MenuItem *item" .Pp .Ft "void" .Fn AG_MenuSection "AG_MenuItem *item" "const char *format" "..." .Pp .Ft "void" .Fn AG_MenuSectionS "AG_MenuItem *item" "const char *text" .Pp .nr nS 0 The .Fn AG_MenuSeparator function inserts a horizontal menu separator. .Pp .Fn AG_MenuSection creates a non-selectable item displaying the given text. .Sh POPUP MENUS .nr nS 1 .Ft "AG_PopupMenu *" .Fn AG_PopupNew "AG_Widget *widget" .Pp .Ft void .Fn AG_PopupShow "AG_PopupMenu *pm" .Pp .Ft void .Fn AG_PopupShowAt "AG_PopupMenu *pm" "int x" "int y" .Pp .Ft void .Fn AG_PopupHide "AG_PopupMenu *pm" .Pp .Ft void .Fn AG_PopupDestroy "AG_Widget *widget" "AG_PopupMenu *pm" .Pp .nr nS 0 The .Fn AG_PopupNew function creates a new popup menu and associates it with the specified widget. This association will cause the popup menu to be automatically freed when the given widget is destroyed. .Pp Once a popup menu is created, new items can be inserted using the .Va root member of the .Ft AG_PopupMenu structure as parent. .Pp .Fn AG_PopupShow displays the popup menu at the current mouse coordinates. .Fn AG_PopupShowAt accepts global (view) coordinates. .Fn AG_PopupHide hides the popup menu from the user. .Pp .Fn AG_PopupDestroy detaches the specified popup menu from its associated widget, and releases its allocated resources. This function is automatically invoked whenever a widget is destroyed. .Sh EVENTS The .Nm widget does not generate any event. .Sh BINDINGS The .Nm widget does not provide any binding. .Sh STRUCTURE DATA For the .Ft AG_Menu object: .Bl -tag -width "AG_MenuItem *itemSel " .It Ft AG_MenuItem *root The root menu item (read-only). .It Ft AG_MenuItem *itemSel The currently selected top-level item (read-only). Top-level items are attached directly to .Va root . .It Ft int selecting Selection is in progress if set to 1 (read-only). .El .Pp For the .Ft AG_MenuItem structure: .Bl -tag -width "int (*stateFn)(AG_Event *)" .It Ft char *text Displayed text for the menu item (read-only, set by .Fn AG_MenuSetLabel ) . .It Ft AG_Surface *icon The .Xr AG_Surface 3 of the menu icon, or NULL (read-only, set by .Fn AG_MenuSetIcon ) . .It Ft int value The boolean state of the item, used by default. If the boolean state was bound to another variable (e.g., using .Fn AG_MenuBool ) then this value will be ignored. .It Ft int state Make item clickable (1) or disabled (0). .It Ft int (*stateFn)(AG_Event *) Evaluate function to determine if item is active. Overrides the .Va state flag. .It Ft AG_Menu *pmenu Back pointer to the parent .Ft AG_Menu (read-only). .El .Sh FLAGS The .Va flags member of the .Nm structure accepts the following flags: .Bl -tag -width "AG_MENU_FAST_COLOR_BG " .It AG_MENU_HFILL Fill any remaining horizontal space (hint to vertically-packing containers). .It AG_MENU_VFILL Fill any remaining vertical space (hint to horizontal-packing containers). .It AG_MENU_EXPAND Shorthand for .Dv AG_MENU_HFILL | AG_MENU_VFILL . .It AG_MENU_NO_COLOR_BG By default, the "background-color" of menu expansion windows is inherited from the "color" attribute associated with the .Ft AG_MenuView class (see .Xr AG_Style 3 ) . This flag disables that behavior, which can be useful for some applications (for example, if alternate colors are to be assigned to specific menu expansions). .It AG_MENU_NO_BOOL_MSG By default, a notification message is displayed in order to provide visual feedback when the user toggles a Menu-bound boolean value with a keyboard shortcut (and the menu is currently hidden). This flag disables that behavior. .It AG_MENU_FAST_BOOL_MSG By default, the notification message displayed when the user toggles a boolean is displayed for 1s. This flag causes the message to be displayed for 250ms instead. .El .Sh EXAMPLES The following code fragment creates a popup menu with a disabled item: .Bd -literal -offset indent .\" SYNTAX(c) AG_PopupMenu *pm; AG_MenuItem *mi; pm = AG_PopupNew(myParentWidget); AG_MenuAction(pm->root, "Copy", NULL, DoCopy, NULL); mi = AG_MenuAction(pm->root, "Paste", NULL, DoPaste, NULL); mi->state = (myClipboard->contents > 0); .Ed .Pp The following code fragment creates a popup menu with a dynamically determined "disabled" state: .Bd -literal -offset indent .\" SYNTAX(c) static int PasteActive(AG_Event *event) { Clipboard *C = AG_PTR(1); return (C->contents > 0); } AG_PopupMenu *pm; AG_MenuItem *mi; pm = AG_PopupNew(myParentWidget); AG_MenuAction(pm->root, "Copy", NULL, DoCopy, NULL); mi = AG_MenuAction(pm->root, "Paste", NULL, DoPaste, NULL); mi->stateFn = AG_SetIntFn(pm->menu, NULL, PasteActive, "%p", myClipboard); .Ed .Pp The following code fragment associates a menu with an .Xr AG_Toolbar 3 . Buttons and menu entries are created for the same actions. .Bd -literal -offset indent .\" SYNTAX(c) AG_Toolbar *toolbar; AG_Menu *menu; AG_MenuItem *item; toolbar = AG_ToolbarNew(win, AG_TOOLBAR_HORIZ, 1, 0); menu = AG_MenuNew(win, 0); item = AG_MenuNode(menu->root, "File", NULL); { AG_MenuToolbar(item, toolbar); AG_MenuAction(item, "Load", NULL, LoadFile, NULL); AG_MenuAction(item, "Save", NULL, SaveFile, NULL); AG_MenuToolbar(item, NULL); } .Ed .Pp The following code fragment creates a menu with an action item, a boolean item and two bitmask items. .Bd -literal -offset indent .\" SYNTAX(c) Uint16 flags = 0; #define FOO_FLAG 0x01 #define BAR_FLAG 0x02 void SayHello(AG_Event *event) { char *s = AG_STRING(1); AG_TextMsg(AG_MSG_INFO, "Hello, %s!", s); } void QuitApplication(AG_Event *event) { AG_Quit(); } .Li ... AG_Menu *menu = AG_MenuNew(win); AG_MenuItem *item = AG_MenuNode(menu->root, "File", NULL); { AG_MenuInt16Flags(item, "Foo", NULL, &flags, FOO_FLAG, 0); AG_MenuInt16Flags(item, "Bar", NULL, &flags, BAR_FLAG, 0); AG_MenuAction(item, "Say hello", NULL, SayHello, "%s", "world"); AG_MenuAction(item, "Quit", NULL, QuitApplication, NULL); } .Ed .Sh SEE ALSO .Xr AG_Button 3 , .Xr AG_Event 3 , .Xr AG_Intro 3 , .Xr AG_KeySym 3 , .Xr AG_StyleSheet 3 , .Xr AG_Surface 3 , .Xr AG_Tlist 3 , .Xr AG_Toolbar 3 , .Xr AG_Widget 3 , .Xr AG_Window 3 .Sh HISTORY The .Nm widget first appeared in Agar 1.0.