mirror of
https://github.com/gdamore/tcell.git
synced 2025-04-24 13:48:51 +08:00
fixes #74 Make Application an object/class
fixes #73 Views package has many go lint issues
This commit is contained in:
parent
ed2fa2d51c
commit
b727b9f424
@ -22,6 +22,9 @@ import (
|
||||
"github.com/gdamore/tcell/views"
|
||||
)
|
||||
|
||||
var app = &views.Application{}
|
||||
var window = &mainWindow{}
|
||||
|
||||
type model struct {
|
||||
x int
|
||||
y int
|
||||
@ -97,7 +100,7 @@ func (m *model) GetCell(x, y int) (rune, tcell.Style, []rune, int) {
|
||||
return ch, style, nil, 1
|
||||
}
|
||||
|
||||
type MyApp struct {
|
||||
type mainWindow struct {
|
||||
view views.View
|
||||
main *views.CellView
|
||||
keybar *views.SimpleStyledText
|
||||
@ -107,18 +110,18 @@ type MyApp struct {
|
||||
views.Panel
|
||||
}
|
||||
|
||||
func (a *MyApp) HandleEvent(ev tcell.Event) bool {
|
||||
func (a *mainWindow) HandleEvent(ev tcell.Event) bool {
|
||||
|
||||
switch ev := ev.(type) {
|
||||
case *tcell.EventKey:
|
||||
switch ev.Key() {
|
||||
case tcell.KeyCtrlL:
|
||||
views.AppRedraw()
|
||||
app.Refresh()
|
||||
return true
|
||||
case tcell.KeyRune:
|
||||
switch ev.Rune() {
|
||||
case 'Q', 'q':
|
||||
views.AppQuit()
|
||||
app.Quit()
|
||||
return true
|
||||
case 'S', 's':
|
||||
a.model.hide = false
|
||||
@ -142,12 +145,12 @@ func (a *MyApp) HandleEvent(ev tcell.Event) bool {
|
||||
return a.Panel.HandleEvent(ev)
|
||||
}
|
||||
|
||||
func (a *MyApp) Draw() {
|
||||
func (a *mainWindow) Draw() {
|
||||
a.status.SetMarkup(a.model.loc)
|
||||
a.Panel.Draw()
|
||||
}
|
||||
|
||||
func (a *MyApp) updateKeys() {
|
||||
func (a *mainWindow) updateKeys() {
|
||||
m := a.model
|
||||
w := "[%AQ%N] Quit"
|
||||
if !m.enab {
|
||||
@ -161,19 +164,12 @@ func (a *MyApp) updateKeys() {
|
||||
}
|
||||
}
|
||||
a.keybar.SetMarkup(w)
|
||||
views.AppDraw()
|
||||
app.Update()
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
app := &MyApp{}
|
||||
|
||||
app.model = &model{endx: 60, endy: 15}
|
||||
|
||||
if e := views.AppInit(); e != nil {
|
||||
fmt.Fprintln(os.Stderr, e.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
window.model = &model{endx: 60, endy: 15}
|
||||
|
||||
title := views.NewTextBar()
|
||||
title.SetStyle(tcell.StyleDefault.
|
||||
@ -182,35 +178,39 @@ func main() {
|
||||
title.SetCenter("CellView Test", tcell.StyleDefault)
|
||||
title.SetRight("Example v1.0", tcell.StyleDefault)
|
||||
|
||||
app.keybar = views.NewSimpleStyledText()
|
||||
app.keybar.SetStyleN(tcell.StyleDefault.
|
||||
window.keybar = views.NewSimpleStyledText()
|
||||
window.keybar.SetStyleN(tcell.StyleDefault.
|
||||
Background(tcell.ColorSilver).
|
||||
Foreground(tcell.ColorBlack))
|
||||
app.keybar.SetStyleA(tcell.StyleDefault.
|
||||
window.keybar.SetStyleA(tcell.StyleDefault.
|
||||
Background(tcell.ColorSilver).
|
||||
Foreground(tcell.ColorRed))
|
||||
app.keybar.SetMarkup("[%AQ%N] Quit")
|
||||
window.keybar.SetMarkup("[%AQ%N] Quit")
|
||||
|
||||
app.status = views.NewSimpleStyledText()
|
||||
app.status.SetStyleN(tcell.StyleDefault.
|
||||
window.status = views.NewSimpleStyledText()
|
||||
window.status.SetStyleN(tcell.StyleDefault.
|
||||
Background(tcell.ColorYellow).
|
||||
Foreground(tcell.ColorBlack))
|
||||
app.status.SetMarkup("My status is here.")
|
||||
window.status.SetMarkup("My status is here.")
|
||||
|
||||
app.main = views.NewCellView()
|
||||
app.main.SetModel(app.model)
|
||||
app.main.SetStyle(tcell.StyleDefault.
|
||||
window.main = views.NewCellView()
|
||||
window.main.SetModel(window.model)
|
||||
window.main.SetStyle(tcell.StyleDefault.
|
||||
Background(tcell.ColorBlack))
|
||||
|
||||
app.SetMenu(app.keybar)
|
||||
app.SetTitle(title)
|
||||
app.SetContent(app.main)
|
||||
app.SetStatus(app.status)
|
||||
window.SetMenu(window.keybar)
|
||||
window.SetTitle(title)
|
||||
window.SetContent(window.main)
|
||||
window.SetStatus(window.status)
|
||||
|
||||
app.updateKeys()
|
||||
views.AppSetStyle(tcell.StyleDefault.
|
||||
window.updateKeys()
|
||||
|
||||
app.SetStyle(tcell.StyleDefault.
|
||||
Foreground(tcell.ColorWhite).
|
||||
Background(tcell.ColorBlack))
|
||||
views.SetApplication(app)
|
||||
views.RunApplication()
|
||||
app.SetRootWidget(window)
|
||||
if e := app.Run(); e != nil {
|
||||
fmt.Fprintln(os.Stderr, e.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
@ -22,15 +22,18 @@ import (
|
||||
"github.com/gdamore/tcell/views"
|
||||
)
|
||||
|
||||
type MyBox struct {
|
||||
type boxL struct {
|
||||
views.BoxLayout
|
||||
}
|
||||
|
||||
func (m *MyBox) HandleEvent(ev tcell.Event) bool {
|
||||
var app = &views.Application{}
|
||||
var box = &boxL{}
|
||||
|
||||
func (m *boxL) HandleEvent(ev tcell.Event) bool {
|
||||
switch ev := ev.(type) {
|
||||
case *tcell.EventKey:
|
||||
if ev.Key() == tcell.KeyEscape {
|
||||
views.AppQuit()
|
||||
app.Quit()
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -39,14 +42,6 @@ func (m *MyBox) HandleEvent(ev tcell.Event) bool {
|
||||
|
||||
func main() {
|
||||
|
||||
if e := views.AppInit(); e != nil {
|
||||
fmt.Fprintln(os.Stderr, e.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
outer := &MyBox{}
|
||||
outer.SetOrientation(views.Vertical)
|
||||
|
||||
title := &views.TextBar{}
|
||||
title.SetStyle(tcell.StyleDefault.
|
||||
Background(tcell.ColorYellow).
|
||||
@ -57,7 +52,7 @@ func main() {
|
||||
Foreground(tcell.ColorWhite))
|
||||
title.SetRight("==>X", tcell.StyleDefault)
|
||||
|
||||
box := views.NewBoxLayout(views.Horizontal)
|
||||
inner := views.NewBoxLayout(views.Horizontal)
|
||||
|
||||
l := views.NewText()
|
||||
m := views.NewText()
|
||||
@ -76,12 +71,16 @@ func main() {
|
||||
m.SetAlignment(views.AlignMiddle)
|
||||
r.SetAlignment(views.AlignEnd)
|
||||
|
||||
box.AddWidget(l, 0)
|
||||
box.AddWidget(m, 0.7)
|
||||
box.AddWidget(r, 0.3)
|
||||
inner.AddWidget(l, 0)
|
||||
inner.AddWidget(m, 0.7)
|
||||
inner.AddWidget(r, 0.3)
|
||||
|
||||
outer.AddWidget(title, 0)
|
||||
outer.AddWidget(box, 1)
|
||||
views.SetApplication(outer)
|
||||
views.RunApplication()
|
||||
box.SetOrientation(views.Vertical)
|
||||
box.AddWidget(title, 0)
|
||||
box.AddWidget(inner, 1)
|
||||
app.SetRootWidget(box)
|
||||
if e := app.Run(); e != nil {
|
||||
fmt.Fprintln(os.Stderr, e.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
@ -22,15 +22,18 @@ import (
|
||||
"github.com/gdamore/tcell/views"
|
||||
)
|
||||
|
||||
type MyBox struct {
|
||||
type boxL struct {
|
||||
views.BoxLayout
|
||||
}
|
||||
|
||||
func (m *MyBox) HandleEvent(ev tcell.Event) bool {
|
||||
var box = &boxL{}
|
||||
var app = &views.Application{}
|
||||
|
||||
func (m *boxL) HandleEvent(ev tcell.Event) bool {
|
||||
switch ev := ev.(type) {
|
||||
case *tcell.EventKey:
|
||||
if ev.Key() == tcell.KeyEscape {
|
||||
views.AppQuit()
|
||||
app.Quit()
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -39,14 +42,6 @@ func (m *MyBox) HandleEvent(ev tcell.Event) bool {
|
||||
|
||||
func main() {
|
||||
|
||||
if e := views.AppInit(); e != nil {
|
||||
fmt.Fprintln(os.Stderr, e.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
box := &MyBox{}
|
||||
box.SetOrientation(views.Vertical)
|
||||
|
||||
title := views.NewTextBar()
|
||||
title.SetStyle(tcell.StyleDefault.
|
||||
Foreground(tcell.ColorBlack).
|
||||
@ -70,11 +65,15 @@ func main() {
|
||||
mid.SetAlignment(views.VAlignCenter | views.HAlignCenter)
|
||||
bot.SetAlignment(views.VAlignBottom | views.HAlignLeft)
|
||||
|
||||
box.SetOrientation(views.Vertical)
|
||||
box.AddWidget(title, 0)
|
||||
box.AddWidget(top, 0)
|
||||
box.AddWidget(mid, 0.7)
|
||||
box.AddWidget(bot, 0.3)
|
||||
|
||||
views.SetApplication(box)
|
||||
views.RunApplication()
|
||||
app.SetRootWidget(box)
|
||||
if e := app.Run(); e != nil {
|
||||
fmt.Fprintln(os.Stderr, e.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
168
views/app.go
168
views/app.go
@ -15,117 +15,167 @@
|
||||
package views
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/gdamore/tcell"
|
||||
)
|
||||
|
||||
var appWidget Widget
|
||||
var appScreen tcell.Screen
|
||||
|
||||
func SetApplication(app Widget) {
|
||||
appWidget = app
|
||||
// Application represents an event-driven application running on a screen.
|
||||
type Application struct {
|
||||
widget Widget
|
||||
screen tcell.Screen
|
||||
style tcell.Style
|
||||
err error
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
func AppInit() error {
|
||||
if appScreen == nil {
|
||||
if scr, e := tcell.NewScreen(); e != nil {
|
||||
return e
|
||||
} else {
|
||||
appScreen = scr
|
||||
// SetRootWidget sets the primary (root, main) Widget to be displayed.
|
||||
func (app *Application) SetRootWidget(widget Widget) {
|
||||
app.widget = widget
|
||||
}
|
||||
|
||||
// initialize initializes the application. It will normally attempt to
|
||||
// allocate a default screen if one is not already established.
|
||||
func (app *Application) initialize() error {
|
||||
if app.screen == nil {
|
||||
if app.screen, app.err = tcell.NewScreen(); app.err != nil {
|
||||
return app.err
|
||||
}
|
||||
app.screen.SetStyle(app.style)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AppQuit causes the application to shutdown gracefully.
|
||||
func AppQuit() {
|
||||
// Quit causes the application to shutdown gracefully. It does not wait
|
||||
// for the application to exit, but returns immediately.
|
||||
func (app *Application) Quit() {
|
||||
ev := &eventAppQuit{}
|
||||
ev.SetEventNow()
|
||||
if appScreen != nil {
|
||||
go func() { appScreen.PostEventWait(ev) }()
|
||||
if scr := app.screen; scr != nil {
|
||||
go func() { scr.PostEventWait(ev) }()
|
||||
}
|
||||
}
|
||||
|
||||
// AppRedraw causes the application forcibly redraw everything. Use this
|
||||
// Refresh causes the application forcibly redraw everything. Use this
|
||||
// to clear up screen corruption, etc.
|
||||
func AppRedraw() {
|
||||
ev := &eventAppRedraw{}
|
||||
func (app *Application) Refresh() {
|
||||
ev := &eventAppRefresh{}
|
||||
ev.SetEventNow()
|
||||
if appScreen != nil {
|
||||
go func() { appScreen.PostEventWait(ev) }()
|
||||
if scr := app.screen; scr != nil {
|
||||
go func() { scr.PostEventWait(ev) }()
|
||||
}
|
||||
}
|
||||
|
||||
// AppDraw asks the application to redraw itself, but only parts of it that
|
||||
// are changed are updated.
|
||||
func AppDraw() {
|
||||
ev := &eventAppDraw{}
|
||||
// Update asks the application to draw any screen updates that have not
|
||||
// been drawn yet.
|
||||
func (app *Application) Update() {
|
||||
ev := &eventAppUpdate{}
|
||||
ev.SetEventNow()
|
||||
if appScreen != nil {
|
||||
go func() { appScreen.PostEventWait(ev) }()
|
||||
if scr := app.screen; scr != nil {
|
||||
go func() { scr.PostEventWait(ev) }()
|
||||
}
|
||||
}
|
||||
|
||||
// AppPostFunc posts a function to be executed in the context of the
|
||||
// PostFunc posts a function to be executed in the context of the
|
||||
// application's event loop. Functions that need to update displayed
|
||||
// state, etc. can do this to avoid holding locks.
|
||||
func AppPostFunc(fn func()) {
|
||||
func (app *Application) PostFunc(fn func()) {
|
||||
ev := &eventAppFunc{fn: fn}
|
||||
ev.SetEventNow()
|
||||
if appScreen != nil {
|
||||
go func() { appScreen.PostEventWait(ev) }()
|
||||
if scr := app.screen; scr != nil {
|
||||
go func() { scr.PostEventWait(ev) }()
|
||||
}
|
||||
}
|
||||
|
||||
func SetScreen(scr tcell.Screen) {
|
||||
appScreen = scr
|
||||
}
|
||||
|
||||
func AppSetStyle(style tcell.Style) {
|
||||
if appScreen != nil {
|
||||
appScreen.SetStyle(style)
|
||||
// SetScreen sets the screen to use for the application. This must be
|
||||
// done before the application starts to run or is initialized.
|
||||
func (app *Application) SetScreen(scr tcell.Screen) {
|
||||
if app.screen == nil {
|
||||
app.screen = scr
|
||||
app.err = nil
|
||||
}
|
||||
}
|
||||
|
||||
func RunApplication() {
|
||||
// SetStyle sets the default style (background) to be used for Widgets
|
||||
// that have not specified any other style.
|
||||
func (app *Application) SetStyle(style tcell.Style) {
|
||||
app.style = style
|
||||
if app.screen != nil {
|
||||
app.screen.SetStyle(style)
|
||||
}
|
||||
}
|
||||
|
||||
if appScreen == nil {
|
||||
func (app *Application) run() {
|
||||
|
||||
screen := app.screen
|
||||
widget := app.widget
|
||||
|
||||
if widget == nil {
|
||||
app.wg.Done()
|
||||
return
|
||||
}
|
||||
if appWidget == nil {
|
||||
return
|
||||
if screen == nil {
|
||||
if e := app.initialize(); e != nil {
|
||||
app.wg.Done()
|
||||
return
|
||||
}
|
||||
screen = app.screen
|
||||
}
|
||||
scr := appScreen
|
||||
scr.Init()
|
||||
|
||||
scr.Clear()
|
||||
appWidget.SetView(appScreen)
|
||||
screen.Init()
|
||||
screen.Clear()
|
||||
widget.SetView(screen)
|
||||
|
||||
loop:
|
||||
for {
|
||||
appWidget.Draw()
|
||||
scr.Show()
|
||||
if widget = app.widget; widget == nil {
|
||||
break
|
||||
}
|
||||
widget.Draw()
|
||||
screen.Show()
|
||||
|
||||
ev := scr.PollEvent()
|
||||
ev := screen.PollEvent()
|
||||
switch nev := ev.(type) {
|
||||
case *eventAppQuit:
|
||||
break loop
|
||||
case *eventAppDraw:
|
||||
scr.Show()
|
||||
case *eventAppRedraw:
|
||||
scr.Sync()
|
||||
case *eventAppUpdate:
|
||||
screen.Show()
|
||||
case *eventAppRefresh:
|
||||
screen.Sync()
|
||||
case *eventAppFunc:
|
||||
nev.fn()
|
||||
case *tcell.EventResize:
|
||||
scr.Sync()
|
||||
appWidget.Resize()
|
||||
screen.Sync()
|
||||
widget.Resize()
|
||||
default:
|
||||
appWidget.HandleEvent(ev)
|
||||
widget.HandleEvent(ev)
|
||||
}
|
||||
}
|
||||
scr.Fini()
|
||||
screen.Fini()
|
||||
app.wg.Done()
|
||||
}
|
||||
|
||||
type eventAppDraw struct {
|
||||
// Start starts the application loop, initializing the screen
|
||||
// and starting the Event loop. The application will run in a goroutine
|
||||
// until Quit is called.
|
||||
func (app *Application) Start() {
|
||||
app.wg.Add(1)
|
||||
go app.run()
|
||||
}
|
||||
|
||||
// Wait waits until the application finishes.
|
||||
func (app *Application) Wait() error {
|
||||
app.wg.Wait()
|
||||
return app.err
|
||||
}
|
||||
|
||||
// Run runs the application, waiting until the application loop exits.
|
||||
// It is equivalent to app.Start() followed by app.Wait()
|
||||
func (app *Application) Run() error {
|
||||
app.Start()
|
||||
return app.Wait()
|
||||
}
|
||||
|
||||
type eventAppUpdate struct {
|
||||
tcell.EventTime
|
||||
}
|
||||
|
||||
@ -133,7 +183,7 @@ type eventAppQuit struct {
|
||||
tcell.EventTime
|
||||
}
|
||||
|
||||
type eventAppRedraw struct {
|
||||
type eventAppRefresh struct {
|
||||
tcell.EventTime
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,7 @@ func (b *BoxLayout) layout() {
|
||||
// the cells with the highest residual fraction. It should be
|
||||
// the case that no single cell gets more than one more cell.
|
||||
for resid > 0 {
|
||||
var best *boxLayoutCell = nil
|
||||
var best *boxLayoutCell
|
||||
for _, c := range b.cells {
|
||||
if c.fill == 0 {
|
||||
continue
|
||||
@ -135,6 +135,7 @@ func (b *BoxLayout) layout() {
|
||||
b.changed = false
|
||||
}
|
||||
|
||||
// Resize adjusts the layout when the underlying View changes size.
|
||||
func (b *BoxLayout) Resize() {
|
||||
b.layout()
|
||||
|
||||
@ -199,7 +200,7 @@ func (b *BoxLayout) HandleEvent(ev tcell.Event) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Add() adds a widget to the end of the BoxLayout.
|
||||
// AddWidget adds a widget to the end of the BoxLayout.
|
||||
func (b *BoxLayout) AddWidget(widget Widget, fill float64) {
|
||||
c := &boxLayoutCell{
|
||||
widget: widget,
|
||||
@ -238,6 +239,7 @@ func (b *BoxLayout) InsertWidget(index int, widget Widget, fill float64) {
|
||||
b.PostEventWidgetContent(b)
|
||||
}
|
||||
|
||||
// RemoveWidget removes a Widget from the layout.
|
||||
func (b *BoxLayout) RemoveWidget(widget Widget) {
|
||||
for i := 0; i < len(b.cells); i++ {
|
||||
if b.cells[i].widget == widget {
|
||||
@ -251,6 +253,7 @@ func (b *BoxLayout) RemoveWidget(widget Widget) {
|
||||
b.PostEventWidgetContent(b)
|
||||
}
|
||||
|
||||
// Widgets returns the list of Widgets for this BoxLayout.
|
||||
func (b *BoxLayout) Widgets() []Widget {
|
||||
w := make([]Widget, 0, len(b.cells))
|
||||
for _, c := range b.cells {
|
||||
@ -259,6 +262,7 @@ func (b *BoxLayout) Widgets() []Widget {
|
||||
return w
|
||||
}
|
||||
|
||||
// SetOrientation sets the orientation as either Horizontal or Vertical.
|
||||
func (b *BoxLayout) SetOrientation(orient Orientation) {
|
||||
if b.orient != orient {
|
||||
b.orient = orient
|
||||
|
@ -28,7 +28,7 @@ type CellModel interface {
|
||||
MoveCursor(offx, offy int)
|
||||
}
|
||||
|
||||
// A CellView is a flexible view of a CellModel, offering both cursor
|
||||
// CellView is a flexible view of a CellModel, offering both cursor
|
||||
// management and a panning.
|
||||
type CellView struct {
|
||||
port *ViewPort
|
||||
@ -44,6 +44,7 @@ type CellView struct {
|
||||
WidgetWatchers
|
||||
}
|
||||
|
||||
// Draw draws the content.
|
||||
func (a *CellView) Draw() {
|
||||
|
||||
port := a.port
|
||||
@ -125,6 +126,8 @@ func (a *CellView) keyRight() {
|
||||
a.MakeCursorVisible()
|
||||
}
|
||||
|
||||
// MakeCursorVisible ensures that the cursor is visible, panning the ViewPort
|
||||
// as necessary, if the cursor is enabled.
|
||||
func (a *CellView) MakeCursorVisible() {
|
||||
if a.model == nil {
|
||||
return
|
||||
@ -135,6 +138,8 @@ func (a *CellView) MakeCursorVisible() {
|
||||
}
|
||||
}
|
||||
|
||||
// HandleEvent handles events. In particular, it handles certain key events
|
||||
// to move the cursor or pan the view.
|
||||
func (a *CellView) HandleEvent(e tcell.Event) bool {
|
||||
if a.model == nil {
|
||||
return false
|
||||
@ -173,6 +178,7 @@ func (a *CellView) Size() (int, int) {
|
||||
return w, h
|
||||
}
|
||||
|
||||
// SetModel sets the model for this CellView.
|
||||
func (a *CellView) SetModel(model CellModel) {
|
||||
w, h := model.GetBounds()
|
||||
model.SetCursor(0, 0)
|
||||
@ -181,6 +187,7 @@ func (a *CellView) SetModel(model CellModel) {
|
||||
a.port.ValidateView()
|
||||
}
|
||||
|
||||
// SetView sets the View context.
|
||||
func (a *CellView) SetView(view View) {
|
||||
port := a.port
|
||||
port.SetView(view)
|
||||
@ -197,6 +204,8 @@ func (a *CellView) SetView(view View) {
|
||||
a.Resize()
|
||||
}
|
||||
|
||||
// Resize is called when the View is resized. It will ensure that the
|
||||
// cursor is visible, if present.
|
||||
func (a *CellView) Resize() {
|
||||
// We might want to reflow text
|
||||
width, height := a.view.Size()
|
||||
@ -205,20 +214,25 @@ func (a *CellView) Resize() {
|
||||
a.MakeCursorVisible()
|
||||
}
|
||||
|
||||
// SetCursor sets the the cursor position.
|
||||
func (a *CellView) SetCursor(x, y int) {
|
||||
a.cursorX = x
|
||||
a.cursorY = y
|
||||
a.model.SetCursor(x, y)
|
||||
}
|
||||
|
||||
// SetCursorX sets the the cursor column.
|
||||
func (a *CellView) SetCursorX(x int) {
|
||||
a.SetCursor(x, a.cursorY)
|
||||
}
|
||||
|
||||
// SetCursorY sets the the cursor row.
|
||||
func (a *CellView) SetCursorY(y int) {
|
||||
a.SetCursor(a.cursorX, y)
|
||||
}
|
||||
|
||||
// MakeVisible makes the given coordinates visible, if they are not already.
|
||||
// It does this by moving the ViewPort for the CellView.
|
||||
func (a *CellView) MakeVisible(x, y int) {
|
||||
a.port.MakeVisible(x, y)
|
||||
}
|
||||
@ -228,6 +242,7 @@ func (a *CellView) SetStyle(s tcell.Style) {
|
||||
a.style = s
|
||||
}
|
||||
|
||||
// NewCellView creates a CellView.
|
||||
func NewCellView() *CellView {
|
||||
return &CellView{
|
||||
port: NewViewPort(nil, 0, 0, 0, 0),
|
||||
|
@ -14,25 +14,47 @@
|
||||
|
||||
package views
|
||||
|
||||
// Alignment represents the alignment of an object, and consists of
|
||||
// either or both of horizontal and vertical alignment.
|
||||
type Alignment int
|
||||
|
||||
const (
|
||||
// HAlignLeft indicates alignment on the left edge.
|
||||
HAlignLeft Alignment = 1 << iota
|
||||
|
||||
// HAlignCenter indicates horizontally centered.
|
||||
HAlignCenter
|
||||
|
||||
// HAlignRight indicates alignment on the right edge.
|
||||
HAlignRight
|
||||
|
||||
// VAlignTop indicates alignment on the top edge.
|
||||
VAlignTop
|
||||
|
||||
// VAlignCenter indicates vertically centered.
|
||||
VAlignCenter
|
||||
|
||||
// VAlignBottom indicates alignment on the bottom edge.
|
||||
VAlignBottom
|
||||
)
|
||||
const (
|
||||
AlignBegin = HAlignLeft | VAlignTop
|
||||
AlignEnd = HAlignRight | VAlignBottom
|
||||
// AlignBegin indicates alignment at the top left corner.
|
||||
AlignBegin = HAlignLeft | VAlignTop
|
||||
|
||||
// AlignEnd indicates alignment at the bottom right corner.
|
||||
AlignEnd = HAlignRight | VAlignBottom
|
||||
|
||||
// AlignMiddle indicates full centering.
|
||||
AlignMiddle = HAlignCenter | VAlignCenter
|
||||
)
|
||||
|
||||
// Orientation represents the direction of a widget or layout.
|
||||
type Orientation int
|
||||
|
||||
const (
|
||||
// Horizontal indicates left to right orientation.
|
||||
Horizontal = iota
|
||||
|
||||
// Vertical indicates top to bottom orientation.
|
||||
Vertical
|
||||
)
|
||||
|
@ -40,11 +40,13 @@ type Panel struct {
|
||||
BoxLayout
|
||||
}
|
||||
|
||||
// Draw draws the Panel.
|
||||
func (p *Panel) Draw() {
|
||||
p.BoxLayout.SetOrientation(Vertical)
|
||||
p.BoxLayout.Draw()
|
||||
}
|
||||
|
||||
// SetTitle sets the Widget to display in the title area.
|
||||
func (p *Panel) SetTitle(w Widget) {
|
||||
if p.title != nil {
|
||||
p.RemoveWidget(p.title)
|
||||
@ -53,6 +55,8 @@ func (p *Panel) SetTitle(w Widget) {
|
||||
p.title = w
|
||||
}
|
||||
|
||||
// SetMenu sets the Widget to display in the menu area, which is
|
||||
// just below the title.
|
||||
func (p *Panel) SetMenu(w Widget) {
|
||||
index := 0
|
||||
if p.title != nil {
|
||||
@ -65,6 +69,7 @@ func (p *Panel) SetMenu(w Widget) {
|
||||
p.menu = w
|
||||
}
|
||||
|
||||
// SetContent sets the Widget to display in the content area.
|
||||
func (p *Panel) SetContent(w Widget) {
|
||||
index := 0
|
||||
if p.title != nil {
|
||||
@ -80,6 +85,8 @@ func (p *Panel) SetContent(w Widget) {
|
||||
p.content = w
|
||||
}
|
||||
|
||||
// SetStatus sets the Widget to display in the status area, which is at
|
||||
// the bottom of the panel.
|
||||
func (p *Panel) SetStatus(w Widget) {
|
||||
index := 0
|
||||
if p.title != nil {
|
||||
@ -98,6 +105,7 @@ func (p *Panel) SetStatus(w Widget) {
|
||||
p.status = w
|
||||
}
|
||||
|
||||
// NewPanel creates a new Panel. A zero valued panel can be created too.
|
||||
func NewPanel() *Panel {
|
||||
return &Panel{}
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ func (t *SimpleStyledText) SetMarkup(s string) {
|
||||
t.markup = markup
|
||||
}
|
||||
|
||||
// SimpleStyledText returns the text that was set, including markup.
|
||||
// Markup returns the text that was set, including markup.
|
||||
func (t *SimpleStyledText) Markup() string {
|
||||
return string(t.markup)
|
||||
}
|
||||
|
@ -18,9 +18,9 @@ import (
|
||||
"github.com/gdamore/tcell"
|
||||
)
|
||||
|
||||
// Spacer is a Widget that occupies no visible real-estate. It is useful to add this
|
||||
// to layouts when expansion space is required - its blank filler.
|
||||
|
||||
// Spacer is a Widget that occupies no visible real-estate. It is useful to
|
||||
// add this to layouts when expansion space is required. It expands as needed
|
||||
// with blank space.
|
||||
type Spacer struct {
|
||||
WidgetWatchers
|
||||
}
|
||||
@ -28,6 +28,7 @@ type Spacer struct {
|
||||
// Draw is called to update the displayed content.
|
||||
func (*Spacer) Draw() {}
|
||||
|
||||
// Size always returns 0, 0, since no size is ever *requird* to display nothing.
|
||||
func (*Spacer) Size() (int, int) {
|
||||
return 0, 0
|
||||
}
|
||||
@ -45,7 +46,8 @@ func (s *Spacer) Resize() {
|
||||
s.PostEventWidgetResize(s)
|
||||
}
|
||||
|
||||
// NewSpacer creates an empty Spacer. Its probably easier just to declare it directly.
|
||||
// NewSpacer creates an empty Spacer. It's probably easier just to declare it
|
||||
// directly.
|
||||
func NewSpacer() *Spacer {
|
||||
return &Spacer{}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ type Text struct {
|
||||
WidgetWatchers
|
||||
}
|
||||
|
||||
// Draw is called to update the displayed content.
|
||||
// Draw draws the Text.
|
||||
func (t *Text) Draw() {
|
||||
v := t.view
|
||||
if v == nil {
|
||||
@ -115,6 +115,7 @@ func (t *Text) Draw() {
|
||||
}
|
||||
}
|
||||
|
||||
// Size returns the width and height in character cells of the Text.
|
||||
func (t *Text) Size() (int, int) {
|
||||
if len(t.text) != 0 {
|
||||
return t.width, t.height
|
||||
@ -132,6 +133,7 @@ func (t *Text) SetAlignment(align Alignment) {
|
||||
}
|
||||
}
|
||||
|
||||
// Alignment returns the alignment of the Text.
|
||||
func (t *Text) Alignment() Alignment {
|
||||
return t.align
|
||||
}
|
||||
|
@ -20,6 +20,11 @@ import (
|
||||
"github.com/gdamore/tcell"
|
||||
)
|
||||
|
||||
// TextArea is a pannable 2 dimensional text widget. It wraps both
|
||||
// the view and the model for text in a single, convenient widget.
|
||||
// Text is provided as an array of strings, each of which represents
|
||||
// a single line to display. All text in the TextArea has the same
|
||||
// style. An optional soft cursor is available.
|
||||
type TextArea struct {
|
||||
view *CellView
|
||||
model *linesModel
|
||||
@ -78,6 +83,7 @@ func (m *linesModel) GetCursor() (int, int, bool, bool) {
|
||||
return m.x, m.y, m.cursor, !m.hide
|
||||
}
|
||||
|
||||
// SetLines sets the content text to display.
|
||||
func (ta *TextArea) SetLines(lines []string) {
|
||||
m := ta.model
|
||||
m.width = 0
|
||||
@ -91,35 +97,46 @@ func (ta *TextArea) SetLines(lines []string) {
|
||||
ta.view.SetModel(m)
|
||||
}
|
||||
|
||||
// EnableCursor enables a soft cursor in the TextArea.
|
||||
func (ta *TextArea) EnableCursor(on bool) {
|
||||
ta.model.cursor = on
|
||||
}
|
||||
|
||||
// HideCursor hides or shows the cursor in the TextArea.
|
||||
// If on is true, the cursor is hidden. Note that a cursor is only
|
||||
// shown if it is enabled.
|
||||
func (ta *TextArea) HideCursor(on bool) {
|
||||
ta.model.hide = on
|
||||
}
|
||||
|
||||
// Draw draws the TextArea.
|
||||
func (ta *TextArea) Draw() {
|
||||
ta.view.Draw()
|
||||
}
|
||||
|
||||
// HandleEvent handles any events.
|
||||
func (ta *TextArea) HandleEvent(ev tcell.Event) bool {
|
||||
return ta.view.HandleEvent(ev)
|
||||
}
|
||||
|
||||
// Resize is called when the drawing context (View) changes size.
|
||||
func (ta *TextArea) Resize() {
|
||||
ta.view.Resize()
|
||||
}
|
||||
|
||||
// SetView sets the drawing context.
|
||||
func (ta *TextArea) SetView(view View) {
|
||||
ta.view.SetView(view)
|
||||
}
|
||||
|
||||
// SetContent is used to set the textual content, passed as a
|
||||
// single string. Lines within the string are delimited by newlines.
|
||||
func (ta *TextArea) SetContent(text string) {
|
||||
lines := strings.Split(strings.Trim(text, "\n"), "\n")
|
||||
ta.SetLines(lines)
|
||||
}
|
||||
|
||||
// NewTextArea creates a blank TextArea.
|
||||
func NewTextArea() *TextArea {
|
||||
lm := &linesModel{lines: []string{}, width: 0}
|
||||
ta := &TextArea{model: lm}
|
||||
|
@ -116,7 +116,7 @@ func (v *ViewPort) SetContent(x, y int, ch rune, comb []rune, s tcell.Style) {
|
||||
v.v.SetContent(x-v.viewx+v.physx, y-v.viewy+v.physy, ch, comb, s)
|
||||
}
|
||||
|
||||
// This moves the ViewPort the minimum necessary to make the given
|
||||
// MakeVisible moves the ViewPort the minimum necessary to make the given
|
||||
// point visible. This should be called before any content is changed with
|
||||
// SetContent, since otherwise it may be possible to move the location onto
|
||||
// a region whose contents have been discarded.
|
||||
|
@ -62,6 +62,7 @@ type Widget interface {
|
||||
Unwatch(handler tcell.EventHandler)
|
||||
}
|
||||
|
||||
// EventWidget is an event delivered by a specific widget.
|
||||
type EventWidget interface {
|
||||
Widget() Widget
|
||||
tcell.Event
|
||||
|
Loading…
x
Reference in New Issue
Block a user