=> 01898c3a1a711c7e22888deeb7c4e64427e99b13
[1mdiff --git a/po/en.po b/po/en.po[m [1mindex f9c6676b..57ab0203 100644[m [1m--- a/po/en.po[m [1m+++ b/po/en.po[m [36m@@ -281,7 +281,7 @@[m [mmsgid "menu.zoom.reset"[m msgstr "Reset Zoom"[m [m msgid "menu.view.split"[m [31m-msgstr "Split View…"[m [32m+[m[32mmsgstr "Split View"[m [m msgid "menu.newfolder"[m msgstr "New Folder…"[m [1mdiff --git a/res/lang/en.bin b/res/lang/en.bin[m [1mindex 8df481fa..1075b5ff 100644[m Binary files a/res/lang/en.bin and b/res/lang/en.bin differ [1mdiff --git a/res/lang/eo.bin b/res/lang/eo.bin[m [1mindex fd40d10e..a6ff2dc5 100644[m Binary files a/res/lang/eo.bin and b/res/lang/eo.bin differ [1mdiff --git a/res/lang/isv.bin b/res/lang/isv.bin[m [1mindex 7febe96e..d97d008e 100644[m Binary files a/res/lang/isv.bin and b/res/lang/isv.bin differ [1mdiff --git a/res/lang/zh_Hans.bin b/res/lang/zh_Hans.bin[m [1mindex 53e5bd1c..af4b0f21 100644[m Binary files a/res/lang/zh_Hans.bin and b/res/lang/zh_Hans.bin differ [1mdiff --git a/src/app.c b/src/app.c[m [1mindex 5323a368..cedbdbd0 100644[m [1m--- a/src/app.c[m [1m+++ b/src/app.c[m [36m@@ -3382,7 +3382,7 @@[m [mstatic iBool handleNonWindowRelatedCommand_App_(iApp *d, const char *cmd) {[m }[m else if (equal_Command(cmd, "snippets.changed")) {[m save_Snippets(dataDir_App_());[m [31m- return iTrue;[m [32m+[m[32m return iFalse;[m }[m else if (equal_Command(cmd, "width.save")) {[m insert_StringHash(d->savedWidths,[m [36m@@ -4721,6 +4721,9 @@[m [miBool handleCommand_App(const char *cmd) {[m /* Detach into a window if it doesn't fit otherwise. */[m promoteDialogToWindow_Widget(dlg);[m }[m [32m+[m[32m if (argLabel_Command(cmd, "sniped")) {[m [32m+[m[32m postCommand_Widget(dlg, "tabs.switch id:sniped");[m [32m+[m[32m }[m }[m else if (equal_Command(cmd, "navigate.home") && isMainWin) {[m /* Look for bookmarks tagged "homepage". */[m [1mdiff --git a/src/macos.m b/src/macos.m[m [1mindex e04774a2..1261082e 100644[m [1m--- a/src/macos.m[m [1m+++ b/src/macos.m[m [36m@@ -843,7 +843,21 @@[m [mstatic NSMenuItem *makeMenuItems_(NSMenu *menu, MenuCommands *commands, int atIn[m NSAttributedString *title = [[NSAttributedString alloc] initWithString:cleanString_(&itemTitle)];[m item.attributedTitle = title;[m [title release];[m [31m- item.action = (hasCommand ? @selector(postMenuItemCommand:) : nil);[m [32m+[m[32m if (hasCommand && startsWith_CStr(items[i].command, "submenu id:")) {[m [32m+[m[32m NSMenu *sub = [[NSMenu alloc] init];[m [32m+[m[32m sub.autoenablesItems = YES;[m [32m+[m[32m iWidget *subwidget = findChild_Widget(get_MainWindow()->base.roots[0]->widget,[m [32m+[m[32m cstr_String(string_Command(items[i].command, "id")));[m [32m+[m[32m iAssert(subwidget);[m [32m+[m[32m const iArray *items = userData_Object(subwidget);[m [32m+[m[32m iAssert(items);[m [32m+[m[32m makeMenuItems_(sub, commands, 0, constData_Array(items), size_Array(items));[m [32m+[m[32m [item setSubmenu:sub];[m [32m+[m[32m [sub release];[m [32m+[m[32m }[m [32m+[m[32m else {[m [32m+[m[32m item.action = (hasCommand ? @selector(postMenuItemCommand:) : nil);[m [32m+[m[32m }[m [menu insertItem:item atIndex:atIndex++];[m deinit_String(&itemTitle);[m [item setTarget:commands];[m [36m@@ -869,6 +883,7 @@[m [mstatic NSMenuItem *makeMenuItems_(NSMenu *menu, MenuCommands *commands, int atIn[m }[m }[m setShortcut_NSMenuItem_(item, key, kmods);[m [32m+[m[32m [item release];[m }[m }[m return selectedItem;[m [1mdiff --git a/src/ui/labelwidget.c b/src/ui/labelwidget.c[m [1mindex 4842b1ee..d0d11d6d 100644[m [1m--- a/src/ui/labelwidget.c[m [1m+++ b/src/ui/labelwidget.c[m [36m@@ -54,7 +54,7 @@[m [mstruct Impl_LabelWidget {[m uint16_t wrap : 1;[m uint16_t allCaps : 1;[m uint16_t removeTrailingColon : 1;[m [31m- uint16_t chevron : 1; [m [32m+[m[32m uint16_t chevron : 1;[m uint16_t checkMark : 1;[m uint16_t truncateToFit : 1;[m } flags;[m [36m@@ -70,15 +70,20 @@[m [mstatic iBool isHover_LabelWidget_(const iLabelWidget *d) {[m static iInt2 padding_LabelWidget_(const iLabelWidget *d, int corner) {[m const iWidget *w = constAs_Widget(d);[m const int64_t flags = flags_Widget(w);[m [31m- const iInt2 widgetPad = (corner == 0 ? init_I2(w->padding[0], w->padding[1])[m [31m- : corner == 1 ? init_I2(w->padding[2], w->padding[1])[m [31m- : corner == 2 ? init_I2(w->padding[2], w->padding[3])[m [31m- : init_I2(w->padding[0], w->padding[3]));[m [32m+[m[32m iInt2 widgetPad = (corner == 0 ? init_I2(w->padding[0], w->padding[1])[m [32m+[m[32m : corner == 1 ? init_I2(w->padding[2], w->padding[1])[m [32m+[m[32m : corner == 2 ? init_I2(w->padding[2], w->padding[3])[m [32m+[m[32m : init_I2(w->padding[0], w->padding[3]));[m if (isMobile_Platform()) {[m return add_I2(widgetPad,[m init_I2(flags & tight_WidgetFlag ? 2 * gap_UI : (4 * gap_UI),[m (flags & extraPadding_WidgetFlag ? 1.5f : 1.0f) * 3 * gap_UI / 2));[m }[m [32m+[m[32m if (d->flags.chevron) {[m [32m+[m[32m if (corner == 1 || corner == 2) {[m [32m+[m[32m widgetPad.x += gap_UI * 5;[m [32m+[m[32m }[m [32m+[m[32m }[m return add_I2(widgetPad,[m init_I2(flags & tight_WidgetFlag ? 3 * gap_UI / 2 : (3 * gap_UI),[m gap_UI * aspect_UI));[m [36m@@ -329,7 +334,7 @@[m [mstatic void getColors_LabelWidget_(const iLabelWidget *d, int *bg, int *fg, int[m *frame1 = *bg;[m }[m }[m [31m- } [m [32m+[m[32m }[m if (isFocus) {[m *frame1 = *frame2 = (isSel ? uiText_ColorId : uiInputFrameFocused_ColorId);[m }[m [36m@@ -453,7 +458,7 @@[m [mstatic void draw_LabelWidget_(const iLabelWidget *d) {[m }[m if (isFocused_Widget(w)) {[m iRect frameRect = adjusted_Rect(rect, zero_I2(), init1_I2(-1));[m [31m- drawRectThickness_Paint(&p, frameRect, gap_UI / 4, uiTextAction_ColorId /*frame*/); [m [32m+[m[32m drawRectThickness_Paint(&p, frameRect, gap_UI / 4, uiTextAction_ColorId /*frame*/);[m }[m else if (~flags & frameless_WidgetFlag) {[m iRect frameRect = adjusted_Rect(rect, zero_I2(), init1_I2(-1));[m [36m@@ -468,7 +473,7 @@[m [mstatic void draw_LabelWidget_(const iLabelWidget *d) {[m #if SDL_COMPILEDVERSION == SDL_VERSIONNUM(2, 0, 16)[m if (isOpenGLRenderer_Window()) {[m /* A very curious regression in SDL 2.0.16. */[m [31m- points[3].x--; [m [32m+[m[32m points[3].x--;[m }[m #endif[m if (d->flags.noBottomFrame && !isFocused_Widget(w) && !isHover) {[m [36m@@ -569,11 +574,17 @@[m [mstatic void draw_LabelWidget_(const iLabelWidget *d) {[m const iRect chRect = rect;[m const int chSize = lineHeight_Text(d->font);[m int offset = 0;[m [31m- if (d->flags.chevron) {[m [31m- offset = -iconPad;[m [32m+[m[32m if (isMobile_Platform()) {[m [32m+[m[32m /* These are used in the sub-panel buttons. */[m [32m+[m[32m if (d->flags.chevron) {[m [32m+[m[32m offset = -iconPad;[m [32m+[m[32m }[m [32m+[m[32m else {[m [32m+[m[32m offset = -10 * gap_UI;[m [32m+[m[32m }[m }[m else {[m [31m- offset = -10 * gap_UI;[m [32m+[m[32m offset = -6 * gap_UI;[m }[m drawCentered_Text(d->font,[m (iRect){ addX_I2(topRight_Rect(chRect), offset),[m [1mdiff --git a/src/ui/root.c b/src/ui/root.c[m [1mindex de5ce0e9..4eb81da9 100644[m [1m--- a/src/ui/root.c[m [1m+++ b/src/ui/root.c[m [36m@@ -33,6 +33,7 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m #include "labelwidget.h"[m #include "lookupwidget.h"[m #include "sidebarwidget.h"[m [32m+[m[32m#include "snippets.h"[m #include "window.h"[m #include "../visited.h"[m #include "../history.h"[m [36m@@ -64,7 +65,7 @@[m [mstatic const iMenuItem desktopNavMenuItems_[] = {[m { "---" },[m { leftHalf_Icon " ${menu.sidebar.left}", leftSidebar_KeyShortcut, "sidebar.toggle" },[m { rightHalf_Icon " ${menu.sidebar.right}", rightSidebar_KeyShortcut, "sidebar2.toggle" },[m [31m- { "${menu.view.split}", SDLK_j, KMOD_PRIMARY, "splitmenu.open" },[m [32m+[m[32m { "${menu.view.split}", SDLK_j, KMOD_PRIMARY, "submenu id:splitmenu" },[m { "${menu.zoom.in}", SDLK_EQUALS, KMOD_PRIMARY, "zoom.delta arg:10" },[m { "${menu.zoom.out}", SDLK_MINUS, KMOD_PRIMARY, "zoom.delta arg:-10" },[m { "${menu.zoom.reset}", SDLK_0, KMOD_PRIMARY, "zoom.set arg:100" },[m [36m@@ -423,14 +424,15 @@[m [miBool handleRootCommands_Widget(iWidget *root, const char *cmd) {[m iUnused(root);[m if (equal_Command(cmd, "menu.open")) {[m iWidget *button = pointer_Command(cmd);[m [31m- iWidget *menu = findChild_Widget(button, "menu");[m [32m+[m[32m iWidget *menu = argLabel_Command(cmd, "self") ? button : findChild_Widget(button, "menu");[m if (!menu) {[m /* Independent popup window. */[m postCommand_App("cancel");[m return iTrue;[m }[m [31m- const iBool isPlacedUnder = argLabel_Command(cmd, "under");[m [31m- const iBool isMenuBar = argLabel_Command(cmd, "bar");[m [32m+[m[32m const iBool isPlacedUnder = argLabel_Command(cmd, "under");[m [32m+[m[32m const iBool isMenuBar = argLabel_Command(cmd, "bar");[m [32m+[m[32m const iBool isSubmenu = argLabel_Command(cmd, "self");[m iAssert(menu);[m if (!isVisible_Widget(menu)) {[m if (isMenuBar) {[m [36m@@ -440,9 +442,12 @@[m [miBool handleRootCommands_Widget(iWidget *root, const char *cmd) {[m if (menu->updateMenuItems) {[m menu->updateMenuItems(menu);[m }[m [31m- openMenu_Widget(menu,[m [31m- isPlacedUnder ? bottomLeft_Rect(bounds_Widget(button))[m [31m- : topLeft_Rect(bounds_Widget(button)));[m [32m+[m[32m openMenuFlags_Widget(menu,[m [32m+[m[32m hasLabel_Command(cmd, "coord") ? coord_Command(cmd)[m [32m+[m[32m : isPlacedUnder ? bottomLeft_Rect(bounds_Widget(button))[m [32m+[m[32m : topLeft_Rect(bounds_Widget(button)),[m [32m+[m[32m postCommands_MenuOpenFlags |[m [32m+[m[32m (isSubmenu ? submenu_MenuOpenFlags : 0));[m }[m else {[m /* Already open, do nothing. */[m [36m@@ -1565,6 +1570,30 @@[m [mstatic iBool updateMobilePageMenuItems_(iWidget *menu, const char *cmd) {[m return handleMenuCommand_Widget(menu, cmd);[m }[m [m [32m+[m[32mvoid recreateSnippetMenu_Root(iRoot *d) {[m [32m+[m[32m const iStringArray *snipNames = names_Snippets();[m [32m+[m[32m iArray *items = collectNew_Array(sizeof(iMenuItem));[m [32m+[m[32m iConstForEach(StringArray, s, snipNames) {[m [32m+[m[32m if (startsWith_String(s.value, "!")) {[m [32m+[m[32m continue;[m [32m+[m[32m }[m [32m+[m[32m pushBack_Array(items,[m [32m+[m[32m &(iMenuItem){ format_CStr(clipboard_Icon " %s", cstr_String(s.value)),[m [32m+[m[32m 0,[m [32m+[m[32m 0,[m [32m+[m[32m format_CStr("!input.paste snippet:%s", cstr_String(s.value)) });[m [32m+[m[32m }[m [32m+[m[32m if (!isEmpty_Array(items)) {[m [32m+[m[32m pushBack_Array(items, &(iMenuItem){ "---" });[m [32m+[m[32m }[m [32m+[m[32m pushBack_Array(items,[m [32m+[m[32m &(iMenuItem){ gear_Icon " ${menu.snip.prefs}", 0, 0, "preferences sniped:1" });[m [32m+[m[32m iWidget *menu = findChild_Widget(d->widget, "snippetmenu");[m [32m+[m[32m destroy_Widget(menu);[m [32m+[m[32m menu = makeMenu_Widget(d->widget, data_Array(items), size_Array(items));[m [32m+[m[32m setId_Widget(menu, "snippetmenu");[m [32m+[m[32m}[m [32m+[m void createUserInterface_Root(iRoot *d) {[m iWidget *root = d->widget = new_Widget();[m root->rect.size = get_Window()->size;[m [36m@@ -1632,6 +1661,7 @@[m [mvoid createUserInterface_Root(iRoot *d) {[m iClob(makeMenuBar_Widget(topLevelMenus_Window, iElemCount(topLevelMenus_Window))),[m collapse_WidgetFlag);[m /* The window menu needs to be dynamically updated with the list of open windows. */[m [32m+[m[32m /* TODO: Use Widget's `updateMenuItems` callback. */[m setCommandHandler_Widget(child_Widget(menuBar, 5), updateWindowMenu_);[m setId_Widget(menuBar, "menubar");[m # if 0[m [36m@@ -2060,20 +2090,24 @@[m [mvoid createUserInterface_Root(iRoot *d) {[m { ">>>" delete_Icon " " uiTextCaution_ColorEscape "${menu.delete}", 0, 0, "input.delete" },[m { ">>>" select_Icon " ${menu.selectall}", 0, 0, "input.selectall" },[m { ">>>" undo_Icon " ${menu.undo}", 0, 0, "input.undo" },[m [31m- }, 7);[m [32m+[m[32m { "---" },[m [32m+[m[32m { "${menu.paste.snippet}", 0, 0, "snippetmenu" },[m [32m+[m[32m }, 9);[m #else[m (iMenuItem[]){[m { scissor_Icon " ${menu.cut}", 0, 0, "input.copy cut:1" },[m { clipCopy_Icon " ${menu.copy}", 0, 0, "input.copy" },[m { clipboard_Icon " ${menu.paste}", 0, 0, "input.paste" },[m { return_Icon " ${menu.paste.go}", 0, 0, "input.paste enter:1" },[m [32m+[m[32m { "${menu.paste.snippet}", 0, 0, "submenu id:snippetmenu" },[m { "---" },[m { delete_Icon " " uiTextCaution_ColorEscape "${menu.delete}", 0, 0, "input.delete" },[m { undo_Icon " ${menu.undo}", 0, 0, "input.undo" },[m { "---" },[m { select_Icon " ${menu.selectall}", 0, 0, "input.selectall" },[m [31m- }, 9);[m [32m+[m[32m }, 10);[m #endif[m [32m+[m[32m recreateSnippetMenu_Root(d);[m if (deviceType_App() == phone_AppDeviceType) {[m /* Small screen; conserve space by removing the Cancel item. */[m iRelease(removeChild_Widget(clipMenu, lastChild_Widget(clipMenu)));[m [1mdiff --git a/src/ui/root.h b/src/ui/root.h[m [1mindex f46e0a53..9618d1b0 100644[m [1m--- a/src/ui/root.h[m [1m+++ b/src/ui/root.h[m [36m@@ -35,6 +35,7 @@[m [miDeclareTypeConstruction(Root)[m /*----------------------------------------------------------------------------------------------*/[m [m void createUserInterface_Root (iRoot *);[m [32m+[m[32mvoid recreateSnippetMenu_Root (iRoot *);[m [m void setCurrent_Root (iRoot *);[m iRoot * current_Root (void);[m [1mdiff --git a/src/ui/util.c b/src/ui/util.c[m [1mindex 5ae3b0e6..73970ab1 100644[m [1m--- a/src/ui/util.c[m [1m+++ b/src/ui/util.c[m [36m@@ -816,11 +816,15 @@[m [miBool handleMenuCommand_Widget(iWidget *menu, const char *cmd) {[m arg_Command(cmd)) {[m /* Dismiss open menus when clicking outside them. */[m closeMenu_Widget(menu);[m [31m- return iTrue;[m [32m+[m[32m return equal_Command(cmd, "mouse.clicked");[m }[m if (equal_Command(cmd, "cancel") && pointerLabel_Command(cmd, "menu") == menu) {[m return iFalse;[m }[m [32m+[m[32m if (equal_Command(cmd, "submenu.close") &&[m [32m+[m[32m (pointerLabel_Command(cmd, "menu") == menu || ~menu->flags & radio_WidgetFlag)) {[m [32m+[m[32m return iFalse;[m [32m+[m[32m }[m if (equal_Command(cmd, "contextclick") && pointer_Command(cmd) == menu) {[m return iFalse;[m }[m [36m@@ -834,7 +838,7 @@[m [miBool handleMenuCommand_Widget(iWidget *menu, const char *cmd) {[m return iFalse;[m }[m if (!isCommandIgnoredByMenus_(cmd)) {[m [31m- //printf("closemenu being called on %p due to cmd: %s\n", menu, cmd);[m [32m+[m[32m// printf("closemenu being called on %p due to cmd: %s\n", menu, cmd);[m closeMenu_Widget(menu);[m }[m }[m [36m@@ -855,12 +859,56 @@[m [mstatic iWidget *makeMenuSeparator_(void) {[m return sep;[m }[m [m [32m+[m[32mstatic void closeSubmenus_(iWidget *menu, iRoot *root) {[m [32m+[m[32m iConstForEach(ObjectList, i, children_Widget(menu)) {[m [32m+[m[32m if (isInstance_Object(i.object, &Class_LabelWidget)) {[m [32m+[m[32m iLabelWidget *label = (iLabelWidget *) i.object;[m [32m+[m[32m const iString *subCmd = command_LabelWidget(label);[m [32m+[m[32m if (startsWith_String(subCmd, "submenu id:")) {[m [32m+[m[32m iWidget *submenu = findChild_Widget(root->widget,[m [32m+[m[32m cstr_Command(cstr_String(subCmd), "id"));[m [32m+[m[32m iAssert(submenu);[m [32m+[m[32m if (isVisible_Widget(submenu)) {[m [32m+[m[32m closeMenu_Widget(submenu);[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic iBool submenuItemHandler_(iWidget *d, const char *cmd) {[m [32m+[m[32m if (equal_Command(cmd, "mouse.hovered") && isVisible_Widget(d)) {[m [32m+[m[32m iAssert(isInstance_Object(d, &Class_LabelWidget));[m [32m+[m[32m iLabelWidget *label = (iLabelWidget *) d;[m [32m+[m[32m const iString *subCmd = command_LabelWidget(label);[m [32m+[m[32m if (startsWith_String(subCmd, "submenu id:")) {[m [32m+[m[32m iWidget *menu = parent_Widget(d);[m [32m+[m[32m const iBool isPopup = type_Window(window_Widget(menu)) == popup_WindowType;[m [32m+[m[32m iRoot *root = isPopup ? constAs_Widget(userData_Object(menu))->root : d->root;[m [32m+[m[32m closeSubmenus_(menu, root);[m [32m+[m[32m iWidget *submenu = findChild_Widget(root->widget,[m [32m+[m[32m cstr_Command(cstr_String(subCmd), "id"));[m [32m+[m[32m iAssert(submenu);[m [32m+[m[32m if (!isVisible_Widget(submenu)) {[m [32m+[m[32m// const iInt2 coord = topRight_Rect(bounds_Widget(d));[m [32m+[m[32m openMenuAnchorFlags_Widget(submenu,[m [32m+[m[32m bounds_Widget(d),[m [32m+[m[32m submenu_MenuOpenFlags |[m [32m+[m[32m (isPopup ? forcePopup_MenuOpenFlags : 0));[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m return iTrue;[m [32m+[m[32m }[m [32m+[m[32m return iFalse;[m [32m+[m[32m}[m [32m+[m void makeMenuItems_Widget(iWidget *menu, const iMenuItem *items, size_t n) {[m const iBool isPortraitPhone = (deviceType_App() == phone_AppDeviceType && isPortrait_App());[m int64_t itemFlags = (deviceType_App() != desktop_AppDeviceType ? 0 : 0) |[m (isPortraitPhone ? extraPadding_WidgetFlag : 0);[m [31m- iBool haveIcons = iFalse;[m [31m- iWidget *horizGroup = NULL;[m [32m+[m[32m iBool haveIcons = iFalse;[m [32m+[m[32m iBool haveSubmenu = iFalse;[m [32m+[m[32m iWidget *horizGroup = NULL;[m for (size_t i = 0; items[i].label && i < n; ++i) {[m const iMenuItem *item = &items[i];[m if (!item->label) {[m [36m@@ -913,6 +961,12 @@[m [mvoid makeMenuItems_Widget(iWidget *menu, const iMenuItem *items, size_t n) {[m setTextColor_LabelWidget(label, uiIcon_ColorId);[m setFont_LabelWidget(label, uiLabelMedium_FontId);[m }[m [32m+[m[32m if (item->command && startsWith_CStr(item->command, "submenu id:")) {[m [32m+[m[32m setChevron_LabelWidget(label, iTrue);[m [32m+[m[32m setFlags_Widget(as_Widget(label), drawKey_WidgetFlag, iFalse);[m [32m+[m[32m haveSubmenu = iTrue;[m [32m+[m[32m }[m [32m+[m[32m as_Widget(label)->flags2 |= commandOnHover_WidgetFlag2;[m setFlags_Widget(as_Widget(label), disabled_WidgetFlag, isDisabled);[m if (isInfo) {[m setFlags_Widget(as_Widget(label), resizeToParentWidth_WidgetFlag |[m [36m@@ -929,13 +983,19 @@[m [mvoid makeMenuItems_Widget(iWidget *menu, const iMenuItem *items, size_t n) {[m itemFlags | noBackground_WidgetFlag | frameless_WidgetFlag |[m alignLeft_WidgetFlag);[m }[m [31m- if (haveIcons) {[m [31m- /* All items must have icons if at least one of them has. */[m [32m+[m[32m if (haveIcons || haveSubmenu) {[m iForEach(ObjectList, i, children_Widget(menu)) {[m if (isInstance_Object(i.object, &Class_LabelWidget)) {[m iLabelWidget *label = i.object;[m [31m- if (!isWrapped_LabelWidget(label) && icon_LabelWidget(label) == 0) {[m [31m- setIcon_LabelWidget(label, ' ');[m [32m+[m[32m if (haveIcons) {[m [32m+[m[32m /* All items must have icons if at least one of them has. */[m [32m+[m[32m if (!isWrapped_LabelWidget(label) && icon_LabelWidget(label) == 0) {[m [32m+[m[32m setIcon_LabelWidget(label, ' ');[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m if (haveSubmenu) {[m [32m+[m[32m /* Open and close submenus on hover. */[m [32m+[m[32m setCommandHandler_Widget(i.object, submenuItemHandler_);[m }[m }[m }[m [36m@@ -1253,10 +1313,17 @@[m [miLocalDef iBool isUsingMenuPopupWindows_(void) {[m }[m [m void openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, int menuOpenFlags) {[m [32m+[m[32m openMenuAnchorFlags_Widget(d, initCorners_Rect(windowCoord, windowCoord), menuOpenFlags);[m [32m+[m[32m}[m [32m+[m [32m+[m[32mvoid openMenuAnchorFlags_Widget(iWidget *d, iRect windowAnchorRect, int menuOpenFlags) {[m [32m+[m[32m iInt2 windowCoord = topRight_Rect(windowAnchorRect);[m const iBool postCommands = (menuOpenFlags & postCommands_MenuOpenFlags) != 0;[m const iBool isMenuFocused = ((menuOpenFlags & setFocus_MenuOpenFlags) ||[m focus_Widget() == parent_Widget(d));[m [31m- if (postCommands) {[m [32m+[m[32m const iBool isPopupForced = (menuOpenFlags & forcePopup_MenuOpenFlags) != 0;[m [32m+[m[32m const iBool isSubmenu = (menuOpenFlags & submenu_MenuOpenFlags) != 0;[m [32m+[m[32m if (postCommands && !isSubmenu) {[m postCommandf_App("cancel menu:%p", d); /* dismiss any other menus */[m }[m /* Menu closes when commands are emitted, so handle any pending ones beforehand. */[m [36m@@ -1282,7 +1349,7 @@[m [mvoid openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, int menuOpenFlags) {[m setFrameColor_Widget(d, isPortraitPhone ? none_ColorId : uiSeparator_ColorId);[m }[m arrange_Widget(d); /* need to know the height */[m [31m- iBool allowOverflow = iFalse;[m [32m+[m[32m iBool allowOverflow = (get_Window()->type == extra_WindowType);[m /* A vertical offset determined by a possible selected label in the menu. */[m if (deviceType_App() == desktop_AppDeviceType &&[m windowCoord.y < rootSize.y - lineHeight_Text(uiNormal_FontSize) * 3) {[m [36m@@ -1315,8 +1382,8 @@[m [mvoid openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, int menuOpenFlags) {[m winRect.size.y /= pixelRatio;[m addv_I2(&winRect.pos, winPos);[m iRect visibleWinRect = intersect_Rect(winRect, displayRect);[m [31m- /* Only use a popup window if the menu can't fit inside the main window. */[m [31m- if (height_Widget(d) / pixelRatio > visibleWinRect.size.y ||[m [32m+[m[32m /* Only use a popup window if the menu can't fit inside the window. */[m [32m+[m[32m if (isPopupForced || height_Widget(d) / pixelRatio > visibleWinRect.size.y ||[m (allowOverflow &&[m (windowCoord.y < 0 || windowCoord.y + height_Widget(d) > get_Window()->size.y))) {[m if (postCommands) {[m [36m@@ -1339,6 +1406,10 @@[m [mvoid openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, int menuOpenFlags) {[m SDL_GetWindowSize(sdlWin, &winSize.x, &winSize.y);[m menuPos = sub_I2(add_I2(winPos, divi_I2(winSize, 2)), divi_I2(menuSize, 2));[m }[m [32m+[m[32m if (isSubmenu && menuPos.x + width_Widget(d) > right_Rect(displayRect)) {[m [32m+[m[32m /* Flip it to the right side. */[m [32m+[m[32m menuPos.x -= menuSize.x + width_Rect(windowAnchorRect) / pixelRatio;[m [32m+[m[32m }[m menuPos.x = iMin(menuPos.x, right_Rect(displayRect) - menuSize.x);[m menuPos.y = iMax(0, iMin(menuPos.y, bottom_Rect(displayRect) - menuSize.y));[m }[m [36m@@ -1354,6 +1425,10 @@[m [mvoid openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, int menuOpenFlags) {[m return;[m }[m }[m [32m+[m[32m if (isSubmenu && windowCoord.x + width_Widget(d) > rootSize.x) {[m [32m+[m[32m /* Flip it to the right side. */[m [32m+[m[32m windowCoord = addX_I2(topLeft_Rect(windowAnchorRect), -width_Widget(d));[m [32m+[m[32m }[m raise_Widget(d);[m if (deviceType_App() != desktop_AppDeviceType) {[m setFlags_Widget(d, arrangeWidth_WidgetFlag | resizeChildrenToWidestChild_WidgetFlag,[m [36m@@ -3620,7 +3695,7 @@[m [miWidget *makePreferences_Widget(void) {[m iSnippetWidget *sniped = new_SnippetWidget();[m appendFramelessTabPage_Widget(tabs,[m iClob(sniped),[m [31m- scissor_Icon " ${heading.prefs.snip}",[m [32m+[m[32m clipboard_Icon " ${heading.prefs.snip}",[m cyan_ColorId,[m '7',[m KMOD_PRIMARY);[m [36m@@ -4181,7 +4256,7 @@[m [miWidget *makeSiteSpecificSettings_Widget(const iString *url) {[m [m /*----------------------------------------------------------------------------------------------*/[m [m [31m-static iBool snippetCreationHandler_(iWidget *dlg, const char *cmd) {[m [32m+[m[32mstatic iBool handleSnippetCreationCommands_(iWidget *dlg, const char *cmd) {[m if (equal_Command(cmd, "widget.resized")) {[m iWidget *headings = findChild_Widget(dlg, "snip.columns.head");[m iWidget *name = findChild_Widget(dlg, "snip.name");[m [36m@@ -4202,7 +4277,7 @@[m [mstatic iBool snippetCreationHandler_(iWidget *dlg, const char *cmd) {[m if (!set_Snippets(text_InputWidget(name), text_InputWidget(content))) {[m return iTrue;[m }[m [31m- postCommand_App("snippets.changed");[m [32m+[m[32m postCommandf_App("snippets.changed added:%s", cstr_String(text_InputWidget(name)));[m setupSheetTransition_Mobile(dlg, dialogTransitionDir_Widget(dlg));[m destroy_Widget(dlg);[m return iTrue;[m [36m@@ -4219,7 +4294,7 @@[m [miWidget *makeSnippetCreation_Widget(void) {[m if (isUsingPanelLayout_Mobile()) {[m /* TODO */[m [m [31m- setCommandHandler_Widget(dlg, snippetCreationHandler_);[m [32m+[m[32m setCommandHandler_Widget(dlg, handleSnippetCreationCommands_);[m }[m else {[m iWidget *headings, *values;[m [36m@@ -4232,12 +4307,13 @@[m [miWidget *makeSnippetCreation_Widget(void) {[m setLineBreaksEnabled_InputWidget(name, iFalse);[m addPrefsInputWithHeading_(headings, values, "snip.name", iClob(name));[m addPrefsInputWithHeading_(headings, values, "snip.content", iClob(content));[m [32m+[m[32m addChild_Widget(dlg, iClob(makePadding_Widget(gap_UI)));[m addChild_Widget(dlg, iClob(makeDialogButtons_Widget(actions, iElemCount(actions))));[m addChild_Widget(get_Root()->widget, iClob(dlg));[m as_Widget(name)->rect.size.x = 60 * gap_UI;[m as_Widget(content)->rect.size.x = 60 * gap_UI;[m arrange_Widget(dlg);[m [31m- setCommandHandler_Widget(dlg, snippetCreationHandler_);[m [32m+[m[32m setCommandHandler_Widget(dlg, handleSnippetCreationCommands_);[m enableResizing_Widget(dlg, width_Widget(dlg), "snip");[m }[m setupSheetTransition_Mobile(dlg, incoming_TransitionFlag | dialogTransitionDir_Widget(dlg));[m [1mdiff --git a/src/ui/util.h b/src/ui/util.h[m [1mindex f51f364b..76a92443 100644[m [1m--- a/src/ui/util.h[m [1m+++ b/src/ui/util.h[m [36m@@ -283,6 +283,8 @@[m [menum iMenuOpenFlags {[m postCommands_MenuOpenFlags = iBit(1),[m center_MenuOpenFlags = iBit(2),[m setFocus_MenuOpenFlags = iBit(3),[m [32m+[m[32m submenu_MenuOpenFlags = iBit(4),[m [32m+[m[32m forcePopup_MenuOpenFlags = iBit(5),[m };[m [m iWidget * makeMenu_Widget (iWidget *parent, const iMenuItem *items, size_t n); /* returns no ref */[m [36m@@ -290,6 +292,7 @@[m [miWidget * makeMenuFlags_Widget (iWidget *parent, const iMenuIte[m void makeMenuItems_Widget (iWidget *menu, const iMenuItem *items, size_t n);[m void openMenu_Widget (iWidget *, iInt2 windowCoord);[m void openMenuFlags_Widget (iWidget *, iInt2 windowCoord, int flags);[m [32m+[m[32mvoid openMenuAnchorFlags_Widget (iWidget *, iRect windowAnchorRect, int menuOpenFlags);[m void closeMenu_Widget (iWidget *);[m iBool handleMenuCommand_Widget (iWidget *menu, const char *cmd); /* used as the command handler */[m void releaseNativeMenu_Widget (iWidget *);[m [1mdiff --git a/src/ui/widget.c b/src/ui/widget.c[m [1mindex 98b86f30..cc7e0b1d 100644[m [1m--- a/src/ui/widget.c[m [1m+++ b/src/ui/widget.c[m [36m@@ -1291,14 +1291,14 @@[m [miBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) {[m else if (ev->type == SDL_MOUSEMOTION &&[m ev->motion.windowID == id_Window(window_Widget(d)) &&[m (!window_Widget(d)->hover || hasParent_Widget(d, window_Widget(d)->hover)) &&[m [31m- flags_Widget(d) & hover_WidgetFlag && !isHidden_Widget_(d) &&[m [32m+[m[32m flags_Widget(d) & hover_WidgetFlag &&[m [32m+[m[32m !isHidden_Widget_(d) /* hidden flag on self */ &&[m ~flags_Widget(d) & disabled_WidgetFlag) {[m if (contains_Widget(d, init_I2(ev->motion.x, ev->motion.y))) {[m setHover_Widget(d);[m #if 0[m [31m- printf("set hover to [%p] %s:'%s'\n",[m [31m- d, class_Widget(d)->name,[m [31m- cstr_String(id_Widget(d)));[m [32m+[m[32m printf("<%u> set hover to ", window_Widget(d)->frameTime);[m [32m+[m[32m identify_Widget(d);[m fflush(stdout);[m #endif[m }[m [36m@@ -2607,7 +2607,7 @@[m [mvoid postCommand_Widget(const iAnyObject *d, const char *cmd, ...) {[m }[m deinit_String(&ptrStr);[m }[m [31m- postCommandString_Root(((const iWidget *) d)->root, &str);[m [32m+[m[32m postCommandString_Root(isGlobal ? NULL : ((const iWidget *) d)->root, &str);[m deinit_String(&str);[m }[m [m [1mdiff --git a/src/ui/window.c b/src/ui/window.c[m [1mindex fc6dbb43..480ef4bb 100644[m [1m--- a/src/ui/window.c[m [1m+++ b/src/ui/window.c[m [36m@@ -32,6 +32,7 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m #include "documentwidget.h"[m #include "sidebarwidget.h"[m #include "paint.h"[m [32m+[m[32m#include "snippets.h"[m #include "root.h"[m #include "touch.h"[m #include "util.h"[m [36m@@ -129,7 +130,7 @@[m [mstatic const iMenuItem viewMenuItems_[] = {[m { "${menu.zoom.out}", SDLK_MINUS, KMOD_PRIMARY, "zoom.delta arg:-10" },[m { "${menu.zoom.reset}", SDLK_0, KMOD_PRIMARY, "zoom.set arg:100" },[m { "---" },[m [31m- { "${menu.view.split}", SDLK_j, KMOD_PRIMARY, "splitmenu.open" },[m [32m+[m[32m { "${menu.view.split}", SDLK_j, KMOD_PRIMARY, "submenu id:splitmenu" },[m { NULL }[m };[m [m [36m@@ -315,9 +316,6 @@[m [mvoid resizeSplits_MainWindow(iMainWindow *d, iBool updateDocumentSize) {[m }[m [m static void setupUserInterface_MainWindow(iMainWindow *d) {[m [31m-#if defined (LAGRANGE_MAC_MENUBAR)[m [31m- insertMacMenus_(); /* TODO: Shouldn't this be in the App? */[m [31m-#endif[m /* One root is created by default. */[m d->base.roots[0] = new_Root();[m d->base.roots[0]->window = as_Window(d);[m [36m@@ -326,6 +324,9 @@[m [mstatic void setupUserInterface_MainWindow(iMainWindow *d) {[m setCurrent_Root(NULL);[m /* One of the roots always has keyboard input focus. */[m d->base.keyRoot = d->base.roots[0];[m [32m+[m[32m#if defined (LAGRANGE_MAC_MENUBAR)[m [32m+[m[32m insertMacMenus_(); /* TODO: Shouldn't this be in the App? */[m [32m+[m[32m#endif[m }[m [m static iBool updateSize_MainWindow_(iMainWindow *d, iBool notifyAlways) {[m [36m@@ -1012,7 +1013,7 @@[m [mstatic iBool handleWindowEvent_Window_(iWindow *d, const SDL_WindowEvent *ev) {[m case SDL_WINDOWEVENT_FOCUS_LOST:[m if (d->type == popup_WindowType) {[m /* Popup windows are currently only used for menus. */[m [31m- closeMenu_Widget(d->roots[0]->widget);[m [32m+[m[32m// closeMenu_Widget(d->roots[0]->widget);[m }[m else {[m postCommandf_App("window.focus.lost arg:%u", id_Window(d));[m [36m@@ -1386,6 +1387,14 @@[m [miBool processEvent_Window(iWindow *d, const SDL_Event *ev) {[m updateMetrics_Root(d->roots[i]);[m }[m }[m [32m+[m[32m if (isCommand_UserEvent(&event, "snippets.changed")) {[m [32m+[m[32m /* Recreate the snippet menus with the new list of snippets. */[m [32m+[m[32m iForIndices(i, d->roots) {[m [32m+[m[32m if (d->roots[i]) {[m [32m+[m[32m recreateSnippetMenu_Root(d->roots[i]);[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m }[m if (isCommand_UserEvent(&event, "lang.changed") && (mw || extraw)) {[m #if defined (LAGRANGE_MAC_MENUBAR)[m /* Retranslate the menus. */[m
text/gemini; charset=utf-8
This content has been proxied by September (3851b).