Have reimplemented the main components and introduced layout components.
This commit is contained in:
parent
eab0eb1caf
commit
96f3271cd6
21
main.go
21
main.go
|
|
@ -1,10 +1,28 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"./ui"
|
||||
)
|
||||
|
||||
func main() {
|
||||
uiManager, err := ui.NewUI()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer uiManager.Close()
|
||||
|
||||
|
||||
statusLayout := &ui.VertLinearLayout{}
|
||||
statusLayout.Append(&ui.StatusBar{"Test", "Component"})
|
||||
statusLayout.Append(&ui.StatusBar{"Another", "Component"})
|
||||
statusLayout.Append(&ui.StatusBar{"Third", "Test"})
|
||||
|
||||
clientArea := &ui.RelativeLayout{ South: statusLayout }
|
||||
|
||||
uiManager.SetRootComponent(clientArea)
|
||||
|
||||
uiManager.Loop()
|
||||
/*
|
||||
uiCtx, _ := NewUI()
|
||||
|
||||
uiCtx.Redraw()
|
||||
|
|
@ -12,4 +30,5 @@ func main() {
|
|||
|
||||
uiCtx.Close()
|
||||
fmt.Printf("OK!")
|
||||
*/
|
||||
}
|
||||
|
|
|
|||
174
ui.go
174
ui.go
|
|
@ -1,174 +0,0 @@
|
|||
/**
|
||||
* UI package.
|
||||
*/
|
||||
package main
|
||||
|
||||
import "github.com/nsf/termbox-go"
|
||||
|
||||
|
||||
// ==========================================================================
|
||||
// UI event.
|
||||
|
||||
/**
|
||||
* The types of events.
|
||||
*/
|
||||
type EventType int
|
||||
const (
|
||||
EventKeyPress EventType = iota
|
||||
)
|
||||
|
||||
/**
|
||||
* An event callback
|
||||
*/
|
||||
type UiEvent struct {
|
||||
eventType EventType
|
||||
eventPar int
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// UI component.
|
||||
|
||||
type UiComponent interface {
|
||||
/**
|
||||
* Request to redraw this component.
|
||||
*/
|
||||
Redraw(x int, y int, w int, h int)
|
||||
|
||||
/**
|
||||
* Request the minimum dimensions of the component (width, height). If
|
||||
* either dimension is -1, no minimum is imposed.
|
||||
*/
|
||||
RequestDims() (int, int)
|
||||
}
|
||||
|
||||
|
||||
// ==========================================================================
|
||||
// UI context.
|
||||
|
||||
/**
|
||||
* Ui context type.
|
||||
*/
|
||||
type Ui struct {
|
||||
grid *Grid
|
||||
statusBar *UiStatusBar
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new UI context. This also initializes the UI state.
|
||||
* Returns the context and an error.
|
||||
*/
|
||||
func NewUI() (*Ui, error) {
|
||||
termboxError := termbox.Init()
|
||||
|
||||
if termboxError != nil {
|
||||
return nil, termboxError
|
||||
} else {
|
||||
uiCtx := new(Ui) // &Ui{&UiStatusBar{"Hello", "World"}}
|
||||
uiCtx.grid = NewGrid(&TestModel{})
|
||||
uiCtx.statusBar = &UiStatusBar{"Hello", "World"}
|
||||
return uiCtx, nil
|
||||
}
|
||||
|
||||
// XXX: Workaround for bug in compiler
|
||||
panic("Unreachable code")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Closes the UI context.
|
||||
*/
|
||||
func (ui *Ui) Close() {
|
||||
termbox.Close()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Redraws the UI.
|
||||
*/
|
||||
func (ui *Ui) Redraw() {
|
||||
var width, height int = termbox.Size()
|
||||
ui.redrawInternal(width, height)
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal redraw function which does not query the terminal size.
|
||||
*/
|
||||
func (ui *Ui) redrawInternal(width, height int) {
|
||||
termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
|
||||
|
||||
// TODO: This will eventually offload to UI "components"
|
||||
ui.grid.Redraw(0, 0, width, height - 2)
|
||||
|
||||
// Draws the status bar
|
||||
ui.statusBar.Redraw(0, height - 2, width, 2)
|
||||
|
||||
termbox.Flush()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Waits for a UI event. Returns the event (if it's relevant to the user).
|
||||
*/
|
||||
func (ui *Ui) NextEvent() UiEvent {
|
||||
for {
|
||||
event := termbox.PollEvent()
|
||||
if event.Type == termbox.EventResize {
|
||||
ui.redrawInternal(event.Width, event.Height)
|
||||
} else {
|
||||
|
||||
// !!TEMP!!
|
||||
if (event.Ch == 'i') {
|
||||
ui.grid.MoveBy(0, -1)
|
||||
} else if (event.Ch == 'k') {
|
||||
ui.grid.MoveBy(0, 1)
|
||||
} else if (event.Ch == 'j') {
|
||||
ui.grid.MoveBy(-1, 0)
|
||||
} else if (event.Ch == 'l') {
|
||||
ui.grid.MoveBy(1, 0)
|
||||
} else {
|
||||
return UiEvent{EventKeyPress, 0}
|
||||
}
|
||||
// !!END TEMP!!
|
||||
|
||||
ui.Redraw()
|
||||
//return UiEvent{EventKeyPress, 0}
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Workaround for bug in compiler
|
||||
panic("Unreachable code")
|
||||
return UiEvent{EventKeyPress, 0}
|
||||
}
|
||||
|
||||
|
||||
// ==========================================================================
|
||||
// Status bar component
|
||||
|
||||
type UiStatusBar struct {
|
||||
left string // Left aligned string
|
||||
right string // Right aligned string
|
||||
}
|
||||
|
||||
// Minimum dimensions
|
||||
func (sbar *UiStatusBar) RequestDims() (int, int) {
|
||||
return -1, 2
|
||||
}
|
||||
|
||||
// Status bar redraw
|
||||
func (sbar *UiStatusBar) Redraw(x int, y int, w int, h int) {
|
||||
leftLen := len(sbar.left)
|
||||
rightLen := len(sbar.right)
|
||||
rightPos := w - rightLen
|
||||
|
||||
for x1 := 0; x1 < w; x1++ {
|
||||
var runeToPrint rune = ' '
|
||||
if x1 < leftLen {
|
||||
runeToPrint = rune(sbar.left[x1])
|
||||
} else if x1 >= rightPos {
|
||||
runeToPrint = rune(sbar.right[x1 - rightPos])
|
||||
}
|
||||
termbox.SetCell(x1, y, runeToPrint, termbox.AttrReverse, termbox.AttrReverse)
|
||||
}
|
||||
}
|
||||
60
ui/component.go
Normal file
60
ui/component.go
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// Components of the UI and various event interfaces.
|
||||
|
||||
package ui
|
||||
|
||||
|
||||
// The set of event types supported by the UI package.
|
||||
|
||||
|
||||
|
||||
|
||||
// An interface of a UI component.
|
||||
type UiComponent interface {
|
||||
|
||||
// Request from the manager for the component to draw itself. This is given a drawable context.
|
||||
Redraw(context *DrawContext)
|
||||
|
||||
// Called to remeasure the size of the component. Provided with the maximum dimensions of the component
|
||||
// and expected to provide the minimum component size. When called to redraw, the component will be
|
||||
// provided with AT LEAST the minimum dimensions returned by this method.
|
||||
Remeasure(w, h int) (int, int)
|
||||
}
|
||||
|
||||
|
||||
// ==========================================================================
|
||||
// UI context.
|
||||
|
||||
|
||||
|
||||
|
||||
// ==========================================================================
|
||||
// Status bar component
|
||||
|
||||
/*
|
||||
type UiStatusBar struct {
|
||||
left string // Left aligned string
|
||||
right string // Right aligned string
|
||||
}
|
||||
|
||||
// Minimum dimensions
|
||||
func (sbar *UiStatusBar) RequestDims() (int, int) {
|
||||
return -1, 2
|
||||
}
|
||||
|
||||
// Status bar redraw
|
||||
func (sbar *UiStatusBar) Redraw(x int, y int, w int, h int) {
|
||||
leftLen := len(sbar.left)
|
||||
rightLen := len(sbar.right)
|
||||
rightPos := w - rightLen
|
||||
|
||||
for x1 := 0; x1 < w; x1++ {
|
||||
var runeToPrint rune = ' '
|
||||
if x1 < leftLen {
|
||||
runeToPrint = rune(sbar.left[x1])
|
||||
} else if x1 >= rightPos {
|
||||
runeToPrint = rune(sbar.right[x1 - rightPos])
|
||||
}
|
||||
termbox.SetCell(x1, y, runeToPrint, termbox.AttrReverse, termbox.AttrReverse)
|
||||
}
|
||||
}
|
||||
*/
|
||||
78
ui/drawable.go
Normal file
78
ui/drawable.go
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
// Provides access to the drawable primitives.
|
||||
|
||||
package ui
|
||||
|
||||
// A drawable context. Each context is allocated part of the screen and provides methods for
|
||||
// drawing within it's context.
|
||||
type DrawContext struct {
|
||||
|
||||
// The left and top position of the context.
|
||||
X, Y int
|
||||
|
||||
// The width and height position of the context.
|
||||
W, H int
|
||||
|
||||
// The current driver
|
||||
driver Driver
|
||||
|
||||
// The current foregound and background attributes
|
||||
fa, ba Attribute
|
||||
}
|
||||
|
||||
|
||||
// Returns a new subcontext. The sub-context must be an area within the current context.
|
||||
func (dc *DrawContext) NewSubContext(offsetX, offsetY, width, height int) *DrawContext {
|
||||
return &DrawContext{
|
||||
X: intMax(dc.X + offsetX, dc.X),
|
||||
Y: intMax(dc.Y + offsetY, dc.Y),
|
||||
W: intMax(width, 0),
|
||||
H: intMax(height, 0),
|
||||
|
||||
driver: dc.driver,
|
||||
}
|
||||
}
|
||||
|
||||
// Sets the foreground attribute
|
||||
func (dc *DrawContext) SetFgAttr(attr Attribute) {
|
||||
dc.fa = attr
|
||||
}
|
||||
|
||||
// Sets the background attribute
|
||||
func (dc *DrawContext) SetBgAttr(attr Attribute) {
|
||||
dc.ba = attr
|
||||
}
|
||||
|
||||
|
||||
// Draws a horizontal rule with a specific rune.
|
||||
func (dc *DrawContext) HorizRule(y int, ch rune) {
|
||||
for x := 0; x < dc.W; x++ {
|
||||
dc.DrawRune(x, y, ch)
|
||||
}
|
||||
}
|
||||
|
||||
// Prints a string at a specific offset. This will be bounded by the size of the drawing context.
|
||||
func (dc *DrawContext) Print(x, y int, str string) {
|
||||
for _, ch := range str {
|
||||
dc.DrawRune(x, y, ch)
|
||||
x++
|
||||
}
|
||||
}
|
||||
|
||||
// Prints a right-justified string at a specific offset. This will be bounded by the size of the drawing context.
|
||||
func (dc *DrawContext) PrintRight(x, y int, str string) {
|
||||
l := len(str)
|
||||
dc.Print(x - l, y, str)
|
||||
}
|
||||
|
||||
// Draws a rune at a local point X, Y with the current foreground and background attributes
|
||||
func (dc *DrawContext) DrawRune(x, y int, ch rune) {
|
||||
if rx, ry, isWithinContext := dc.localPointToRealPoint(x, y); isWithinContext {
|
||||
dc.driver.SetCell(rx, ry, ch, dc.fa, dc.ba)
|
||||
}
|
||||
}
|
||||
|
||||
// Converts a local point to a real point. If the point is within the context, also returns true
|
||||
func (dc *DrawContext) localPointToRealPoint(x, y int) (int, int, bool) {
|
||||
rx, ry := x + dc.X, y + dc.Y
|
||||
return rx, ry, (rx >= dc.X) && (ry >= dc.Y) && (rx < dc.X + dc.W) && (ry < dc.Y + dc.H)
|
||||
}
|
||||
65
ui/driver.go
Normal file
65
ui/driver.go
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
// The UI driver. This is used to interact with the terminal drawing routines.
|
||||
|
||||
package ui
|
||||
|
||||
// The set of attributes a specific cell can have
|
||||
type Attribute uint16
|
||||
|
||||
const (
|
||||
// Can have only one of these
|
||||
ColorDefault Attribute = iota
|
||||
ColorBlack
|
||||
ColorRed
|
||||
ColorGreen
|
||||
ColorYellow
|
||||
ColorBlue
|
||||
ColorMagenta
|
||||
ColorCyan
|
||||
ColorWhite
|
||||
)
|
||||
|
||||
// and zero or more of these (combined using OR '|')
|
||||
const (
|
||||
AttrBold Attribute = 1 << (iota + 9)
|
||||
AttrUnderline
|
||||
AttrReverse
|
||||
)
|
||||
|
||||
// The type of events supported by the driver
|
||||
type EventType int
|
||||
|
||||
const (
|
||||
// Event indicating a key press. The event parameter is the key scancode?
|
||||
EventKeyPress EventType = iota
|
||||
)
|
||||
|
||||
// Data from an event callback.
|
||||
type Event struct {
|
||||
Type EventType
|
||||
Par int
|
||||
}
|
||||
|
||||
|
||||
// The terminal driver interface.
|
||||
type Driver interface {
|
||||
|
||||
// Initializes the driver. Returns an error if there was an error
|
||||
Init() error
|
||||
|
||||
// Closes the driver
|
||||
Close()
|
||||
|
||||
// Returns the size of the window.
|
||||
Size() (int, int)
|
||||
|
||||
// Sets the value of a specific cell
|
||||
SetCell(x, y int, ch rune, fg, bg Attribute)
|
||||
|
||||
// Synchronizes the internal buffer with the real buffer
|
||||
Sync()
|
||||
|
||||
// Wait for an event
|
||||
WaitForEvent() Event
|
||||
}
|
||||
|
||||
//
|
||||
114
ui/layout.go
Normal file
114
ui/layout.go
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
// Standard layout components.
|
||||
|
||||
package ui
|
||||
|
||||
// Instance of a component.
|
||||
type componentInstance struct {
|
||||
component UiComponent
|
||||
x, y int // X and Y offset of this component
|
||||
height int // Height allocated to the component
|
||||
width int // Width allocated to the component
|
||||
}
|
||||
|
||||
// A layout component.
|
||||
type LinearLayout struct {
|
||||
// The set of components that this layout component contains
|
||||
subcomponents []*componentInstance
|
||||
}
|
||||
|
||||
// Adds a component to the end of the component list managed by this layout.
|
||||
func (l *LinearLayout) Append(component UiComponent) {
|
||||
l.subcomponents = append(l.subcomponents, &componentInstance{component, 0, 0, 0, 0})
|
||||
}
|
||||
|
||||
|
||||
// A vertical layout component.
|
||||
type VertLinearLayout struct {
|
||||
LinearLayout
|
||||
maxHeight int
|
||||
}
|
||||
|
||||
|
||||
// Request from the manager for the component to draw itself. This is given a drawable context.
|
||||
func (vl *VertLinearLayout) Redraw(context *DrawContext) {
|
||||
for _, ci := range vl.LinearLayout.subcomponents {
|
||||
subContext := context.NewSubContext(ci.x, ci.y, ci.width, ci.height)
|
||||
ci.component.Redraw(subContext)
|
||||
}
|
||||
}
|
||||
|
||||
// Remeasures the components currently managed within this layout.
|
||||
func (vl *VertLinearLayout) Remeasure(w, h int) (int, int) {
|
||||
posy := 0
|
||||
|
||||
// TODO: At the moment, this simply takes the minimum and maximum dimensions requested
|
||||
// by the components. This needs to be extended to allow for "special" components which
|
||||
// take up dynamic space.
|
||||
for _, ci := range vl.LinearLayout.subcomponents {
|
||||
_, rh := ci.component.Remeasure(w, h - posy)
|
||||
|
||||
// All components within this layer are given the full width of the screen.
|
||||
ci.x = 0
|
||||
ci.width = w
|
||||
ci.y = posy
|
||||
ci.height = rh
|
||||
|
||||
// Put the next component directly below the previous one
|
||||
posy += rh
|
||||
}
|
||||
|
||||
return w, posy
|
||||
}
|
||||
|
||||
|
||||
// A relative layout component. This has a "client" component, bordered by a north,
|
||||
// south, east and west component. The N,S,E,W components will be provided with the full dimensions
|
||||
// whereas the client component will be provided with the remaining size. Each one of the components
|
||||
// can be null.
|
||||
type RelativeLayout struct {
|
||||
North, South, East, West, Client UiComponent
|
||||
|
||||
// Measured client borders
|
||||
ct, cb, cl, cr, ch, cw int
|
||||
|
||||
// North/south heights and east/west widths
|
||||
nh, sh int
|
||||
ew, ww int
|
||||
}
|
||||
|
||||
func (rl *RelativeLayout) Remeasure(w, h int) (int, int) {
|
||||
if rl.North != nil {
|
||||
_, rl.nh = rl.North.Remeasure(w, h)
|
||||
rl.ct = rl.nh
|
||||
} else {
|
||||
rl.ct = 0
|
||||
}
|
||||
|
||||
if rl.South != nil {
|
||||
_, rl.sh = rl.South.Remeasure(w, h - rl.nh)
|
||||
rl.cb = h - rl.sh
|
||||
} else {
|
||||
rl.cb = h
|
||||
}
|
||||
|
||||
// TODO: East and west
|
||||
rl.cl = 0
|
||||
rl.cr = w
|
||||
|
||||
rl.ch = h - rl.nh - rl.sh
|
||||
rl.cw = w
|
||||
|
||||
return w, h
|
||||
}
|
||||
|
||||
func (vl *RelativeLayout) Redraw(context *DrawContext) {
|
||||
if vl.North != nil {
|
||||
vl.North.Redraw(context.NewSubContext(0, 0, context.W, vl.nh))
|
||||
}
|
||||
if vl.South != nil {
|
||||
vl.South.Redraw(context.NewSubContext(0, vl.cb, context.W, vl.sh))
|
||||
}
|
||||
if vl.Client != nil {
|
||||
vl.Client.Redraw(context.NewSubContext(vl.cl, vl.ct, vl.cw, vl.ch))
|
||||
}
|
||||
}
|
||||
131
ui/manager.go
Normal file
131
ui/manager.go
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
// The UI manager. This manages the components that make up the UI and dispatches
|
||||
// events.
|
||||
|
||||
package ui
|
||||
|
||||
|
||||
// The UI manager
|
||||
type Ui struct {
|
||||
//grid *Grid
|
||||
//statusBar *UiStatusBar
|
||||
|
||||
// The root component
|
||||
rootComponent UiComponent
|
||||
|
||||
drawContext *DrawContext
|
||||
driver Driver
|
||||
}
|
||||
|
||||
|
||||
// Creates a new UI context. This also initializes the UI state.
|
||||
// Returns the context and an error.
|
||||
func NewUI() (*Ui, error) {
|
||||
driver := &TermboxDriver{}
|
||||
err := driver.Init()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
drawContext := &DrawContext{ driver: driver }
|
||||
ui := &Ui{ drawContext: drawContext, driver: driver }
|
||||
|
||||
/*
|
||||
termboxError := termbox.Init()
|
||||
|
||||
if termboxError != nil {
|
||||
return nil, termboxError
|
||||
} else {
|
||||
uiCtx := new(Ui) // &Ui{&UiStatusBar{"Hello", "World"}}
|
||||
uiCtx.grid = NewGrid(&TestModel{})
|
||||
uiCtx.statusBar = &UiStatusBar{"Hello", "World"}
|
||||
return uiCtx, nil
|
||||
}
|
||||
|
||||
// XXX: Workaround for bug in compiler
|
||||
panic("Unreachable code")
|
||||
return nil, nil
|
||||
*/
|
||||
return ui, nil
|
||||
}
|
||||
|
||||
|
||||
// Closes the UI context.
|
||||
func (ui *Ui) Close() {
|
||||
ui.driver.Close()
|
||||
}
|
||||
|
||||
// Sets the root component
|
||||
func (ui *Ui) SetRootComponent(comp UiComponent) {
|
||||
ui.rootComponent = comp
|
||||
ui.Remeasure()
|
||||
}
|
||||
|
||||
// Remeasures the UI
|
||||
func (ui *Ui) Remeasure() {
|
||||
ui.drawContext.X = 0
|
||||
ui.drawContext.Y = 0
|
||||
ui.drawContext.W, ui.drawContext.H = ui.driver.Size()
|
||||
|
||||
ui.rootComponent.Remeasure(ui.drawContext.W, ui.drawContext.H)
|
||||
}
|
||||
|
||||
// Redraws the UI.
|
||||
func (ui *Ui) Redraw() {
|
||||
ui.Remeasure()
|
||||
|
||||
ui.rootComponent.Redraw(ui.drawContext)
|
||||
ui.driver.Sync()
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal redraw function which does not query the terminal size.
|
||||
*/
|
||||
/*
|
||||
func (ui *Ui) redrawInternal(width, height int) {
|
||||
termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
|
||||
|
||||
// TODO: This will eventually offload to UI "components"
|
||||
ui.grid.Redraw(0, 0, width, height - 2)
|
||||
|
||||
// Draws the status bar
|
||||
ui.statusBar.Redraw(0, height - 2, width, 2)
|
||||
|
||||
termbox.Flush()
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// Enter the UI loop
|
||||
func (ui *Ui) Loop() {
|
||||
//for {
|
||||
ui.Redraw()
|
||||
ui.driver.WaitForEvent()
|
||||
|
||||
/*
|
||||
if event.Type == termbox.EventResize {
|
||||
ui.redrawInternal(event.Width, event.Height)
|
||||
} else {
|
||||
|
||||
// !!TEMP!!
|
||||
if (event.Ch == 'i') {
|
||||
ui.grid.MoveBy(0, -1)
|
||||
} else if (event.Ch == 'k') {
|
||||
ui.grid.MoveBy(0, 1)
|
||||
} else if (event.Ch == 'j') {
|
||||
ui.grid.MoveBy(-1, 0)
|
||||
} else if (event.Ch == 'l') {
|
||||
ui.grid.MoveBy(1, 0)
|
||||
} else {
|
||||
return UiEvent{EventKeyPress, 0}
|
||||
}
|
||||
// !!END TEMP!!
|
||||
|
||||
ui.Redraw()
|
||||
//return UiEvent{EventKeyPress, 0}
|
||||
}
|
||||
*/
|
||||
//}
|
||||
|
||||
// XXX: Workaround for bug in compiler
|
||||
}
|
||||
41
ui/stdcomps.go
Normal file
41
ui/stdcomps.go
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// Standard components
|
||||
|
||||
package ui
|
||||
|
||||
|
||||
// Status bar component. This component displays text on the left and right of it's
|
||||
// allocated space.
|
||||
type StatusBar struct {
|
||||
Left string // Left aligned string
|
||||
Right string // Right aligned string
|
||||
}
|
||||
|
||||
// Minimum dimensions
|
||||
func (sbar *StatusBar) Remeasure(w, h int) (int, int) {
|
||||
return w, 1
|
||||
}
|
||||
|
||||
// Status bar redraw
|
||||
func (sbar *StatusBar) Redraw(context *DrawContext) {
|
||||
context.SetFgAttr(AttrReverse)
|
||||
context.SetBgAttr(AttrReverse)
|
||||
|
||||
context.HorizRule(0, ' ')
|
||||
context.Print(0, 0, sbar.Left)
|
||||
context.PrintRight(context.W, 0, sbar.Right)
|
||||
/*
|
||||
leftLen := len(sbar.left)
|
||||
rightLen := len(sbar.right)
|
||||
rightPos := w - rightLen
|
||||
|
||||
for x1 := 0; x1 < w; x1++ {
|
||||
var runeToPrint rune = ' '
|
||||
if x1 < leftLen {
|
||||
runeToPrint = rune(sbar.left[x1])
|
||||
} else if x1 >= rightPos {
|
||||
runeToPrint = rune(sbar.right[x1 - rightPos])
|
||||
}
|
||||
termbox.SetCell(x1, y, runeToPrint, termbox.AttrReverse, termbox.AttrReverse)
|
||||
}
|
||||
*/
|
||||
}
|
||||
43
ui/termboxdriver.go
Normal file
43
ui/termboxdriver.go
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// The terminal-box driver
|
||||
|
||||
package ui
|
||||
|
||||
import (
|
||||
"github.com/nsf/termbox-go"
|
||||
)
|
||||
|
||||
|
||||
type TermboxDriver struct {
|
||||
}
|
||||
|
||||
|
||||
// Initializes the driver. Returns an error if there was an error
|
||||
func (td *TermboxDriver) Init() error {
|
||||
return termbox.Init()
|
||||
}
|
||||
|
||||
// Closes the driver
|
||||
func (td *TermboxDriver) Close() {
|
||||
termbox.Close()
|
||||
}
|
||||
|
||||
// Returns the size of the window.
|
||||
func (td *TermboxDriver) Size() (int, int) {
|
||||
return termbox.Size()
|
||||
}
|
||||
|
||||
// Sets the value of a specific cell
|
||||
func (td *TermboxDriver) SetCell(x, y int, ch rune, fg, bg Attribute) {
|
||||
termbox.SetCell(x, y, ch, termbox.Attribute(fg), termbox.Attribute(bg))
|
||||
}
|
||||
|
||||
// Synchronizes the internal buffer with the real buffer
|
||||
func (td *TermboxDriver) Sync() {
|
||||
termbox.Sync()
|
||||
}
|
||||
|
||||
// Wait for an event
|
||||
func (td *TermboxDriver) WaitForEvent() Event {
|
||||
termbox.PollEvent()
|
||||
return Event{}
|
||||
}
|
||||
13
ui/utils.go
Normal file
13
ui/utils.go
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// Various utilities
|
||||
|
||||
package ui
|
||||
|
||||
|
||||
// Returns the maximum value of either x or y.
|
||||
func intMax(x, y int) int {
|
||||
if (x < y) {
|
||||
return y
|
||||
} else {
|
||||
return x
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue