From 358d6b2b3293145a0af1320abf57c093238f212d Mon Sep 17 00:00:00 2001 From: Dorbmon Date: Fri, 19 Apr 2024 14:09:39 +0800 Subject: [PATCH 1/7] Double-click to select a file in FileOpen / FileSave dialogs --- dialog/file.go | 22 ++++++++++++---------- dialog/fileitem.go | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/dialog/file.go b/dialog/file.go index cd1edb39c0..d861468949 100644 --- a/dialog/file.go +++ b/dialog/file.go @@ -533,7 +533,14 @@ func (f *fileDialog) setSelected(file fyne.URI, id int) { func (f *fileDialog) setView(view ViewLayout) { f.view = view fyne.CurrentApp().Preferences().SetInt(viewLayoutKey, int(view)) - + var selectF func(id int) + choose := func(id int) { + selectF(id) + if file, ok := f.getDataItem(id); ok { + f.selectedID = id + f.setSelected(file, id) + } + } count := func() int { f.dataLock.RLock() defer f.dataLock.RUnlock() @@ -547,26 +554,21 @@ func (f *fileDialog) setView(view ViewLayout) { if dir, ok := f.getDataItem(id); ok { parent := id == 0 && len(dir.Path()) < len(f.dir.Path()) _, isDir := dir.(fyne.ListableURI) - o.(*fileDialogItem).setLocation(dir, isDir || parent, parent) - } - } - choose := func(id int) { - if file, ok := f.getDataItem(id); ok { - f.selectedID = id - f.setSelected(file, id) + o.(*fileDialogItem).setLocation(dir, isDir || parent, parent, id) + o.(*fileDialogItem).setChooseAndOpenCallBack(choose, f.open.OnTapped) } } if f.view == GridView { grid := widget.NewGridWrap(count, template, update) - grid.OnSelected = choose f.files = grid f.toggleViewButton.SetIcon(theme.ListIcon()) + selectF = grid.Select } else { list := widget.NewList(count, template, update) - list.OnSelected = choose f.files = list f.toggleViewButton.SetIcon(theme.GridIcon()) + selectF = list.Select } if f.dir != nil { diff --git a/dialog/fileitem.go b/dialog/fileitem.go index a915bd2f24..4098da7222 100644 --- a/dialog/fileitem.go +++ b/dialog/fileitem.go @@ -2,8 +2,11 @@ package dialog import ( "path/filepath" + "time" "fyne.io/fyne/v2" + "fyne.io/fyne/v2/driver/desktop" + "fyne.io/fyne/v2/driver/mobile" "fyne.io/fyne/v2/lang" "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" @@ -20,8 +23,13 @@ type fileDialogItem struct { picker *fileDialog name string + id int // id in the father container + choose func(id int) + open func() location fyne.URI dir bool + + lastClick time.Time } func (i *fileDialogItem) CreateRenderer() fyne.WidgetRenderer { @@ -39,7 +47,8 @@ func (i *fileDialogItem) CreateRenderer() fyne.WidgetRenderer { } } -func (i *fileDialogItem) setLocation(l fyne.URI, dir, up bool) { +func (i *fileDialogItem) setLocation(l fyne.URI, dir, up bool, id int) { + i.id = id i.dir = dir i.location = l i.name = l.Name() @@ -55,6 +64,31 @@ func (i *fileDialogItem) setLocation(l fyne.URI, dir, up bool) { i.Refresh() } +func (i *fileDialogItem) tapped() { + if i.choose != nil { + i.choose(i.id) + } + now := time.Now() + if !i.dir && now.Sub(i.lastClick) < fyne.CurrentApp().Driver().DoubleTapDelay() && i.open != nil { + // It is a double click, so we ask the dialog to open + i.open() + } + i.lastClick = now +} + +func (i *fileDialogItem) TouchDown(*mobile.TouchEvent) {} + +func (i *fileDialogItem) TouchUp(*mobile.TouchEvent) { + i.tapped() +} + +func (i *fileDialogItem) TouchCancel(*mobile.TouchEvent) {} + +func (i *fileDialogItem) MouseDown(*desktop.MouseEvent) {} + +func (i *fileDialogItem) MouseUp(e *desktop.MouseEvent) { + i.tapped() +} func (f *fileDialog) newFileItem(location fyne.URI, dir, up bool) *fileDialogItem { item := &fileDialogItem{ @@ -76,6 +110,10 @@ func (f *fileDialog) newFileItem(location fyne.URI, dir, up bool) *fileDialogIte item.ExtendBaseWidget(item) return item } +func (i *fileDialogItem) setChooseAndOpenCallBack(choose func(id int), open func()) { + i.choose = choose + i.open = open +} type fileItemRenderer struct { item *fileDialogItem From 1492268ad52401744b72adda69e206be83b70c69 Mon Sep 17 00:00:00 2001 From: Dorbmon Date: Fri, 19 Apr 2024 14:21:03 +0800 Subject: [PATCH 2/7] fix: test code --- dialog/fileitem_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dialog/fileitem_test.go b/dialog/fileitem_test.go index 1187847fd5..08d4fb0db9 100644 --- a/dialog/fileitem_test.go +++ b/dialog/fileitem_test.go @@ -120,7 +120,7 @@ func TestFileItem_Wrap(t *testing.T) { texts := test.WidgetRenderer(label).Objects() assert.Equal(t, 1, len(texts)) - item.setLocation(storage.NewFileURI("/path/to/averylongfilename.svg"), false, false) + item.setLocation(storage.NewFileURI("/path/to/averylongfilename.svg"), false, false, 0) rich := test.WidgetRenderer(label).Objects()[0].(*widget.RichText) texts = test.WidgetRenderer(rich).Objects() assert.Equal(t, 2, len(texts)) From 54b25af3ce9ed44005867999a7fc8ee69da42cc1 Mon Sep 17 00:00:00 2001 From: Dorbmon Date: Fri, 19 Apr 2024 18:19:55 +0800 Subject: [PATCH 3/7] Fix select --- dialog/file.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dialog/file.go b/dialog/file.go index d861468949..f66d0c1412 100644 --- a/dialog/file.go +++ b/dialog/file.go @@ -558,14 +558,17 @@ func (f *fileDialog) setView(view ViewLayout) { o.(*fileDialogItem).setChooseAndOpenCallBack(choose, f.open.OnTapped) } } - + // Acutally, during the real interaction, the choose won't be called. + // It will be called only when we directly calls container.select(i) if f.view == GridView { grid := widget.NewGridWrap(count, template, update) + grid.OnSelected = choose f.files = grid f.toggleViewButton.SetIcon(theme.ListIcon()) selectF = grid.Select } else { list := widget.NewList(count, template, update) + list.OnSelected = choose f.files = list f.toggleViewButton.SetIcon(theme.GridIcon()) selectF = list.Select From 8a424d145745fc46603f784909da11030b7139d9 Mon Sep 17 00:00:00 2001 From: Dorbmon Date: Thu, 25 Apr 2024 00:50:10 +0800 Subject: [PATCH 4/7] implement Tappable interface --- dialog/fileitem.go | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/dialog/fileitem.go b/dialog/fileitem.go index 4098da7222..53b7727593 100644 --- a/dialog/fileitem.go +++ b/dialog/fileitem.go @@ -5,8 +5,6 @@ import ( "time" "fyne.io/fyne/v2" - "fyne.io/fyne/v2/driver/desktop" - "fyne.io/fyne/v2/driver/mobile" "fyne.io/fyne/v2/lang" "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" @@ -64,7 +62,8 @@ func (i *fileDialogItem) setLocation(l fyne.URI, dir, up bool, id int) { i.Refresh() } -func (i *fileDialogItem) tapped() { + +func (i *fileDialogItem) Tapped(*fyne.PointEvent) { if i.choose != nil { i.choose(i.id) } @@ -76,20 +75,6 @@ func (i *fileDialogItem) tapped() { i.lastClick = now } -func (i *fileDialogItem) TouchDown(*mobile.TouchEvent) {} - -func (i *fileDialogItem) TouchUp(*mobile.TouchEvent) { - i.tapped() -} - -func (i *fileDialogItem) TouchCancel(*mobile.TouchEvent) {} - -func (i *fileDialogItem) MouseDown(*desktop.MouseEvent) {} - -func (i *fileDialogItem) MouseUp(e *desktop.MouseEvent) { - i.tapped() -} - func (f *fileDialog) newFileItem(location fyne.URI, dir, up bool) *fileDialogItem { item := &fileDialogItem{ picker: f, @@ -110,6 +95,7 @@ func (f *fileDialog) newFileItem(location fyne.URI, dir, up bool) *fileDialogIte item.ExtendBaseWidget(item) return item } + func (i *fileDialogItem) setChooseAndOpenCallBack(choose func(id int), open func()) { i.choose = choose i.open = open From 7b34e47f88dfd514f273a2c851392825580f0509 Mon Sep 17 00:00:00 2001 From: Dorbmon Date: Fri, 26 Apr 2024 00:40:45 +0800 Subject: [PATCH 5/7] simpify code --- dialog/file.go | 3 ++- dialog/fileitem.go | 5 ----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/dialog/file.go b/dialog/file.go index f66d0c1412..1f3c5ecf81 100644 --- a/dialog/file.go +++ b/dialog/file.go @@ -555,7 +555,8 @@ func (f *fileDialog) setView(view ViewLayout) { parent := id == 0 && len(dir.Path()) < len(f.dir.Path()) _, isDir := dir.(fyne.ListableURI) o.(*fileDialogItem).setLocation(dir, isDir || parent, parent, id) - o.(*fileDialogItem).setChooseAndOpenCallBack(choose, f.open.OnTapped) + o.(*fileDialogItem).choose = choose + o.(*fileDialogItem).open = f.open.OnTapped } } // Acutally, during the real interaction, the choose won't be called. diff --git a/dialog/fileitem.go b/dialog/fileitem.go index 53b7727593..744b0c3a9b 100644 --- a/dialog/fileitem.go +++ b/dialog/fileitem.go @@ -96,11 +96,6 @@ func (f *fileDialog) newFileItem(location fyne.URI, dir, up bool) *fileDialogIte return item } -func (i *fileDialogItem) setChooseAndOpenCallBack(choose func(id int), open func()) { - i.choose = choose - i.open = open -} - type fileItemRenderer struct { item *fileDialogItem fileTextSize float32 From a69e76fa4b08eda5b11f2341e8df9f56344750ad Mon Sep 17 00:00:00 2001 From: Dorbmon Date: Fri, 26 Apr 2024 10:42:22 +0800 Subject: [PATCH 6/7] Update dialog/fileitem.go Co-authored-by: Drew Weymouth --- dialog/fileitem.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dialog/fileitem.go b/dialog/fileitem.go index 744b0c3a9b..86ec6936fb 100644 --- a/dialog/fileitem.go +++ b/dialog/fileitem.go @@ -21,7 +21,7 @@ type fileDialogItem struct { picker *fileDialog name string - id int // id in the father container + id int // id in the parent container choose func(id int) open func() location fyne.URI From 81ed920aa271c121e2cbce2542c575e66ce5d6f3 Mon Sep 17 00:00:00 2001 From: Dorbmon Date: Fri, 26 Apr 2024 10:44:06 +0800 Subject: [PATCH 7/7] fix --- dialog/file.go | 5 +++-- dialog/fileitem.go | 3 +-- dialog/fileitem_test.go | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dialog/file.go b/dialog/file.go index 1f3c5ecf81..dec134e779 100644 --- a/dialog/file.go +++ b/dialog/file.go @@ -554,12 +554,13 @@ func (f *fileDialog) setView(view ViewLayout) { if dir, ok := f.getDataItem(id); ok { parent := id == 0 && len(dir.Path()) < len(f.dir.Path()) _, isDir := dir.(fyne.ListableURI) - o.(*fileDialogItem).setLocation(dir, isDir || parent, parent, id) + o.(*fileDialogItem).setLocation(dir, isDir || parent, parent) o.(*fileDialogItem).choose = choose + o.(*fileDialogItem).id = id o.(*fileDialogItem).open = f.open.OnTapped } } - // Acutally, during the real interaction, the choose won't be called. + // Actually, during the real interaction, the OnSelected won't be called. // It will be called only when we directly calls container.select(i) if f.view == GridView { grid := widget.NewGridWrap(count, template, update) diff --git a/dialog/fileitem.go b/dialog/fileitem.go index 744b0c3a9b..3a86f0503f 100644 --- a/dialog/fileitem.go +++ b/dialog/fileitem.go @@ -45,8 +45,7 @@ func (i *fileDialogItem) CreateRenderer() fyne.WidgetRenderer { } } -func (i *fileDialogItem) setLocation(l fyne.URI, dir, up bool, id int) { - i.id = id +func (i *fileDialogItem) setLocation(l fyne.URI, dir, up bool) { i.dir = dir i.location = l i.name = l.Name() diff --git a/dialog/fileitem_test.go b/dialog/fileitem_test.go index 08d4fb0db9..1187847fd5 100644 --- a/dialog/fileitem_test.go +++ b/dialog/fileitem_test.go @@ -120,7 +120,7 @@ func TestFileItem_Wrap(t *testing.T) { texts := test.WidgetRenderer(label).Objects() assert.Equal(t, 1, len(texts)) - item.setLocation(storage.NewFileURI("/path/to/averylongfilename.svg"), false, false, 0) + item.setLocation(storage.NewFileURI("/path/to/averylongfilename.svg"), false, false) rich := test.WidgetRenderer(label).Objects()[0].(*widget.RichText) texts = test.WidgetRenderer(rich).Objects() assert.Equal(t, 2, len(texts))