Add borders widget
This commit is contained in:
parent
7f67162f43
commit
f0791d4ba7
|
@ -52,22 +52,23 @@ func main() {
|
||||||
tabs.Add(fill('★'), "白い星")
|
tabs.Add(fill('★'), "白い星")
|
||||||
tabs.Add(fill('☆'), "empty stars")
|
tabs.Add(fill('☆'), "empty stars")
|
||||||
|
|
||||||
grid := ui.NewGrid()
|
grid := ui.NewGrid().Rows([]ui.GridSpec{
|
||||||
grid.Rows = []ui.DimSpec{
|
ui.GridSpec{ui.SIZE_EXACT, 1},
|
||||||
ui.DimSpec{ui.SIZE_EXACT, 1},
|
ui.GridSpec{ui.SIZE_WEIGHT, 1},
|
||||||
ui.DimSpec{ui.SIZE_WEIGHT, 1},
|
ui.GridSpec{ui.SIZE_EXACT, 1},
|
||||||
ui.DimSpec{ui.SIZE_WEIGHT, 1},
|
}).Columns([]ui.GridSpec{
|
||||||
ui.DimSpec{ui.SIZE_EXACT, 1},
|
ui.GridSpec{ui.SIZE_EXACT, 20},
|
||||||
}
|
ui.GridSpec{ui.SIZE_WEIGHT, 1},
|
||||||
grid.Columns = []ui.DimSpec{
|
})
|
||||||
ui.DimSpec{ui.SIZE_WEIGHT, 3},
|
|
||||||
ui.DimSpec{ui.SIZE_WEIGHT, 2},
|
// TODO: move sidebar into tab content, probably
|
||||||
}
|
// sidebar placeholder:
|
||||||
grid.AddChild(tabs.TabStrip).At(0, 0).Span(1, 2)
|
grid.AddChild(ui.NewBordered(
|
||||||
grid.AddChild(tabs.TabContent).At(1, 0).Span(1, 2)
|
fill('.'), ui.BORDER_RIGHT)).At(1, 0).Span(2, 1)
|
||||||
grid.AddChild(fill('.')).At(2, 0).Span(1, 2)
|
grid.AddChild(tabs.TabStrip).At(0, 1)
|
||||||
grid.AddChild(fill('•')).At(2, 1).Span(1, 1)
|
grid.AddChild(tabs.TabContent).At(1, 1)
|
||||||
grid.AddChild(fill('+')).At(3, 0).Span(1, 2)
|
// ex line placeholder:
|
||||||
|
grid.AddChild(fill('+')).At(2, 1)
|
||||||
|
|
||||||
_ui, err := ui.Initialize(conf, grid)
|
_ui, err := ui.Initialize(conf, grid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
tb "github.com/nsf/termbox-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
BORDER_LEFT = 1 << iota
|
||||||
|
BORDER_TOP = 1 << iota
|
||||||
|
BORDER_RIGHT = 1 << iota
|
||||||
|
BORDER_BOTTOM = 1 << iota
|
||||||
|
)
|
||||||
|
|
||||||
|
type Bordered struct {
|
||||||
|
borders uint
|
||||||
|
content Drawable
|
||||||
|
onInvalidate func(d Drawable)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBordered(content Drawable, borders uint) *Bordered {
|
||||||
|
b := &Bordered{
|
||||||
|
borders: borders,
|
||||||
|
content: content,
|
||||||
|
}
|
||||||
|
content.OnInvalidate(b.contentInvalidated)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bordered *Bordered) contentInvalidated(d Drawable) {
|
||||||
|
bordered.Invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bordered *Bordered) Invalidate() {
|
||||||
|
if bordered.onInvalidate != nil {
|
||||||
|
bordered.onInvalidate(bordered)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bordered *Bordered) OnInvalidate(onInvalidate func(d Drawable)) {
|
||||||
|
bordered.onInvalidate = onInvalidate
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bordered *Bordered) Draw(ctx *Context) {
|
||||||
|
x := 0
|
||||||
|
y := 0
|
||||||
|
width := ctx.Width()
|
||||||
|
height := ctx.Height()
|
||||||
|
cell := tb.Cell{
|
||||||
|
Ch: ' ',
|
||||||
|
Fg: tb.ColorBlack,
|
||||||
|
Bg: tb.ColorWhite,
|
||||||
|
}
|
||||||
|
if bordered.borders&BORDER_LEFT != 0 {
|
||||||
|
ctx.Fill(0, 0, 1, ctx.Height(), cell)
|
||||||
|
x += 1
|
||||||
|
width -= 1
|
||||||
|
}
|
||||||
|
if bordered.borders&BORDER_TOP != 0 {
|
||||||
|
ctx.Fill(0, 0, ctx.Width(), 1, cell)
|
||||||
|
y += 1
|
||||||
|
height -= 1
|
||||||
|
}
|
||||||
|
if bordered.borders&BORDER_RIGHT != 0 {
|
||||||
|
ctx.Fill(ctx.Width()-1, 0, 1, ctx.Height(), cell)
|
||||||
|
width -= 1
|
||||||
|
}
|
||||||
|
if bordered.borders&BORDER_BOTTOM != 0 {
|
||||||
|
ctx.Fill(0, ctx.Height()-1, ctx.Width(), 1, cell)
|
||||||
|
height -= 1
|
||||||
|
}
|
||||||
|
subctx := ctx.Subcontext(x, y, width, height)
|
||||||
|
bordered.content.Draw(subctx)
|
||||||
|
}
|
56
ui/grid.go
56
ui/grid.go
|
@ -6,10 +6,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Grid struct {
|
type Grid struct {
|
||||||
Rows []DimSpec
|
rows []GridSpec
|
||||||
rowLayout []dimLayout
|
rowLayout []gridLayout
|
||||||
Columns []DimSpec
|
columns []GridSpec
|
||||||
columnLayout []dimLayout
|
columnLayout []gridLayout
|
||||||
Cells []*GridCell
|
Cells []*GridCell
|
||||||
onInvalidate func(d Drawable)
|
onInvalidate func(d Drawable)
|
||||||
invalid bool
|
invalid bool
|
||||||
|
@ -21,17 +21,17 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Specifies the layout of a single row or column
|
// Specifies the layout of a single row or column
|
||||||
type DimSpec struct {
|
type GridSpec struct {
|
||||||
// One of SIZE_EXACT or SIZE_WEIGHT
|
// One of SIZE_EXACT or SIZE_WEIGHT
|
||||||
Strategy int
|
Strategy int
|
||||||
// If Strategy = SIZE_EXACT, this is the number of cells this dim shall
|
// If Strategy = SIZE_EXACT, this is the number of cells this row/col shall
|
||||||
// occupy. If SIZE_WEIGHT, the space left after all exact dims are measured
|
// occupy. If SIZE_WEIGHT, the space left after all exact rows/cols are
|
||||||
// is distributed amonst the remaining dims weighted by this value.
|
// measured is distributed amonst the remainder weighted by this value.
|
||||||
Size int
|
Size int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to cache layout of each row/column
|
// Used to cache layout of each row/column
|
||||||
type dimLayout struct {
|
type gridLayout struct {
|
||||||
Offset int
|
Offset int
|
||||||
Size int
|
Size int
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,16 @@ func (cell *GridCell) Span(rows, cols int) *GridCell {
|
||||||
return cell
|
return cell
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (grid *Grid) Rows(spec []GridSpec) *Grid {
|
||||||
|
grid.rows = spec
|
||||||
|
return grid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (grid *Grid) Columns(spec []GridSpec) *Grid {
|
||||||
|
grid.columns = spec
|
||||||
|
return grid
|
||||||
|
}
|
||||||
|
|
||||||
func (grid *Grid) Draw(ctx *Context) {
|
func (grid *Grid) Draw(ctx *Context) {
|
||||||
invalid := grid.invalid
|
invalid := grid.invalid
|
||||||
if invalid {
|
if invalid {
|
||||||
|
@ -90,25 +100,25 @@ func (grid *Grid) Draw(ctx *Context) {
|
||||||
func (grid *Grid) reflow(ctx *Context) {
|
func (grid *Grid) reflow(ctx *Context) {
|
||||||
grid.rowLayout = nil
|
grid.rowLayout = nil
|
||||||
grid.columnLayout = nil
|
grid.columnLayout = nil
|
||||||
flow := func(specs *[]DimSpec, layouts *[]dimLayout, extent int) {
|
flow := func(specs *[]GridSpec, layouts *[]gridLayout, extent int) {
|
||||||
exact := 0
|
exact := 0
|
||||||
weight := 0
|
weight := 0
|
||||||
nweights := 0
|
nweights := 0
|
||||||
for _, dim := range *specs {
|
for _, spec := range *specs {
|
||||||
if dim.Strategy == SIZE_EXACT {
|
if spec.Strategy == SIZE_EXACT {
|
||||||
exact += dim.Size
|
exact += spec.Size
|
||||||
} else if dim.Strategy == SIZE_WEIGHT {
|
} else if spec.Strategy == SIZE_WEIGHT {
|
||||||
nweights += 1
|
nweights += 1
|
||||||
weight += dim.Size
|
weight += spec.Size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
offset := 0
|
offset := 0
|
||||||
for _, dim := range *specs {
|
for _, spec := range *specs {
|
||||||
layout := dimLayout{Offset: offset}
|
layout := gridLayout{Offset: offset}
|
||||||
if dim.Strategy == SIZE_EXACT {
|
if spec.Strategy == SIZE_EXACT {
|
||||||
layout.Size = dim.Size
|
layout.Size = spec.Size
|
||||||
} else if dim.Strategy == SIZE_WEIGHT {
|
} else if spec.Strategy == SIZE_WEIGHT {
|
||||||
size := float64(dim.Size) / float64(weight)
|
size := float64(spec.Size) / float64(weight)
|
||||||
size *= float64(extent - exact)
|
size *= float64(extent - exact)
|
||||||
layout.Size = int(math.Floor(size))
|
layout.Size = int(math.Floor(size))
|
||||||
}
|
}
|
||||||
|
@ -116,8 +126,8 @@ func (grid *Grid) reflow(ctx *Context) {
|
||||||
*layouts = append(*layouts, layout)
|
*layouts = append(*layouts, layout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
flow(&grid.Rows, &grid.rowLayout, ctx.Height())
|
flow(&grid.rows, &grid.rowLayout, ctx.Height())
|
||||||
flow(&grid.Columns, &grid.columnLayout, ctx.Width())
|
flow(&grid.columns, &grid.columnLayout, ctx.Width())
|
||||||
grid.invalid = false
|
grid.invalid = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue