Skip to content

Commit

Permalink
Add flex weight to BoxView
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaq committed Jan 19, 2025
1 parent 107a625 commit f186ddf
Show file tree
Hide file tree
Showing 10 changed files with 57 additions and 45 deletions.
2 changes: 1 addition & 1 deletion pkg/etk/comps/hiernav.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func HierNav(c etk.Context) (etk.View, etk.React) {
}
}

return etk.Box("parent* 1 [current*] 1 preview*", parent, currentView, preview),
return etk.Box("parent*1 1 [current*3] 1 preview*4", parent, currentView, preview),
func(e term.Event) etk.Reaction {
switch e {
case term.K(ui.Left):
Expand Down
80 changes: 46 additions & 34 deletions pkg/etk/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,32 +140,34 @@ type BoxView struct {

type BoxChild struct {
View View
Flex bool
Flex int // 0 for non-flex child, > 0 for flex weight
}

// Child verbs
// - "=" for non-flex child
// - "*" for flex child
// - "*" for flex child, may be followed by weight (default is 1)
//
// Example:
//
// a* b= c*

// Expressing focus
// a* b= c*2
//
// Names don't matter
//
// Expressing focus:
//
// a* [b=] c*2
//
// Expressing gap:
//
// a* 2 [b=] 1 c*2
//
// a* [b=] c*

// Expressing gap

// a* 2 [b=] 1 c*

// Calling box
//
// Box("a* [b=] c*", aView, bView, cView)
// Box("a* [b=] c*2", aView, bView, cView)
//
// Box(`a*
// [b=]
// c*`, aView, bView, cView)
// c*2`, aView, bView, cView)

func Box(layout string, views ...View) BoxView {
return BoxFocus(layout, 0, views...)
Expand Down Expand Up @@ -199,9 +201,17 @@ func BoxFocus(layout string, focus int, views ...View) BoxView {
verb = verb[1 : len(verb)-1]
focus = len(children)
}
var flex bool
if strings.HasSuffix(verb, "*") {
flex = true
var flexWeight int
if _, weight, ok := strings.Cut(verb, "*"); ok {
if weight == "" {
flexWeight = 1
} else {
var err error
flexWeight, err = strconv.Atoi(weight)
if err != nil {
panic(fmt.Sprintf("bad weight: %s", weight))
}
}
} else if strings.HasSuffix(verb, "=") {
} else if n, err := strconv.Atoi(verb); err == nil {
var view View
Expand All @@ -210,12 +220,12 @@ func BoxFocus(layout string, focus int, views ...View) BoxView {
} else {
view = VerticalGapView{n}
}
children = append(children, BoxChild{view, false})
children = append(children, BoxChild{view, 0})
continue
} else {
panic(fmt.Sprintf("invalid verb (must be number or end in * or =): %q", verb))
}
children = append(children, BoxChild{views[j], flex})
children = append(children, BoxChild{views[j], flexWeight})
j++
}
if j != len(views) {
Expand All @@ -225,19 +235,20 @@ func BoxFocus(layout string, focus int, views ...View) BoxView {
}

func (v BoxView) Render(width, height int) *term.Buffer {
var render func(View, bool) *term.Buffer
var flexChildren int
var render func(View, int) *term.Buffer
var flexWeightSum int
if v.Horizontal {
budget := width
render = func(v View, flex bool) *term.Buffer {
render = func(v View, flexWeight int) *term.Buffer {
width := budget
if flex {
width = budget / flexChildren
if flexWeight > 0 {
width = budget * flexWeight / flexWeightSum
flexWeightSum -= flexWeight
}
buf := v.Render(width, height)
// TODO: Maybe term.Buffer should keep track of the actual width
// itself
if !flex {
if flexWeight == 0 {
actualWidth := 0
for _, line := range buf.Lines {
actualWidth = max(actualWidth, cellsWidth(line))
Expand All @@ -249,10 +260,11 @@ func (v BoxView) Render(width, height int) *term.Buffer {
}
} else {
budget := height
render = func(v View, flex bool) *term.Buffer {
render = func(v View, flexWeight int) *term.Buffer {
height := budget
if flex {
height = budget / flexChildren
if flexWeight > 0 {
height = budget * flexWeight / flexWeightSum
flexWeightSum -= flexWeight
}
buf := v.Render(width, height)
budget -= len(buf.Lines)
Expand All @@ -263,17 +275,17 @@ func (v BoxView) Render(width, height int) *term.Buffer {
childBufs := make([]*term.Buffer, len(v.Children))
// Render non-flex children first.
for i, child := range v.Children {
if child.Flex {
flexChildren++
if child.Flex > 0 {
flexWeightSum += child.Flex
} else {
childBufs[i] = render(child.View, false)
childBufs[i] = render(child.View, 0)
}
}
// Render flex children first.
// Render flex children now.
for i, child := range v.Children {
if child.Flex {
childBufs[i] = render(child.View, true)
flexChildren--
if child.Flex > 0 {
childBufs[i] = render(child.View, child.Flex)
flexWeightSum--
}
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/etkedit/addon_completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func startCompletion(ed *Editor, c etk.Context) {
}
return r
}),
true,
1,
func() { pendingVar.Set(comps.PendingText{}) },
)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/etkedit/addon_histlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func startHistlist(ed *Editor, c etk.Context) {
// TODO: Implement insertion of selected item
return r
},
), true)
), 1)
}

type histlistItems struct {
Expand Down
2 changes: 1 addition & 1 deletion pkg/etkedit/addon_histwalk.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func startHistwalk(ed *Editor, c etk.Context) {
// TODO: Handle up/down
return r
}),
true,
1,
func() { pendingVar.Set(comps.PendingText{}) },
)
}
2 changes: 1 addition & 1 deletion pkg/etkedit/addon_lastcmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func startLastcmd(ed *Editor, c etk.Context) {
return items, 0
},
"binding", etkBindingFromBindingMap(ed, &ed.lastcmdBinding),
), true)
), 1)
}

type lastcmdItems struct {
Expand Down
2 changes: 1 addition & 1 deletion pkg/etkedit/addon_location.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func startLocation(ed *Editor, c etk.Context) {
return locationItems{dirs}, 0
},
"binding", etkBindingFromBindingMap(ed, &ed.locationBinding),
), true)
), 1)
}

type locationItems struct {
Expand Down
2 changes: 1 addition & 1 deletion pkg/etkedit/addon_minibuf.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func startMinibuf(c etk.Context) {
c.AddMsg(modes.ErrorText(err))
}
},
), true)
), 1)
}

// TODO: Is this the correct abstraction??
Expand Down
2 changes: 1 addition & 1 deletion pkg/etkedit/addon_navigation.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import "src.elv.sh/pkg/etk"
func startNavigation(ed *Editor, c etk.Context) {
pushAddon(c, etk.WithInit(
navigation,
"binding", etkBindingFromBindingMap(ed, &ed.navigationBinding)), true)
"binding", etkBindingFromBindingMap(ed, &ed.navigationBinding)), 1)
}

func navigation(c etk.Context) (etk.View, etk.React) {
Expand Down
6 changes: 3 additions & 3 deletions pkg/etkedit/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type addons struct {

type addon struct {
Comp etk.Comp
Flex bool
Flex int
Dismiss func()
ID int
}
Expand Down Expand Up @@ -77,11 +77,11 @@ func app(c etk.Context) (etk.View, etk.React) {
}
}

func pushAddon(c etk.Context, f etk.Comp, flex bool) {
func pushAddon(c etk.Context, f etk.Comp, flex int) {
pushAddonWithDismiss(c, f, flex, nil)
}

func pushAddonWithDismiss(c etk.Context, f etk.Comp, flex bool, dismiss func()) {
func pushAddonWithDismiss(c etk.Context, f etk.Comp, flex int, dismiss func()) {
addonsVar := etk.BindState(c, "addons", addons{})
addonsVar.Swap(func(a addons) addons {
// TODO: Is the use of append correct here??
Expand Down

0 comments on commit f186ddf

Please sign in to comment.