From 20a4aeab6e92c8f16fa02783c750b86558d8fb51 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 1 Jun 2024 20:21:25 +0200 Subject: [PATCH 1/3] Support showing checkboxes or radio buttons in menus For checkboxes it probably doesn't really make sense to use them yet, because we'd have to find a way how you can toggle them without closing the dialog; but we already provide rendering for them to lay the ground. But radio buttons can be used already, because for those it is ok to close the dialog when choosing a different option (as long as there is only one grounp of radio buttons in the panel, that is). --- pkg/gui/context/menu_context.go | 16 +++++++++++++++- pkg/gui/types/common.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/pkg/gui/context/menu_context.go b/pkg/gui/context/menu_context.go index e4b26f884..f1438b221 100644 --- a/pkg/gui/context/menu_context.go +++ b/pkg/gui/context/menu_context.go @@ -107,7 +107,21 @@ func (self *MenuViewModel) GetDisplayStrings(_ int, _ int) [][]string { keyLabel = style.FgCyan.Sprint(keybindings.LabelFromKey(item.Key)) } - displayStrings = utils.Prepend(displayStrings, keyLabel) + checkMark := "" + switch item.Widget { + case types.MenuWidgetNone: + // do nothing + case types.MenuWidgetRadioButtonSelected: + checkMark = "(•)" + case types.MenuWidgetRadioButtonUnselected: + checkMark = "( )" + case types.MenuWidgetCheckboxSelected: + checkMark = "[✓]" + case types.MenuWidgetCheckboxUnselected: + checkMark = "[ ]" + } + + displayStrings = utils.Prepend(displayStrings, keyLabel, checkMark) return displayStrings }) } diff --git a/pkg/gui/types/common.go b/pkg/gui/types/common.go index fc9168406..61c27de49 100644 --- a/pkg/gui/types/common.go +++ b/pkg/gui/types/common.go @@ -217,6 +217,30 @@ type DisabledReason struct { ShowErrorInPanel bool } +type MenuWidget int + +const ( + MenuWidgetNone MenuWidget = iota + MenuWidgetRadioButtonSelected + MenuWidgetRadioButtonUnselected + MenuWidgetCheckboxSelected + MenuWidgetCheckboxUnselected +) + +func MakeMenuRadioButton(value bool) MenuWidget { + if value { + return MenuWidgetRadioButtonSelected + } + return MenuWidgetRadioButtonUnselected +} + +func MakeMenuCheckBox(value bool) MenuWidget { + if value { + return MenuWidgetCheckboxSelected + } + return MenuWidgetCheckboxUnselected +} + type MenuItem struct { Label string @@ -232,6 +256,12 @@ type MenuItem struct { // item, as opposed to having to navigate to it Key Key + // A widget to show in front of the menu item. Supported widget types are + // checkboxes and radio buttons, + // This only handles the rendering of the widget; the behavior needs to be + // provided by the client. + Widget MenuWidget + // The tooltip will be displayed upon highlighting the menu item Tooltip string From 68c966567cbff30dddfa2a30c8b2518f30498b58 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 1 Jun 2024 20:21:43 +0200 Subject: [PATCH 2/3] Show radio buttons in the sort order menu for branches --- pkg/gui/controllers/branches_controller.go | 3 ++- pkg/gui/controllers/helpers/refs_helper.go | 5 +++-- pkg/gui/controllers/remote_branches_controller.go | 3 ++- pkg/integration/tests/branch/sort_local_branches.go | 12 ++++++++++++ pkg/integration/tests/branch/sort_remote_branches.go | 5 +++++ 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/pkg/gui/controllers/branches_controller.go b/pkg/gui/controllers/branches_controller.go index 62eda703e..8b4a5d395 100644 --- a/pkg/gui/controllers/branches_controller.go +++ b/pkg/gui/controllers/branches_controller.go @@ -696,7 +696,8 @@ func (self *BranchesController) createSortMenu() error { return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}}) } return nil - }) + }, + self.c.GetAppState().LocalBranchSortOrder) } func (self *BranchesController) createResetMenu(selectedBranch *models.Branch) error { diff --git a/pkg/gui/controllers/helpers/refs_helper.go b/pkg/gui/controllers/helpers/refs_helper.go index ccfe71799..08c6e173a 100644 --- a/pkg/gui/controllers/helpers/refs_helper.go +++ b/pkg/gui/controllers/helpers/refs_helper.go @@ -190,7 +190,7 @@ func (self *RefsHelper) ResetToRef(ref string, strength string, envVars []string return nil } -func (self *RefsHelper) CreateSortOrderMenu(sortOptionsOrder []string, onSelected func(sortOrder string) error) error { +func (self *RefsHelper) CreateSortOrderMenu(sortOptionsOrder []string, onSelected func(sortOrder string) error, currentValue string) error { type sortMenuOption struct { key types.Key label string @@ -221,7 +221,8 @@ func (self *RefsHelper) CreateSortOrderMenu(sortOptionsOrder []string, onSelecte OnPress: func() error { return onSelected(opt.sortOrder) }, - Key: opt.key, + Key: opt.key, + Widget: types.MakeMenuRadioButton(opt.sortOrder == currentValue), } }) return self.c.Menu(types.CreateMenuOptions{ diff --git a/pkg/gui/controllers/remote_branches_controller.go b/pkg/gui/controllers/remote_branches_controller.go index 97dbf56b0..d793c6148 100644 --- a/pkg/gui/controllers/remote_branches_controller.go +++ b/pkg/gui/controllers/remote_branches_controller.go @@ -145,7 +145,8 @@ func (self *RemoteBranchesController) createSortMenu() error { return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.REMOTES}}) } return nil - }) + }, + self.c.GetAppState().RemoteBranchSortOrder) } func (self *RemoteBranchesController) createResetMenu(selectedBranch *models.RemoteBranch) error { diff --git a/pkg/integration/tests/branch/sort_local_branches.go b/pkg/integration/tests/branch/sort_local_branches.go index 9daf28424..ceff654be 100644 --- a/pkg/integration/tests/branch/sort_local_branches.go +++ b/pkg/integration/tests/branch/sort_local_branches.go @@ -37,6 +37,12 @@ var SortLocalBranches = NewIntegrationTest(NewIntegrationTestArgs{ Press(keys.Branches.SortOrder) t.ExpectPopup().Menu().Title(Equals("Sort order")). + Lines( + Contains("r (•) Recency").IsSelected(), + Contains("a ( ) Alphabetical"), + Contains("d ( ) Date"), + Contains(" Cancel"), + ). Select(Contains("-committerdate")). Confirm() @@ -53,6 +59,12 @@ var SortLocalBranches = NewIntegrationTest(NewIntegrationTestArgs{ Press(keys.Branches.SortOrder) t.ExpectPopup().Menu().Title(Equals("Sort order")). + Lines( + Contains("r ( ) Recency").IsSelected(), + Contains("a ( ) Alphabetical"), + Contains("d (•) Date"), + Contains(" Cancel"), + ). Select(Contains("refname")). Confirm() diff --git a/pkg/integration/tests/branch/sort_remote_branches.go b/pkg/integration/tests/branch/sort_remote_branches.go index 35e2f700a..2cbbdb31d 100644 --- a/pkg/integration/tests/branch/sort_remote_branches.go +++ b/pkg/integration/tests/branch/sort_remote_branches.go @@ -41,6 +41,11 @@ var SortRemoteBranches = NewIntegrationTest(NewIntegrationTestArgs{ Press(keys.Branches.SortOrder) t.ExpectPopup().Menu().Title(Equals("Sort order")). + Lines( + Contains("a (•) Alphabetical").IsSelected(), + Contains("d ( ) Date"), + Contains(" Cancel"), + ). Select(Contains("-committerdate")). Confirm() From 4967e5136e641bfc2bdb3eaa3ca0bd81ba68878f Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 1 Jun 2024 20:26:24 +0200 Subject: [PATCH 3/3] Show radio buttons in the show log graph and commit sort order menus --- pkg/gui/controllers/local_commits_controller.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index de5116b74..f95062fdb 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -1085,6 +1085,7 @@ func (self *LocalCommitsController) handleOpenLogMenu() error { Label: self.c.Tr.ShowGitGraph, OpensMenu: true, OnPress: func() error { + currentValue := self.c.GetAppState().GitLogShowGraph onPress := func(value string) func() error { return func() error { self.c.GetAppState().GitLogShowGraph = value @@ -1101,14 +1102,17 @@ func (self *LocalCommitsController) handleOpenLogMenu() error { { Label: "always", OnPress: onPress("always"), + Widget: types.MakeMenuRadioButton(currentValue == "always"), }, { Label: "never", OnPress: onPress("never"), + Widget: types.MakeMenuRadioButton(currentValue == "never"), }, { Label: "when maximised", OnPress: onPress("when-maximised"), + Widget: types.MakeMenuRadioButton(currentValue == "when-maximised"), }, }, }) @@ -1118,6 +1122,7 @@ func (self *LocalCommitsController) handleOpenLogMenu() error { Label: self.c.Tr.SortCommits, OpensMenu: true, OnPress: func() error { + currentValue := self.c.GetAppState().GitLogOrder onPress := func(value string) func() error { return func() error { self.c.GetAppState().GitLogOrder = value @@ -1139,14 +1144,17 @@ func (self *LocalCommitsController) handleOpenLogMenu() error { { Label: "topological (topo-order)", OnPress: onPress("topo-order"), + Widget: types.MakeMenuRadioButton(currentValue == "topo-order"), }, { Label: "date-order", OnPress: onPress("date-order"), + Widget: types.MakeMenuRadioButton(currentValue == "date-order"), }, { Label: "author-date-order", OnPress: onPress("author-date-order"), + Widget: types.MakeMenuRadioButton(currentValue == "author-date-order"), }, }, })