dive/runtime/ui/components/wrapper_primative.go
2021-02-15 13:13:08 -05:00

145 lines
3.6 KiB
Go

package components
import (
"fmt"
"strings"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
"github.com/wagoodman/dive/runtime/ui/components/helpers"
"github.com/wagoodman/dive/runtime/ui/format"
)
// This was pretty helpful: https://github.com/rivo/tview/wiki/Primitives
type wrappable interface {
getBox() *tview.Box
getDraw() drawFn
getInputWrapper() inputFn
GetKeyBindings() []helpers.KeyBindingDisplay
}
type Wrapper struct {
*tview.Box
flex *tview.Flex
titleTextView *tview.TextView
subtitleTextView *tview.TextView
inner wrappable
titleRightBox *tview.Box
title string
subtitle string
visible VisibleFunc
getKeyBindings func() []helpers.KeyBindingDisplay
}
type drawFn func(screen tcell.Screen)
type inputFn func() func(event *tcell.EventKey, setFocus func(p tview.Primitive))
func NewWrapper(title, subtitle string, inner wrappable) *Wrapper {
flex := tview.NewFlex().SetDirection(tview.FlexRow)
w := &Wrapper{
Box: flex.Box,
flex: flex,
title: title,
subtitle: subtitle,
titleTextView: tview.NewTextView().SetDynamicColors(true),
subtitleTextView: tview.NewTextView().SetText(subtitle),
inner: inner,
visible: Always(true),
getKeyBindings: inner.GetKeyBindings,
}
w.setTitle(w.inner.getBox().HasFocus())
return w
}
func (b *Wrapper) Setup() *Wrapper {
if b.title != "" {
innerflex := tview.NewFlex().SetDirection(tview.FlexColumn)
titleRightBox := tview.NewBox()
b.titleRightBox = titleRightBox
innerflex.AddItem(b.titleTextView.SetWrap(false).SetBorder(false), len(b.title)+10, 1, false)
innerflex.AddItem(titleRightBox, 0, 1, false)
b.flex.AddItem(innerflex, 1, 1, false)
}
if b.subtitle != "" {
b.flex.AddItem(b.subtitleTextView.SetText(b.subtitle).SetWrap(false).SetBorder(false), 1, 1, false)
}
b.flex.AddItem(b.inner.getBox().SetBorder(false), 0, 1, true)
return b
}
func (b *Wrapper) Draw(screen tcell.Screen) {
b.flex.Draw(screen)
if b.title != "" {
b.titleTextView.Draw(screen)
x, y, width, _ := b.titleRightBox.GetRect()
boarderRune := tview.BoxDrawingsLightHorizontal
if b.HasFocus() {
boarderRune = tview.BoxDrawingsHeavyHorizontal
}
for cx := x; cx < x+width; cx++ {
screen.SetContent(cx, y, boarderRune, nil, tcell.StyleDefault)
}
}
if b.subtitle != "" {
b.subtitleTextView.Draw(screen)
}
b.inner.getDraw()(screen)
}
func (b *Wrapper) Focus(delegate func(p tview.Primitive)) {
if b.title != "" {
b.setTitle(true)
}
b.inner.getBox().Focus(delegate)
}
func (b *Wrapper) Blur() {
if b.title != "" {
b.setTitle(false)
}
b.inner.getBox().Blur()
}
func (b *Wrapper) HasFocus() bool {
return b.inner.getBox().HasFocus()
}
func (b *Wrapper) InputHandler() func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
return b.inner.getInputWrapper()()
}
func (b *Wrapper) setTitle(hasFocus bool) {
prefix := ""
postfix := strings.Repeat(string(tview.BoxDrawingsLightHorizontal), 10)
if hasFocus {
prefix = "● "
postfix = strings.Repeat(string(tview.BoxDrawingsHeavyHorizontal), 10)
}
content := format.Header(fmt.Sprintf("%s%s", prefix, b.title))
title := fmt.Sprintf("│ %s ├%s", content, postfix)
if hasFocus {
content = format.Header(fmt.Sprintf("%s%s", prefix, b.title))
title = fmt.Sprintf("┃ %s ┣%s", content, postfix)
}
b.titleTextView.SetText(title)
}
func (b *Wrapper) Visible() bool {
return b.visible(b)
}
func (b *Wrapper) SetVisibility(visibleFunc VisibleFunc) *Wrapper {
b.visible = visibleFunc
return b
}
func (b *Wrapper) GetKeyBindings() []helpers.KeyBindingDisplay {
return b.getKeyBindings()
}