From e59fbb50cf76bbec3ccf734c11ece631a7e237a5 Mon Sep 17 00:00:00 2001 From: "5684185+vsariola@users.noreply.github.com" <5684185+vsariola@users.noreply.github.com> Date: Tue, 24 Jun 2025 20:39:27 +0300 Subject: [PATCH] refactor(tracker/gioui): separate SplitStyle from SplitState --- tracker/gioui/split.go | 162 +++++++++++++++++++-------------------- tracker/gioui/theme.go | 1 + tracker/gioui/theme.yml | 1 + tracker/gioui/tracker.go | 15 ++-- 4 files changed, 92 insertions(+), 87 deletions(-) diff --git a/tracker/gioui/split.go b/tracker/gioui/split.go index f9aaae9..63ab7f9 100644 --- a/tracker/gioui/split.go +++ b/tracker/gioui/split.go @@ -11,83 +11,29 @@ import ( "gioui.org/unit" ) -type Split struct { - // Ratio keeps the current layout. - // 0 is center, -1 completely to the left, 1 completely to the right. - Ratio float32 - // Bar is the width for resizing the layout - Bar unit.Dp - // Axis is the split direction: layout.Horizontal splits the view in left - // and right, layout.Vertical splits the view in top and bottom - Axis layout.Axis - // Minimum sizes of the first and second widget in the split, in dp - MinSize1, MinSize2 unit.Dp - - drag bool - dragID pointer.ID - dragCoord float32 -} - -var defaultBarWidth = unit.Dp(10) - -func (s *Split) Update(gtx layout.Context) { - for { - ev, ok := gtx.Event(pointer.Filter{ - Target: s, - Kinds: pointer.Press | pointer.Drag | pointer.Release, - // TODO: there should be a grab; there was Grab: s.drag, - }) - if !ok { - break - } - e, ok := ev.(pointer.Event) - if !ok { - continue - } - - switch e.Kind { - case pointer.Press: - if s.drag { - break - } - - s.dragID = e.PointerID - if s.Axis == layout.Horizontal { - s.dragCoord = e.Position.X - } else { - s.dragCoord = e.Position.Y - } - s.drag = true - // when the user start dragging, the new display ratio becomes the underlying ratio - s.Ratio = s.calculateRatio(gtx) - - case pointer.Drag: - if s.dragID != e.PointerID { - break - } - - if s.Axis == layout.Horizontal { - s.Ratio += (e.Position.X - s.dragCoord) / float32(gtx.Constraints.Max.X) * 2 - s.dragCoord = e.Position.X - } else { - s.Ratio += (e.Position.Y - s.dragCoord) / float32(gtx.Constraints.Max.Y) * 2 - s.dragCoord = e.Position.Y - } - - case pointer.Release, pointer.Cancel: - if s.dragID == e.PointerID { - // when the user release the grab, the new display ratio becomes the underlying ratio - s.Ratio = s.calculateRatio(gtx) - } - s.drag = false - } +type ( + SplitState struct { + // Ratio keeps the current layout. + // 0 is center, -1 completely to the left, 1 completely to the right. + Ratio float32 + // Axis is the split direction: layout.Horizontal splits the view in left + // and right, layout.Vertical splits the view in top and bottom + Axis layout.Axis + drag bool + dragID pointer.ID + dragCoord float32 } -} -func (s *Split) Layout(gtx layout.Context, first, second layout.Widget) layout.Dimensions { - s.Update(gtx) + SplitStyle struct { + Bar unit.Dp + MinSize1, MinSize2 unit.Dp + } +) - size1, size2, bar := s.calculateSplitSizes(gtx) +func (s *SplitState) Layout(gtx layout.Context, st *SplitStyle, first, second layout.Widget) layout.Dimensions { + s.update(gtx, st) + + size1, size2, bar := s.calculateSplitSizes(gtx, st) secondOffset := size1 + bar { @@ -142,8 +88,62 @@ func (s *Split) Layout(gtx layout.Context, first, second layout.Widget) layout.D return layout.Dimensions{Size: gtx.Constraints.Max} } -func (s *Split) calculateRatio(gtx layout.Context) float32 { - size1, size2, bar := s.calculateSplitSizes(gtx) +func (s *SplitState) update(gtx layout.Context, st *SplitStyle) { + for { + ev, ok := gtx.Event(pointer.Filter{ + Target: s, + Kinds: pointer.Press | pointer.Drag | pointer.Release, + // TODO: there should be a grab; there was Grab: s.drag, + }) + if !ok { + break + } + e, ok := ev.(pointer.Event) + if !ok { + continue + } + + switch e.Kind { + case pointer.Press: + if s.drag { + break + } + + s.dragID = e.PointerID + if s.Axis == layout.Horizontal { + s.dragCoord = e.Position.X + } else { + s.dragCoord = e.Position.Y + } + s.drag = true + // when the user start dragging, the new display ratio becomes the underlying ratio + s.Ratio = s.calculateRatio(gtx, st) + + case pointer.Drag: + if s.dragID != e.PointerID { + break + } + + if s.Axis == layout.Horizontal { + s.Ratio += (e.Position.X - s.dragCoord) / float32(gtx.Constraints.Max.X) * 2 + s.dragCoord = e.Position.X + } else { + s.Ratio += (e.Position.Y - s.dragCoord) / float32(gtx.Constraints.Max.Y) * 2 + s.dragCoord = e.Position.Y + } + + case pointer.Release, pointer.Cancel: + if s.dragID == e.PointerID { + // when the user release the grab, the new display ratio becomes the underlying ratio + s.Ratio = s.calculateRatio(gtx, st) + } + s.drag = false + } + } +} + +func (s *SplitState) calculateRatio(gtx layout.Context, st *SplitStyle) float32 { + size1, size2, bar := s.calculateSplitSizes(gtx, st) total := size1 + size2 + bar if total <= 0 { return 0 @@ -151,10 +151,10 @@ func (s *Split) calculateRatio(gtx layout.Context) float32 { return 2*float32(size1+bar/2)/float32(total) - 1 } -func (s *Split) calculateSplitSizes(gtx layout.Context) (size1, size2, bar int) { - bar = gtx.Dp(s.Bar) +func (s *SplitState) calculateSplitSizes(gtx layout.Context, st *SplitStyle) (size1, size2, bar int) { + bar = gtx.Dp(st.Bar) if bar <= 1 { - bar = gtx.Dp(defaultBarWidth) + bar = gtx.Dp(1) } total := gtx.Constraints.Max.Y @@ -169,8 +169,8 @@ func (s *Split) calculateSplitSizes(gtx layout.Context) (size1, size2, bar int) } totalSize := total - bar size1 = int((s.Ratio+1)/2*float32(total) - float32(bar)/2) - minSize1 := gtx.Dp(s.MinSize1) - minSize2 := gtx.Dp(s.MinSize2) + minSize1 := gtx.Dp(st.MinSize1) + minSize2 := gtx.Dp(st.MinSize2) // we always hide the smaller split first if s.Ratio < 0 { diff --git a/tracker/gioui/theme.go b/tracker/gioui/theme.go index 46461ba..b511c6c 100644 --- a/tracker/gioui/theme.go +++ b/tracker/gioui/theme.go @@ -100,6 +100,7 @@ type Theme struct { Menu PopupStyle Dialog PopupStyle } + Split SplitStyle ScrollBar ScrollBarStyle // iconCache is used to cache the icons created from iconvg data diff --git a/tracker/gioui/theme.yml b/tracker/gioui/theme.yml index 13e4ba0..ad328d7 100644 --- a/tracker/gioui/theme.yml +++ b/tracker/gioui/theme.yml @@ -210,3 +210,4 @@ dialog: titleinset: { top: 12, left: 20, right: 20 } textinset: { top: 12, bottom: 12, left: 20, right: 20 } buttons: *textbutton +split: { bar: 10, minsize1: 180, minsize2: 180 } diff --git a/tracker/gioui/tracker.go b/tracker/gioui/tracker.go index 5b30d0d..bef5c56 100644 --- a/tracker/gioui/tracker.go +++ b/tracker/gioui/tracker.go @@ -33,9 +33,9 @@ type ( Theme *Theme OctaveNumberInput *NumericUpDownState InstrumentVoices *NumericUpDownState - TopHorizontalSplit *Split - BottomHorizontalSplit *Split - VerticalSplit *Split + TopHorizontalSplit *SplitState + BottomHorizontalSplit *SplitState + VerticalSplit *SplitState KeyNoteMap Keyboard[key.Name] PopupAlert *AlertsState Zoom int @@ -79,9 +79,9 @@ func NewTracker(model *tracker.Model) *Tracker { OctaveNumberInput: NewNumericUpDownState(), InstrumentVoices: NewNumericUpDownState(), - TopHorizontalSplit: &Split{Ratio: -.5, MinSize1: 180, MinSize2: 180}, - BottomHorizontalSplit: &Split{Ratio: -.6, MinSize1: 180, MinSize2: 180}, - VerticalSplit: &Split{Axis: layout.Vertical, MinSize1: 180, MinSize2: 180}, + TopHorizontalSplit: &SplitState{Ratio: -.5}, + BottomHorizontalSplit: &SplitState{Ratio: -.6}, + VerticalSplit: &SplitState{Axis: layout.Vertical}, DialogState: new(DialogState), InstrumentEditor: NewInstrumentEditor(model), @@ -219,6 +219,7 @@ func (t *Tracker) Layout(gtx layout.Context, w *app.Window) { t.layoutTop(gtx) } else { t.VerticalSplit.Layout(gtx, + &t.Theme.Split, t.layoutTop, t.layoutBottom) } @@ -341,6 +342,7 @@ func (t *Tracker) explorerCreateFile(success func(io.WriteCloser), filename stri func (t *Tracker) layoutBottom(gtx layout.Context) layout.Dimensions { return t.BottomHorizontalSplit.Layout(gtx, + &t.Theme.Split, func(gtx C) D { return t.OrderEditor.Layout(gtx, t) }, @@ -352,6 +354,7 @@ func (t *Tracker) layoutBottom(gtx layout.Context) layout.Dimensions { func (t *Tracker) layoutTop(gtx layout.Context) layout.Dimensions { return t.TopHorizontalSplit.Layout(gtx, + &t.Theme.Split, func(gtx C) D { return t.SongPanel.Layout(gtx, t) },