Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(SplitLayout): support different sashPos interpretations #925

Merged
merged 3 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 80 additions & 11 deletions SplitLayout.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@ const (
DirectionVertical
)

// SplitRefType describes how sashPos argument to the SplitLayout should be interpreted.
type SplitRefType byte

const (
// SplitRefLeft is the default. Splitter placed counting from left/top layout's edge.
SplitRefLeft SplitRefType = iota
// SplitRefRight splitter placed counting from right/bottom layout's edge.
SplitRefRight
// SplitRefProc sashPos will be clamped in range [0, 1]. Then the position is considered a percent of GetAvailableRegion.
SplitRefProc
)

var _ Disposable = &splitLayoutState{}

type splitLayoutState struct {
Expand All @@ -40,6 +52,7 @@ type SplitLayoutWidget struct {
originFramePaddingY float32
sashPos *float32
border bool
splitRefType SplitRefType
}

// SplitLayout creates split layout widget.
Expand All @@ -66,42 +79,75 @@ func (s *SplitLayoutWidget) ID(id ID) *SplitLayoutWidget {
return s
}

// SplitRefType allows to set how sashPos should be interpreted.
// Default is counting from left/top layout's edge in px.
func (s *SplitLayoutWidget) SplitRefType(refType SplitRefType) *SplitLayoutWidget {
s.splitRefType = refType
return s
}

// Build implements widget interface.
func (s *SplitLayoutWidget) Build() {
splitLayoutState := s.getState()
s.originItemSpacingX, s.originItemSpacingY = GetItemInnerSpacing()
s.originFramePaddingX, s.originFramePaddingY = GetFramePadding()
availableW, availableH := GetAvailableRegion()

var layout Layout

*s.sashPos += splitLayoutState.delta
if *s.sashPos < 1 {
*s.sashPos = 1
var sashPos float32

switch s.splitRefType {
case SplitRefLeft:
sashPos = *s.sashPos
case SplitRefRight:
switch s.direction {
case DirectionHorizontal:
sashPos = availableH - *s.sashPos
case DirectionVertical:
sashPos = availableW - *s.sashPos
}
case SplitRefProc:
if *s.sashPos < 0 {
*s.sashPos = 0
} else if *s.sashPos > 1 {
*s.sashPos = 1
}

switch s.direction {
case DirectionHorizontal:
sashPos = availableH * *s.sashPos
case DirectionVertical:
sashPos = availableW * *s.sashPos
}
}

sashPos += splitLayoutState.delta
if sashPos < 1 {
sashPos = 1
}

switch s.direction {
case DirectionHorizontal:
_, availableH := GetAvailableRegion()
if *s.sashPos >= availableH {
*s.sashPos = availableH
if sashPos >= availableH {
sashPos = availableH
}

layout = Layout{
Column(
s.buildChild(Auto, *s.sashPos, s.layout1),
s.buildChild(Auto, sashPos, s.layout1),
Splitter(DirectionHorizontal, &(splitLayoutState.delta)).Size(0, s.originItemSpacingY),
s.buildChild(Auto, Auto, s.layout2),
),
}
case DirectionVertical:
availableW, _ := GetAvailableRegion()
if *s.sashPos >= availableW {
*s.sashPos = availableW
if sashPos >= availableW {
sashPos = availableW
}

layout = Layout{
Row(
s.buildChild(*s.sashPos, Auto, s.layout1),
s.buildChild(sashPos, Auto, s.layout1),
Splitter(DirectionVertical, &(splitLayoutState.delta)).Size(s.originItemSpacingX, 0),
s.buildChild(Auto, Auto, s.layout2),
),
Expand All @@ -111,6 +157,29 @@ func (s *SplitLayoutWidget) Build() {
PushItemSpacing(0, 0)
layout.Build()
PopStyle()

s.encodeSashPos(sashPos, availableW, availableH)
}

func (s *SplitLayoutWidget) encodeSashPos(sashPos, availableW, availableH float32) {
switch s.splitRefType {
case SplitRefLeft:
*s.sashPos = sashPos
case SplitRefRight:
switch s.direction {
case DirectionHorizontal:
*s.sashPos = availableH - sashPos
case DirectionVertical:
*s.sashPos = availableW - sashPos
}
case SplitRefProc:
switch s.direction {
case DirectionHorizontal:
*s.sashPos = sashPos / availableH
case DirectionVertical:
*s.sashPos = sashPos / availableW
}
}
}

func (s *SplitLayoutWidget) restoreItemSpacing(layout Widget) Layout {
Expand Down
17 changes: 11 additions & 6 deletions examples/splitter/splitter.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (

var (
sashPos1 float32 = 200
sashPos2 float32 = 200
sashPos3 float32 = 200
sashPos2 float32 = 400
sashPos3 float32 = 0.5
sashPos4 float32 = 100
)

Expand All @@ -18,17 +18,22 @@ func loop() {
g.Layout{
g.Label("Left panel"),
g.Row(g.Button("Button1"), g.Button("Button2")),
g.Label("Info: These SplitLayouts have different SplitRefTypes. Try to resize MasterWindow and see what happens."),
},
g.SplitLayout(g.DirectionVertical, &sashPos2,
g.Layout{},
g.Layout{
g.Label("This split is counted from right edge."),
},
g.SplitLayout(g.DirectionHorizontal, &sashPos3,
g.Layout{},
g.Layout{
g.Label("This starts from 50%"),
},
g.SplitLayout(g.DirectionVertical, &sashPos4,
g.Layout{},
g.Layout{},
),
),
),
).SplitRefType(g.SplitRefProc),
).SplitRefType(g.SplitRefRight),
),
)
}
Expand Down
Loading