mirror of
https://github.com/mum4k/termdash.git
synced 2025-05-03 22:17:06 +08:00
Adding canvas function that sets area of cells.
This commit is contained in:
parent
0490734d1e
commit
417eee0799
@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
"github.com/mum4k/termdash/area"
|
"github.com/mum4k/termdash/area"
|
||||||
"github.com/mum4k/termdash/cell"
|
"github.com/mum4k/termdash/cell"
|
||||||
|
"github.com/mum4k/termdash/cell/runewidth"
|
||||||
"github.com/mum4k/termdash/terminalapi"
|
"github.com/mum4k/termdash/terminalapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -117,6 +118,32 @@ func (c *Canvas) SetCellOpts(p image.Point, opts ...cell.Option) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetAreaCells is like SetCell, but sets the specified rune and options on all
|
||||||
|
// the cells within the provided area.
|
||||||
|
// This method is idempotent.
|
||||||
|
func (c *Canvas) SetAreaCells(cellArea image.Rectangle, r rune, opts ...cell.Option) error {
|
||||||
|
haveArea := c.Area()
|
||||||
|
if !cellArea.In(haveArea) {
|
||||||
|
return fmt.Errorf("unable to set cell runes in area %v, it must fit inside the available cell area is %v", cellArea, haveArea)
|
||||||
|
}
|
||||||
|
|
||||||
|
rw := runewidth.RuneWidth(r)
|
||||||
|
for row := cellArea.Min.Y; row < cellArea.Max.Y; row++ {
|
||||||
|
for col := cellArea.Min.X; col < cellArea.Max.X; {
|
||||||
|
p := image.Point{col, row}
|
||||||
|
if col+rw > cellArea.Max.X {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
cells, err := c.SetCell(p, r, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
col += cells
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// SetAreaCellOpts is like SetCellOpts, but sets the specified options on all
|
// SetAreaCellOpts is like SetCellOpts, but sets the specified options on all
|
||||||
// the cells within the provided area.
|
// the cells within the provided area.
|
||||||
func (c *Canvas) SetAreaCellOpts(cellArea image.Rectangle, opts ...cell.Option) error {
|
func (c *Canvas) SetAreaCellOpts(cellArea image.Rectangle, opts ...cell.Option) error {
|
||||||
|
@ -317,6 +317,173 @@ func TestCanvas(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := cvs.Apply(ft); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ft, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "SetAreaCells sets cells in the full canvas",
|
||||||
|
canvas: image.Rect(0, 0, 1, 1),
|
||||||
|
ops: func(cvs *Canvas) error {
|
||||||
|
return cvs.SetAreaCells(image.Rect(0, 0, 1, 1), 'r')
|
||||||
|
},
|
||||||
|
want: func(size image.Point) (*faketerm.Terminal, error) {
|
||||||
|
ft := faketerm.MustNew(size)
|
||||||
|
cvs, err := New(ft.Area())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := cvs.SetCell(image.Point{0, 0}, 'r'); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cvs.Apply(ft); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ft, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "SetAreaCells is idempotent",
|
||||||
|
canvas: image.Rect(0, 0, 1, 1),
|
||||||
|
ops: func(cvs *Canvas) error {
|
||||||
|
if err := cvs.SetAreaCells(image.Rect(0, 0, 1, 1), 'r'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return cvs.SetAreaCells(image.Rect(0, 0, 1, 1), 'r')
|
||||||
|
},
|
||||||
|
want: func(size image.Point) (*faketerm.Terminal, error) {
|
||||||
|
ft := faketerm.MustNew(size)
|
||||||
|
cvs, err := New(ft.Area())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := cvs.SetCell(image.Point{0, 0}, 'r'); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cvs.Apply(ft); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ft, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "SetAreaCells fails on area too large",
|
||||||
|
canvas: image.Rect(0, 0, 1, 1),
|
||||||
|
ops: func(cvs *Canvas) error {
|
||||||
|
return cvs.SetAreaCells(image.Rect(0, 0, 2, 2), 'r', cell.FgColor(cell.ColorRed), cell.BgColor(cell.ColorBlue))
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "SetAreaCells sets cell options",
|
||||||
|
canvas: image.Rect(0, 0, 1, 1),
|
||||||
|
ops: func(cvs *Canvas) error {
|
||||||
|
return cvs.SetAreaCells(image.Rect(0, 0, 1, 1), 'r', cell.FgColor(cell.ColorRed), cell.BgColor(cell.ColorBlue))
|
||||||
|
},
|
||||||
|
want: func(size image.Point) (*faketerm.Terminal, error) {
|
||||||
|
ft := faketerm.MustNew(size)
|
||||||
|
cvs, err := New(ft.Area())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := cvs.SetCell(image.Point{0, 0}, 'r', cell.FgColor(cell.ColorRed), cell.BgColor(cell.ColorBlue)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cvs.Apply(ft); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ft, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "SetAreaCells sets cell in a sub-area",
|
||||||
|
canvas: image.Rect(0, 0, 3, 3),
|
||||||
|
ops: func(cvs *Canvas) error {
|
||||||
|
return cvs.SetAreaCells(image.Rect(0, 0, 2, 2), 'p')
|
||||||
|
},
|
||||||
|
want: func(size image.Point) (*faketerm.Terminal, error) {
|
||||||
|
ft := faketerm.MustNew(size)
|
||||||
|
cvs, err := New(ft.Area())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range []image.Point{
|
||||||
|
{0, 0},
|
||||||
|
{0, 1},
|
||||||
|
{1, 0},
|
||||||
|
{1, 1},
|
||||||
|
} {
|
||||||
|
if _, err := cvs.SetCell(p, 'p'); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cvs.Apply(ft); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ft, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "SetAreaCells sets full-width runes that fit",
|
||||||
|
canvas: image.Rect(0, 0, 3, 3),
|
||||||
|
ops: func(cvs *Canvas) error {
|
||||||
|
return cvs.SetAreaCells(image.Rect(0, 0, 2, 2), '世')
|
||||||
|
},
|
||||||
|
want: func(size image.Point) (*faketerm.Terminal, error) {
|
||||||
|
ft := faketerm.MustNew(size)
|
||||||
|
cvs, err := New(ft.Area())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range []image.Point{
|
||||||
|
{0, 0},
|
||||||
|
{0, 1},
|
||||||
|
} {
|
||||||
|
if _, err := cvs.SetCell(p, '世'); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cvs.Apply(ft); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ft, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "SetAreaCells sets full-width runes that will leave a gap at the end of each row",
|
||||||
|
canvas: image.Rect(0, 0, 3, 3),
|
||||||
|
ops: func(cvs *Canvas) error {
|
||||||
|
return cvs.SetAreaCells(image.Rect(0, 0, 3, 3), '世')
|
||||||
|
},
|
||||||
|
want: func(size image.Point) (*faketerm.Terminal, error) {
|
||||||
|
ft := faketerm.MustNew(size)
|
||||||
|
cvs, err := New(ft.Area())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range []image.Point{
|
||||||
|
{0, 0},
|
||||||
|
{0, 1},
|
||||||
|
{0, 2},
|
||||||
|
} {
|
||||||
|
if _, err := cvs.SetCell(p, '世'); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := cvs.Apply(ft); err != nil {
|
if err := cvs.Apply(ft); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user