Merge branch 'master' into master

pull/497/head
Eze Olea Figueroa 3 years ago committed by GitHub
commit da88cafbf9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,6 +1,6 @@
# Rich Interactive Widgets for Terminal UIs
[![Godoc Reference](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/rivo/tview)
[![PkgGoDev](https://pkg.go.dev/badge/github.com/rivo/tview)](https://pkg.go.dev/github.com/rivo/tview)
[![Go Report](https://img.shields.io/badge/go%20report-A%2B-brightgreen.svg)](https://goreportcard.com/report/github.com/rivo/tview)
This Go package provides commonly needed components for terminal based user interfaces.
@ -51,6 +51,7 @@ For a presentation highlighting this package, compile and run the program found
## Projects using `tview`
- [IRCCloud Terminal Client](https://github.com/termoose/irccloud)
- [Window manager for `tview`](https://github.com/epiclabs-io/winman)
- [Password manager](https://github.com/7onetella/password)
- [CLI bookmark manager](https://github.com/Endi1/drawer)
@ -84,15 +85,25 @@ For a presentation highlighting this package, compile and run the program found
- [Cryptowatch Go SDK](https://github.com/y3sh/cw-sdk-go)
- [Discord, TUI and SIXEL.](https://gitlab.com/diamondburned/6cord)
- [A terminal based blogs reader](https://github.com/ezeoleaf/tblogs)
- [A CLI Audio Player](https://www.github.com/dhulihan/grump)
- [GLab, a GitLab CLI tool](https://gitlab.com/profclems/glab)
## Documentation
Refer to https://pkg.go.dev/github.com/rivo/tview for the package's documentation.
Refer to https://pkg.go.dev/github.com/rivo/tview for the package's documentation. Also check out the [Wiki](https://github.com/rivo/tview/wiki).
## Dependencies
This package is based on [github.com/gdamore/tcell](https://github.com/gdamore/tcell) (and its dependencies) as well as on [github.com/rivo/uniseg](https://github.com/rivo/uniseg).
## Versioning and Backwards-Compatibility
I try really hard to keep this project backwards compatible. Your software should not break when you upgrade `tview`. But this also means that some of its shortcomings that were present in the initial versions will remain. In addition, at least for the time being, you won't find any version tags in this repo. The newest version should be the one to upgrade to. It has all the bugfixes and latest features. Having said that, backwards compatibility may still break when:
- a new version of an imported package (most likely [`tcell`](https://github.com/gdamore/tcell)) changes in such a way that forces me to make changes in `tview` as well,
- I fix something that I consider a bug, rather than a feature, something that does not work as originally intended,
- I make changes to "internal" interfaces such as [`Primitive`](https://pkg.go.dev/github.com/rivo/tview#Primitive). You shouldn't need these interfaces unless you're writing your own primitives for `tview`. (Yes, I realize these are public interfaces. This has advantages as well as disadvantages. For the time being, it is what it is.)
## Your Feedback
Add your issue here on GitHub. Feel free to get in touch if you have any questions.

@ -4,7 +4,7 @@ import (
"sync"
"time"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
)
const (
@ -325,7 +325,7 @@ EventLoop:
}
// Pass other key events to the root primitive.
if root != nil && root.GetFocusable().HasFocus() {
if root != nil && root.HasFocus() {
if handler := root.InputHandler(); handler != nil {
handler(event, func(p Primitive) {
a.SetFocus(p)
@ -514,6 +514,14 @@ func (a *Application) Suspend(f func()) bool {
// Wait for "f" to return.
f()
// If stop was called in the meantime (a.screen is nil), we're done already.
a.RLock()
screen = a.screen
a.RUnlock()
if screen == nil {
return true
}
// Make a new screen.
var err error
screen, err = tcell.NewScreen()

@ -1,7 +1,7 @@
package tview
import (
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
)
// Box implements the Primitive interface with an empty background and optional
@ -30,11 +30,8 @@ type Box struct {
// two in width and height.
border bool
// The color of the border.
borderColor tcell.Color
// The style attributes of the border.
borderAttributes tcell.AttrMask
// The border style.
borderStyle tcell.Style
// The title. Only visible if there is a border, too.
title string
@ -45,10 +42,6 @@ type Box struct {
// The alignment of the title.
titleAlign int
// Provides a way to find out if this box has focus. We always go through
// this interface because it may be overridden by implementing classes.
focus Focusable
// Whether or not this box has focus.
hasFocus bool
@ -73,11 +66,10 @@ func NewBox() *Box {
height: 10,
innerX: -1, // Mark as uninitialized.
backgroundColor: Styles.PrimitiveBackgroundColor,
borderColor: Styles.BorderColor,
borderStyle: tcell.StyleDefault.Foreground(Styles.BorderColor),
titleColor: Styles.TitleColor,
titleAlign: AlignCenter,
}
b.focus = b
return b
}
@ -267,7 +259,7 @@ func (b *Box) SetBorder(show bool) *Box {
// SetBorderColor sets the box's border color.
func (b *Box) SetBorderColor(color tcell.Color) *Box {
b.borderColor = color
b.borderStyle = b.borderStyle.Foreground(color)
return b
}
@ -276,18 +268,20 @@ func (b *Box) SetBorderColor(color tcell.Color) *Box {
//
// box.SetBorderAttributes(tcell.AttrUnderline | tcell.AttrBold)
func (b *Box) SetBorderAttributes(attr tcell.AttrMask) *Box {
b.borderAttributes = attr
b.borderStyle = b.borderStyle.Attributes(attr)
return b
}
// GetBorderAttributes returns the border's style attributes.
func (b *Box) GetBorderAttributes() tcell.AttrMask {
return b.borderAttributes
_, _, attr := b.borderStyle.Decompose()
return attr
}
// GetBorderColor returns the box's border color.
func (b *Box) GetBorderColor() tcell.Color {
return b.borderColor
color, _, _ := b.borderStyle.Decompose()
return color
}
// GetBackgroundColor returns the box's background color.
@ -321,6 +315,16 @@ func (b *Box) SetTitleAlign(align int) *Box {
// Draw draws this primitive onto the screen.
func (b *Box) Draw(screen tcell.Screen) {
b.DrawForSubclass(screen, b)
}
// DrawForSubclass draws this box under the assumption that primitive p is a
// subclass of this box. This is needed e.g. to draw proper box frames which
// depend on the subclass's focus.
//
// Only call this function from your own custom primitives. It is not needed in
// applications that have no custom primitives.
func (b *Box) DrawForSubclass(screen tcell.Screen, p Primitive) {
// Don't draw anything if there is no space.
if b.width <= 0 || b.height <= 0 {
return
@ -340,9 +344,8 @@ func (b *Box) Draw(screen tcell.Screen) {
// Draw border.
if b.border && b.width >= 2 && b.height >= 2 {
border := background.Foreground(b.borderColor) | tcell.Style(b.borderAttributes)
var vertical, horizontal, topLeft, topRight, bottomLeft, bottomRight rune
if b.focus.HasFocus() {
if p.HasFocus() {
horizontal = Borders.HorizontalFocus
vertical = Borders.VerticalFocus
topLeft = Borders.TopLeftFocus
@ -358,17 +361,17 @@ func (b *Box) Draw(screen tcell.Screen) {
bottomRight = Borders.BottomRight
}
for x := b.x + 1; x < b.x+b.width-1; x++ {
screen.SetContent(x, b.y, horizontal, nil, border)
screen.SetContent(x, b.y+b.height-1, horizontal, nil, border)
screen.SetContent(x, b.y, horizontal, nil, b.borderStyle)
screen.SetContent(x, b.y+b.height-1, horizontal, nil, b.borderStyle)
}
for y := b.y + 1; y < b.y+b.height-1; y++ {
screen.SetContent(b.x, y, vertical, nil, border)
screen.SetContent(b.x+b.width-1, y, vertical, nil, border)
screen.SetContent(b.x, y, vertical, nil, b.borderStyle)
screen.SetContent(b.x+b.width-1, y, vertical, nil, b.borderStyle)
}
screen.SetContent(b.x, b.y, topLeft, nil, border)
screen.SetContent(b.x+b.width-1, b.y, topRight, nil, border)
screen.SetContent(b.x, b.y+b.height-1, bottomLeft, nil, border)
screen.SetContent(b.x+b.width-1, b.y+b.height-1, bottomRight, nil, border)
screen.SetContent(b.x, b.y, topLeft, nil, b.borderStyle)
screen.SetContent(b.x+b.width-1, b.y, topRight, nil, b.borderStyle)
screen.SetContent(b.x, b.y+b.height-1, bottomLeft, nil, b.borderStyle)
screen.SetContent(b.x+b.width-1, b.y+b.height-1, bottomRight, nil, b.borderStyle)
// Draw title.
if b.title != "" && b.width >= 4 {
@ -405,8 +408,3 @@ func (b *Box) Blur() {
func (b *Box) HasFocus() bool {
return b.hasFocus
}
// GetFocusable returns the item's Focusable.
func (b *Box) GetFocusable() Focusable {
return b.focus
}

@ -1,7 +1,7 @@
package tview
import (
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
)
// Button is labeled box that triggers an action when selected.
@ -95,16 +95,16 @@ func (b *Button) SetBlurFunc(handler func(key tcell.Key)) *Button {
// Draw draws this primitive onto the screen.
func (b *Button) Draw(screen tcell.Screen) {
// Draw the box.
borderColor := b.borderColor
backgroundColor := b.backgroundColor
if b.focus.HasFocus() {
b.backgroundColor = b.backgroundColorActivated
b.borderColor = b.labelColorActivated
borderColor := b.GetBorderColor()
backgroundColor := b.GetBackgroundColor()
if b.HasFocus() {
b.SetBackgroundColor(b.backgroundColorActivated)
b.SetBorderColor(b.labelColorActivated)
defer func() {
b.borderColor = borderColor
b.SetBorderColor(borderColor)
}()
}
b.Box.Draw(screen)
b.Box.DrawForSubclass(screen, b)
b.backgroundColor = backgroundColor
// Draw label.
@ -112,7 +112,7 @@ func (b *Button) Draw(screen tcell.Screen) {
if width > 0 && height > 0 {
y = y + height/2
labelColor := b.labelColor
if b.focus.HasFocus() {
if b.HasFocus() {
labelColor = b.labelColorActivated
}
Print(screen, b.label, x, y, width, AlignCenter, labelColor)

@ -1,7 +1,9 @@
package tview
import (
"github.com/gdamore/tcell"
"strings"
"github.com/gdamore/tcell/v2"
)
// Checkbox implements a simple box for boolean values which can be checked and
@ -30,6 +32,9 @@ type Checkbox struct {
// The text color of the input area.
fieldTextColor tcell.Color
// The string use to display a checked box.
checkedString string
// An optional function which is called when the user changes the checked
// state of this checkbox.
changed func(checked bool)
@ -51,6 +56,7 @@ func NewCheckbox() *Checkbox {
labelColor: Styles.SecondaryTextColor,
fieldBackgroundColor: Styles.ContrastBackgroundColor,
fieldTextColor: Styles.PrimaryTextColor,
checkedString: "X",
}
}
@ -101,6 +107,13 @@ func (c *Checkbox) SetFieldTextColor(color tcell.Color) *Checkbox {
return c
}
// SetCheckedString sets the string to be displayed when the checkbox is
// checked (defaults to "X").
func (c *Checkbox) SetCheckedString(checked string) *Checkbox {
c.checkedString = checked
return c
}
// SetFormAttributes sets attributes shared by all form items.
func (c *Checkbox) SetFormAttributes(labelWidth int, labelColor, bgColor, fieldTextColor, fieldBgColor tcell.Color) FormItem {
c.labelWidth = labelWidth
@ -144,7 +157,7 @@ func (c *Checkbox) SetFinishedFunc(handler func(key tcell.Key)) FormItem {
// Draw draws this primitive onto the screen.
func (c *Checkbox) Draw(screen tcell.Screen) {
c.Box.Draw(screen)
c.Box.DrawForSubclass(screen, c)
// Prepare
x, y, width, height := c.GetInnerRect()
@ -168,14 +181,15 @@ func (c *Checkbox) Draw(screen tcell.Screen) {
// Draw checkbox.
fieldStyle := tcell.StyleDefault.Background(c.fieldBackgroundColor).Foreground(c.fieldTextColor)
if c.focus.HasFocus() {
if c.HasFocus() {
fieldStyle = fieldStyle.Background(c.fieldTextColor).Foreground(c.fieldBackgroundColor)
}
checkedRune := 'X'
checkboxWidth := stringWidth(c.checkedString)
checkedString := c.checkedString
if !c.checked {
checkedRune = ' '
checkedString = strings.Repeat(" ", checkboxWidth)
}
screen.SetContent(x, y, checkedRune, nil, fieldStyle)
printWithStyle(screen, checkedString, x, y, checkboxWidth, AlignLeft, fieldStyle)
}
// InputHandler returns the handler for this primitive.

@ -2,7 +2,7 @@
package main
import (
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)

@ -2,7 +2,7 @@
package main
import (
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)

@ -3,7 +3,7 @@ package main
import (
"strings"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)

@ -7,7 +7,7 @@ import (
"strings"
"sync"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)

@ -2,7 +2,7 @@
package main
import (
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)

@ -3,7 +3,7 @@ package main
import (
"strings"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)

@ -4,7 +4,7 @@ import (
"fmt"
"strings"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)

@ -3,7 +3,7 @@ package main
import (
"fmt"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)

@ -1,7 +1,7 @@
package main
import (
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)

@ -1,7 +1,7 @@
package main
import (
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)

@ -1,7 +1,7 @@
package main
import (
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)

@ -1,7 +1,7 @@
package main
import (
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)
@ -10,7 +10,7 @@ const inputField = `[green]package[white] main
[green]import[white] (
[red]"strconv"[white]
[red]"github.com/gdamore/tcell"[white]
[red]"github.com/gdamore/tcell/v2"[white]
[red]"github.com/rivo/tview"[white]
)

@ -16,7 +16,7 @@ import (
"fmt"
"strconv"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)

@ -4,7 +4,7 @@ import (
"fmt"
"strings"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)

@ -5,7 +5,7 @@ import (
"strconv"
"time"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)
@ -68,7 +68,7 @@ const textView2 = `[green]package[white] main
[green]import[white] (
[red]"strconv"[white]
[red]"github.com/gdamore/tcell"[white]
[red]"github.com/gdamore/tcell/v2"[white]
[red]"github.com/rivo/tview"[white]
)

@ -3,7 +3,7 @@ package main
import (
"strings"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)

@ -4,7 +4,7 @@ package main
import (
"fmt"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)
@ -25,7 +25,7 @@ func NewRadioButtons(options []string) *RadioButtons {
// Draw draws this primitive onto the screen.
func (r *RadioButtons) Draw(screen tcell.Screen) {
r.Box.Draw(screen)
r.Box.DrawForSubclass(screen, r)
x, y, width, height := r.GetInnerRect()
for index, option := range r.options {
@ -59,12 +59,34 @@ func (r *RadioButtons) InputHandler() func(event *tcell.EventKey, setFocus func(
})
}
// MouseHandler returns the mouse handler for this primitive.
func (r *RadioButtons) MouseHandler() func(action tview.MouseAction, event *tcell.EventMouse, setFocus func(p tview.Primitive)) (consumed bool, capture tview.Primitive) {
return r.WrapMouseHandler(func(action tview.MouseAction, event *tcell.EventMouse, setFocus func(p tview.Primitive)) (consumed bool, capture tview.Primitive) {
x, y := event.Position()
_, rectY, _, _ := r.GetInnerRect()
if !r.InRect(x, y) {
return false, nil
}
if action == tview.MouseLeftClick {
setFocus(r)
index := y - rectY
if index >= 0 && index < len(r.options) {
r.currentOption = index
consumed = true
}
}
return
})
}
func main() {
radioButtons := NewRadioButtons([]string{"Lions", "Elephants", "Giraffes"})
radioButtons.SetBorder(true).
SetTitle("Radio Button Demo").
SetRect(0, 0, 30, 5)
if err := tview.NewApplication().SetRoot(radioButtons, false).Run(); err != nil {
if err := tview.NewApplication().SetRoot(radioButtons, false).EnableMouse(true).Run(); err != nil {
panic(err)
}
}

@ -4,7 +4,7 @@ package main
import (
"strings"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)

@ -7,7 +7,7 @@ import (
"strings"
"time"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)

@ -5,7 +5,7 @@ import (
"io/ioutil"
"path/filepath"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)

@ -169,8 +169,7 @@ Type Hierarchy
All widgets listed above contain the Box type. All of Box's functions are
therefore available for all widgets, too.
All widgets also implement the Primitive interface. There is also the Focusable
interface which is used to override functions in subclassing types.
All widgets also implement the Primitive interface.
The tview package is based on https://github.com/gdamore/tcell. It uses types
and constants from that package (e.g. colors and keyboard values).

@ -3,7 +3,7 @@ package tview
import (
"strings"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
)
// dropDownOption is one option that can be selected in a drop-down primitive.
@ -103,8 +103,6 @@ func NewDropDown() *DropDown {
prefixTextColor: Styles.ContrastSecondaryTextColor,
}
d.focus = d
return d
}
@ -288,7 +286,7 @@ func (d *DropDown) SetFinishedFunc(handler func(key tcell.Key)) FormItem {
// Draw draws this primitive onto the screen.
func (d *DropDown) Draw(screen tcell.Screen) {
d.Box.Draw(screen)
d.Box.DrawForSubclass(screen, d)
// Prepare.
x, y, width, height := d.GetInnerRect()
@ -340,7 +338,7 @@ func (d *DropDown) Draw(screen tcell.Screen) {
fieldWidth = rightLimit - x
}
fieldStyle := tcell.StyleDefault.Background(d.fieldBackgroundColor)
if d.GetFocusable().HasFocus() && !d.open {
if d.HasFocus() && !d.open {
fieldStyle = fieldStyle.Background(d.fieldTextColor)
}
for index := 0; index < fieldWidth; index++ {
@ -365,7 +363,7 @@ func (d *DropDown) Draw(screen tcell.Screen) {
text = d.currentOptionPrefix + d.options[d.currentOption].Text + d.currentOptionSuffix
}
// Just show the current selection.
if d.GetFocusable().HasFocus() && !d.open {
if d.HasFocus() && !d.open {
color = d.fieldBackgroundColor
}
Print(screen, text, x, y, fieldWidth, AlignLeft, color)
@ -397,7 +395,7 @@ func (d *DropDown) Draw(screen tcell.Screen) {
func (d *DropDown) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
return d.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) {
// If the list has focus, let it process its own key events.
if d.list.GetFocusable().HasFocus() {
if d.list.HasFocus() {
if handler := d.list.InputHandler(); handler != nil {
handler(event, setFocus)
}

@ -1,7 +1,7 @@
package tview
import (
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
)
// Configuration values.
@ -53,7 +53,6 @@ func NewFlex() *Flex {
Box: NewBox().SetBackgroundColor(tcell.ColorDefault),
direction: FlexColumn,
}
f.focus = f
return f
}
@ -122,7 +121,7 @@ func (f *Flex) ResizeItem(p Primitive, fixedSize, proportion int) *Flex {
// Draw draws this primitive onto the screen.
func (f *Flex) Draw(screen tcell.Screen) {
f.Box.Draw(screen)
f.Box.DrawForSubclass(screen, f)
// Calculate size and position of the items.
@ -173,7 +172,7 @@ func (f *Flex) Draw(screen tcell.Screen) {
pos += size
if item.Item != nil {
if item.Item.GetFocusable().HasFocus() {
if item.Item.HasFocus() {
defer item.Item.Draw(screen)
} else {
item.Item.Draw(screen)
@ -195,7 +194,7 @@ func (f *Flex) Focus(delegate func(p Primitive)) {
// HasFocus returns whether or not this primitive has focus.
func (f *Flex) HasFocus() bool {
for _, item := range f.items {
if item.Item != nil && item.Item.GetFocusable().HasFocus() {
if item.Item != nil && item.Item.HasFocus() {
return true
}
}
@ -228,7 +227,7 @@ func (f *Flex) MouseHandler() func(action MouseAction, event *tcell.EventMouse,
func (f *Flex) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
return f.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) {
for _, item := range f.items {
if item.Item != nil && item.Item.GetFocusable().HasFocus() {
if item.Item != nil && item.Item.HasFocus() {
if handler := item.Item.InputHandler(); handler != nil {
handler(event, setFocus)
return

@ -1,8 +0,0 @@
package tview
// Focusable provides a method which determines if a primitive has focus.
// Composed primitives may be focused based on the focused state of their
// contained primitives.
type Focusable interface {
HasFocus() bool
}

@ -1,7 +1,7 @@
package tview
import (
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
)
// DefaultFormFieldWidth is the default field screen width of form elements
@ -96,8 +96,6 @@ func NewForm() *Form {
buttonTextColor: Styles.PrimaryTextColor,
}
f.focus = f
return f
}
@ -363,7 +361,7 @@ func (f *Form) SetCancelFunc(callback func()) *Form {
// Draw draws this primitive onto the screen.
func (f *Form) Draw(screen tcell.Screen) {
f.Box.Draw(screen)
f.Box.DrawForSubclass(screen, f)
// Determine the actual item that has focus.
if index := f.focusIndex(); index >= 0 {
@ -430,7 +428,7 @@ func (f *Form) Draw(screen tcell.Screen) {
positions[index].y = y
positions[index].width = itemWidth
positions[index].height = 1
if item.GetFocusable().HasFocus() {
if item.HasFocus() {
focusedPosition = positions[index]
}
@ -524,7 +522,7 @@ func (f *Form) Draw(screen tcell.Screen) {
}
// Draw items with focus last (in case of overlaps).
if item.GetFocusable().HasFocus() {
if item.HasFocus() {
defer item.Draw(screen)
} else {
item.Draw(screen)
@ -608,12 +606,12 @@ func (f *Form) HasFocus() bool {
// has focus.
func (f *Form) focusIndex() int {
for index, item := range f.items {
if item.GetFocusable().HasFocus() {
if item.HasFocus() {
return index
}
}
for index, button := range f.buttons {
if button.focus.HasFocus() {
if button.HasFocus() {
return len(f.items) + index
}
}
@ -666,7 +664,7 @@ func (f *Form) MouseHandler() func(action MouseAction, event *tcell.EventMouse,
func (f *Form) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
return f.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) {
for _, item := range f.items {
if item != nil && item.GetFocusable().HasFocus() {
if item != nil && item.HasFocus() {
if handler := item.InputHandler(); handler != nil {
handler(event, setFocus)
return
@ -675,7 +673,7 @@ func (f *Form) InputHandler() func(event *tcell.EventKey, setFocus func(p Primit
}
for _, button := range f.buttons {
if button.GetFocusable().HasFocus() {
if button.HasFocus() {
if handler := button.InputHandler(); handler != nil {
handler(event, setFocus)
return

@ -1,7 +1,7 @@
package tview
import (
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
)
// frameText holds information about a line of text shown in the frame.
@ -46,8 +46,6 @@ func NewFrame(primitive Primitive) *Frame {
right: 1,
}
f.focus = f
return f
}
@ -83,7 +81,7 @@ func (f *Frame) SetBorders(top, bottom, header, footer, left, right int) *Frame
// Draw draws this primitive onto the screen.
func (f *Frame) Draw(screen tcell.Screen) {
f.Box.Draw(screen)
f.Box.DrawForSubclass(screen, f)
// Calculate start positions.
x, top, width, height := f.GetInnerRect()
@ -159,11 +157,7 @@ func (f *Frame) HasFocus() bool {
if f.primitive == nil {
return f.hasFocus
}
focusable, ok := f.primitive.(Focusable)
if ok {
return focusable.HasFocus()
}
return f.hasFocus
return f.primitive.HasFocus()
}
// MouseHandler returns the mouse handler for this primitive.
@ -188,7 +182,7 @@ func (f *Frame) InputHandler() func(event *tcell.EventKey, setFocus func(p Primi
if f.primitive == nil {
return
}
if f.primitive.GetFocusable().HasFocus() {
if f.primitive.HasFocus() {
if handler := f.primitive.InputHandler(); handler != nil {
handler(event, setFocus)
return

@ -3,10 +3,10 @@ module github.com/rivo/tview
go 1.12
require (
github.com/gdamore/tcell v1.3.0
github.com/gdamore/tcell/v2 v2.0.1-0.20201017141208-acf90d56d591
github.com/lucasb-eyer/go-colorful v1.0.3
github.com/mattn/go-runewidth v0.0.9
github.com/rivo/uniseg v0.1.0
golang.org/x/sys v0.0.0-20200817155316-9781c653f443 // indirect
golang.org/x/text v0.3.2 // indirect
github.com/rivo/uniseg v0.2.0
golang.org/x/sys v0.0.0-20201017003518-b09fb700fbb7 // indirect
golang.org/x/text v0.3.3 // indirect
)

@ -1,25 +1,24 @@
github.com/DATA-DOG/go-sqlmock v1.3.3 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08=
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell v1.3.0 h1:r35w0JBADPZCVQijYebl6YMWWtHRqVEGt7kL2eBADRM=
github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM=
github.com/lucasb-eyer/go-colorful v1.0.2 h1:mCMFu6PgSozg9tDNMMK3g18oJBX7oYGrC09mS6CXfO4=
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
github.com/gdamore/tcell/v2 v2.0.0 h1:GRWG8aLfWAlekj9Q6W29bVvkHENc6hp79XOqG4AWDOs=
github.com/gdamore/tcell/v2 v2.0.0/go.mod h1:vSVL/GV5mCSlPC6thFP5kfOFdM9MGZcalipmpTxTgQA=
github.com/gdamore/tcell/v2 v2.0.1-0.20201017141208-acf90d56d591 h1:0WWUDZ1oxq7NxVyGo8M3KI5jbkiwNAdZFFzAdC68up4=
github.com/gdamore/tcell/v2 v2.0.1-0.20201017141208-acf90d56d591/go.mod h1:vSVL/GV5mCSlPC6thFP5kfOFdM9MGZcalipmpTxTgQA=
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756 h1:9nuHUbU8dRnRRfj9KjWUVrJeoexdbeMjttk6Oh1rD10=
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200817155316-9781c653f443 h1:X18bCaipMcoJGm27Nv7zr4XYPKGUy92GtqboKC2Hxaw=
golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201017003518-b09fb700fbb7 h1:XtNJkfEjb4zR3q20BBBcYUykVOEMgZeIUOpBPfNYgxg=
golang.org/x/sys v0.0.0-20201017003518-b09fb700fbb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

@ -3,7 +3,7 @@ package tview
import (
"math"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
)
// gridItem represents one primitive and its possible position on a grid.
@ -71,7 +71,6 @@ func NewGrid() *Grid {
Box: NewBox().SetBackgroundColor(tcell.ColorDefault),
bordersColor: Styles.GraphicsColor,
}
g.focus = g
return g
}
@ -261,7 +260,7 @@ func (g *Grid) Blur() {
// HasFocus returns whether or not this primitive has focus.
func (g *Grid) HasFocus() bool {
for _, item := range g.items {
if item.visible && item.Item.GetFocusable().HasFocus() {
if item.visible && item.Item.HasFocus() {
return true
}
}
@ -274,7 +273,7 @@ func (g *Grid) InputHandler() func(event *tcell.EventKey, setFocus func(p Primit
if !g.hasFocus {
// Pass event on to child primitive.
for _, item := range g.items {
if item != nil && item.Item.GetFocusable().HasFocus() {
if item != nil && item.Item.HasFocus() {
if handler := item.Item.InputHandler(); handler != nil {
handler(event, setFocus)
return
@ -319,7 +318,7 @@ func (g *Grid) InputHandler() func(event *tcell.EventKey, setFocus func(p Primit
// Draw draws this primitive onto the screen.
func (g *Grid) Draw(screen tcell.Screen) {
g.Box.Draw(screen)
g.Box.DrawForSubclass(screen, g)
x, y, width, height := g.GetInnerRect()
screenWidth, screenHeight := screen.Size()
@ -497,7 +496,7 @@ func (g *Grid) Draw(screen tcell.Screen) {
}
item.x, item.y, item.w, item.h = px, py, pw, ph
item.visible = true
if primitive.GetFocusable().HasFocus() {
if primitive.HasFocus() {
focus = item
}
}

@ -7,7 +7,7 @@ import (
"sync"
"unicode/utf8"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
)
// InputField is a one-line box (three lines if there is a title) where the
@ -303,7 +303,7 @@ func (i *InputField) SetFinishedFunc(handler func(key tcell.Key)) FormItem {
// Draw draws this primitive onto the screen.
func (i *InputField) Draw(screen tcell.Screen) {
i.Box.Draw(screen)
i.Box.DrawForSubclass(screen, i)
// Prepare
x, y, width, height := i.GetInnerRect()
@ -428,7 +428,7 @@ func (i *InputField) Draw(screen tcell.Screen) {
}
// Set cursor.
if i.focus.HasFocus() {
if i.HasFocus() {
screen.ShowCursor(x+cursorScreenPos, y)
}
}
@ -573,6 +573,7 @@ func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p
}
i.autocompleteList.SetCurrentItem(newEntry)
currentText, _ = i.autocompleteList.GetItemText(newEntry) // Don't trigger changed function twice.
currentText = stripTags(currentText)
i.SetText(currentText)
} else {
finish(key)
@ -585,6 +586,7 @@ func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p
}
i.autocompleteList.SetCurrentItem(newEntry)
currentText, _ = i.autocompleteList.GetItemText(newEntry) // Don't trigger changed function twice.
currentText = stripTags(currentText)
i.SetText(currentText)
} else {
finish(key)

@ -4,7 +4,7 @@ import (
"fmt"
"strings"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
)
// listItem represents one item in a List.
@ -389,7 +389,7 @@ func (l *List) Clear() *List {
// Draw draws this primitive onto the screen.
func (l *List) Draw(screen tcell.Screen) {
l.Box.Draw(screen)
l.Box.DrawForSubclass(screen, l)
// Determine the dimensions.
x, y, width, height := l.GetInnerRect()

@ -1,7 +1,7 @@
package tview
import (
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
)
// Modal is a centered message window used to inform the user or prompt them
@ -49,7 +49,6 @@ func NewModal() *Modal {
m.frame.SetBorder(true).
SetBackgroundColor(Styles.ContrastBackgroundColor).
SetBorderPadding(1, 1, 1, 1)
m.focus = m
return m
}
@ -208,7 +207,7 @@ func (m *Modal) MouseHandler() func(action MouseAction, event *tcell.EventMouse,
// InputHandler returns the handler for this primitive.
func (m *Modal) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
return m.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) {
if m.frame.GetFocusable().HasFocus() {
if m.frame.HasFocus() {
if handler := m.frame.InputHandler(); handler != nil {
handler(event, setFocus)
return

@ -1,7 +1,7 @@
package tview
import (
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
)
// page represents one page of a Pages object.
@ -37,7 +37,6 @@ func NewPages() *Pages {
p := &Pages{
Box: NewBox(),
}
p.focus = p
return p
}
@ -240,7 +239,7 @@ func (p *Pages) GetFrontPage() (name string, item Primitive) {
// HasFocus returns whether or not this primitive has focus.
func (p *Pages) HasFocus() bool {
for _, page := range p.pages {
if page.Item.GetFocusable().HasFocus() {
if page.Item.HasFocus() {
return true
}
}
@ -266,7 +265,7 @@ func (p *Pages) Focus(delegate func(p Primitive)) {
// Draw draws this primitive onto the screen.
func (p *Pages) Draw(screen tcell.Screen) {
p.Box.Draw(screen)
p.Box.DrawForSubclass(screen, p)
for _, page := range p.pages {
if !page.Visible {
continue
@ -305,7 +304,7 @@ func (p *Pages) MouseHandler() func(action MouseAction, event *tcell.EventMouse,
func (p *Pages) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
return p.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) {
for _, page := range p.pages {
if page.Item.GetFocusable().HasFocus() {
if page.Item.HasFocus() {
if handler := page.Item.InputHandler(); handler != nil {
handler(event, setFocus)
return

@ -1,6 +1,6 @@
package tview
import "github.com/gdamore/tcell"
import "github.com/gdamore/tcell/v2"
// Primitive is the top-most interface for all graphical primitives.
type Primitive interface {
@ -38,12 +38,13 @@ type Primitive interface {
// Implementers may call delegate() to pass the focus on to another primitive.
Focus(delegate func(p Primitive))
// HasFocus determines if the primitive has focus. This function must return
// true also if one of this primitive's child elements has focus.
HasFocus() bool
// Blur is called by the application when the primitive loses focus.
Blur()
// GetFocusable returns the item's Focusable.
GetFocusable() Focusable
// MouseHandler returns a handler which receives mouse events.
// It is called by the Application class.
//

@ -1,6 +1,6 @@
package tview
import "github.com/gdamore/tcell"
import "github.com/gdamore/tcell/v2"
// Semigraphics provides an easy way to access unicode characters for drawing.
//

@ -1,6 +1,6 @@
package tview
import "github.com/gdamore/tcell"
import "github.com/gdamore/tcell/v2"
// Theme defines the colors used when primitives are initialized.
type Theme struct {

@ -3,7 +3,7 @@ package tview
import (
"sort"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
colorful "github.com/lucasb-eyer/go-colorful"
)
@ -42,6 +42,11 @@ type TableCell struct {
// If set to true, this cell cannot be selected.
NotSelectable bool
// An optional handler for mouse clicks. This also fires if the cell is not
// selectable. If true is returned, no additional "selected" event is fired
// on selectable cells.
Clicked func() bool
// The position and width of the cell the last time table was drawn.
x, y, width int
}
@ -160,6 +165,14 @@ func (c *TableCell) GetLastPosition() (x, y, width int) {
return c.x, c.y, c.width
}
// SetClickedFunc sets a handler which fires when this cell is clicked. This is
// independent of whether the cell is selectable or not. But for selectable
// cells, if the function returns "true", the "selected" event is not fired.
func (c *TableCell) SetClickedFunc(clicked func() bool) *TableCell {
c.Clicked = clicked
return c
}
// Table visualizes two-dimensional data consisting of rows and columns. Each
// Table cell is defined via SetCell() by the TableCell type. They can be added
// dynamically to the table and changed any time.
@ -258,8 +271,8 @@ type Table struct {
// drawn.
visibleColumnWidths []int
// The style of the selected rows. If this value is 0, selected rows are
// simply inverted.
// The style of the selected rows. If this value is the empty struct,
// selected rows are simply inverted.
selectedStyle tcell.Style
// An optional function which gets called when the user presses Enter on a
@ -314,8 +327,8 @@ func (t *Table) SetBordersColor(color tcell.Color) *Table {
// To reset a previous setting to its default, make the following call:
//
// table.SetSelectedStyle(tcell.ColorDefault, tcell.ColorDefault, 0)
func (t *Table) SetSelectedStyle(foregroundColor, backgroundColor tcell.Color, attributes tcell.AttrMask) *Table {
t.selectedStyle = tcell.StyleDefault.Foreground(foregroundColor).Background(backgroundColor) | tcell.Style(attributes)
func (t *Table) SetSelectedStyle(style tcell.Style) *Table {
t.selectedStyle = style
return t
}
@ -437,8 +450,9 @@ func (t *Table) SetDoneFunc(handler func(key tcell.Key)) *Table {
// the Text and Color fields should be set.
//
// Note that setting cells in previously unknown rows and columns will
// automatically extend the internal table representation, e.g. starting with
// a row of 100,000 will immediately create 100,000 empty rows.
// automatically extend the internal table representation with empty TableCell
// objects, e.g. starting with a row of 100,000 will immediately create 100,000
// empty rows.
//
// To avoid unnecessary garbage collection, fill columns from left to right.
func (t *Table) SetCell(row, column int, cell *TableCell) *Table {
@ -610,7 +624,7 @@ func (t *Table) ScrollToEnd() *Table {
// Draw draws this primitive onto the screen.
func (t *Table) Draw(screen tcell.Screen) {
t.Box.Draw(screen)
t.Box.DrawForSubclass(screen, t)
// What's our available screen space?
_, totalHeight := screen.Size()
@ -639,7 +653,7 @@ func (t *Table) Draw(screen tcell.Screen) {
}
for t.selectedRow < len(t.cells) {
cell := getCell(t.selectedRow, t.selectedColumn)
if cell == nil || !cell.NotSelectable {
if cell != nil && !cell.NotSelectable {
break
}
t.selectedColumn++
@ -872,7 +886,7 @@ ColumnLoop:
finalWidth = width - columnX - 1
}
cell.x, cell.y, cell.width = x+columnX+1, y+rowY, finalWidth
_, printed := printWithStyle(screen, cell.Text, x+columnX+1, y+rowY, finalWidth, cell.Align, tcell.StyleDefault.Foreground(cell.Color)|tcell.Style(cell.Attributes))
_, printed := printWithStyle(screen, cell.Text, x+columnX+1, y+rowY, finalWidth, cell.Align, tcell.StyleDefault.Foreground(cell.Color).Attributes(cell.Attributes))
if TaggedStringWidth(cell.Text)-printed > 0 && printed > 0 {
_, _, style, _ := screen.GetContent(x+columnX+finalWidth, y+rowY)
printWithStyle(screen, string(SemigraphicsHorizontalEllipsis), x+columnX+finalWidth, y+rowY, 1, AlignLeft, style)
@ -941,7 +955,7 @@ ColumnLoop:
if attr != 0 {
a = attr
}
style = style.Background(bg).Foreground(fg) | tcell.Style(a)
style = style.Background(bg).Foreground(fg).Attributes(a)
}
screen.SetContent(fromX+bx, fromY+by, m, c, style)
}
@ -1004,7 +1018,7 @@ ColumnLoop:
entries := cellsByBackgroundColor[bgColor]
for _, cell := range entries {
if cell.selected {
if t.selectedStyle != 0 {
if t.selectedStyle != (tcell.Style{}) {
defer colorBackground(cell.x, cell.y, cell.w, cell.h, selBg, selFg, selAttr, false)
} else {
defer colorBackground(cell.x, cell.y, cell.w, cell.h, bgColor, cell.text, 0, true)
@ -1047,7 +1061,7 @@ func (t *Table) InputHandler() func(event *tcell.EventKey, setFocus func(p Primi
previous = func() {
for t.selectedRow >= 0 {
cell := getCell(t.selectedRow, t.selectedColumn)
if cell == nil || !cell.NotSelectable {
if cell != nil && !cell.NotSelectable {
return
}
t.selectedColumn--
@ -1068,7 +1082,7 @@ func (t *Table) InputHandler() func(event *tcell.EventKey, setFocus func(p Primi
}
for t.selectedRow < len(t.cells) {
cell := getCell(t.selectedRow, t.selectedColumn)
if cell == nil || !cell.NotSelectable {
if cell != nil && !cell.NotSelectable {
return
}
t.selectedColumn++
@ -1145,9 +1159,6 @@ func (t *Table) InputHandler() func(event *tcell.EventKey, setFocus func(p Primi
right = func() {
if t.columnsSelectable {
t.selectedColumn++
if t.selectedColumn > t.lastColumn {
t.selectedColumn = t.lastColumn
}
next()
} else {
t.columnOffset++
@ -1247,8 +1258,21 @@ func (t *Table) MouseHandler() func(action MouseAction, event *tcell.EventMouse,
switch action {
case MouseLeftClick:
if t.rowsSelectable || t.columnsSelectable {
t.Select(t.cellAt(x, y))
selectEvent := true
row, column := t.cellAt(x, y)
if row >= 0 && row < len(t.cells) && column >= 0 {
cells := t.cells[row]
if column < len(cells) {
cell := cells[column]
if cell != nil && cell.Clicked != nil {
if noSelect := cell.Clicked(); noSelect {
selectEvent = false
}
}
}
}
if selectEvent && (t.rowsSelectable || t.columnsSelectable) {
t.Select(row, column)
}
setFocus(t)
consumed = true

@ -8,7 +8,7 @@ import (
"sync"
"unicode/utf8"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
colorful "github.com/lucasb-eyer/go-colorful"
runewidth "github.com/mattn/go-runewidth"
"github.com/rivo/uniseg"
@ -269,12 +269,13 @@ func (t *TextView) SetText(text string) *TextView {
return t
}
// GetText returns the current text of this text view. If "stripTags" is set
// GetText returns the current text of this text view. If "stripAllTags" is set
// to true, any region/color tags are stripped from the text.
func (t *TextView) GetText(stripTags bool) string {
func (t *TextView) GetText(stripAllTags bool) string {
// Get the buffer.
buffer := t.buffer
if !stripTags {
buffer := make([]string, len(t.buffer), len(t.buffer)+1)
copy(buffer, t.buffer)
if !stripAllTags {
buffer = append(buffer, string(t.recentBytes))
}
@ -282,19 +283,14 @@ func (t *TextView) GetText(stripTags bool) string {
text := strings.Join(buffer, "\n")
// Strip from tags if required.
if stripTags {
if stripAllTags {
if t.regions {
text = regionPattern.ReplaceAllString(text, "")
}
if t.dynamicColors {
text = colorPattern.ReplaceAllStringFunc(text, func(match string) string {
if len(match) > 2 {
return ""
}
return match
})
text = stripTags(text)
}
if t.regions || t.dynamicColors {
if t.regions && !t.dynamicColors {
text = escapePattern.ReplaceAllString(text, `[$1$2]`)
}
}
@ -849,9 +845,9 @@ func (t *TextView) reindexBuffer(width int) {
// Draw draws this primitive onto the screen.
func (t *TextView) Draw(screen tcell.Screen) {
t.Box.DrawForSubclass(screen, t)
t.Lock()
defer t.Unlock()
t.Box.Draw(screen)
totalWidth, totalHeight := screen.Size()
// Get the available size.

@ -1,7 +1,7 @@
package tview
import (
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
)
// Tree navigation events.
@ -41,9 +41,13 @@ type TreeNode struct {
// An optional function which is called when the user selects this node.
selected func()
// The hierarchy level (0 for the root, 1 for its children, and so on). This
// is only up to date immediately after a call to process() (e.g. via
// Draw()).
level int
// Temporary member variables.
parent *TreeNode // The parent node (nil for the root).
level int // The hierarchy level (0 for the root, 1 for its children, and so on).
graphicsX int // The x-coordinate of the left-most graphics rune.
textX int // The x-coordinate of the first rune of the text.
}
@ -207,6 +211,14 @@ func (n *TreeNode) SetIndent(indent int) *TreeNode {
return n
}
// GetLevel returns the node's level within the hierarchy, where 0 corresponds
// to the root node, 1 corresponds to its children, and so on. This is only
// guaranteed to be up to date immediately after the tree that contains this
// node is drawn.
func (n *TreeNode) GetLevel() int {
return n.level
}
// TreeView displays tree structures. A tree consists of nodes (TreeNode
// objects) where each node has zero or more child nodes and exactly one parent
// node (except for the root node which has no parent node).
@ -571,7 +583,7 @@ func (t *TreeView) process() {
// Draw draws this primitive onto the screen.
func (t *TreeView) Draw(screen tcell.Screen) {
t.Box.Draw(screen)
t.Box.DrawForSubclass(screen, t)
if t.root == nil {
return
}
@ -744,7 +756,7 @@ func (t *TreeView) MouseHandler() func(action MouseAction, event *tcell.EventMou
case MouseLeftClick:
setFocus(t)
_, rectY, _, _ := t.GetInnerRect()
y -= rectY
y += t.offsetY - rectY
if y >= 0 && y < len(t.nodes) {
node := t.nodes[y]
if node.selectable {

@ -6,7 +6,7 @@ import (
"sort"
"strconv"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
runewidth "github.com/mattn/go-runewidth"
"github.com/rivo/uniseg"
)
@ -628,3 +628,15 @@ func iterateStringReverse(text string, callback func(main rune, comb []rune, tex
return false
}
// stripTags strips colour tags from the given string. (Region tags are not
// stripped.)
func stripTags(text string) string {
stripped := colorPattern.ReplaceAllStringFunc(text, func(match string) string {
if len(match) > 2 {
return ""
}
return match
})
return escapePattern.ReplaceAllString(stripped, `[$1$2]`)
}

Loading…
Cancel
Save