Fixed a number of bugs and added missing useful functions.
parent
91d78f146b
commit
3670319cd6
|
@ -23,6 +23,9 @@ type Application struct {
|
|||
// The root primitive to be seen on the screen.
|
||||
root Primitive
|
||||
|
||||
// Whether or not the application resizes the root primitive.
|
||||
rootAutoSize bool
|
||||
|
||||
// Key overrides.
|
||||
keyOverrides map[tcell.Key]func(p Primitive) bool
|
||||
|
||||
|
@ -103,6 +106,10 @@ func (a *Application) Run() error {
|
|||
}()
|
||||
|
||||
// Draw the screen for the first time.
|
||||
if a.rootAutoSize && a.root != nil {
|
||||
width, height := a.screen.Size()
|
||||
a.root.SetRect(0, 0, width, height)
|
||||
}
|
||||
a.Unlock()
|
||||
a.Draw()
|
||||
|
||||
|
@ -158,6 +165,13 @@ func (a *Application) Run() error {
|
|||
}
|
||||
}
|
||||
case *tcell.EventResize:
|
||||
if a.rootAutoSize && a.root != nil {
|
||||
a.Lock()
|
||||
width, height := a.screen.Size()
|
||||
a.root.SetRect(0, 0, width, height)
|
||||
a.Unlock()
|
||||
a.Draw()
|
||||
}
|
||||
a.Draw()
|
||||
}
|
||||
}
|
||||
|
@ -198,15 +212,26 @@ func (a *Application) Draw() *Application {
|
|||
|
||||
// SetRoot sets the root primitive for this application. This function must be
|
||||
// called or nothing will be displayed when the application starts.
|
||||
func (a *Application) SetRoot(root Primitive) *Application {
|
||||
func (a *Application) SetRoot(root Primitive, autoSize bool) *Application {
|
||||
a.Lock()
|
||||
defer a.Unlock()
|
||||
|
||||
a.root = root
|
||||
a.rootAutoSize = autoSize
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// ResizeToFullScreen resizes the given primitive such that it fills the entire
|
||||
// screen.
|
||||
func (a *Application) ResizeToFullScreen(p Primitive) *Application {
|
||||
a.RLock()
|
||||
width, height := a.screen.Size()
|
||||
a.RUnlock()
|
||||
p.SetRect(0, 0, width, height)
|
||||
return a
|
||||
}
|
||||
|
||||
// SetFocus sets the focus on a new primitive. All key events will be redirected
|
||||
// to that primitive. Callers must ensure that the primitive will handle key
|
||||
// events.
|
||||
|
|
18
button.go
18
button.go
|
@ -31,6 +31,7 @@ type Button struct {
|
|||
// NewButton returns a new input field.
|
||||
func NewButton(label string) *Button {
|
||||
box := NewBox().SetBackgroundColor(tcell.ColorBlue)
|
||||
box.SetRect(0, 0, len([]rune(label))+4, 1)
|
||||
return &Button{
|
||||
Box: box,
|
||||
label: label,
|
||||
|
@ -92,21 +93,28 @@ 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
|
||||
defer func() {
|
||||
b.borderColor = borderColor
|
||||
}()
|
||||
}
|
||||
b.Box.Draw(screen)
|
||||
b.backgroundColor = backgroundColor
|
||||
|
||||
// Draw label.
|
||||
x, y, width, height := b.GetInnerRect()
|
||||
y = y + height/2
|
||||
labelColor := b.labelColor
|
||||
if b.focus.HasFocus() {
|
||||
labelColor = b.labelColorActivated
|
||||
if width > 0 && height > 0 {
|
||||
y = y + height/2
|
||||
labelColor := b.labelColor
|
||||
if b.focus.HasFocus() {
|
||||
labelColor = b.labelColorActivated
|
||||
}
|
||||
Print(screen, b.label, x, y, width, AlignCenter, labelColor)
|
||||
}
|
||||
Print(screen, b.label, x, y, width, AlignCenter, labelColor)
|
||||
|
||||
if b.focus.HasFocus() {
|
||||
screen.HideCursor()
|
||||
|
|
2
frame.go
2
frame.go
|
@ -12,7 +12,7 @@ type frameText struct {
|
|||
Color tcell.Color // The text color.
|
||||
}
|
||||
|
||||
// Frame is a wrapper which adds a border around another box. The top area
|
||||
// Frame is a wrapper which adds a border around another primitive. The top area
|
||||
// (header) and the bottom area (footer) may also contain text.
|
||||
type Frame struct {
|
||||
*Box
|
||||
|
|
|
@ -3,52 +3,10 @@ package tview
|
|||
import (
|
||||
"math"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"github.com/gdamore/tcell"
|
||||
)
|
||||
|
||||
var (
|
||||
// InputFieldInteger accepts integers.
|
||||
InputFieldInteger func(text string, ch rune) bool
|
||||
|
||||
// InputFieldFloat accepts floating-point numbers.
|
||||
InputFieldFloat func(text string, ch rune) bool
|
||||
|
||||
// InputFieldMaxLength returns an input field accept handler which accepts
|
||||
// input strings up to a given length. Use it like this:
|
||||
//
|
||||
// inputField.SetAcceptanceFunc(InputFieldMaxLength(10)) // Accept up to 10 characters.
|
||||
InputFieldMaxLength func(maxLength int) func(text string, ch rune) bool
|
||||
)
|
||||
|
||||
// Package initialization.
|
||||
func init() {
|
||||
// Initialize the predefined handlers.
|
||||
|
||||
InputFieldInteger = func(text string, ch rune) bool {
|
||||
if text == "-" {
|
||||
return true
|
||||
}
|
||||
_, err := strconv.Atoi(text)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
InputFieldFloat = func(text string, ch rune) bool {
|
||||
if text == "-" || text == "." {
|
||||
return true
|
||||
}
|
||||
_, err := strconv.ParseFloat(text, 64)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
InputFieldMaxLength = func(maxLength int) func(text string, ch rune) bool {
|
||||
return func(text string, ch rune) bool {
|
||||
return len([]rune(text)) <= maxLength
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// InputField is a one-line box (three lines if there is a title) where the
|
||||
// user can enter text.
|
||||
type InputField struct {
|
||||
|
@ -229,7 +187,7 @@ func (i *InputField) setCursor(screen tcell.Screen) {
|
|||
rightLimit -= 2
|
||||
}
|
||||
fieldLength := len([]rune(i.text))
|
||||
if fieldLength > i.fieldLength-1 {
|
||||
if i.fieldLength > 0 && fieldLength > i.fieldLength-1 {
|
||||
fieldLength = i.fieldLength - 1
|
||||
}
|
||||
x += len([]rune(i.label)) + fieldLength
|
||||
|
|
52
pages.go
52
pages.go
|
@ -1,6 +1,8 @@
|
|||
package tview
|
||||
|
||||
import "github.com/gdamore/tcell"
|
||||
import (
|
||||
"github.com/gdamore/tcell"
|
||||
)
|
||||
|
||||
// page represents one page of a Pages object.
|
||||
type page struct {
|
||||
|
@ -18,6 +20,10 @@ type Pages struct {
|
|||
// The contained pages.
|
||||
pages []*page
|
||||
|
||||
// We keep a reference to the function which allows us to set the focus to
|
||||
// a newly visible page.
|
||||
setFocus func(p Primitive)
|
||||
|
||||
// An optional handler which is called whenever the visibility or the order of
|
||||
// pages changes.
|
||||
changed func()
|
||||
|
@ -46,10 +52,11 @@ func (p *Pages) SetChangedFunc(handler func()) *Pages {
|
|||
// Visible pages will be drawn in the order they were added (unless that order
|
||||
// was changed in one of the other functions).
|
||||
func (p *Pages) AddPage(name string, item Primitive, visible bool) *Pages {
|
||||
p.pages = append(p.pages, &page{Item: item, Name: name, Visible: true})
|
||||
p.pages = append(p.pages, &page{Item: item, Name: name, Visible: visible})
|
||||
if p.changed != nil {
|
||||
p.changed()
|
||||
}
|
||||
p.refocus()
|
||||
return p
|
||||
}
|
||||
|
||||
|
@ -64,6 +71,7 @@ func (p *Pages) RemovePage(name string) *Pages {
|
|||
break
|
||||
}
|
||||
}
|
||||
p.refocus()
|
||||
return p
|
||||
}
|
||||
|
||||
|
@ -79,6 +87,7 @@ func (p *Pages) ShowPage(name string) *Pages {
|
|||
break
|
||||
}
|
||||
}
|
||||
p.refocus()
|
||||
return p
|
||||
}
|
||||
|
||||
|
@ -93,6 +102,7 @@ func (p *Pages) HidePage(name string) *Pages {
|
|||
break
|
||||
}
|
||||
}
|
||||
p.refocus()
|
||||
return p
|
||||
}
|
||||
|
||||
|
@ -109,6 +119,7 @@ func (p *Pages) SwitchToPage(name string) *Pages {
|
|||
if p.changed != nil {
|
||||
p.changed()
|
||||
}
|
||||
p.refocus()
|
||||
return p
|
||||
}
|
||||
|
||||
|
@ -127,6 +138,7 @@ func (p *Pages) SendToFront(name string) *Pages {
|
|||
break
|
||||
}
|
||||
}
|
||||
p.refocus()
|
||||
return p
|
||||
}
|
||||
|
||||
|
@ -145,6 +157,7 @@ func (p *Pages) SendToBack(name string) *Pages {
|
|||
break
|
||||
}
|
||||
}
|
||||
p.refocus()
|
||||
return p
|
||||
}
|
||||
|
||||
|
@ -158,6 +171,36 @@ func (p *Pages) HasFocus() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// Focus is called by the application when the primitive receives focus.
|
||||
func (p *Pages) Focus(delegate func(p Primitive)) {
|
||||
p.setFocus = delegate
|
||||
var topItem Primitive
|
||||
for _, page := range p.pages {
|
||||
if page.Visible {
|
||||
topItem = page.Item
|
||||
}
|
||||
}
|
||||
if topItem != nil {
|
||||
delegate(topItem)
|
||||
}
|
||||
}
|
||||
|
||||
// refocus sets the focus to the topmost visible page but only if we have focus.
|
||||
func (p *Pages) refocus() {
|
||||
if !p.HasFocus() || p.setFocus == nil {
|
||||
return
|
||||
}
|
||||
var topItem Primitive
|
||||
for _, page := range p.pages {
|
||||
if page.Visible {
|
||||
topItem = page.Item
|
||||
}
|
||||
}
|
||||
if topItem != nil {
|
||||
p.setFocus(topItem)
|
||||
}
|
||||
}
|
||||
|
||||
// Draw draws this primitive onto the screen.
|
||||
func (p *Pages) Draw(screen tcell.Screen) {
|
||||
for _, page := range p.pages {
|
||||
|
@ -167,3 +210,8 @@ func (p *Pages) Draw(screen tcell.Screen) {
|
|||
page.Item.Draw(screen)
|
||||
}
|
||||
}
|
||||
|
||||
// InputHandler returns the handler for this primitive.
|
||||
func (p *Pages) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
||||
return func(event *tcell.EventKey, setFocus func(p Primitive)) {}
|
||||
}
|
||||
|
|
18
textview.go
18
textview.go
|
@ -272,6 +272,14 @@ func (t *TextView) Highlight(regionIDs ...string) *TextView {
|
|||
return t
|
||||
}
|
||||
|
||||
// GetHighlights returns the IDs of all currently highlighted regions.
|
||||
func (t *TextView) GetHighlights() (regionIDs []string) {
|
||||
for id := range t.highlights {
|
||||
regionIDs = append(regionIDs, id)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ScrollToHighlight will cause the visible area to be scrolled so that the
|
||||
// highlighted regions appear in the visible area of the text view. This
|
||||
// repositioning happens the next time the text view is drawn. It happens only
|
||||
|
@ -452,6 +460,16 @@ func (t *TextView) reindexBuffer(width int) {
|
|||
regions = regionPattern.FindAllStringSubmatch(str, -1)
|
||||
}
|
||||
|
||||
// We also keep a reference to empty lines.
|
||||
if len(str) == 0 {
|
||||
t.index = append(t.index, &textViewIndex{
|
||||
Line: index,
|
||||
Pos: 0,
|
||||
Color: color,
|
||||
Region: regionID,
|
||||
})
|
||||
}
|
||||
|
||||
// Break down the line.
|
||||
var currentTag, currentRegion, currentWidth int
|
||||
for pos := range str {
|
||||
|
|
42
util.go
42
util.go
|
@ -2,6 +2,7 @@ package tview
|
|||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gdamore/tcell"
|
||||
|
@ -36,6 +37,47 @@ const (
|
|||
GraphicsEllipsis = '\u2026'
|
||||
)
|
||||
|
||||
var (
|
||||
// InputFieldInteger accepts integers.
|
||||
InputFieldInteger func(text string, ch rune) bool
|
||||
|
||||
// InputFieldFloat accepts floating-point numbers.
|
||||
InputFieldFloat func(text string, ch rune) bool
|
||||
|
||||
// InputFieldMaxLength returns an input field accept handler which accepts
|
||||
// input strings up to a given length. Use it like this:
|
||||
//
|
||||
// inputField.SetAcceptanceFunc(InputFieldMaxLength(10)) // Accept up to 10 characters.
|
||||
InputFieldMaxLength func(maxLength int) func(text string, ch rune) bool
|
||||
)
|
||||
|
||||
// Package initialization.
|
||||
func init() {
|
||||
// Initialize the predefined handlers.
|
||||
|
||||
InputFieldInteger = func(text string, ch rune) bool {
|
||||
if text == "-" {
|
||||
return true
|
||||
}
|
||||
_, err := strconv.Atoi(text)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
InputFieldFloat = func(text string, ch rune) bool {
|
||||
if text == "-" || text == "." {
|
||||
return true
|
||||
}
|
||||
_, err := strconv.ParseFloat(text, 64)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
InputFieldMaxLength = func(maxLength int) func(text string, ch rune) bool {
|
||||
return func(text string, ch rune) bool {
|
||||
return len([]rune(text)) <= maxLength
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Print prints text onto the screen into the given box at (x,y,maxWidth,1),
|
||||
// no exceeding that box. "align" is one of AlignLeft, AlignCenter, or
|
||||
// AlignRight. The screen's background color will be maintained.
|
||||
|
|
Loading…
Reference in New Issue