diff --git a/pkg/gui/confirmation_panel.go b/pkg/gui/confirmation_panel.go index f1b555b4..0db7e787 100644 --- a/pkg/gui/confirmation_panel.go +++ b/pkg/gui/confirmation_panel.go @@ -52,8 +52,8 @@ func (gui *Gui) getMessageHeight(wrap bool, message string, width int) int { return lineCount } -func (gui *Gui) getConfirmationPanelDimensions(g *gocui.Gui, wrap bool, prompt string) (int, int, int, int) { - width, height := g.Size() +func (gui *Gui) getConfirmationPanelDimensions(wrap bool, prompt string) (int, int, int, int) { + width, height := gui.g.Size() panelWidth := width / 2 panelHeight := gui.getMessageHeight(wrap, prompt, panelWidth) return width/2 - panelWidth/2, @@ -73,7 +73,7 @@ func (gui *Gui) createPromptPanel(title string, handleConfirm func(*gocui.Gui, * } func (gui *Gui) prepareConfirmationPanel(title, prompt string, hasLoader bool) error { - x0, y0, x1, y1 := gui.getConfirmationPanelDimensions(gui.g, true, prompt) + x0, y0, x1, y1 := gui.getConfirmationPanelDimensions(true, prompt) confirmationView := gui.Views.Confirmation _, err := gui.g.SetView("confirmation", x0, y0, x1, y1, 0) if err != nil { diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 8cc6caad..aae2ca3c 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -88,6 +88,7 @@ type guiState struct { type searchingState struct { view *gocui.View + panel ISideListPanel isSearching bool searchString string } diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 65685908..bf56ddfe 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -450,13 +450,6 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { Handler: gui.handleImagesBulkCommand, Description: gui.Tr.ViewBulkCommands, }, - { - ViewName: "images", - Key: '/', - Modifier: gocui.ModNone, - Handler: wrappedHandler(gui.handleOpenImageSearch), - Description: gui.Tr.FilterList, - }, { ViewName: "volumes", Key: '[', @@ -620,6 +613,17 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { }) } + for _, panel := range gui.allListPanels() { + bindings = append(bindings, + &Binding{ + ViewName: panel.View().Name(), + Key: '/', + Modifier: gocui.ModNone, + Handler: wrappedHandler(gui.handleOpenSearch), + Description: gui.Tr.LcFilter, + }) + } + return bindings } diff --git a/pkg/gui/list_panel.go b/pkg/gui/list_panel.go index f9101283..abdd960a 100644 --- a/pkg/gui/list_panel.go +++ b/pkg/gui/list_panel.go @@ -73,6 +73,9 @@ type SideListPanel[T comparable] struct { onClick func(T) error getDisplayStrings func(T) []string + + // function to be called after re-rendering list. Can be nil + onRerender func() error } type ISideListPanel interface { @@ -80,6 +83,7 @@ type ISideListPanel interface { HandleSelect() error View() *gocui.View Refocus() + RerenderList() error } var _ ISideListPanel = &SideListPanel[int]{} @@ -275,6 +279,12 @@ func (self *SideListPanel[T]) RerenderList() error { } fmt.Fprint(self.view, renderedTable) + if self.onRerender != nil { + if err := self.onRerender(); err != nil { + return err + } + } + if self.view == self.gui.CurrentView() { return self.HandleSelect() } diff --git a/pkg/gui/menu_panel.go b/pkg/gui/menu_panel.go index 36916a1f..c951449d 100644 --- a/pkg/gui/menu_panel.go +++ b/pkg/gui/menu_panel.go @@ -39,6 +39,9 @@ func (gui *Gui) getMenuPanel() *SideListPanel[*MenuItem] { getDisplayStrings: func(menuItem *MenuItem) []string { return menuItem.LabelColumns }, + onRerender: func() error { + return gui.resizePopupPanel(gui.Views.Menu) + }, // the menu panel doesn't actually have any contexts to display on the main view // so what follows are all dummy values diff --git a/pkg/gui/searching.go b/pkg/gui/searching.go index c5c8db71..437c9c30 100644 --- a/pkg/gui/searching.go +++ b/pkg/gui/searching.go @@ -4,13 +4,15 @@ import ( "github.com/jesseduffield/gocui" ) -func (gui *Gui) handleOpenImageSearch() error { - return gui.handleOpenSearch(gui.Views.Images) -} +func (gui *Gui) handleOpenSearch() error { + panel, ok := gui.currentListPanel() + if !ok { + return nil + } -func (gui *Gui) handleOpenSearch(view *gocui.View) error { gui.State.Searching.isSearching = true - gui.State.Searching.view = view + gui.State.Searching.view = panel.View() + gui.State.Searching.panel = panel return gui.switchFocus(gui.Views.Search) } @@ -18,7 +20,7 @@ func (gui *Gui) handleOpenSearch(view *gocui.View) error { func (gui *Gui) onNewSearchString(value string) error { // need to refresh the right list panel. gui.State.Searching.searchString = value - return gui.Panels.Images.RerenderList() + return gui.State.Searching.panel.RerenderList() } func (gui *Gui) wrapEditor(f func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool) func(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool { @@ -44,9 +46,11 @@ func (gui *Gui) clearSearch() error { gui.State.Searching.searchString = "" gui.State.Searching.isSearching = false gui.State.Searching.view = nil + panel := gui.State.Searching.panel + gui.State.Searching.panel = nil gui.Views.Search.ClearTextArea() - return gui.Panels.Images.RerenderList() + return panel.RerenderList() } // returns to the list view with the filter still applied diff --git a/pkg/gui/view_helpers.go b/pkg/gui/view_helpers.go index e6d6b7d3..8e7fcbaa 100644 --- a/pkg/gui/view_helpers.go +++ b/pkg/gui/view_helpers.go @@ -133,9 +133,12 @@ func (gui *Gui) returnFocus() error { // Not to be called directly. Use `switchFocus` instead func (gui *Gui) pushView(name string) { // No matter what view we're pushing, we first remove all popup panels from the stack - gui.State.ViewStack = lo.Filter(gui.State.ViewStack, func(viewName string, _ int) bool { - return !gui.isPopupPanel(viewName) - }) + // (unless it's the search view because we may be searching the menu panel) + if name != "search" { + gui.State.ViewStack = lo.Filter(gui.State.ViewStack, func(viewName string, _ int) bool { + return !gui.isPopupPanel(viewName) + }) + } // If we're pushing a side panel, we remove all other panels if lo.Contains(gui.sideViewNames(), name) { @@ -318,21 +321,21 @@ func (gui *Gui) currentViewName() string { func (gui *Gui) resizeCurrentPopupPanel(g *gocui.Gui) error { v := g.CurrentView() if gui.isPopupPanel(v.Name()) { - return gui.resizePopupPanel(g, v) + return gui.resizePopupPanel(v) } return nil } -func (gui *Gui) resizePopupPanel(g *gocui.Gui, v *gocui.View) error { +func (gui *Gui) resizePopupPanel(v *gocui.View) error { // If the confirmation panel is already displayed, just resize the width, // otherwise continue content := v.Buffer() - x0, y0, x1, y1 := gui.getConfirmationPanelDimensions(g, v.Wrap, content) + x0, y0, x1, y1 := gui.getConfirmationPanelDimensions(v.Wrap, content) vx0, vy0, vx1, vy1 := v.Dimensions() if vx0 == x0 && vy0 == y0 && vx1 == x1 && vy1 == y1 { return nil } - _, err := g.SetView(v.Name(), x0, y0, x1, y1, 0) + _, err := gui.g.SetView(v.Name(), x0, y0, x1, y1, 0) return err } @@ -482,6 +485,7 @@ func (gui *Gui) currentSidePanel() (ISideListPanel, bool) { return nil, false } +// returns the current list panel. If no list panel is focused, returns false. func (gui *Gui) currentListPanel() (ISideListPanel, bool) { viewName := gui.currentViewName() diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index dcbd43bd..40aac5bd 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -38,6 +38,7 @@ type TranslationSet struct { Confirm string Return string FocusMain string + LcFilter string StopContainer string RestartingStatus string StartingStatus string @@ -148,6 +149,7 @@ func englishSet() TranslationSet { Return: "return", FocusMain: "focus main panel", + LcFilter: "filter list", Navigate: "navigate", Execute: "execute", Close: "close",