Smash Border into Block
This commit is contained in:
parent
7aed750f64
commit
b65224cdc9
1
.gitignore
vendored
1
.gitignore
vendored
@ -22,3 +22,4 @@ _testmain.go
|
|||||||
*.exe
|
*.exe
|
||||||
*.test
|
*.test
|
||||||
*.prof
|
*.prof
|
||||||
|
.DS_Store
|
||||||
|
228
block.go
228
block.go
@ -6,17 +6,116 @@ package termui
|
|||||||
|
|
||||||
import "image"
|
import "image"
|
||||||
|
|
||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Hline is a horizontal line.
|
||||||
|
type Hline struct {
|
||||||
|
X int
|
||||||
|
Y int
|
||||||
|
Len int
|
||||||
|
Fg Attribute
|
||||||
|
Bg Attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vline is a vertical line.
|
||||||
|
type Vline struct {
|
||||||
|
X int
|
||||||
|
Y int
|
||||||
|
Len int
|
||||||
|
Fg Attribute
|
||||||
|
Bg Attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer draws a horizontal line.
|
||||||
|
func (l Hline) Buffer() Buffer {
|
||||||
|
if l.Len <= 0 {
|
||||||
|
return NewBuffer()
|
||||||
|
}
|
||||||
|
return NewFilledBuffer(l.X, l.Y, l.X+l.Len, l.Y, HORIZONTAL_LINE, l.Fg, l.Bg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer draws a vertical line.
|
||||||
|
func (l Vline) Buffer() Buffer {
|
||||||
|
if l.Len <= 0 {
|
||||||
|
return NewBuffer()
|
||||||
|
}
|
||||||
|
return NewFilledBuffer(l.X, l.Y, l.X, l.Y+l.Len, VERTICAL_LINE, l.Fg, l.Bg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer draws a box border.
|
||||||
|
func (b Block) drawBorder(buf Buffer) {
|
||||||
|
if !b.Border {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
min := b.area.Min
|
||||||
|
max := b.area.Max
|
||||||
|
|
||||||
|
x0 := min.X
|
||||||
|
y0 := min.Y
|
||||||
|
x1 := max.X
|
||||||
|
y1 := max.Y
|
||||||
|
|
||||||
|
// draw lines
|
||||||
|
if b.BorderTop {
|
||||||
|
buf.Merge(Hline{x0, y0, x1 - x0, b.BorderFg, b.BorderBg}.Buffer())
|
||||||
|
}
|
||||||
|
if b.BorderBottom {
|
||||||
|
buf.Merge(Hline{x0, y1, x1 - x0, b.BorderFg, b.BorderBg}.Buffer())
|
||||||
|
}
|
||||||
|
if b.BorderLeft {
|
||||||
|
buf.Merge(Vline{x0, y0, y1 - y0, b.BorderFg, b.BorderBg}.Buffer())
|
||||||
|
}
|
||||||
|
if b.BorderRight {
|
||||||
|
buf.Merge(Vline{x1, y0, y1 - y0, b.BorderFg, b.BorderBg}.Buffer())
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw corners
|
||||||
|
if b.BorderTop && b.BorderLeft && b.area.Dx() > 0 && b.area.Dy() > 0 {
|
||||||
|
buf.Set(x0, y0, Cell{TOP_LEFT, b.BorderFg, b.BorderBg})
|
||||||
|
}
|
||||||
|
if b.BorderTop && b.BorderRight && b.area.Dx() > 1 && b.area.Dy() > 0 {
|
||||||
|
buf.Set(x1, y0, Cell{TOP_RIGHT, b.BorderFg, b.BorderBg})
|
||||||
|
}
|
||||||
|
if b.BorderBottom && b.BorderLeft && b.area.Dx() > 0 && b.area.Dy() > 1 {
|
||||||
|
buf.Set(x0, y1, Cell{BOTTOM_LEFT, b.BorderFg, b.BorderBg})
|
||||||
|
}
|
||||||
|
if b.BorderBottom && b.BorderRight && b.area.Dx() > 1 && b.area.Dy() > 1 {
|
||||||
|
buf.Set(x1, y1, Cell{BOTTOM_RIGHT, b.BorderFg, b.BorderBg})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Block) drawBorderLabel(buf Buffer) {
|
||||||
|
maxTxtW := b.area.Dx() - 2
|
||||||
|
tx := DTrimTxCls(TextCells(b.BorderLabel, b.BorderLabelFg, b.BorderLabelBg), maxTxtW)
|
||||||
|
|
||||||
|
for i, w := 0, 0; i < len(tx); i++ {
|
||||||
|
buf.Set(b.area.Min.X+1+w, b.area.Min.Y, tx[i])
|
||||||
|
w += tx[i].Width()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Block is a base struct for all other upper level widgets,
|
// Block is a base struct for all other upper level widgets,
|
||||||
// consider it as css: display:block.
|
// consider it as css: display:block.
|
||||||
// Normally you do not need to create it manually.
|
// Normally you do not need to create it manually.
|
||||||
type Block struct {
|
type Block struct {
|
||||||
Area image.Rectangle
|
area image.Rectangle
|
||||||
innerArea image.Rectangle
|
innerArea image.Rectangle
|
||||||
X int
|
X int
|
||||||
Y int
|
Y int
|
||||||
Border LabeledBorder
|
Border bool
|
||||||
IsDisplay bool
|
BorderFg Attribute
|
||||||
HasBorder bool
|
BorderBg Attribute
|
||||||
|
BorderLeft bool
|
||||||
|
BorderRight bool
|
||||||
|
BorderTop bool
|
||||||
|
BorderBottom bool
|
||||||
|
BorderLabel string
|
||||||
|
BorderLabelFg Attribute
|
||||||
|
BorderLabelBg Attribute
|
||||||
|
Display bool
|
||||||
Bg Attribute
|
Bg Attribute
|
||||||
Width int
|
Width int
|
||||||
Height int
|
Height int
|
||||||
@ -28,103 +127,90 @@ type Block struct {
|
|||||||
|
|
||||||
// NewBlock returns a *Block which inherits styles from current theme.
|
// NewBlock returns a *Block which inherits styles from current theme.
|
||||||
func NewBlock() *Block {
|
func NewBlock() *Block {
|
||||||
d := Block{}
|
b := Block{}
|
||||||
d.IsDisplay = true
|
b.Display = true
|
||||||
d.HasBorder = theme.HasBorder
|
b.Border = theme.HasBorder
|
||||||
d.Border.Left = true
|
b.BorderLeft = true
|
||||||
d.Border.Right = true
|
b.BorderRight = true
|
||||||
d.Border.Top = true
|
b.BorderTop = true
|
||||||
d.Border.Bottom = true
|
b.BorderBottom = true
|
||||||
d.Border.Bg = theme.BorderBg
|
b.BorderBg = theme.BorderBg
|
||||||
d.Border.Fg = theme.BorderFg
|
b.BorderFg = theme.BorderFg
|
||||||
d.Border.LabelBgClr = theme.BorderLabelTextBg
|
b.BorderLabelBg = theme.BorderLabelTextBg
|
||||||
d.Border.LabelFgClr = theme.BorderLabelTextFg
|
b.BorderLabelFg = theme.BorderLabelTextFg
|
||||||
d.Bg = theme.BlockBg
|
b.Bg = theme.BlockBg
|
||||||
d.Width = 2
|
b.Width = 2
|
||||||
d.Height = 2
|
b.Height = 2
|
||||||
return &d
|
return &b
|
||||||
}
|
}
|
||||||
|
|
||||||
// Align computes box model
|
// Align computes box mob.l
|
||||||
func (d *Block) Align() {
|
func (b *Block) Align() {
|
||||||
d.Area.Min.X = d.X
|
b.area.Min.X = b.X
|
||||||
d.Area.Min.Y = d.Y
|
b.area.Min.Y = b.Y
|
||||||
d.Area.Max.X = d.X + d.Width - 1
|
b.area.Max.X = b.X + b.Width - 1
|
||||||
d.Area.Max.Y = d.Y + d.Height - 1
|
b.area.Max.Y = b.Y + b.Height - 1
|
||||||
|
|
||||||
d.innerArea.Min.X = d.X + d.PaddingLeft
|
b.innerArea.Min.X = b.X + b.PaddingLeft
|
||||||
d.innerArea.Min.Y = d.Y + d.PaddingTop
|
b.innerArea.Min.Y = b.Y + b.PaddingTop
|
||||||
d.innerArea.Max.X = d.Area.Max.X - d.PaddingRight
|
b.innerArea.Max.X = b.area.Max.X - b.PaddingRight
|
||||||
d.innerArea.Max.Y = d.Area.Max.Y - d.PaddingBottom
|
b.innerArea.Max.Y = b.area.Max.Y - b.PaddingBottom
|
||||||
|
|
||||||
d.Border.Area = d.Area
|
if b.Border {
|
||||||
|
if b.BorderLeft {
|
||||||
if d.HasBorder {
|
b.innerArea.Min.X++
|
||||||
switch {
|
}
|
||||||
case d.Border.Left:
|
if b.BorderRight {
|
||||||
d.innerArea.Min.X++
|
b.innerArea.Max.X--
|
||||||
fallthrough
|
}
|
||||||
case d.Border.Right:
|
if b.BorderTop {
|
||||||
d.innerArea.Max.X--
|
b.innerArea.Min.Y++
|
||||||
fallthrough
|
}
|
||||||
case d.Border.Top:
|
if b.BorderBottom {
|
||||||
d.innerArea.Min.Y++
|
b.innerArea.Max.Y--
|
||||||
fallthrough
|
|
||||||
case d.Border.Bottom:
|
|
||||||
d.innerArea.Max.Y--
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// InnerBounds returns the internal bounds of the block after aligning and
|
// InnerBounds returns the internal bounds of the block after aligning and
|
||||||
// calculating the padding and border, if any.
|
// calculating the padding and border, if any.
|
||||||
func (d *Block) InnerBounds() image.Rectangle {
|
func (b *Block) InnerBounds() image.Rectangle {
|
||||||
d.Align()
|
b.Align()
|
||||||
return d.innerArea
|
return b.innerArea
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buffer implements Bufferer interface.
|
// Buffer implements Bufferer interface.
|
||||||
// Draw background and border (if any).
|
// Draw background and border (if any).
|
||||||
func (d *Block) Buffer() Buffer {
|
func (b *Block) Buffer() Buffer {
|
||||||
d.Align()
|
b.Align()
|
||||||
|
|
||||||
buf := NewBuffer()
|
buf := NewBuffer()
|
||||||
buf.Area = d.Area
|
buf.SetArea(b.area)
|
||||||
if !d.IsDisplay {
|
buf.Fill(' ', ColorDefault, b.Bg)
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
// render border
|
b.drawBorder(buf)
|
||||||
if d.HasBorder {
|
b.drawBorderLabel(buf)
|
||||||
buf.Union(d.Border.Buffer())
|
|
||||||
}
|
|
||||||
|
|
||||||
// render background
|
|
||||||
for p := range buf.CellMap {
|
|
||||||
if p.In(d.innerArea) {
|
|
||||||
buf.CellMap[p] = Cell{' ', ColorDefault, d.Bg}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHeight implements GridBufferer.
|
// GetHeight implements GridBufferer.
|
||||||
// It returns current height of the block.
|
// It returns current height of the block.
|
||||||
func (d Block) GetHeight() int {
|
func (b Block) GetHeight() int {
|
||||||
return d.Height
|
return b.Height
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetX implements GridBufferer interface, which sets block's x position.
|
// SetX implements GridBufferer interface, which sets block's x position.
|
||||||
func (d *Block) SetX(x int) {
|
func (b *Block) SetX(x int) {
|
||||||
d.X = x
|
b.X = x
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetY implements GridBufferer interface, it sets y position for block.
|
// SetY implements GridBufferer interface, it sets y position for block.
|
||||||
func (d *Block) SetY(y int) {
|
func (b *Block) SetY(y int) {
|
||||||
d.Y = y
|
b.Y = y
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetWidth implements GridBuffer interface, it sets block's width.
|
// SetWidth implements GridBuffer interface, it sets block's width.
|
||||||
func (d *Block) SetWidth(w int) {
|
func (b *Block) SetWidth(w int) {
|
||||||
d.Width = w
|
b.Width = w
|
||||||
}
|
}
|
||||||
|
123
box.go
123
box.go
@ -1,123 +0,0 @@
|
|||||||
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
|
||||||
// Use of this source code is governed by a MIT license that can
|
|
||||||
// be found in the LICENSE file.
|
|
||||||
|
|
||||||
package termui
|
|
||||||
|
|
||||||
import "image"
|
|
||||||
|
|
||||||
type Border struct {
|
|
||||||
Area image.Rectangle
|
|
||||||
Left bool
|
|
||||||
Top bool
|
|
||||||
Right bool
|
|
||||||
Bottom bool
|
|
||||||
Fg Attribute
|
|
||||||
Bg Attribute
|
|
||||||
}
|
|
||||||
|
|
||||||
type Hline struct {
|
|
||||||
X int
|
|
||||||
Y int
|
|
||||||
Len int
|
|
||||||
Fg Attribute
|
|
||||||
Bg Attribute
|
|
||||||
}
|
|
||||||
|
|
||||||
type Vline struct {
|
|
||||||
X int
|
|
||||||
Y int
|
|
||||||
Len int
|
|
||||||
Fg Attribute
|
|
||||||
Bg Attribute
|
|
||||||
}
|
|
||||||
|
|
||||||
// Buffer draws a horizontal line.
|
|
||||||
func (l Hline) Buffer() Buffer {
|
|
||||||
buf := NewBuffer()
|
|
||||||
for i := 0; i < l.Len; i++ {
|
|
||||||
buf.Set(l.X+i, l.Y, Cell{HORIZONTAL_LINE, l.Fg, l.Bg})
|
|
||||||
}
|
|
||||||
buf.Align()
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
// Buffer draws a vertical line.
|
|
||||||
func (l Vline) Buffer() Buffer {
|
|
||||||
buf := NewBuffer()
|
|
||||||
for i := 0; i < l.Len; i++ {
|
|
||||||
buf.Set(l.X, l.Y+i, Cell{VERTICAL_LINE, l.Fg, l.Bg})
|
|
||||||
}
|
|
||||||
buf.Align()
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
// Buffer draws a box border.
|
|
||||||
func (b Border) Buffer() Buffer {
|
|
||||||
buf := NewBuffer()
|
|
||||||
if b.Area.Size().X < 2 || b.Area.Size().Y < 2 {
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
min := b.Area.Min
|
|
||||||
max := b.Area.Max
|
|
||||||
|
|
||||||
x0 := min.X
|
|
||||||
y0 := min.Y
|
|
||||||
x1 := max.X
|
|
||||||
y1 := max.Y
|
|
||||||
|
|
||||||
// draw lines
|
|
||||||
switch {
|
|
||||||
case b.Top:
|
|
||||||
buf.Union(Hline{x0, y0, x1 - x0, b.Fg, b.Bg}.Buffer())
|
|
||||||
fallthrough
|
|
||||||
case b.Bottom:
|
|
||||||
buf.Union(Hline{x0, y1, x1 - x0, b.Fg, b.Bg}.Buffer())
|
|
||||||
fallthrough
|
|
||||||
case b.Left:
|
|
||||||
buf.Union(Vline{x0, y0, y1 - y0, b.Fg, b.Bg}.Buffer())
|
|
||||||
fallthrough
|
|
||||||
case b.Right:
|
|
||||||
buf.Union(Vline{x1, y0, y1 - y0, b.Fg, b.Bg}.Buffer())
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw corners
|
|
||||||
switch {
|
|
||||||
case b.Top && b.Left:
|
|
||||||
buf.Set(x0, y0, Cell{TOP_LEFT, b.Fg, b.Bg})
|
|
||||||
fallthrough
|
|
||||||
case b.Top && b.Right:
|
|
||||||
buf.Set(x1, y0, Cell{TOP_RIGHT, b.Fg, b.Bg})
|
|
||||||
fallthrough
|
|
||||||
case b.Bottom && b.Left:
|
|
||||||
buf.Set(x0, y1, Cell{BOTTOM_LEFT, b.Fg, b.Bg})
|
|
||||||
fallthrough
|
|
||||||
case b.Bottom && b.Right:
|
|
||||||
buf.Set(x1, y1, Cell{BOTTOM_RIGHT, b.Fg, b.Bg})
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
// LabeledBorder defined label upon Border
|
|
||||||
type LabeledBorder struct {
|
|
||||||
Border
|
|
||||||
Label string
|
|
||||||
LabelFgClr Attribute
|
|
||||||
LabelBgClr Attribute
|
|
||||||
}
|
|
||||||
|
|
||||||
// Buffer draw a box border with label.
|
|
||||||
func (lb LabeledBorder) Buffer() Buffer {
|
|
||||||
border := lb.Border.Buffer()
|
|
||||||
maxTxtW := lb.Area.Dx() + 1 - 2
|
|
||||||
tx := DTrimTxCls(TextCells(lb.Label, lb.LabelFgClr, lb.LabelBgClr), maxTxtW)
|
|
||||||
|
|
||||||
for i, w := 0, 0; i < len(tx); i++ {
|
|
||||||
border.Set(border.Area.Min.X+1+w, border.Area.Min.Y, tx[i])
|
|
||||||
w += tx[i].Width()
|
|
||||||
}
|
|
||||||
|
|
||||||
return border
|
|
||||||
}
|
|
74
buffer.go
74
buffer.go
@ -15,7 +15,7 @@ type Cell struct {
|
|||||||
|
|
||||||
// Buffer is a renderable rectangle cell data container.
|
// Buffer is a renderable rectangle cell data container.
|
||||||
type Buffer struct {
|
type Buffer struct {
|
||||||
Area image.Rectangle // selected drawing area
|
Area *image.Rectangle // selected drawing area
|
||||||
CellMap map[image.Point]Cell
|
CellMap map[image.Point]Cell
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,23 +33,31 @@ func (b Buffer) Set(x, y int, c Cell) {
|
|||||||
func (b Buffer) Bounds() image.Rectangle {
|
func (b Buffer) Bounds() image.Rectangle {
|
||||||
x0, y0, x1, y1 := 0, 0, 0, 0
|
x0, y0, x1, y1 := 0, 0, 0, 0
|
||||||
for p := range b.CellMap {
|
for p := range b.CellMap {
|
||||||
switch {
|
if p.X > x1 {
|
||||||
case p.X > x1:
|
|
||||||
x1 = p.X
|
x1 = p.X
|
||||||
case p.X < x0:
|
}
|
||||||
|
if p.X < x0 {
|
||||||
x0 = p.X
|
x0 = p.X
|
||||||
case p.Y > y1:
|
}
|
||||||
|
if p.Y > y1 {
|
||||||
y1 = p.Y
|
y1 = p.Y
|
||||||
case p.Y < y0:
|
}
|
||||||
|
if p.Y < y0 {
|
||||||
y0 = p.Y
|
y0 = p.Y
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return image.Rect(x0, y0, x1, y1)
|
return image.Rect(x0, y0, x1, y1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Align sets drawing area to the buffer's bound
|
// SetArea assigns a new rect area to Buffer b.
|
||||||
func (b *Buffer) Align() {
|
func (b Buffer) SetArea(r image.Rectangle) {
|
||||||
b.Area = b.Bounds()
|
b.Area.Max = r.Max
|
||||||
|
b.Area.Min = r.Min
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync sets drawing area to the buffer's bound
|
||||||
|
func (b Buffer) Sync() {
|
||||||
|
b.SetArea(b.Bounds())
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCell returns a new cell
|
// NewCell returns a new cell
|
||||||
@ -57,23 +65,16 @@ func NewCell(ch rune, fg, bg Attribute) Cell {
|
|||||||
return Cell{ch, fg, bg}
|
return Cell{ch, fg, bg}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Union squeezes buf into b
|
// Merge merges bs Buffers onto b
|
||||||
func (b Buffer) Union(buf Buffer) {
|
func (b Buffer) Merge(bs ...Buffer) {
|
||||||
for p, c := range buf.CellMap {
|
for _, buf := range bs {
|
||||||
b.Set(p.X, p.Y, c)
|
for p, v := range buf.CellMap {
|
||||||
|
b.Set(p.X, p.Y, v)
|
||||||
|
}
|
||||||
|
b.SetArea(b.Area.Union(*buf.Area))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Union returns a new Buffer formed by squeezing bufs into one Buffer
|
|
||||||
func Union(bufs ...Buffer) Buffer {
|
|
||||||
buf := NewBuffer()
|
|
||||||
for _, b := range bufs {
|
|
||||||
buf.Union(b)
|
|
||||||
}
|
|
||||||
buf.Align()
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
// Point for adapting use, will be removed after resolving bridging.
|
// Point for adapting use, will be removed after resolving bridging.
|
||||||
type Point struct {
|
type Point struct {
|
||||||
X int
|
X int
|
||||||
@ -85,5 +86,30 @@ type Point struct {
|
|||||||
|
|
||||||
// NewBuffer returns a new Buffer
|
// NewBuffer returns a new Buffer
|
||||||
func NewBuffer() Buffer {
|
func NewBuffer() Buffer {
|
||||||
return Buffer{CellMap: make(map[image.Point]Cell)}
|
return Buffer{
|
||||||
|
CellMap: make(map[image.Point]Cell),
|
||||||
|
Area: &image.Rectangle{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill fills the Buffer b with ch,fg and bg.
|
||||||
|
func (b Buffer) Fill(ch rune, fg, bg Attribute) {
|
||||||
|
for x := b.Area.Min.X; x < b.Area.Max.X; x++ {
|
||||||
|
for y := b.Area.Min.Y; y < b.Area.Max.Y; y++ {
|
||||||
|
b.Set(x, y, Cell{ch, fg, bg})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFilledBuffer returns a new Buffer filled with ch, fb and bg.
|
||||||
|
func NewFilledBuffer(x0, y0, x1, y1 int, ch rune, fg, bg Attribute) Buffer {
|
||||||
|
buf := NewBuffer()
|
||||||
|
buf.Area.Min = image.Pt(x0, y0)
|
||||||
|
buf.Area.Max = image.Pt(x1, y1)
|
||||||
|
|
||||||
|
for x := buf.Area.Min.X; x < buf.Area.Max.X; x++ {
|
||||||
|
for y := buf.Area.Min.Y; y < buf.Area.Max.Y; y++ {
|
||||||
|
buf.Set(x, y, Cell{ch, fg, bg})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user