From 7f9818cfa2a3115ecd0f043b5e94044be1346cda Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Tue, 5 Sep 2023 21:49:33 +0200 Subject: [PATCH] Add DisabledReason field to MenuItem This is useful to disable items that are not applicable right now because of some condition (e.g. the "delete branch" menu item when the currently checked-out branch is selected). When a DisabledReason is set on a menu item, we - show it in a tooltip (below the regular tooltip of the item, if it has one) - strike through the item's key, if it has one - show an error message with the DisabledReason if the user tries to invoke the command --- pkg/gui/context/menu_context.go | 7 +++++++ pkg/gui/controllers/helpers/confirmation_helper.go | 13 ++++++++++++- pkg/gui/controllers/menu_controller.go | 2 +- pkg/gui/types/common.go | 4 ++++ pkg/i18n/english.go | 2 ++ 5 files changed, 26 insertions(+), 2 deletions(-) diff --git a/pkg/gui/context/menu_context.go b/pkg/gui/context/menu_context.go index 287ed92ec..f972f2fbb 100644 --- a/pkg/gui/context/menu_context.go +++ b/pkg/gui/context/menu_context.go @@ -90,6 +90,9 @@ func (self *MenuViewModel) GetDisplayStrings(_ int, _ int) [][]string { return lo.Map(menuItems, func(item *types.MenuItem, _ int) []string { displayStrings := item.LabelColumns + if item.DisabledReason != "" { + displayStrings[0] = style.FgDefault.SetStrikethrough().Sprint(displayStrings[0]) + } if !showKeys { return displayStrings @@ -169,6 +172,10 @@ func (self *MenuContext) GetKeybindings(opts types.KeybindingsOpts) []*types.Bin } func (self *MenuContext) OnMenuPress(selectedItem *types.MenuItem) error { + if selectedItem != nil && selectedItem.DisabledReason != "" { + return self.c.ErrorMsg(selectedItem.DisabledReason) + } + if err := self.c.PopContext(); err != nil { return err } diff --git a/pkg/gui/controllers/helpers/confirmation_helper.go b/pkg/gui/controllers/helpers/confirmation_helper.go index c920df39f..7d4ca1464 100644 --- a/pkg/gui/controllers/helpers/confirmation_helper.go +++ b/pkg/gui/controllers/helpers/confirmation_helper.go @@ -333,7 +333,7 @@ func (self *ConfirmationHelper) resizeMenu() { tooltip := "" selectedItem := self.c.Contexts().Menu.GetSelected() if selectedItem != nil { - tooltip = selectedItem.Tooltip + tooltip = self.TooltipForMenuItem(selectedItem) } tooltipHeight := getMessageHeight(true, tooltip, panelWidth) + 2 // plus 2 for the frame _, _ = self.c.GocuiGui().SetView(self.c.Views().Tooltip.Name(), x0, tooltipTop, x1, tooltipTop+tooltipHeight-1, 0) @@ -382,3 +382,14 @@ func (self *ConfirmationHelper) IsPopupPanel(viewName string) bool { func (self *ConfirmationHelper) IsPopupPanelFocused() bool { return self.IsPopupPanel(self.c.CurrentContext().GetViewName()) } + +func (self *ConfirmationHelper) TooltipForMenuItem(menuItem *types.MenuItem) string { + tooltip := menuItem.Tooltip + if menuItem.DisabledReason != "" { + if tooltip != "" { + tooltip += "\n\n" + } + tooltip += style.FgRed.Sprintf(self.c.Tr.DisabledMenuItemPrefix) + menuItem.DisabledReason + } + return tooltip +} diff --git a/pkg/gui/controllers/menu_controller.go b/pkg/gui/controllers/menu_controller.go index 108bd9cf7..0af32ef71 100644 --- a/pkg/gui/controllers/menu_controller.go +++ b/pkg/gui/controllers/menu_controller.go @@ -54,7 +54,7 @@ func (self *MenuController) GetOnFocus() func(types.OnFocusOpts) error { return func(types.OnFocusOpts) error { selectedMenuItem := self.context().GetSelected() if selectedMenuItem != nil { - self.c.Views().Tooltip.SetContent(selectedMenuItem.Tooltip) + self.c.Views().Tooltip.SetContent(self.c.Helpers().Confirmation.TooltipForMenuItem(selectedMenuItem)) } return nil } diff --git a/pkg/gui/types/common.go b/pkg/gui/types/common.go index 6eacd882b..21ba78d9a 100644 --- a/pkg/gui/types/common.go +++ b/pkg/gui/types/common.go @@ -204,6 +204,10 @@ type MenuItem struct { // The tooltip will be displayed upon highlighting the menu item Tooltip string + // If non-empty, show this in a tooltip, style the menu item as disabled, + // and refuse to invoke the command + DisabledReason string + // Can be used to group menu items into sections with headers. MenuItems // with the same Section should be contiguous, and will automatically get a // section header. If nil, the item is not part of a section. diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 09577c210..0f788c317 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -612,6 +612,7 @@ type TranslationSet struct { MarkAsBaseCommitTooltip string MarkedCommitMarker string PleaseGoToURL string + DisabledMenuItemPrefix string Actions Actions Bisect Bisect Log Log @@ -1403,6 +1404,7 @@ func EnglishTranslationSet() TranslationSet { MarkAsBaseCommitTooltip: "Select a base commit for the next rebase; this will effectively perform a 'git rebase --onto'.", MarkedCommitMarker: "↑↑↑ Will rebase from here ↑↑↑", PleaseGoToURL: "Please go to {{.url}}", + DisabledMenuItemPrefix: "Disabled: ", Actions: Actions{ // TODO: combine this with the original keybinding descriptions (those are all in lowercase atm) CheckoutCommit: "Checkout commit",