diff --git a/center.go b/center.go new file mode 100644 index 00000000..e767ffae --- /dev/null +++ b/center.go @@ -0,0 +1,113 @@ +package tview + +import ( + "github.com/gdamore/tcell/v2" +) + +// Center is a wrapper which adds space around another primitive to shot up in the middle. +type Center struct { + *Box + + // the contained primitive + primitive Primitive + + width, height int + + // keep a reference in case we need it when we change the primitive + setFocus func(p Primitive) +} + +// NewCenter returns a new frame around the given primitive. +func NewCenter(primitive Primitive, width, height int) *Center { + return &Center{Box: NewBox(), primitive: primitive, width: width, height: height} +} + +func (c *Center) Resize(width, height int) *Center { + if width > 0 { + c.width = width + } + if height > 0 { + c.height = height + } + return c +} + +// SetPrimitive replaces the contained primitive with the given one. +func (c *Center) SetPrimitive(p Primitive) *Center { + hasFocus := c.primitive.HasFocus() + c.primitive = p + if hasFocus && c.setFocus != nil { + c.setFocus(p) // Restore focus. + } + return c +} + +// Primitive returns the primitive contained in this frame. +func (c *Center) Primitive() Primitive { + return c.primitive +} + +// Draw draws this primitive onto the screen. +func (c *Center) Draw(screen tcell.Screen) { + x, y, inWidth, inHeight := c.GetInnerRect() + width, height := c.width, c.height + if width < inWidth { + x += (inWidth - width) >> 1 + } else if width > inWidth { + width = inWidth + } + if height < inHeight { + y += (inHeight - height) >> 1 + } else if height > inHeight { + height = inHeight + } + + c.Box.Draw(screen) + c.primitive.SetRect(x, y, width, height) + c.primitive.Draw(screen) +} + +// Focus is called when this primitive receives focus. +func (c *Center) Focus(delegate func(p Primitive)) { + c.setFocus = delegate + delegate(c.primitive) + c.Box.Focus(delegate) +} + +// HasFocus returns whether or not this primitive has focus. +func (c *Center) HasFocus() bool { + return c.primitive.HasFocus() +} + +// MouseHandler returns the mouse handler for this primitive. +func (c *Center) MouseHandler() func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) { + return c.WrapMouseHandler(func(action MouseAction, event *tcell.EventMouse, setFocus func(p Primitive)) (consumed bool, capture Primitive) { + if !c.InRect(event.Position()) { + return false, nil + } + + // Pass mouse events on to contained primitive. + consumed, capture = c.primitive.MouseHandler()(action, event, setFocus) + if consumed { + return true, capture + } + + // Clicking on the frame parts. + if action == MouseLeftDown { + setFocus(c) + consumed = true + } + + return + }) +} + +// InputHandler returns the handler for this primitive. +func (c *Center) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) { + return c.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) { + if handler := c.primitive.InputHandler(); handler != nil { + handler(event, setFocus) + return + } + }) +} diff --git a/demos/center/README.md b/demos/center/README.md new file mode 100644 index 00000000..4a14e6c1 --- /dev/null +++ b/demos/center/README.md @@ -0,0 +1 @@ +![Screenshot](screenshot.png) diff --git a/demos/center/main.go b/demos/center/main.go new file mode 100644 index 00000000..a95c75fd --- /dev/null +++ b/demos/center/main.go @@ -0,0 +1,29 @@ +// Demo code for the Centered Modal primitive. +package main + +import ( + "strings" + + "github.com/gdamore/tcell/v2" + "github.com/rivo/tview" +) + +func main() { + app := tview.NewApplication() + + background := tview.NewTextView(). + SetTextColor(tcell.ColorBlue). + SetText(strings.Repeat("background ", 1000)) + + box := tview.NewBox(). + SetBorder(true). + SetTitle("Centered Box") + + pages := tview.NewPages(). + AddPage("background", background, true, true). + AddPage("modal", tview.NewCenter(box, 40, 10), true, true) + + if err := app.SetRoot(pages, true).Run(); err != nil { + panic(err) + } +} diff --git a/demos/modal/centered.png b/demos/center/screenshot.png similarity index 100% rename from demos/modal/centered.png rename to demos/center/screenshot.png diff --git a/demos/presentation/center.go b/demos/presentation/center.go deleted file mode 100644 index dd34da0a..00000000 --- a/demos/presentation/center.go +++ /dev/null @@ -1,16 +0,0 @@ -package main - -import "github.com/rivo/tview" - -// Center returns a new primitive which shows the provided primitive in its -// center, given the provided primitive's size. -func Center(width, height int, p tview.Primitive) tview.Primitive { - return tview.NewFlex(). - AddItem(nil, 0, 1, false). - AddItem(tview.NewFlex(). - SetDirection(tview.FlexRow). - AddItem(nil, 0, 1, false). - AddItem(p, height, 1, true). - AddItem(nil, 0, 1, false), width, 1, true). - AddItem(nil, 0, 1, false) -} diff --git a/demos/presentation/code.go b/demos/presentation/code.go index 59fd0485..74ff1700 100644 --- a/demos/presentation/code.go +++ b/demos/presentation/code.go @@ -20,6 +20,6 @@ func Code(p tview.Primitive, width, height int, code string) tview.Primitive { fmt.Fprint(codeView, code) return tview.NewFlex(). - AddItem(Center(width, height, p), 0, 1, true). + AddItem(tview.NewCenter(p, width, height), 0, 1, true). AddItem(codeView, codeWidth, 1, false) } diff --git a/demos/presentation/colors.go b/demos/presentation/colors.go index d2777506..a0d7f870 100644 --- a/demos/presentation/colors.go +++ b/demos/presentation/colors.go @@ -29,5 +29,5 @@ func Colors(nextSlide func()) (title string, content tview.Primitive) { table.SetBorderPadding(1, 1, 2, 2). SetBorder(true). SetTitle("A [red]c[yellow]o[green]l[darkcyan]o[blue]r[darkmagenta]f[red]u[yellow]l[white] [black:red]c[:yellow]o[:green]l[:darkcyan]o[:blue]r[:darkmagenta]f[:red]u[:yellow]l[white:] [::bu]title") - return "Colors", Center(78, 19, table) + return "Colors", tview.NewCenter(table, 78, 19) } diff --git a/demos/presentation/end.go b/demos/presentation/end.go index c085b31d..9ce481b4 100644 --- a/demos/presentation/end.go +++ b/demos/presentation/end.go @@ -14,5 +14,5 @@ func End(nextSlide func()) (title string, content tview.Primitive) { }) url := "https://github.com/rivo/tview" fmt.Fprint(textView, url) - return "End", Center(len(url), 1, textView) + return "End", tview.NewCenter(textView, len(url), 1) } diff --git a/demos/presentation/introduction.go b/demos/presentation/introduction.go index 8dc0f0c8..876ce2d2 100644 --- a/demos/presentation/introduction.go +++ b/demos/presentation/introduction.go @@ -10,5 +10,5 @@ func Introduction(nextSlide func()) (title string, content tview.Primitive) { AddItem("Designed to be simple", `"Hello world" is 5 lines of code`, '3', nextSlide). AddItem("Good for data entry", `For charts, use "termui" - for low-level views, use "gocui" - ...`, '4', nextSlide). AddItem("Extensive documentation", "Everything is documented, examples in GitHub wiki, demo code for each widget", '5', nextSlide) - return "Introduction", Center(80, 10, list) + return "Introduction", tview.NewCenter(list, 80, 10) }