From b60b4345bb279c448e7e253b323b95e8d258b90e Mon Sep 17 00:00:00 2001 From: Tom5521 Date: Sat, 25 May 2024 22:51:22 -0400 Subject: [PATCH] feat(pkg/widgets)!: Add DropDown and PointerDropDown types --- pkg/widgets/dropdown.go | 93 +++++++++++++++++++++++++++------ pkg/widgets/pointer-dropdown.go | 81 ++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+), 15 deletions(-) create mode 100644 pkg/widgets/pointer-dropdown.go diff --git a/pkg/widgets/dropdown.go b/pkg/widgets/dropdown.go index cccf162..d542903 100644 --- a/pkg/widgets/dropdown.go +++ b/pkg/widgets/dropdown.go @@ -1,34 +1,97 @@ package widgets -import "github.com/diamondburned/gotk4/pkg/gtk/v4" +import ( + "slices" -type DropDown struct { + "github.com/diamondburned/gotk4/pkg/core/gioutil" + "github.com/diamondburned/gotk4/pkg/gtk/v4" +) + +type DropDown[T any] struct { *gtk.DropDown - Items []string - OnSelected func(selected uint) + Items []T + Model *gioutil.ListModel[T] + Factory *gtk.SignalListItemFactory + + OnChanged func(index int) + + Setup FactorySetup + Bind ListBind[T] } -func NewDropDown(items []string) *DropDown { - d := &DropDown{ - Items: items, - DropDown: gtk.NewDropDownFromStrings(items), +func NewDropDown[T any]( + items []T, + setup FactorySetup, + bind ListBind[T], +) *DropDown[T] { + d := &DropDown[T]{ + Items: items, + Model: gioutil.NewListModel[T](), + Factory: gtk.NewSignalListItemFactory(), + + Setup: setup, + Bind: bind, } - d.reConnectOnSelected() + + d.RefreshModel() + d.connectFactory() + + d.DropDown = gtk.NewDropDown(d.Model.ListModel, nil) + d.SetFactory(&d.Factory.ListItemFactory) + + d.connectChanged() + return d } -func (d *DropDown) Refresh() { - d.reConnectOnSelected() +func (d *DropDown[T]) Append(v T) { + d.Items = append(d.Items, v) + d.Model.Append(v) +} + +func (d *DropDown[T]) Remove(index int) { + d.Items = slices.Delete(d.Items, index, index+1) + d.Model.Remove(index) +} + +func (d *DropDown[T]) Splice(pos, rms int, values ...T) { + d.Items = splice(d.Items, pos, rms, values) + d.Model.Splice(pos, rms, values...) } -// Internal functions +func (d *DropDown[T]) RefreshModel() { + if d.Model.NItems() == 0 { + for _, i := range d.Items { + d.Model.Append(i) + } + return + } + d.Model.Splice(0, 0, d.Items...) +} -func (d *DropDown) reConnectOnSelected() { +// Private methods. + +func (d *DropDown[T]) connectChanged() { d.ConnectAfter("notify::selected", func() { - if d.OnSelected == nil { + if d.OnChanged == nil { + return + } + d.OnChanged(int(d.Selected())) + }) +} + +func (d *DropDown[T]) connectFactory() { + d.Factory.ConnectSetup(func(listitem *gtk.ListItem) { + if d.Setup == nil { + return + } + d.Setup(listitem) + }) + d.Factory.ConnectBind(func(listitem *gtk.ListItem) { + if d.Bind == nil { return } - d.OnSelected(d.Selected()) + d.Bind(listitem, d.Items[listitem.Position()]) }) } diff --git a/pkg/widgets/pointer-dropdown.go b/pkg/widgets/pointer-dropdown.go new file mode 100644 index 0000000..aea7485 --- /dev/null +++ b/pkg/widgets/pointer-dropdown.go @@ -0,0 +1,81 @@ +package widgets + +import ( + "slices" + + "github.com/diamondburned/gotk4/pkg/core/gioutil" + "github.com/diamondburned/gotk4/pkg/gtk/v4" +) + +type PointerDropDown[T any] struct { + *DropDown[T] + + Items *[]T +} + +func NewPointerDropDown[T any]( + items *[]T, + setup FactorySetup, + bind ListBind[T], +) *PointerDropDown[T] { + d := &PointerDropDown[T]{ + DropDown: &DropDown[T]{ + Model: gioutil.NewListModel[T](), + Factory: gtk.NewSignalListItemFactory(), + + Setup: setup, + Bind: bind, + }, + Items: items, + } + + d.RefreshModel() + d.connectFactory() + + d.DropDown.DropDown = gtk.NewDropDown(d.Model.ListModel, nil) + d.SetFactory(&d.Factory.ListItemFactory) + + d.connectChanged() + + return d +} + +func (d *PointerDropDown[T]) Append(v T) { + *d.Items = append(*d.Items, v) + d.Model.Append(v) +} + +func (d *PointerDropDown[T]) Remove(index int) { + *d.Items = slices.Delete(*d.Items, index, index+1) + d.Model.Remove(index) +} + +func (d *PointerDropDown[T]) Splice(pos, rms int, values ...T) { + *d.Items = splice(*d.Items, pos, rms, values) + d.Model.Splice(pos, rms, values...) +} + +func (d *PointerDropDown[T]) RefreshModel() { + if d.Model.NItems() == 0 { + for _, i := range *d.Items { + d.Model.Append(i) + } + return + } + d.Model.Splice(0, 0, *d.Items...) +} + +func (d *PointerDropDown[T]) connectFactory() { + d.Factory.ConnectSetup(func(listitem *gtk.ListItem) { + if d.Setup == nil { + return + } + d.Setup(listitem) + }) + d.Factory.ConnectBind(func(listitem *gtk.ListItem) { + if d.Bind == nil { + return + } + d.Bind(listitem, (*d.Items)[listitem.Position()]) + }) +}