/* Copyright (c) 2021 Alex Diener This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Alex Diener alex@ludobloom.com */ #ifndef __UIMenuBar_H__ #define __UIMenuBar_H__ #ifdef __cplusplus extern "C" { #endif typedef struct UIMenuBar UIMenuBar; #define UIMenuBar_superclass UIElement #include "font/String.h" #include "shell/Shell.h" #include "shell/ShellKeyCodes.h" #include "uitoolkit/UIElement.h" #include "uitoolkit/UIKeyShortcut.h" #include "uitoolkit/UITypes.h" #include "utilities/AutoFreePool.h" typedef struct UIMenuItem { String title; // Set to STR_NULL for a separator int identifier; bool enabled; bool checked; UIKeyShortcut * shortcut; unsigned int subitemCount; // Set to 0 for no subitems struct UIMenuItem * subitems; } UIMenuItem; typedef struct UIMenu { String title; int identifier; unsigned int itemCount; UIMenuItem * items; } UIMenu; #define MENU_DEPTH_MAX 16 #define MENU_TITLE_MAX 128 #define MENU_BAR_CLOSED_HIT_TEST_PRIORITY 500 #define MENU_BAR_OPEN_HIT_TEST_PRIORITY 1000 #define MENU_BAR_KEY_DOWN_PRIORITY -10 #define MENU_ITEM(title, identifier, shortcut) ((UIMenuItem) {title, identifier, true, false, shortcut, 0, NULL}) #define MENU_SEPARATOR ((UIMenuItem) {STR_NULL, -1, false, false, UIKeyShortcut_none, 0, NULL}) #define MENU_SUBMENU(title, identifier, item_count, items) ((UIMenuItem) {title, identifier, true, false, UIKeyShortcut_none, item_count, items}) #define MENU_SHORTCUT(key_code, additional_modifiers) AutoFreePool_add(UIKeyShortcut_single(key_code, (additional_modifiers) | MODIFIER_PLATFORM_MENU_COMMAND_BIT)) #define MENU_NO_SHORTCUT UIKeyShortcut_none #ifdef __APPLE__ #define PLATFORM_MENU_COMMAND_MODIFIER_KEY_SHORTCUT_STRING "Cmd" #else #define PLATFORM_MENU_COMMAND_MODIFIER_KEY_SHORTCUT_STRING "Ctrl" #endif typedef struct UIMenuItemProperties { bool enabled; bool checked; char title[MENU_TITLE_MAX]; // UTF-8 Color4f textColor; UIAtlasEntry customIcon; } UIMenuItemProperties; typedef void (* UIMenuBar_actionCallback)(UIMenuBar * menuBar, int menuIdentifier, int menuItemIdentifier, unsigned int modifiers, double referenceTime, void * context); typedef void (* UIMenuBar_validateCallback)(UIMenuBar * menuBar, int menuIdentifier, int menuItemIdentifier, UIMenuItemProperties * ioProperties, void * context); typedef void (* UIMenuBar_displayContextMenuCallback)(unsigned int itemCount, UIMenuItem * items, void * menuBarContext); typedef void (* UIMenuBar_contextMenuCallback)(UIMenuBar * menuBar, int menuIdentifier, int menuItemIdentifier, UIMenuBar_displayContextMenuCallback displayContextMenu, void * menuBarContext, void * context); #define UIMenuBar_ivars \ UIElement_ivars \ \ unsigned int menuCount; \ struct UIMenu_private * menus; \ struct UIMenuContents * contextMenuContents; \ float width; \ UIMenuBar_actionCallback actionCallback; \ UIMenuBar_validateCallback validateCallback; \ UIMenuBar_contextMenuCallback contextMenuCallback; \ void * callbackContext; \ unsigned int openItems[MENU_DEPTH_MAX]; \ double openTime; \ unsigned int submenuToOpenAfterDelay; \ ShellTimer submenuOpenTimerID; \ unsigned int openingSubmenuDepth; \ float leftRightIconPadding; \ unsigned int actionAnimationMenuIndex; \ double actionAnimationEndTime; \ int pendingMenuIdentifier; \ int pendingMenuItemIdentifier; \ unsigned int pendingMenuModifiers; \ double pendingMenuReferenceTime; \ ShellTimer pendingMenuTimerID; #define UIMenuBar_vtable(self_type) \ UIElement_vtable(self_type) stemobject_declare(UIMenuBar) UIMenuBar * UIMenuBar_create(unsigned int menuCount, UIMenu * menus, Vector2f position, Vector2f relativeOrigin, float width, UIMenuBar_actionCallback actionCallback, UIMenuBar_validateCallback validateCallback, UIMenuBar_contextMenuCallback contextMenuCallback, void * callbackContext, UIAppearance appearance); bool UIMenuBar_init(UIMenuBar * self, unsigned int menuCount, UIMenu * menus, Vector2f position, Vector2f relativeOrigin, float width, UIMenuBar_actionCallback actionCallback, UIMenuBar_validateCallback validateCallback, UIMenuBar_contextMenuCallback contextMenuCallback, void * callbackContext, UIAppearance appearance); void UIMenuBar_dispose(UIMenuBar * self); bool UIMenuBar_hitTest(UIMenuBar * self, float x, float y, UIHitTestType type, int * outPriority, bool * outForwardNext); UIEventResponse UIMenuBar_mouseDown(UIMenuBar * self, unsigned int buttonNumber, unsigned int buttonMask, float x, float y, unsigned int modifiers, bool isFinalTarget, double referenceTime); bool UIMenuBar_mouseUp(UIMenuBar * self, unsigned int buttonNumber, unsigned int buttonMask, float x, float y, unsigned int modifiers, double referenceTime); bool UIMenuBar_mouseMoved(UIMenuBar * self, float x, float y, float deltaX, float deltaY, unsigned int modifiers, double referenceTime); bool UIMenuBar_mouseDragged(UIMenuBar * self, unsigned int buttonMask, float x, float y, float deltaX, float deltaY, unsigned int modifiers, double referenceTime); UIEventResponse UIMenuBar_scrollWheel(UIMenuBar * self, float x, float y, int deltaX, int deltaY, unsigned int modifiers, bool isFinalTarget, double referenceTime); UIEventResponse UIMenuBar_keyDown(UIMenuBar * self, unsigned int charCode, unsigned int keyCode, unsigned int modifiers, bool isRepeat, bool isFinalTarget, double referenceTime); bool UIMenuBar_menuActionDown(UIMenuBar * self, unsigned int actionNumber, bool isRepeat, double referenceTime); bool UIMenuBar_menuActionUp(UIMenuBar * self, unsigned int actionNumber, double referenceTime); bool UIMenuBar_menuDirectionDown(UIMenuBar * self, UINavigationDirection direction, bool isRepeat, double referenceTime); bool UIMenuBar_acceptsFocus(UIMenuBar * self); Rect4f UIMenuBar_getBounds(UIMenuBar * self); Rect4f UIMenuBar_getFocusBounds(UIMenuBar * self); void UIMenuBar_draw(UIMenuBar * self, Vector2f offset, UIDrawingInterface * drawingInterface, VertexIO * vertexIO); void UIMenuBar_listRenderables(UIMenuBar * self, RenderableIO * renderableIO, int drawOrderOffset, Rect4i clipBounds); bool UIMenuBar_isOpen(UIMenuBar * self); void UIMenuBar_close(UIMenuBar * self); void UIMenuBar_playKeyShortcutAnimation(UIMenuBar * self, int menuIdentifier); void UIMenuBar_addMenu(UIMenuBar * self, UIMenu * menu); void UIMenuBar_insertMenu(UIMenuBar * self, UIMenu * menu, unsigned int menuIndex); void UIMenuBar_removeMenu(UIMenuBar * self, int menuIdentifier); void UIMenuBar_setMenuTitle(UIMenuBar * self, int menuIdentifier, String title); void UIMenuBar_setMenuContents(UIMenuBar * self, int menuIdentifier, unsigned int itemCount, UIMenuItem * items); void UIMenuBar_setSubmenuContents(UIMenuBar * self, int menuIdentifier, int menuItemIdentifier, unsigned int itemCount, UIMenuItem * items); void UIMenuBar_setItemChecked(UIMenuBar * self, int menuIdentifier, int menuItemIdentifier, bool checked); bool UIMenuBar_getItemChecked(UIMenuBar * self, int menuIdentifier, int menuItemIdentifier); void UIMenuBar_setItemEnabled(UIMenuBar * self, int menuIdentifier, int menuItemIdentifier, bool enabled); bool UIMenuBar_getItemEnabled(UIMenuBar * self, int menuIdentifier, int menuItemIdentifier); void UIMenuBar_setItemTitle(UIMenuBar * self, int menuIdentifier, int menuItemIdentifier, String title); String UIMenuBar_getItemTitle(UIMenuBar * self, int menuIdentifier, int menuItemIdentifier); void UIMenuBar_setItemShortcut(UIMenuBar * self, int menuIdentifier, int menuItemIdentifier, UIKeyShortcut * shortcut); // Shortcut strings are automatically generated from the first specified key shortcut. Only use this to override with a different string. void UIMenuBar_setItemShortcutString(UIMenuBar * self, int menuIdentifier, int menuItemIdentifier, String shortcutString); // Custom icons will be overridden by check mark icon if the item is checked. atlasEntry must exist within this menu bar's appearance's atlas. Set to RECT4f_EMPTY to clear. void UIMenuBar_setItemCustomIcon(UIMenuBar * self, int menuIdentifier, int menuItemIdentifier, UIAtlasEntry atlasEntry); void UIMenuBar_setItemTextColor(UIMenuBar * self, int menuIdentifier, int menuItemIdentifier, Color4f textColor); // By default, items with key shortcuts that involve MODIFIER_PLATFORM_MENU_COMMAND_BIT will animate, and ones without will not. Call this after initializing items to override the default behavior for any item. void UIMenuBar_setItemAnimatesMenuWhenInvoked(UIMenuBar * self, int menuIdentifier, int menuItemIdentifier, bool animate); void UIMenuBar_addMenuItem(UIMenuBar * self, int menuIdentifier, UIMenuItem item); void UIMenuBar_insertMenuItem(UIMenuBar * self, int menuIdentifier, unsigned int itemIndex, UIMenuItem item); void UIMenuBar_removeMenuItem(UIMenuBar * self, int menuIdentifier, int menuItemIdentifier); void UIMenuBar_removeMenuItemAtIndex(UIMenuBar * self, int menuIdentifier, unsigned int itemIndex); void UIMenuBar_addSubmenuItem(UIMenuBar * self, int menuIdentifier, int parentMenuItemIdentifier, UIMenuItem item); void UIMenuBar_insertSubmenuItem(UIMenuBar * self, int menuIdentifier, int parentMenuItemIdentifier, unsigned int itemIndex, UIMenuItem item); #ifdef __cplusplus } #endif #endif