package tracker import ( "image" "gioui.org/f32" "gioui.org/io/pointer" "gioui.org/layout" "gioui.org/op" "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.Value drag bool dragID pointer.ID dragX float32 } var defaultBarWidth = unit.Dp(10) func (s *Split) Layout(gtx layout.Context, left, right layout.Widget) layout.Dimensions { bar := gtx.Px(s.Bar) if bar <= 1 { bar = gtx.Px(defaultBarWidth) } proportion := (s.Ratio + 1) / 2 leftsize := int(proportion*float32(gtx.Constraints.Max.X) - float32(bar)) rightoffset := leftsize + bar rightsize := gtx.Constraints.Max.X - rightoffset { // handle input // Avoid affecting the input tree with pointer events. stack := op.Push(gtx.Ops) for _, ev := range gtx.Events(s) { e, ok := ev.(pointer.Event) if !ok { continue } switch e.Type { case pointer.Press: if s.drag { break } s.dragID = e.PointerID s.dragX = e.Position.X case pointer.Drag: if s.dragID != e.PointerID { break } deltaX := e.Position.X - s.dragX s.dragX = e.Position.X deltaRatio := deltaX * 2 / float32(gtx.Constraints.Max.X) s.Ratio += deltaRatio case pointer.Release: fallthrough case pointer.Cancel: s.drag = false } } // register for input barRect := image.Rect(leftsize, 0, rightoffset, gtx.Constraints.Max.X) pointer.Rect(barRect).Add(gtx.Ops) pointer.InputOp{Tag: s, Types: pointer.Press | pointer.Drag | pointer.Release, Grab: s.drag, }.Add(gtx.Ops) stack.Pop() } { stack := op.Push(gtx.Ops) gtx := gtx gtx.Constraints = layout.Exact(image.Pt(leftsize, gtx.Constraints.Max.Y)) left(gtx) stack.Pop() } { stack := op.Push(gtx.Ops) op.Offset(f32.Pt(float32(rightoffset), 0)).Add(gtx.Ops) gtx := gtx gtx.Constraints = layout.Exact(image.Pt(rightsize, gtx.Constraints.Max.Y)) right(gtx) stack.Pop() } return layout.Dimensions{Size: gtx.Constraints.Max} }