A lot of work. Started working on the session objects and added a new text display component and componant switcher.

This commit is contained in:
lmika 2015-01-06 22:34:06 +11:00
parent e86cb4fd63
commit 910bdbc854
7 changed files with 391 additions and 42 deletions

View file

@ -13,22 +13,22 @@ type GridModel interface {
/**
* Returns the size of the grid model (width x height)
*/
GetDimensions() (int, int)
Dimensions() (int, int)
/**
* Returns the size of the particular column. If the size is 0, this indicates that the column is hidden.
*/
GetColWidth(int) int
ColWidth(int) int
/**
* Returns the size of the particular row. If the size is 0, this indicates that the row is hidden.
*/
GetRowHeight(int) int
RowHeight(int) int
/**
* Returns the value of the cell a position X, Y
*/
GetCellValue(int, int) string
CellValue(int, int) string
}
@ -38,7 +38,8 @@ type gridPoint int
* The grid component.
*/
type Grid struct {
model GridModel
model GridModel // The grid model
viewCellX int // Left most cell
viewCellY int // Top most cell
selCellX int // The currently selected cell
@ -72,11 +73,9 @@ func NewGrid(model GridModel) *Grid {
return &Grid{model, 0, 0, 0, 0, -1, -1}
}
/**
* Returns the requested dimensions of a grid (as required by UiComponent)
*/
func (grid *Grid) Remeasure(w, h int) (int, int) {
return w, h
// Returns the model
func (grid *Grid) Model() GridModel {
return grid.model
}
/**
@ -88,11 +87,44 @@ func (grid *Grid) ShiftBy(x int, y int) {
}
// Moves the currently selected cell by a delta.
// Returns the display value of the currently selected cell.
func (grid *Grid) CurrentCellDisplayValue() string {
if grid.isCellValid(grid.selCellX, grid.selCellY) {
return grid.model.CellValue(grid.selCellX, grid.selCellY)
} else {
return ""
}
}
// Moves the currently selected cell by a delta. This will be implemented as single stepped
// moveTo calls to handle invalid cells.
func (grid *Grid) MoveBy(x int, y int) {
grid.selCellX += x
grid.selCellY += y
grid.reposition()
grid.MoveTo(grid.selCellX + x, grid.selCellY + y)
}
// Moves the currently selected cell to a specific row. The row must be valid, otherwise the
// currently selected cell will not be changed. Returns true if the move was successful
func (grid *Grid) MoveTo(newX, newY int) {
maxX, maxY := grid.model.Dimensions()
newX = intMinMax(newX, 0, maxX - 1)
newY = intMinMax(newY, 0, maxY - 1)
if grid.isCellValid(newX, newY) {
grid.selCellX = newX
grid.selCellY = newY
grid.reposition()
}
}
// Returns the currently selected cell position.
func (grid *Grid) CellPosition() (int, int) {
return grid.selCellX, grid.selCellY
}
// Returns true if the user can enter the specific cell
func (grid *Grid) isCellValid(x int, y int) bool {
maxX, maxY := grid.model.Dimensions()
return (x >= 0) && (y >= 0) && (x < maxX) && (y < maxY)
}
@ -118,17 +150,15 @@ func (grid *Grid) reposition() {
}
// Gets the cell value and attributes of a particular cell
func (grid *Grid) getCellData(cellX, cellY int) (text string, fg, bg Attribute) {
// The fixed cells
modelCellX := cellX - 1 + grid.viewCellX
modelCellY := cellY - 1 + grid.viewCellY
modelMaxX, modelMaxY := grid.model.GetDimensions()
modelMaxX, modelMaxY := grid.model.Dimensions()
if (cellX == 0) && (cellY == 0) {
return strconv.Itoa(grid.cellsWide), AttrBold, AttrBold
return "", AttrBold, AttrBold
} else if (cellX == 0) {
if (modelCellY == grid.selCellY) {
return strconv.Itoa(modelCellY), AttrBold | AttrReverse, AttrBold | AttrReverse
@ -145,18 +175,14 @@ func (grid *Grid) getCellData(cellX, cellY int) (text string, fg, bg Attribute)
// The data from the model
if (modelCellX >= 0) && (modelCellY >= 0) && (modelCellX < modelMaxX) && (modelCellY < modelMaxY) {
if (modelCellX == grid.selCellX) && (modelCellY == grid.selCellY) {
return grid.model.GetCellValue(modelCellX, modelCellY), AttrReverse, AttrReverse
return grid.model.CellValue(modelCellX, modelCellY), AttrReverse, AttrReverse
} else {
return grid.model.GetCellValue(modelCellX, modelCellY), 0, 0
return grid.model.CellValue(modelCellX, modelCellY), 0, 0
}
} else {
return "~", 0, 0
return "~", ColorBlue | AttrBold, 0
}
}
// XXX: Workaround for bug in compiler
panic("Unreachable code")
return "", 0, 0
}
// Gets the cell dimensions
@ -166,17 +192,17 @@ func (grid *Grid) getCellDimensions(cellX, cellY int) (width, height int) {
modelCellX := cellX - 1 + grid.viewCellX
modelCellY := cellY - 1 + grid.viewCellY
modelMaxX, modelMaxY := grid.model.GetDimensions()
modelMaxX, modelMaxY := grid.model.Dimensions()
// Get the cell width & height from model (if within range)
if (modelCellX >= 0) && (modelCellX < modelMaxX) {
cellWidth = grid.model.GetColWidth(modelCellX)
cellWidth = grid.model.ColWidth(modelCellX)
} else {
cellWidth = 8
}
if (modelCellY >= 0) && (modelCellY < modelMaxY) {
cellHeight = grid.model.GetRowHeight(modelCellY)
cellHeight = grid.model.RowHeight(modelCellY)
} else {
cellHeight = 2
}
@ -212,8 +238,6 @@ func (grid *Grid) renderCell(ctx *DrawContext, cellClipRect gridRect, sx int, sy
}
}
//termbox.SetCell(int(x - cellClipRect.x1) + sx, int(y - cellClipRect.y1) + sy, currRune, fg, bg)
// TODO: This might be better if this wasn't so low-level
ctx.DrawRuneWithAttrs(int(x - cellClipRect.x1) + sx, int(y - cellClipRect.y1) + sy, currRune, fg, bg)
}
@ -288,7 +312,7 @@ func (grid *Grid) renderGrid(ctx *DrawContext, screenViewPort gridRect, cellX in
* Returns the cell of the particular point, along with the top-left position of the cell.
*/
func (grid *Grid) pointToCell(x int, y int) (cellX int, cellY int, posX int, posY int) {
var wid, hei int = grid.model.GetDimensions()
var wid, hei int = grid.model.Dimensions()
posX = 0
posY = 0
@ -297,7 +321,7 @@ func (grid *Grid) pointToCell(x int, y int) (cellX int, cellY int, posX int, pos
// Go through columns to locate the particular cellX
for cx := 0; cx < wid; cx++ {
if (x >= posX) && (x < posX + grid.model.GetColWidth(cx)) {
if (x >= posX) && (x < posX + grid.model.ColWidth(cx)) {
// We found the X position
cellX = int(cx)
break
@ -305,7 +329,7 @@ func (grid *Grid) pointToCell(x int, y int) (cellX int, cellY int, posX int, pos
}
for cy := 0; cy < hei; cy++ {
if (y >= posY) && (y < posY + grid.model.GetRowHeight(cy)) {
if (y >= posY) && (y < posY + grid.model.RowHeight(cy)) {
// And the Y position
cellY = int(cy)
break
@ -315,6 +339,13 @@ func (grid *Grid) pointToCell(x int, y int) (cellX int, cellY int, posX int, pos
return
}
/**
* Returns the requested dimensions of a grid (as required by UiComponent)
*/
func (grid *Grid) Remeasure(w, h int) (int, int) {
return w, h
}
/**
* Redraws the grid.
*/
@ -323,8 +354,10 @@ func (grid *Grid) Redraw(ctx *DrawContext) {
grid.cellsWide, grid.cellsHigh = grid.renderGrid(ctx, viewportRect, 0, 0, 0, 0)
}
// Called when the component has focus and a key has been pressed
func (grid *Grid) KeyPressed(key rune) {
// Called when the component has focus and a key has been pressed.
// This is the default behaviour of the grid, but it is not used by the main grid.
func (grid *Grid) KeyPressed(key rune, mod int) {
// TODO: Not sure if this would be better handled using commands
if (key == 'i') || (key == KeyArrowUp) {
grid.MoveBy(0, -1)
} else if (key == 'k') || (key == KeyArrowDown) {
@ -347,27 +380,27 @@ type TestModel struct {
/**
* Returns the size of the grid model (width x height)
*/
func (model *TestModel) GetDimensions() (int, int) {
func (model *TestModel) Dimensions() (int, int) {
return 100, 100
}
/**
* Returns the size of the particular column. If the size is 0, this indicates that the column is hidden.
*/
func (model *TestModel) GetColWidth(int) int {
func (model *TestModel) ColWidth(int) int {
return 16
}
/**
* Returns the size of the particular row. If the size is 0, this indicates that the row is hidden.
*/
func (model *TestModel) GetRowHeight(int) int {
func (model *TestModel) RowHeight(int) int {
return 1
}
/**
* Returns the value of the cell a position X, Y
*/
func (model *TestModel) GetCellValue(x int, y int) string {
func (model *TestModel) CellValue(x int, y int) string {
return strconv.Itoa(x) + "," + strconv.Itoa(y)
}

View file

@ -61,6 +61,29 @@ func (vl *VertLinearLayout) Remeasure(w, h int) (int, int) {
}
// A layout component which defers calls to the nested component. If no control is defined,
// will not draw itself. Used for switching controls dynamically.
type ProxyLayout struct {
Component UiComponent
}
func (pl *ProxyLayout) Remeasure(w, h int) (int, int) {
if pl.Component != nil {
return pl.Component.Remeasure(w, h)
} else {
return 0, 0
}
}
func (pl *ProxyLayout) Redraw(context *DrawContext) {
if pl.Component != nil {
pl.Component.Redraw(context)
}
}
// 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

View file

@ -4,6 +4,30 @@ package ui
import "unicode"
// A text component. This simply renders a text string.
type TextView struct {
// The string to render
Text string
}
// Minimum dimensions
func (tv *TextView) Remeasure(w, h int) (int, int) {
return w, 1
}
// Status bar redraw
func (tv *TextView) Redraw(context *DrawContext) {
context.SetFgAttr(0)
context.SetBgAttr(0)
context.HorizRule(0, ' ')
context.Print(0, 0, tv.Text)
}
// Status bar component. This component displays text on the left and right of it's
// allocated space.
type StatusBar struct {