parent
f9f139caaf
commit
b83a7766a6
@ -0,0 +1,135 @@
|
||||
package tview
|
||||
|
||||
import (
|
||||
"github.com/gdamore/tcell"
|
||||
)
|
||||
|
||||
// Button is labeled box that triggers an action when selected.
|
||||
type Button struct {
|
||||
Box
|
||||
|
||||
// The text to be displayed before the input area.
|
||||
label string
|
||||
|
||||
// The label color.
|
||||
labelColor tcell.Color
|
||||
|
||||
// The label color when the button is in focus.
|
||||
labelColorActivated tcell.Color
|
||||
|
||||
// The background color when the button is in focus.
|
||||
backgroundColorActivated tcell.Color
|
||||
|
||||
// An optional function which is called when the button was selected.
|
||||
selected func()
|
||||
|
||||
// An optional function which is called when the user leaves the button. A
|
||||
// key is provided indicating which key was pressed to leave (tab or backtab).
|
||||
blur func(tcell.Key)
|
||||
}
|
||||
|
||||
// NewButton returns a new input field.
|
||||
func NewButton(label string) *Button {
|
||||
box := NewBox().SetBackgroundColor(tcell.ColorBlue)
|
||||
return &Button{
|
||||
Box: *box,
|
||||
label: label,
|
||||
labelColor: tcell.ColorWhite,
|
||||
labelColorActivated: tcell.ColorBlue,
|
||||
backgroundColorActivated: tcell.ColorWhite,
|
||||
}
|
||||
}
|
||||
|
||||
// SetLabel sets the button text.
|
||||
func (b *Button) SetLabel(label string) *Button {
|
||||
b.label = label
|
||||
return b
|
||||
}
|
||||
|
||||
// GetLabel returns the button text.
|
||||
func (b *Button) GetLabel() string {
|
||||
return b.label
|
||||
}
|
||||
|
||||
// SetLabelColor sets the color of the button text.
|
||||
func (b *Button) SetLabelColor(color tcell.Color) *Button {
|
||||
b.labelColor = color
|
||||
return b
|
||||
}
|
||||
|
||||
// SetLabelColorActivated sets the color of the button text when the button is
|
||||
// in focus.
|
||||
func (b *Button) SetLabelColorActivated(color tcell.Color) *Button {
|
||||
b.labelColorActivated = color
|
||||
return b
|
||||
}
|
||||
|
||||
// SetBackgroundColorActivated sets the background color of the button text when
|
||||
// the button is in focus.
|
||||
func (b *Button) SetBackgroundColorActivated(color tcell.Color) *Button {
|
||||
b.backgroundColorActivated = color
|
||||
return b
|
||||
}
|
||||
|
||||
// SetSelectedFunc sets a handler which is called when the button was selected.
|
||||
func (b *Button) SetSelectedFunc(handler func()) *Button {
|
||||
b.selected = handler
|
||||
return b
|
||||
}
|
||||
|
||||
// SetBlurFunc sets a handler which is called when the user leaves the button.
|
||||
// The callback function is provided with the key that was pressed, which is one
|
||||
// of the following:
|
||||
//
|
||||
// - KeyEscape: Leaving the button with no specific direction.
|
||||
// - KeyTab: Move to the next field.
|
||||
// - KeyBacktab: Move to the previous field.
|
||||
func (b *Button) SetBlurFunc(handler func(key tcell.Key)) *Button {
|
||||
b.blur = handler
|
||||
return b
|
||||
}
|
||||
|
||||
// Draw draws this primitive onto the screen.
|
||||
func (b *Button) Draw(screen tcell.Screen) {
|
||||
// Draw the box.
|
||||
backgroundColor := b.backgroundColor
|
||||
if b.hasFocus {
|
||||
b.backgroundColor = b.backgroundColorActivated
|
||||
}
|
||||
b.Box.Draw(screen)
|
||||
b.backgroundColor = backgroundColor
|
||||
|
||||
// Draw label.
|
||||
x := b.x + b.width/2
|
||||
y := b.y + b.height/2
|
||||
width := b.width
|
||||
if b.border {
|
||||
width -= 2
|
||||
}
|
||||
labelColor := b.labelColor
|
||||
if b.hasFocus {
|
||||
labelColor = b.labelColorActivated
|
||||
}
|
||||
Print(screen, b.label, x, y, width, AlignCenter, labelColor)
|
||||
|
||||
if b.hasFocus {
|
||||
screen.HideCursor()
|
||||
}
|
||||
}
|
||||
|
||||
// InputHandler returns the handler for this primitive.
|
||||
func (b *Button) InputHandler() func(event *tcell.EventKey) {
|
||||
return func(event *tcell.EventKey) {
|
||||
// Process key event.
|
||||
switch key := event.Key(); key {
|
||||
case tcell.KeyEnter: // Selected.
|
||||
if b.selected != nil {
|
||||
b.selected()
|
||||
}
|
||||
case tcell.KeyBacktab, tcell.KeyTab, tcell.KeyEscape: // Leave. No action.
|
||||
if b.blur != nil {
|
||||
b.blur(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
package tview
|
||||
|
||||
import (
|
||||
"github.com/gdamore/tcell"
|
||||
)
|
||||
|
||||
// frameText holds information about a line of text shown in the frame.
|
||||
type frameText struct {
|
||||
Text string // The text to be displayed.
|
||||
Header bool // true = place in header, false = place in footer.
|
||||
Align int // One of the Align constants.
|
||||
Color tcell.Color // The text color.
|
||||
}
|
||||
|
||||
// Frame is a wrapper which adds a border around another primitive. The top and
|
||||
// the bottom border may also contain text.
|
||||
type Frame struct {
|
||||
Box
|
||||
|
||||
// The contained primitive.
|
||||
primitive Primitive
|
||||
|
||||
// The lines of text to be displayed.
|
||||
text []*frameText
|
||||
|
||||
// Border spacing.
|
||||
top, bottom, header, footer, left, right int
|
||||
}
|
||||
|
||||
// NewFrame returns a new frame around the given primitive. The primitive's
|
||||
// size will be changed to fit within this frame.
|
||||
func NewFrame(primitive Primitive) *Frame {
|
||||
return &Frame{
|
||||
Box: *NewBox(),
|
||||
primitive: primitive,
|
||||
top: 1,
|
||||
bottom: 1,
|
||||
header: 1,
|
||||
footer: 1,
|
||||
left: 1,
|
||||
right: 1,
|
||||
}
|
||||
}
|
||||
|
||||
// AddText adds text to the frame. Set "header" to true if the text is to appear
|
||||
// in the header, above the contained primitive. Set it to false for it to
|
||||
// appear in the footer, below the contained primitive. "align" must be one of
|
||||
// the Align constants. Rows in the header are printed top to bottom, rows in
|
||||
// the footer are printed bottom to top. Note that long text can overlap as
|
||||
// different alignments will be placed on the same row.
|
||||
func (f *Frame) AddText(text string, header bool, align int, color tcell.Color) *Frame {
|
||||
f.text = append(f.text, &frameText{
|
||||
Text: text,
|
||||
Header: header,
|
||||
Align: align,
|
||||
Color: color,
|
||||
})
|
||||
return f
|
||||
}
|
||||
|
||||
// SetBorders sets the width of the frame borders as well as "header" and
|
||||
// "footer", the vertical space between the header and footer text and the
|
||||
// contained primitive (does not apply if there is no text).
|
||||
func (f *Frame) SetBorders(top, bottom, header, footer, left, right int) *Frame {
|
||||
f.top, f.bottom, f.header, f.footer, f.left, f.right = top, bottom, header, footer, left, right
|
||||
return f
|
||||
}
|
||||
|
||||
// Draw draws this primitive onto the screen.
|
||||
func (f *Frame) Draw(screen tcell.Screen) {
|
||||
f.Box.Draw(screen)
|
||||
|
||||
// Calculate start positions.
|
||||
left := f.x
|
||||
right := f.x + f.width - 1
|
||||
top := f.y
|
||||
bottom := f.y + f.height - 1
|
||||
if f.border {
|
||||
left++
|
||||
right--
|
||||
top++
|
||||
bottom--
|
||||
}
|
||||
left += f.left
|
||||
right -= f.right
|
||||
top += f.top
|
||||
bottom -= f.bottom
|
||||
center := (left + right) / 2
|
||||
if left >= right || top >= bottom {
|
||||
return // No space left.
|
||||
}
|
||||
|
||||
// Draw text.
|
||||
var rows [6]int // top-left, top-center, top-right, bottom-left, bottom-center, bottom-right.
|
||||
topMax := top
|
||||
bottomMin := bottom
|
||||
for _, text := range f.text {
|
||||
// Where do we place this text?
|
||||
var y int
|
||||
if text.Header {
|
||||
y = top + rows[text.Align]
|
||||
rows[text.Align]++
|
||||
if y >= bottomMin {
|
||||
continue
|
||||
}
|
||||
if y+1 > topMax {
|
||||
topMax = y + 1
|
||||
}
|
||||
} else {
|
||||
y = bottom - rows[3+text.Align]
|
||||
rows[3+text.Align]++
|
||||
if y <= topMax {
|
||||
continue
|
||||
}
|
||||
if y-1 < bottomMin {
|
||||
bottomMin = y - 1
|
||||
}
|
||||
}
|
||||
x := left
|
||||
if text.Align == AlignCenter {
|
||||
x = center
|
||||
} else if text.Align == AlignRight {
|
||||
x = right
|
||||
}
|
||||
|
||||
// Draw text.
|
||||
Print(screen, text.Text, x, y, right-left+1, text.Align, text.Color)
|
||||
}
|
||||
|
||||
// Set the size of the contained primitive.
|
||||
if topMax > top {
|
||||
top = topMax + 1 + f.header
|
||||
}
|
||||
if bottomMin < bottom {
|
||||
bottom = bottomMin - f.footer
|
||||
}
|
||||
if top >= bottom {
|
||||
return // No space for the primitive.
|
||||
}
|
||||
f.primitive.SetRect(left, top, right+1-left, bottom-top)
|
||||
|
||||
// Finally, draw the contained primitive.
|
||||
f.primitive.Draw(screen)
|
||||
}
|
||||
|
||||
// Focus is called when this primitive receives focus.
|
||||
func (f *Frame) Focus(app *Application) {
|
||||
app.SetFocus(f.primitive)
|
||||
}
|
||||
|
||||
// InputHandler returns the handler for this primitive.
|
||||
func (f *Frame) InputHandler() func(event *tcell.EventKey) {
|
||||
return func(event *tcell.EventKey) {
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package tview
|
||||
|
||||
import "github.com/gdamore/tcell"
|
||||
|
||||
// Text alignment within a box.
|
||||
const (
|
||||
AlignLeft = iota
|
||||
AlignCenter
|
||||
AlignRight
|
||||
)
|
||||
|
||||
// Print prints text onto the screen at position (x,y). "align" is one of the
|
||||
// Align constants and will affect the direction starting at (x,y) into which
|
||||
// the text is printed. The screen's background color will be maintained. The
|
||||
// number of runes printed will not exceed "maxWidth".
|
||||
//
|
||||
// Returns the number of runes printed.
|
||||
func Print(screen tcell.Screen, text string, x, y, maxWidth, align int, color tcell.Color) int {
|
||||
// We deal with runes, not with bytes.
|
||||
runes := []rune(text)
|
||||
if maxWidth < 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Shorten text if it's too long.
|
||||
if len(runes) > maxWidth {
|
||||
switch align {
|
||||
case AlignCenter:
|
||||
trim := (len(runes) - maxWidth) / 2
|
||||
runes = runes[trim : maxWidth+trim]
|
||||
case AlignRight:
|
||||
runes = runes[len(runes)-maxWidth:]
|
||||
default: // AlignLeft.
|
||||
runes = runes[:maxWidth]
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust x-position.
|
||||
if align == AlignCenter {
|
||||
x -= len(runes) / 2
|
||||
} else if align == AlignRight {
|
||||
x -= len(runes) - 1
|
||||
}
|
||||
|
||||
// Draw text.
|
||||
for _, ch := range runes {
|
||||
_, _, style, _ := screen.GetContent(x, y)
|
||||
style = style.Foreground(color)
|
||||
screen.SetContent(x, y, ch, nil, style)
|
||||
x++
|
||||
}
|
||||
|
||||
return len(runes)
|
||||
}
|
Loading…
Reference in new issue