tcell/views/textbar.go

194 lines
4.3 KiB
Go

// Copyright 2015 The Tcell Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use file except in compliance with the License.
// You may obtain a copy of the license at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package views
import (
"sync"
"github.com/gdamore/tcell"
)
// TextBar is a Widget that provides a single line of text, but with
// distinct left, center, and right areas. Each of the areas can be styled
// differently, and they align to the left, center, and right respectively.
// This is basically a convenience type on top Text and BoxLayout.
type TextBar struct {
changed bool
style tcell.Style
left Text
right Text
center Text
view View
lview ViewPort
rview ViewPort
cview ViewPort
once sync.Once
WidgetWatchers
}
// SetCenter sets the center text for the textbar. The text is
// always center aligned.
func (t *TextBar) SetCenter(s string, style tcell.Style) {
t.initialize()
if style == tcell.StyleDefault {
style = t.style
}
t.center.SetText(s)
t.center.SetStyle(style)
}
// SetLeft sets the left text for the textbar. It is always left-aligned.
func (t *TextBar) SetLeft(s string, style tcell.Style) {
t.initialize()
if style == tcell.StyleDefault {
style = t.style
}
t.left.SetText(s)
t.left.SetStyle(style)
}
// SetRight sets the right text for the textbar. It is always right-aligned.
func (t *TextBar) SetRight(s string, style tcell.Style) {
t.initialize()
if style == tcell.StyleDefault {
style = t.style
}
t.right.SetText(s)
t.right.SetStyle(style)
}
// SetStyle is used to set a default style to use for the textbar, including
// areas where no text is present. Note that this will not change the text
// already displayed, so call this before changing or setting text.
func (t *TextBar) SetStyle(style tcell.Style) {
t.initialize()
t.style = style
}
func (t *TextBar) initialize() {
t.once.Do(func() {
t.center.SetView(&t.cview)
t.left.SetView(&t.lview)
t.right.SetView(&t.rview)
t.center.SetAlignment(VAlignTop | HAlignCenter)
t.left.SetAlignment(VAlignTop | HAlignLeft)
t.right.SetAlignment(VAlignTop | HAlignRight)
t.center.Watch(t)
t.left.Watch(t)
t.right.Watch(t)
})
}
func (t *TextBar) layout() {
w, _ := t.view.Size()
ww, wh := t.left.Size()
t.lview.Resize(0, 0, ww, wh)
ww, wh = t.center.Size()
t.cview.Resize((w-ww)/2, 0, ww, wh)
ww, wh = t.right.Size()
t.rview.Resize(w-ww, 0, ww, wh)
t.changed = false
}
// SetView sets the View drawing context for this TextBar.
func (t *TextBar) SetView(view View) {
t.initialize()
t.view = view
t.lview.SetView(view)
t.rview.SetView(view)
t.cview.SetView(view)
t.changed = true
}
// Draw draws the TextBar into its View context.
func (t *TextBar) Draw() {
t.initialize()
if t.changed {
t.layout()
}
w, h := t.view.Size()
for y := 0; y < h; y++ {
for x := 0; x < w; x++ {
t.view.SetContent(x, y, ' ', nil, t.style)
}
}
// Draw in reverse order -- if we clip, we will clip at the
// right side.
t.right.Draw()
t.center.Draw()
t.left.Draw()
}
// Resize is called when the TextBar's View changes size, and
// updates the layout.
func (t *TextBar) Resize() {
t.initialize()
t.layout()
t.left.Resize()
t.center.Resize()
t.right.Resize()
t.PostEventWidgetResize(t)
}
// Size implements the Size method for Widget, returning the width
// and height in character cells.
func (t *TextBar) Size() (int, int) {
w, h := 0, 0
ww, wh := t.left.Size()
w += ww
if wh > h {
h = wh
}
ww, wh = t.center.Size()
w += ww
if wh > h {
h = wh
}
ww, wh = t.right.Size()
w += ww
if wh > h {
h = wh
}
return w, h
}
// HandleEvent handles incoming events. The only events handled are
// those for the Text objects; when those change, the TextBar adjusts
// the layout to accommodate.
func (t *TextBar) HandleEvent(ev tcell.Event) bool {
switch ev.(type) {
case *EventWidgetContent:
t.changed = true
return true
}
return false
}
// NewTextBar creates an empty, initialized TextBar.
func NewTextBar() *TextBar {
t := &TextBar{}
t.initialize()
return t
}