mirror of
https://github.com/mum4k/termdash.git
synced 2025-04-25 13:48:50 +08:00
Merge branch 'text-widget/3/line-scanner' into text-widget/4/scroll-tracker
This commit is contained in:
commit
a13c1f6be2
@ -72,3 +72,7 @@ development](doc/widget_development.md) section.
|
||||
Run the [gaugedemo](widgets/gauge/demo/gaugedemo.go).
|
||||
|
||||
[<img src="./images/gaugedemo.gif" alt="gaugedemo" type="image/png" width="100%">](widgets/gauge/demo/gaugedemo.go)
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This is not an official Google product.
|
||||
|
@ -40,6 +40,7 @@ var colorNames = map[Color]string{
|
||||
ColorWhite: "ColorWhite",
|
||||
}
|
||||
|
||||
// The supported terminal colors.
|
||||
const (
|
||||
ColorDefault Color = iota
|
||||
ColorBlack
|
||||
|
@ -105,9 +105,8 @@ func (c *Container) hasWidget() bool {
|
||||
func (c *Container) usable() image.Rectangle {
|
||||
if c.hasBorder() {
|
||||
return area.ExcludeBorder(c.area)
|
||||
} else {
|
||||
return c.area
|
||||
}
|
||||
return c.area
|
||||
}
|
||||
|
||||
// widgetArea returns the area in the container that is available for the
|
||||
@ -142,11 +141,11 @@ func (c *Container) widgetArea() (image.Rectangle, error) {
|
||||
// split splits the container's usable area into child areas.
|
||||
// Panics if the container isn't configured for a split.
|
||||
func (c *Container) split() (image.Rectangle, image.Rectangle) {
|
||||
if ar := c.usable(); c.opts.split == splitTypeVertical {
|
||||
ar := c.usable()
|
||||
if c.opts.split == splitTypeVertical {
|
||||
return area.VSplit(ar)
|
||||
} else {
|
||||
return area.HSplit(ar)
|
||||
}
|
||||
return area.HSplit(ar)
|
||||
}
|
||||
|
||||
// createFirst creates and returns the first sub container of this container.
|
||||
|
@ -133,8 +133,7 @@ func drawResize(c *Container, area image.Rectangle) error {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = draw.Text(cvs, "⇄", image.Point{0, 0})
|
||||
if err != nil {
|
||||
if err := draw.Text(cvs, "⇄", image.Point{0, 0}); err != nil {
|
||||
return err
|
||||
}
|
||||
return cvs.Apply(c.term)
|
||||
|
@ -56,7 +56,7 @@ A typical unit test creates the expected fake terminal, executes the widget to
|
||||
get the actual fake terminal and compares the two:
|
||||
|
||||
```go
|
||||
TestWidget(t *testing.T) {
|
||||
func TestWidget(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
canvas image.Rectangle
|
||||
|
@ -124,13 +124,12 @@ func drawTitle(c *canvas.Canvas, border image.Rectangle, opt *borderOptions) err
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = Text(
|
||||
return Text(
|
||||
c, opt.title, start,
|
||||
TextCellOpts(opt.titleCellOpts...),
|
||||
TextOverrunMode(opt.titleOM),
|
||||
TextMaxX(available.Max.X),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
// Border draws a border on the canvas.
|
||||
|
@ -56,6 +56,7 @@ var lineStyleNames = map[LineStyle]string{
|
||||
LineStyleLight: "LineStyleLight",
|
||||
}
|
||||
|
||||
// Supported line styles.
|
||||
const (
|
||||
LineStyleNone LineStyle = iota
|
||||
LineStyleLight
|
||||
|
@ -31,13 +31,10 @@ func MustBorder(c *canvas.Canvas, border image.Rectangle, opts ...draw.BorderOpt
|
||||
}
|
||||
|
||||
// MustText draws the text on the canvas or panics.
|
||||
// Returns the number of written cells.
|
||||
func MustText(c *canvas.Canvas, text string, start image.Point, opts ...draw.TextOption) int {
|
||||
cells, err := draw.Text(c, text, start, opts...)
|
||||
if err != nil {
|
||||
func MustText(c *canvas.Canvas, text string, start image.Point, opts ...draw.TextOption) {
|
||||
if err := draw.Text(c, text, start, opts...); err != nil {
|
||||
panic(fmt.Sprintf("draw.Text => unexpected error: %v", err))
|
||||
}
|
||||
return cells
|
||||
}
|
||||
|
||||
// MustRectangle draws the rectangle on the canvas or panics.
|
||||
|
13
draw/text.go
13
draw/text.go
@ -125,11 +125,10 @@ func bounds(text string, maxRunes int, om OverrunMode) (string, error) {
|
||||
}
|
||||
|
||||
// Text prints the provided text on the canvas starting at the provided point.
|
||||
// Returns the number of cells written.
|
||||
func Text(c *canvas.Canvas, text string, start image.Point, opts ...TextOption) (int, error) {
|
||||
func Text(c *canvas.Canvas, text string, start image.Point, opts ...TextOption) error {
|
||||
ar := c.Area()
|
||||
if !start.In(ar) {
|
||||
return -1, fmt.Errorf("the requested start point %v falls outside of the provided canvas %v", start, ar)
|
||||
return fmt.Errorf("the requested start point %v falls outside of the provided canvas %v", start, ar)
|
||||
}
|
||||
|
||||
opt := &textOptions{}
|
||||
@ -138,7 +137,7 @@ func Text(c *canvas.Canvas, text string, start image.Point, opts ...TextOption)
|
||||
}
|
||||
|
||||
if opt.maxX < 0 || opt.maxX > ar.Max.X {
|
||||
return -1, fmt.Errorf("invalid TextMaxX(%v), must be a positive number that is <= canvas.width %v", opt.maxX, ar.Dx())
|
||||
return fmt.Errorf("invalid TextMaxX(%v), must be a positive number that is <= canvas.width %v", opt.maxX, ar.Dx())
|
||||
}
|
||||
|
||||
var wantMaxX int
|
||||
@ -151,15 +150,15 @@ func Text(c *canvas.Canvas, text string, start image.Point, opts ...TextOption)
|
||||
maxRunes := wantMaxX - start.X
|
||||
trimmed, err := bounds(text, maxRunes, opt.overrunMode)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
return err
|
||||
}
|
||||
|
||||
cur := start
|
||||
for _, r := range trimmed {
|
||||
if err := c.SetCell(cur, r, opt.cellOpts...); err != nil {
|
||||
return -1, err
|
||||
return err
|
||||
}
|
||||
cur = image.Point{cur.X + 1, cur.Y}
|
||||
}
|
||||
return cur.X - start.X, nil
|
||||
return nil
|
||||
}
|
||||
|
@ -26,14 +26,13 @@ import (
|
||||
|
||||
func TestText(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
canvas image.Rectangle
|
||||
text string
|
||||
start image.Point
|
||||
opts []TextOption
|
||||
want func(size image.Point) *faketerm.Terminal
|
||||
wantCells int
|
||||
wantErr bool
|
||||
desc string
|
||||
canvas image.Rectangle
|
||||
text string
|
||||
start image.Point
|
||||
opts []TextOption
|
||||
want func(size image.Point) *faketerm.Terminal
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "start falls outside of the canvas",
|
||||
@ -65,7 +64,6 @@ func TestText(t *testing.T) {
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
return faketerm.MustNew(size)
|
||||
},
|
||||
wantCells: 0,
|
||||
},
|
||||
{
|
||||
desc: "text falls outside of the canvas on OverrunModeStrict",
|
||||
@ -93,7 +91,6 @@ func TestText(t *testing.T) {
|
||||
testcanvas.MustApply(c, ft)
|
||||
return ft
|
||||
},
|
||||
wantCells: 1,
|
||||
},
|
||||
{
|
||||
desc: "OverrunModeTrim trims longer text",
|
||||
@ -112,7 +109,6 @@ func TestText(t *testing.T) {
|
||||
testcanvas.MustApply(c, ft)
|
||||
return ft
|
||||
},
|
||||
wantCells: 2,
|
||||
},
|
||||
{
|
||||
desc: "text falls outside of the canvas on OverrunModeThreeDot",
|
||||
@ -130,7 +126,6 @@ func TestText(t *testing.T) {
|
||||
testcanvas.MustApply(c, ft)
|
||||
return ft
|
||||
},
|
||||
wantCells: 1,
|
||||
},
|
||||
{
|
||||
desc: "OverrunModeThreeDot trims longer text",
|
||||
@ -149,7 +144,6 @@ func TestText(t *testing.T) {
|
||||
testcanvas.MustApply(c, ft)
|
||||
return ft
|
||||
},
|
||||
wantCells: 2,
|
||||
},
|
||||
{
|
||||
desc: "requested MaxX is negative",
|
||||
@ -190,6 +184,15 @@ func TestText(t *testing.T) {
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "text is empty, nothing to do",
|
||||
canvas: image.Rect(0, 0, 1, 1),
|
||||
text: "",
|
||||
start: image.Point{0, 0},
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
return faketerm.MustNew(size)
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "draws text",
|
||||
canvas: image.Rect(0, 0, 3, 2),
|
||||
@ -204,7 +207,6 @@ func TestText(t *testing.T) {
|
||||
testcanvas.MustApply(c, ft)
|
||||
return ft
|
||||
},
|
||||
wantCells: 2,
|
||||
},
|
||||
{
|
||||
desc: "draws text with cell options",
|
||||
@ -223,7 +225,6 @@ func TestText(t *testing.T) {
|
||||
testcanvas.MustApply(c, ft)
|
||||
return ft
|
||||
},
|
||||
wantCells: 2,
|
||||
},
|
||||
{
|
||||
desc: "draws unicode character",
|
||||
@ -238,7 +239,6 @@ func TestText(t *testing.T) {
|
||||
testcanvas.MustApply(c, ft)
|
||||
return ft
|
||||
},
|
||||
wantCells: 1,
|
||||
},
|
||||
{
|
||||
desc: "draws multiple unicode characters",
|
||||
@ -255,7 +255,6 @@ func TestText(t *testing.T) {
|
||||
testcanvas.MustApply(c, ft)
|
||||
return ft
|
||||
},
|
||||
wantCells: 3,
|
||||
},
|
||||
}
|
||||
|
||||
@ -266,7 +265,7 @@ func TestText(t *testing.T) {
|
||||
t.Fatalf("canvas.New => unexpected error: %v", err)
|
||||
}
|
||||
|
||||
gotCells, err := Text(c, tc.text, tc.start, tc.opts...)
|
||||
err = Text(c, tc.text, tc.start, tc.opts...)
|
||||
if (err != nil) != tc.wantErr {
|
||||
t.Errorf("Text => unexpected error: %v, wantErr: %v", err, tc.wantErr)
|
||||
}
|
||||
@ -286,10 +285,6 @@ func TestText(t *testing.T) {
|
||||
if diff := faketerm.Diff(tc.want(c.Size()), got); diff != "" {
|
||||
t.Errorf("Text => %v", diff)
|
||||
}
|
||||
|
||||
if gotCells != tc.wantCells {
|
||||
t.Errorf("Text => unexpected number of cells, got %d, want %d", gotCells, tc.wantCells)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ func (u *Unbound) empty() bool {
|
||||
return u.first == nil
|
||||
}
|
||||
|
||||
// Put puts an event onto the queue.
|
||||
// Push pushes an event onto the queue.
|
||||
func (u *Unbound) Push(e terminalapi.Event) {
|
||||
u.mu.Lock()
|
||||
defer u.mu.Unlock()
|
||||
@ -98,7 +98,7 @@ func (u *Unbound) Push(e terminalapi.Event) {
|
||||
u.cond.Signal()
|
||||
}
|
||||
|
||||
// Get gets an event from the queue. Returns nil if the queue is empty.
|
||||
// Pop pops an event from the queue. Returns nil if the queue is empty.
|
||||
func (u *Unbound) Pop() terminalapi.Event {
|
||||
u.mu.Lock()
|
||||
defer u.mu.Unlock()
|
||||
|
@ -36,6 +36,7 @@ var buttonNames = map[Button]string{
|
||||
ButtonWheelDown: "ButtonWheelDown",
|
||||
}
|
||||
|
||||
// Buttons recognized on the mouse.
|
||||
const (
|
||||
buttonUnknown Button = iota
|
||||
ButtonLeft
|
||||
|
@ -132,7 +132,7 @@ func (t *Terminal) String() string {
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// Implements terminalapi.Terminal.Size.
|
||||
// Size implements terminalapi.Terminal.Size.
|
||||
func (t *Terminal) Size() image.Point {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
@ -146,7 +146,7 @@ func (t *Terminal) Area() image.Rectangle {
|
||||
return image.Rect(0, 0, s.X, s.Y)
|
||||
}
|
||||
|
||||
// Implements terminalapi.Terminal.Clear.
|
||||
// Clear implements terminalapi.Terminal.Clear.
|
||||
func (t *Terminal) Clear(opts ...cell.Option) error {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
@ -159,22 +159,22 @@ func (t *Terminal) Clear(opts ...cell.Option) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Implements terminalapi.Terminal.Flush.
|
||||
// Flush implements terminalapi.Terminal.Flush.
|
||||
func (t *Terminal) Flush() error {
|
||||
return nil // nowhere to flush to.
|
||||
}
|
||||
|
||||
// Implements terminalapi.Terminal.SetCursor.
|
||||
// SetCursor implements terminalapi.Terminal.SetCursor.
|
||||
func (t *Terminal) SetCursor(p image.Point) {
|
||||
log.Fatal("unimplemented")
|
||||
}
|
||||
|
||||
// Implements terminalapi.Terminal.HideCursor.
|
||||
// HideCursor implements terminalapi.Terminal.HideCursor.
|
||||
func (t *Terminal) HideCursor() {
|
||||
log.Fatal("unimplemented")
|
||||
}
|
||||
|
||||
// Implements terminalapi.Terminal.SetCell.
|
||||
// SetCell implements terminalapi.Terminal.SetCell.
|
||||
func (t *Terminal) SetCell(p image.Point, r rune, opts ...cell.Option) error {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
@ -193,7 +193,7 @@ func (t *Terminal) SetCell(p image.Point, r rune, opts ...cell.Option) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Implements terminalapi.Terminal.Event.
|
||||
// Event implements terminalapi.Terminal.Event.
|
||||
func (t *Terminal) Event(ctx context.Context) terminalapi.Event {
|
||||
if t.events == nil {
|
||||
return terminalapi.NewErrorf("no event queue provided, use the WithEventQueue option when creating the fake terminal")
|
||||
@ -210,5 +210,5 @@ func (t *Terminal) Event(ctx context.Context) terminalapi.Event {
|
||||
return ev
|
||||
}
|
||||
|
||||
// Closes the terminal. This is a no-op on the fake terminal.
|
||||
// Close closes the terminal. This is a no-op on the fake terminal.
|
||||
func (t *Terminal) Close() {}
|
||||
|
@ -86,13 +86,13 @@ func New(opts ...Option) (*Terminal, error) {
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// Implements terminalapi.Terminal.Size.
|
||||
// Size implements terminalapi.Terminal.Size.
|
||||
func (t *Terminal) Size() image.Point {
|
||||
w, h := tbx.Size()
|
||||
return image.Point{w, h}
|
||||
}
|
||||
|
||||
// Implements terminalapi.Terminal.Clear.
|
||||
// Clear implements terminalapi.Terminal.Clear.
|
||||
func (t *Terminal) Clear(opts ...cell.Option) error {
|
||||
o := cell.NewOptions(opts...)
|
||||
fg, err := cellOptsToFg(o)
|
||||
@ -107,22 +107,22 @@ func (t *Terminal) Clear(opts ...cell.Option) error {
|
||||
return tbx.Clear(fg, bg)
|
||||
}
|
||||
|
||||
// Implements terminalapi.Terminal.Flush.
|
||||
// Flush implements terminalapi.Terminal.Flush.
|
||||
func (t *Terminal) Flush() error {
|
||||
return tbx.Flush()
|
||||
}
|
||||
|
||||
// Implements terminalapi.Terminal.SetCursor.
|
||||
// SetCursor implements terminalapi.Terminal.SetCursor.
|
||||
func (t *Terminal) SetCursor(p image.Point) {
|
||||
tbx.SetCursor(p.X, p.Y)
|
||||
}
|
||||
|
||||
// Implements terminalapi.Terminal.HideCursor.
|
||||
// HideCursor implements terminalapi.Terminal.HideCursor.
|
||||
func (t *Terminal) HideCursor() {
|
||||
tbx.HideCursor()
|
||||
}
|
||||
|
||||
// Implements terminalapi.Terminal.SetCell.
|
||||
// SetCell implements terminalapi.Terminal.SetCell.
|
||||
func (t *Terminal) SetCell(p image.Point, r rune, opts ...cell.Option) error {
|
||||
o := cell.NewOptions(opts...)
|
||||
fg, err := cellOptsToFg(o)
|
||||
@ -154,7 +154,7 @@ func (t *Terminal) pollEvents() {
|
||||
}
|
||||
}
|
||||
|
||||
// Implements terminalapi.Terminal.Event.
|
||||
// Event implements terminalapi.Terminal.Event.
|
||||
func (t *Terminal) Event(ctx context.Context) terminalapi.Event {
|
||||
ev, err := t.events.Pull(ctx)
|
||||
if err != nil {
|
||||
@ -163,8 +163,9 @@ func (t *Terminal) Event(ctx context.Context) terminalapi.Event {
|
||||
return ev
|
||||
}
|
||||
|
||||
// Closes the terminal, should be called when the terminal isn't required
|
||||
// Close closes the terminal, should be called when the terminal isn't required
|
||||
// anymore to return the screen to a sane state.
|
||||
// Implements terminalapi.Terminal.Close.
|
||||
func (t *Terminal) Close() {
|
||||
close(t.done)
|
||||
tbx.Close()
|
||||
|
@ -35,6 +35,7 @@ var colorModeNames = map[ColorMode]string{
|
||||
ColorModeGrayscale: "ColorModeGrayscale",
|
||||
}
|
||||
|
||||
// Supported color modes.
|
||||
const (
|
||||
ColorMode8 ColorMode = iota
|
||||
ColorMode256
|
||||
|
@ -96,8 +96,7 @@ func (mi *Mirror) Draw(cvs *canvas.Canvas) error {
|
||||
break
|
||||
}
|
||||
|
||||
_, err := draw.Text(cvs, mi.lines[i], start, draw.TextMaxX(usable.Max.X))
|
||||
if err != nil {
|
||||
if err := draw.Text(cvs, mi.lines[i], start, draw.TextMaxX(usable.Max.X)); err != nil {
|
||||
return err
|
||||
}
|
||||
start = image.Point{start.X, start.Y + 1}
|
||||
|
@ -29,26 +29,26 @@ import (
|
||||
"github.com/mum4k/termdash/widgetapi"
|
||||
)
|
||||
|
||||
// kEvents are keyboard events to send to the widget.
|
||||
type kEvents struct {
|
||||
// keyEvents are keyboard events to send to the widget.
|
||||
type keyEvents struct {
|
||||
k *terminalapi.Keyboard
|
||||
wantErr bool
|
||||
}
|
||||
|
||||
// mEvents are mouse events to send to the widget.
|
||||
type mEvents struct {
|
||||
// mouseEvents are mouse events to send to the widget.
|
||||
type mouseEvents struct {
|
||||
m *terminalapi.Mouse
|
||||
wantErr bool
|
||||
}
|
||||
|
||||
func TestMirror(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
kEvents []kEvents // Keyboard events to send before calling Draw().
|
||||
mEvents []mEvents // Mouse events to send before calling Draw().
|
||||
cvs *canvas.Canvas
|
||||
want func(size image.Point) *faketerm.Terminal
|
||||
wantErr bool
|
||||
desc string
|
||||
keyEvents []keyEvents // Keyboard events to send before calling Draw().
|
||||
mouseEvents []mouseEvents // Mouse events to send before calling Draw().
|
||||
cvs *canvas.Canvas
|
||||
want func(size image.Point) *faketerm.Terminal
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "canvas too small to draw a box",
|
||||
@ -91,7 +91,7 @@ func TestMirror(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "draws the last keyboard event",
|
||||
kEvents: []kEvents{
|
||||
keyEvents: []keyEvents{
|
||||
{
|
||||
k: &terminalapi.Keyboard{Key: keyboard.KeyEnter},
|
||||
},
|
||||
@ -112,7 +112,7 @@ func TestMirror(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "skips the keyboard event if there isn't a line for it",
|
||||
kEvents: []kEvents{
|
||||
keyEvents: []keyEvents{
|
||||
{
|
||||
k: &terminalapi.Keyboard{Key: keyboard.KeyEnd},
|
||||
},
|
||||
@ -129,7 +129,7 @@ func TestMirror(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "draws the last mouse event",
|
||||
mEvents: []mEvents{
|
||||
mouseEvents: []mouseEvents{
|
||||
{
|
||||
m: &terminalapi.Mouse{Button: mouse.ButtonLeft},
|
||||
},
|
||||
@ -152,7 +152,7 @@ func TestMirror(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "skips the mouse event if there isn't a line for it",
|
||||
mEvents: []mEvents{
|
||||
mouseEvents: []mouseEvents{
|
||||
{
|
||||
m: &terminalapi.Mouse{Button: mouse.ButtonLeft},
|
||||
},
|
||||
@ -169,12 +169,12 @@ func TestMirror(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "draws both keyboard and mouse events",
|
||||
kEvents: []kEvents{
|
||||
keyEvents: []keyEvents{
|
||||
{
|
||||
k: &terminalapi.Keyboard{Key: keyboard.KeyEnter},
|
||||
},
|
||||
},
|
||||
mEvents: []mEvents{
|
||||
mouseEvents: []mouseEvents{
|
||||
{
|
||||
m: &terminalapi.Mouse{Button: mouse.ButtonLeft},
|
||||
},
|
||||
@ -193,7 +193,7 @@ func TestMirror(t *testing.T) {
|
||||
},
|
||||
{
|
||||
desc: "KeyEsc and ButtonRight reset the last event and return error",
|
||||
kEvents: []kEvents{
|
||||
keyEvents: []keyEvents{
|
||||
{
|
||||
k: &terminalapi.Keyboard{Key: keyboard.KeyEnter},
|
||||
},
|
||||
@ -202,7 +202,7 @@ func TestMirror(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
},
|
||||
mEvents: []mEvents{
|
||||
mouseEvents: []mouseEvents{
|
||||
{
|
||||
m: &terminalapi.Mouse{Button: mouse.ButtonLeft},
|
||||
},
|
||||
@ -227,17 +227,17 @@ func TestMirror(t *testing.T) {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
w := New(widgetapi.Options{})
|
||||
|
||||
for _, kEv := range tc.kEvents {
|
||||
err := w.Keyboard(kEv.k)
|
||||
if (err != nil) != kEv.wantErr {
|
||||
t.Errorf("Keyboard => got error:%v, wantErr: %v", err, kEv.wantErr)
|
||||
for _, keyEv := range tc.keyEvents {
|
||||
err := w.Keyboard(keyEv.k)
|
||||
if (err != nil) != keyEv.wantErr {
|
||||
t.Errorf("Keyboard => got error:%v, wantErr: %v", err, keyEv.wantErr)
|
||||
}
|
||||
}
|
||||
|
||||
for _, mEv := range tc.mEvents {
|
||||
err := w.Mouse(mEv.m)
|
||||
if (err != nil) != mEv.wantErr {
|
||||
t.Errorf("Mouse => got error:%v, wantErr: %v", err, mEv.wantErr)
|
||||
for _, mouseEv := range tc.mouseEvents {
|
||||
err := w.Mouse(mouseEv.m)
|
||||
if (err != nil) != mouseEv.wantErr {
|
||||
t.Errorf("Mouse => got error:%v, wantErr: %v", err, mouseEv.wantErr)
|
||||
}
|
||||
}
|
||||
|
||||
|
Binary file not shown.
@ -204,21 +204,19 @@ func (g *Gauge) drawText(cvs *canvas.Canvas) error {
|
||||
switch {
|
||||
case gaugeEndX < textStart.X:
|
||||
// The text entirely falls outside of the drawn gauge.
|
||||
_, err := draw.Text(cvs, text, textStart,
|
||||
return draw.Text(cvs, text, textStart,
|
||||
draw.TextOverrunMode(draw.OverrunModeThreeDot),
|
||||
draw.TextCellOpts(cell.FgColor(g.opts.emptyTextColor)),
|
||||
draw.TextMaxX(ar.Max.X),
|
||||
)
|
||||
return err
|
||||
|
||||
case gaugeEndX >= textEndX:
|
||||
// The text entirely falls inside of the drawn gauge.
|
||||
_, err := draw.Text(cvs, text, textStart,
|
||||
return draw.Text(cvs, text, textStart,
|
||||
draw.TextOverrunMode(draw.OverrunModeThreeDot),
|
||||
draw.TextCellOpts(cell.FgColor(g.opts.filledTextColor)),
|
||||
draw.TextMaxX(ar.Max.X),
|
||||
)
|
||||
return err
|
||||
|
||||
default:
|
||||
// Part of the text falls inside of the drawn gauge and part outside.
|
||||
@ -227,17 +225,16 @@ func (g *Gauge) drawText(cvs *canvas.Canvas) error {
|
||||
insideText := utfText.Slice(0, insideCount)
|
||||
outsideText := utfText.Slice(insideCount, utfText.RuneCount())
|
||||
|
||||
_, err := draw.Text(cvs, insideText, textStart,
|
||||
if err := draw.Text(cvs, insideText, textStart,
|
||||
draw.TextOverrunMode(draw.OverrunModeTrim),
|
||||
draw.TextCellOpts(cell.FgColor(g.opts.filledTextColor)),
|
||||
)
|
||||
if err != nil {
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
outsideStart := image.Point{textStart.X + insideCount, textStart.Y}
|
||||
if outsideStart.In(ar) {
|
||||
if _, err := draw.Text(cvs, outsideText, outsideStart,
|
||||
if err := draw.Text(cvs, outsideText, outsideStart,
|
||||
draw.TextOverrunMode(draw.OverrunModeThreeDot),
|
||||
draw.TextCellOpts(cell.FgColor(g.opts.emptyTextColor)),
|
||||
draw.TextMaxX(ar.Max.X),
|
||||
|
@ -57,7 +57,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "gauge showing percentage",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
),
|
||||
percent: &percentCall{p: 35},
|
||||
canvas: image.Rect(0, 0, 10, 3),
|
||||
@ -77,7 +77,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "aligns the progress text top and left",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
HorizontalTextAlign(align.HorizontalLeft),
|
||||
VerticalTextAlign(align.VerticalTop),
|
||||
),
|
||||
@ -95,7 +95,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "aligns the progress text top and left with border",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
HorizontalTextAlign(align.HorizontalLeft),
|
||||
VerticalTextAlign(align.VerticalTop),
|
||||
Border(draw.LineStyleLight),
|
||||
@ -115,7 +115,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "aligns the progress text bottom and right",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
HorizontalTextAlign(align.HorizontalRight),
|
||||
VerticalTextAlign(align.VerticalBottom),
|
||||
),
|
||||
@ -133,7 +133,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "aligns the progress text bottom and right with border",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
HorizontalTextAlign(align.HorizontalRight),
|
||||
VerticalTextAlign(align.VerticalBottom),
|
||||
Border(draw.LineStyleLight),
|
||||
@ -153,7 +153,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "gauge showing percentage with border",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
Border(draw.LineStyleLight),
|
||||
BorderTitle("title"),
|
||||
),
|
||||
@ -178,7 +178,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "respects border options",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
Border(draw.LineStyleLight, cell.FgColor(cell.ColorBlue)),
|
||||
BorderTitle("title"),
|
||||
BorderTitleAlign(align.HorizontalRight),
|
||||
@ -206,7 +206,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "gauge showing zero percentage",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
),
|
||||
percent: &percentCall{},
|
||||
canvas: image.Rect(0, 0, 10, 3),
|
||||
@ -222,7 +222,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "gauge showing 100 percent",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
),
|
||||
percent: &percentCall{p: 100},
|
||||
canvas: image.Rect(0, 0, 10, 3),
|
||||
@ -244,7 +244,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "gauge showing 100 percent with border",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
Border(draw.LineStyleLight),
|
||||
),
|
||||
percent: &percentCall{p: 100},
|
||||
@ -268,7 +268,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "gauge showing absolute progress",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
),
|
||||
absolute: &absoluteCall{done: 20, total: 100},
|
||||
canvas: image.Rect(0, 0, 10, 3),
|
||||
@ -288,7 +288,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "gauge without text progress",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
HideTextProgress(),
|
||||
),
|
||||
percent: &percentCall{p: 35},
|
||||
@ -308,7 +308,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "passing option to Percent() overrides one provided to New()",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
HideTextProgress(),
|
||||
),
|
||||
percent: &percentCall{p: 35, opts: []Option{ShowTextProgress()}},
|
||||
@ -329,7 +329,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "passing option to Absolute() overrides one provided to New()",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
HideTextProgress(),
|
||||
),
|
||||
absolute: &absoluteCall{done: 20, total: 100, opts: []Option{ShowTextProgress()}},
|
||||
@ -350,7 +350,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "gauge takes full size of the canvas",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
HideTextProgress(),
|
||||
),
|
||||
percent: &percentCall{p: 100},
|
||||
@ -370,7 +370,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "gauge with text label",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
HideTextProgress(),
|
||||
TextLabel("label"),
|
||||
),
|
||||
@ -394,7 +394,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "gauge with progress text and text label",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
TextLabel("l"),
|
||||
),
|
||||
percent: &percentCall{p: 100},
|
||||
@ -417,7 +417,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "text fully outside of gauge respects EmptyTextColor",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
TextLabel("l"),
|
||||
EmptyTextColor(cell.ColorMagenta),
|
||||
FilledTextColor(cell.ColorBlue),
|
||||
@ -442,7 +442,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "text fully inside of gauge respects FilledTextColor",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
TextLabel("l"),
|
||||
EmptyTextColor(cell.ColorMagenta),
|
||||
FilledTextColor(cell.ColorBlue),
|
||||
@ -467,7 +467,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "part of the text is inside and part outside of gauge",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
TextLabel("l"),
|
||||
EmptyTextColor(cell.ColorMagenta),
|
||||
FilledTextColor(cell.ColorBlue),
|
||||
@ -495,7 +495,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "truncates text that is outside of gauge",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
TextLabel("long label"),
|
||||
),
|
||||
percent: &percentCall{p: 0},
|
||||
@ -514,7 +514,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "truncates text that is outside of gauge when drawn with border",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
TextLabel("long label"),
|
||||
Border(draw.LineStyleLight),
|
||||
),
|
||||
@ -535,7 +535,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "truncates text that is inside of gauge",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
TextLabel("long label"),
|
||||
),
|
||||
percent: &percentCall{p: 100},
|
||||
@ -558,7 +558,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "truncates text that is inside of gauge when drawn with border",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
TextLabel("long label"),
|
||||
Border(draw.LineStyleLight),
|
||||
),
|
||||
@ -583,7 +583,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "truncates text that is inside and outside of gauge",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
TextLabel("long label"),
|
||||
),
|
||||
percent: &percentCall{p: 50},
|
||||
@ -609,7 +609,7 @@ func TestGauge(t *testing.T) {
|
||||
{
|
||||
desc: "truncates text that is inside and outside of gauge with border",
|
||||
gauge: New(
|
||||
GaugeChar('o'),
|
||||
Char('o'),
|
||||
TextLabel("long label"),
|
||||
Border(draw.LineStyleLight),
|
||||
),
|
||||
|
@ -65,12 +65,12 @@ func (o option) set(opts *options) {
|
||||
o(opts)
|
||||
}
|
||||
|
||||
// DefaultGaugeChar is the default value for the GaugeChar option.
|
||||
const DefaultGaugeChar = draw.DefaultRectChar
|
||||
// DefaultChar is the default value for the Char option.
|
||||
const DefaultChar = draw.DefaultRectChar
|
||||
|
||||
// GaugeChar sets the rune that is used when drawing the rectangle representing
|
||||
// the current progress.
|
||||
func GaugeChar(ch rune) Option {
|
||||
// Char sets the rune that is used when drawing the rectangle representing the
|
||||
// current progress.
|
||||
func Char(ch rune) Option {
|
||||
return option(func(opts *options) {
|
||||
opts.gaugeChar = ch
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user