diff --git a/internal/app/focus.go b/internal/app/focus.go index 80a4d4e6b4..4cd9e19d0d 100644 --- a/internal/app/focus.go +++ b/internal/app/focus.go @@ -24,22 +24,7 @@ func NewFocusManager(c fyne.CanvasObject) *FocusManager { func (f *FocusManager) Focus(obj fyne.Focusable) { f.Lock() defer f.Unlock() - - if f.focused == obj { - return - } - - if dis, ok := obj.(fyne.Disableable); ok && dis.Disabled() { - obj = nil - } - - if f.focused != nil { - f.focused.FocusLost() - } - f.focused = obj - if obj != nil { - obj.FocusGained() - } + f.focus(obj) } // Focused returns the currently focused object or nil if none. @@ -54,7 +39,7 @@ func (f *FocusManager) Focused() fyne.Focusable { func (f *FocusManager) FocusNext() { f.Lock() defer f.Unlock() - f.focused = f.nextInChain(f.focused) + f.focus(f.nextInChain(f.focused)) } // FocusPrevious will find the item before the current that can be focused and focus it. @@ -62,7 +47,25 @@ func (f *FocusManager) FocusNext() { func (f *FocusManager) FocusPrevious() { f.Lock() defer f.Unlock() - f.focused = f.previousInChain(f.focused) + f.focus(f.previousInChain(f.focused)) +} + +func (f *FocusManager) focus(obj fyne.Focusable) { + if f.focused == obj { + return + } + + if dis, ok := obj.(fyne.Disableable); ok && dis.Disabled() { + obj = nil + } + + if f.focused != nil { + f.focused.FocusLost() + } + f.focused = obj + if obj != nil { + obj.FocusGained() + } } func (f *FocusManager) nextInChain(current fyne.Focusable) fyne.Focusable { diff --git a/internal/app/focus_test.go b/internal/app/focus_test.go index b812b837c7..21e08b32c9 100644 --- a/internal/app/focus_test.go +++ b/internal/app/focus_test.go @@ -10,13 +10,13 @@ import ( ) func TestFocusManager_Focus(t *testing.T) { - entry1 := widget.NewEntry() + entry1 := &focusable{} hidden := widget.NewCheck("test", func(bool) {}) hidden.Hide() - entry2 := widget.NewEntry() + entry2 := &focusable{} disabled := widget.NewCheck("test", func(bool) {}) disabled.Disable() - entry3 := widget.NewEntry() + entry3 := &focusable{} c := widget.NewVBox(entry1, hidden, entry2, disabled, entry3) manager := app.NewFocusManager(c) @@ -24,25 +24,31 @@ func TestFocusManager_Focus(t *testing.T) { manager.Focus(entry2) assert.Equal(t, entry2, manager.Focused()) + assert.True(t, entry2.focused) manager.Focus(entry1) assert.Equal(t, entry1, manager.Focused()) + assert.True(t, entry1.focused) + assert.False(t, entry2.focused) manager.Focus(entry3) assert.Equal(t, entry3, manager.Focused()) + assert.True(t, entry3.focused) + assert.False(t, entry1.focused) manager.Focus(nil) assert.Nil(t, manager.Focused()) + assert.False(t, entry3.focused) } func TestFocusManager_FocusNext(t *testing.T) { - entry1 := widget.NewEntry() + entry1 := &focusable{} hidden := widget.NewCheck("test", func(bool) {}) hidden.Hide() - entry2 := widget.NewEntry() + entry2 := &focusable{} disabled := widget.NewCheck("test", func(bool) {}) disabled.Disable() - entry3 := widget.NewEntry() + entry3 := &focusable{} c := widget.NewVBox(entry1, hidden, entry2, disabled, entry3) manager := app.NewFocusManager(c) @@ -50,25 +56,32 @@ func TestFocusManager_FocusNext(t *testing.T) { manager.FocusNext() assert.Equal(t, entry1, manager.Focused()) + assert.True(t, entry1.focused) manager.FocusNext() assert.Equal(t, entry2, manager.Focused()) + assert.True(t, entry2.focused) + assert.False(t, entry1.focused) manager.FocusNext() assert.Equal(t, entry3, manager.Focused()) + assert.True(t, entry3.focused) + assert.False(t, entry2.focused) manager.FocusNext() assert.Equal(t, entry1, manager.Focused()) + assert.True(t, entry1.focused) + assert.False(t, entry3.focused) } func TestFocusManager_FocusPrevious(t *testing.T) { - entry1 := widget.NewEntry() + entry1 := &focusable{} hidden := widget.NewCheck("test", func(bool) {}) hidden.Hide() - entry2 := widget.NewEntry() + entry2 := &focusable{} disabled := widget.NewCheck("test", func(bool) {}) disabled.Disable() - entry3 := widget.NewEntry() + entry3 := &focusable{} c := widget.NewVBox(entry1, hidden, entry2, disabled, entry3) manager := app.NewFocusManager(c) @@ -76,13 +89,36 @@ func TestFocusManager_FocusPrevious(t *testing.T) { manager.FocusPrevious() assert.Equal(t, entry3, manager.Focused()) + assert.True(t, entry3.focused) manager.FocusPrevious() assert.Equal(t, entry2, manager.Focused()) + assert.True(t, entry2.focused) + assert.False(t, entry3.focused) manager.FocusPrevious() assert.Equal(t, entry1, manager.Focused()) + assert.True(t, entry1.focused) + assert.False(t, entry2.focused) manager.FocusPrevious() assert.Equal(t, entry3, manager.Focused()) + assert.True(t, entry3.focused) + assert.False(t, entry1.focused) +} + +type focusable struct { + widget.Entry + focused bool +} + +func (f *focusable) FocusGained() { + if f.Disabled() { + return + } + f.focused = true +} + +func (f *focusable) FocusLost() { + f.focused = false }