Add borders widget
This commit is contained in:
parent
7f67162f43
commit
f0791d4ba7
3 changed files with 123 additions and 39 deletions
|
@ -52,22 +52,23 @@ func main() {
|
|||
tabs.Add(fill('★'), "白い星")
|
||||
tabs.Add(fill('☆'), "empty stars")
|
||||
|
||||
grid := ui.NewGrid()
|
||||
grid.Rows = []ui.DimSpec{
|
||||
ui.DimSpec{ui.SIZE_EXACT, 1},
|
||||
ui.DimSpec{ui.SIZE_WEIGHT, 1},
|
||||
ui.DimSpec{ui.SIZE_WEIGHT, 1},
|
||||
ui.DimSpec{ui.SIZE_EXACT, 1},
|
||||
}
|
||||
grid.Columns = []ui.DimSpec{
|
||||
ui.DimSpec{ui.SIZE_WEIGHT, 3},
|
||||
ui.DimSpec{ui.SIZE_WEIGHT, 2},
|
||||
}
|
||||
grid.AddChild(tabs.TabStrip).At(0, 0).Span(1, 2)
|
||||
grid.AddChild(tabs.TabContent).At(1, 0).Span(1, 2)
|
||||
grid.AddChild(fill('.')).At(2, 0).Span(1, 2)
|
||||
grid.AddChild(fill('•')).At(2, 1).Span(1, 1)
|
||||
grid.AddChild(fill('+')).At(3, 0).Span(1, 2)
|
||||
grid := ui.NewGrid().Rows([]ui.GridSpec{
|
||||
ui.GridSpec{ui.SIZE_EXACT, 1},
|
||||
ui.GridSpec{ui.SIZE_WEIGHT, 1},
|
||||
ui.GridSpec{ui.SIZE_EXACT, 1},
|
||||
}).Columns([]ui.GridSpec{
|
||||
ui.GridSpec{ui.SIZE_EXACT, 20},
|
||||
ui.GridSpec{ui.SIZE_WEIGHT, 1},
|
||||
})
|
||||
|
||||
// TODO: move sidebar into tab content, probably
|
||||
// sidebar placeholder:
|
||||
grid.AddChild(ui.NewBordered(
|
||||
fill('.'), ui.BORDER_RIGHT)).At(1, 0).Span(2, 1)
|
||||
grid.AddChild(tabs.TabStrip).At(0, 1)
|
||||
grid.AddChild(tabs.TabContent).At(1, 1)
|
||||
// ex line placeholder:
|
||||
grid.AddChild(fill('+')).At(2, 1)
|
||||
|
||||
_ui, err := ui.Initialize(conf, grid)
|
||||
if err != nil {
|
||||
|
|
73
ui/borders.go
Normal file
73
ui/borders.go
Normal file
|
@ -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 {
|
||||
Rows []DimSpec
|
||||
rowLayout []dimLayout
|
||||
Columns []DimSpec
|
||||
columnLayout []dimLayout
|
||||
rows []GridSpec
|
||||
rowLayout []gridLayout
|
||||
columns []GridSpec
|
||||
columnLayout []gridLayout
|
||||
Cells []*GridCell
|
||||
onInvalidate func(d Drawable)
|
||||
invalid bool
|
||||
|
@ -21,17 +21,17 @@ const (
|
|||
)
|
||||
|
||||
// Specifies the layout of a single row or column
|
||||
type DimSpec struct {
|
||||
type GridSpec struct {
|
||||
// One of SIZE_EXACT or SIZE_WEIGHT
|
||||
Strategy int
|
||||
// If Strategy = SIZE_EXACT, this is the number of cells this dim shall
|
||||
// occupy. If SIZE_WEIGHT, the space left after all exact dims are measured
|
||||
// is distributed amonst the remaining dims weighted by this value.
|
||||
// If Strategy = SIZE_EXACT, this is the number of cells this row/col shall
|
||||
// occupy. If SIZE_WEIGHT, the space left after all exact rows/cols are
|
||||
// measured is distributed amonst the remainder weighted by this value.
|
||||
Size int
|
||||
}
|
||||
|
||||
// Used to cache layout of each row/column
|
||||
type dimLayout struct {
|
||||
type gridLayout struct {
|
||||
Offset int
|
||||
Size int
|
||||
}
|
||||
|
@ -61,6 +61,16 @@ func (cell *GridCell) Span(rows, cols int) *GridCell {
|
|||
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) {
|
||||
invalid := grid.invalid
|
||||
if invalid {
|
||||
|
@ -90,25 +100,25 @@ func (grid *Grid) Draw(ctx *Context) {
|
|||
func (grid *Grid) reflow(ctx *Context) {
|
||||
grid.rowLayout = nil
|
||||
grid.columnLayout = nil
|
||||
flow := func(specs *[]DimSpec, layouts *[]dimLayout, extent int) {
|
||||
flow := func(specs *[]GridSpec, layouts *[]gridLayout, extent int) {
|
||||
exact := 0
|
||||
weight := 0
|
||||
nweights := 0
|
||||
for _, dim := range *specs {
|
||||
if dim.Strategy == SIZE_EXACT {
|
||||
exact += dim.Size
|
||||
} else if dim.Strategy == SIZE_WEIGHT {
|
||||
for _, spec := range *specs {
|
||||
if spec.Strategy == SIZE_EXACT {
|
||||
exact += spec.Size
|
||||
} else if spec.Strategy == SIZE_WEIGHT {
|
||||
nweights += 1
|
||||
weight += dim.Size
|
||||
weight += spec.Size
|
||||
}
|
||||
}
|
||||
offset := 0
|
||||
for _, dim := range *specs {
|
||||
layout := dimLayout{Offset: offset}
|
||||
if dim.Strategy == SIZE_EXACT {
|
||||
layout.Size = dim.Size
|
||||
} else if dim.Strategy == SIZE_WEIGHT {
|
||||
size := float64(dim.Size) / float64(weight)
|
||||
for _, spec := range *specs {
|
||||
layout := gridLayout{Offset: offset}
|
||||
if spec.Strategy == SIZE_EXACT {
|
||||
layout.Size = spec.Size
|
||||
} else if spec.Strategy == SIZE_WEIGHT {
|
||||
size := float64(spec.Size) / float64(weight)
|
||||
size *= float64(extent - exact)
|
||||
layout.Size = int(math.Floor(size))
|
||||
}
|
||||
|
@ -116,8 +126,8 @@ func (grid *Grid) reflow(ctx *Context) {
|
|||
*layouts = append(*layouts, layout)
|
||||
}
|
||||
}
|
||||
flow(&grid.Rows, &grid.rowLayout, ctx.Height())
|
||||
flow(&grid.Columns, &grid.columnLayout, ctx.Width())
|
||||
flow(&grid.rows, &grid.rowLayout, ctx.Height())
|
||||
flow(&grid.columns, &grid.columnLayout, ctx.Width())
|
||||
grid.invalid = false
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue