Removed Focusable interface.

pull/532/head
Oliver 4 years ago
parent c3a49506be
commit 675ed5b96b

@ -99,7 +99,7 @@ I try really hard to keep this project backwards compatible. Your software shoul
- 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) or [`Focusable`](https://pkg.go.dev/github.com/rivo/tview#Focusable). 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.)
- 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

@ -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)

@ -42,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
@ -74,7 +70,6 @@ func NewBox() *Box {
titleColor: Styles.TitleColor,
titleAlign: AlignCenter,
}
b.focus = b
return b
}
@ -320,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,7 +345,7 @@ func (b *Box) Draw(screen tcell.Screen) {
// Draw border.
if b.border && b.width >= 2 && b.height >= 2 {
var vertical, horizontal, topLeft, topRight, bottomLeft, bottomRight rune
if b.focus.HasFocus() {
if p.HasFocus() {
horizontal = Borders.HorizontalFocus
vertical = Borders.VerticalFocus
topLeft = Borders.TopLeftFocus
@ -403,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
}

@ -97,14 +97,14 @@ func (b *Button) Draw(screen tcell.Screen) {
// Draw the box.
borderColor := b.GetBorderColor()
backgroundColor := b.GetBackgroundColor()
if b.focus.HasFocus() {
if b.HasFocus() {
b.SetBackgroundColor(b.backgroundColorActivated)
b.SetBorderColor(b.labelColorActivated)
defer func() {
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)

@ -144,7 +144,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,7 +168,7 @@ 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'

@ -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)
}
}

@ -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).

@ -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)
}

@ -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
}

@ -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

@ -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

@ -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
}
}

@ -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)
}
}

@ -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()

@ -49,7 +49,6 @@ func NewModal() *Modal {
m.frame.SetBorder(true).
SetBackgroundColor(Styles.ContrastBackgroundColor).
SetBorderPadding(1, 1, 1, 1)
m.focus = m
return m
}
@ -192,7 +191,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

@ -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

@ -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.
//

@ -623,7 +623,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()

@ -845,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.

@ -571,7 +571,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
}

Loading…
Cancel
Save