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:
parent
e86cb4fd63
commit
910bdbc854
7 changed files with 391 additions and 42 deletions
111
ui/grid.go
111
ui/grid.go
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
23
ui/layout.go
23
ui/layout.go
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue