1
0
mirror of https://github.com/mum4k/termdash.git synced 2025-04-27 13:48:49 +08:00

Improve the look of display with segment width/height of two.

This commit is contained in:
Jakub Sobon 2019-01-31 23:51:33 -05:00
parent 50b18902c8
commit a2c4512b47
No known key found for this signature in database
GPG Key ID: F2451A77FB05D3B7
4 changed files with 115 additions and 73 deletions

View File

@ -61,7 +61,7 @@ type Option interface {
// options stores the provided options.
type options struct {
cellOpts []cell.Option
skipSlopes bool
skipSlopesLTE int
reverseSlopes bool
}
@ -82,10 +82,12 @@ func CellOpts(cOpts ...cell.Option) Option {
})
}
// SkipSlopes if provided instructs HV to not create slopes at the ends of a segment.
func SkipSlopes() Option {
// SkipSlopesLTE if provided instructs HV to not create slopes at the ends of a
// segment if the height of the horizontal or the width of the vertical segment
// is less or equal to the provided value.
func SkipSlopesLTE(v int) Option {
return option(func(opts *options) {
opts.skipSlopes = true
opts.skipSlopesLTE = v
})
}
@ -94,12 +96,12 @@ func SkipSlopes() Option {
// or the vertical segment has width of two.
// Without this option segments with height / width of two look like this:
// - |
// --- ||
// --- ||
// |
//
// With this option:
// --- |
// - ||
// - ||
// |
func ReverseSlopes() Option {
return option(func(opts *options) {
@ -171,7 +173,7 @@ func nextHorizLine(num int, ar image.Rectangle, opt *options) (image.Point, imag
height := ar.Dy()
width := ar.Dx()
if opt.skipSlopes || height < 2 || width < 3 {
if height <= opt.skipSlopesLTE || height < 2 || width < 3 {
// No slopes under these dimensions as we don't have the resolution.
return start, end
}
@ -226,7 +228,7 @@ func nextVertLine(num int, ar image.Rectangle, opt *options) (image.Point, image
height := ar.Dy()
width := ar.Dx()
if opt.skipSlopes || height < 3 || width < 2 {
if width <= opt.skipSlopesLTE || height < 3 || width < 2 {
// No slopes under these dimensions as we don't have the resolution.
return start, end
}
@ -336,16 +338,16 @@ func (dt DiagonalType) String() string {
// diagonalTypeNames maps DiagonalType values to human readable names.
var diagonalTypeNames = map[DiagonalType]string{
DiagonalTypeLeftToRight: "DiagonalTypeLeftToRight",
DiagonalTypeRightToLeft: "DiagonalTypeRightToLeft",
LeftToRight: "LeftToRight",
RightToLeft: "RightToLeft",
}
const (
diagonalTypeUnknown DiagonalType = iota
// DiagonalTypeLeftToRight is a diagonal segment from top left to bottom right.
DiagonalTypeLeftToRight
// DiagonalTypeRightToLeft is a diagonal segment from top right to bottom left.
DiagonalTypeRightToLeft
// LeftToRight is a diagonal segment from top left to bottom right.
LeftToRight
// RightToLeft is a diagonal segment from top right to bottom left.
RightToLeft
diagonalTypeMax // Used for validation.
)
@ -401,12 +403,12 @@ func Diagonal(bc *braille.Canvas, ar image.Rectangle, width int, dt DiagonalType
var start, end image.Point
var nextFn nextDiagLineFn
switch dt {
case DiagonalTypeLeftToRight:
case LeftToRight:
start = ar.Min
end = image.Point{ar.Max.X - 1, ar.Max.Y - 1}
nextFn = nextLRLine
case DiagonalTypeRightToLeft:
case RightToLeft:
start = image.Point{ar.Max.X - 1, ar.Min.Y}
end = image.Point{ar.Min.X, ar.Max.Y - 1}
nextFn = nextRLLine

View File

@ -366,7 +366,7 @@ func TestHV(t *testing.T) {
{
desc: "horizontal, segment 3x3, skip slopes",
opts: []Option{
SkipSlopes(),
SkipSlopesLTE(3),
},
cellCanvas: image.Rect(0, 0, 2, 1),
ar: image.Rect(0, 0, 3, 3),
@ -382,6 +382,25 @@ func TestHV(t *testing.T) {
return ft
},
},
{
desc: "horizontal, segment 3x3, doesn't skip slopes because is taller",
opts: []Option{
SkipSlopesLTE(2),
},
cellCanvas: image.Rect(0, 0, 2, 1),
ar: image.Rect(0, 0, 3, 3),
st: Horizontal,
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testdraw.MustBrailleLine(bc, image.Point{1, 0}, image.Point{1, 0})
testdraw.MustBrailleLine(bc, image.Point{0, 1}, image.Point{2, 1})
testdraw.MustBrailleLine(bc, image.Point{1, 2}, image.Point{1, 2})
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "horizontal, segment 3x4",
cellCanvas: image.Rect(0, 0, 2, 1),
@ -823,7 +842,7 @@ func TestHV(t *testing.T) {
{
desc: "vertical, segment 3x3, skips slopes",
opts: []Option{
SkipSlopes(),
SkipSlopesLTE(3),
},
cellCanvas: image.Rect(0, 0, 2, 1),
ar: image.Rect(0, 0, 3, 3),
@ -839,6 +858,25 @@ func TestHV(t *testing.T) {
return ft
},
},
{
desc: "vertical, segment 3x3, doesn't skips slopes because is wider",
opts: []Option{
SkipSlopesLTE(2),
},
cellCanvas: image.Rect(0, 0, 2, 1),
ar: image.Rect(0, 0, 3, 3),
st: Vertical,
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
bc := testbraille.MustNew(ft.Area())
testdraw.MustBrailleLine(bc, image.Point{1, 0}, image.Point{1, 0})
testdraw.MustBrailleLine(bc, image.Point{0, 1}, image.Point{2, 1})
testdraw.MustBrailleLine(bc, image.Point{1, 2}, image.Point{1, 2})
testbraille.MustApply(bc, ft)
return ft
},
},
{
desc: "vertical, segment 3x4",
cellCanvas: image.Rect(0, 0, 2, 1),
@ -1226,7 +1264,7 @@ func TestDiagonal(t *testing.T) {
cellCanvas: image.Rect(0, 0, 1, 1),
ar: image.Rect(-1, 0, 1, 1),
width: 1,
dt: DiagonalTypeLeftToRight,
dt: LeftToRight,
wantErr: true,
},
{
@ -1234,7 +1272,7 @@ func TestDiagonal(t *testing.T) {
cellCanvas: image.Rect(0, 0, 1, 1),
ar: image.Rect(0, -1, 1, 1),
width: 1,
dt: DiagonalTypeLeftToRight,
dt: LeftToRight,
wantErr: true,
},
{
@ -1242,7 +1280,7 @@ func TestDiagonal(t *testing.T) {
cellCanvas: image.Rect(0, 0, 1, 1),
ar: image.Rectangle{image.Point{0, 0}, image.Point{-1, 1}},
width: 1,
dt: DiagonalTypeLeftToRight,
dt: LeftToRight,
wantErr: true,
},
{
@ -1250,7 +1288,7 @@ func TestDiagonal(t *testing.T) {
cellCanvas: image.Rect(0, 0, 1, 1),
ar: image.Rectangle{image.Point{0, 0}, image.Point{1, -1}},
width: 1,
dt: DiagonalTypeLeftToRight,
dt: LeftToRight,
wantErr: true,
},
{
@ -1258,7 +1296,7 @@ func TestDiagonal(t *testing.T) {
cellCanvas: image.Rect(0, 0, 1, 1),
ar: image.Rect(0, 0, 0, 1),
width: 1,
dt: DiagonalTypeLeftToRight,
dt: LeftToRight,
wantErr: true,
},
{
@ -1266,7 +1304,7 @@ func TestDiagonal(t *testing.T) {
cellCanvas: image.Rect(0, 0, 1, 1),
ar: image.Rect(0, 0, 1, 0),
width: 1,
dt: DiagonalTypeLeftToRight,
dt: LeftToRight,
wantErr: true,
},
{
@ -1282,7 +1320,7 @@ func TestDiagonal(t *testing.T) {
cellCanvas: image.Rect(0, 0, 1, 1),
ar: image.Rect(0, 0, 2, 2),
width: 1,
dt: DiagonalType(int(DiagonalTypeRightToLeft) + 1),
dt: DiagonalType(int(RightToLeft) + 1),
wantErr: true,
},
{
@ -1290,7 +1328,7 @@ func TestDiagonal(t *testing.T) {
cellCanvas: image.Rect(0, 0, 1, 1),
ar: image.Rect(0, 0, 3, 1),
width: 1,
dt: DiagonalTypeLeftToRight,
dt: LeftToRight,
wantErr: true,
},
{
@ -1298,14 +1336,14 @@ func TestDiagonal(t *testing.T) {
cellCanvas: image.Rect(0, 0, 1, 1),
ar: image.Rect(0, 0, 3, 1),
width: 0,
dt: DiagonalTypeLeftToRight,
dt: LeftToRight,
wantErr: true,
},
{
desc: "left to right, area 4x4, width 1",
cellCanvas: image.Rect(0, 0, 2, 1),
ar: image.Rect(0, 0, 4, 4),
dt: DiagonalTypeLeftToRight,
dt: LeftToRight,
width: 1,
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
@ -1321,7 +1359,7 @@ func TestDiagonal(t *testing.T) {
desc: "right to left, area 4x4, width 1",
cellCanvas: image.Rect(0, 0, 2, 1),
ar: image.Rect(0, 0, 4, 4),
dt: DiagonalTypeRightToLeft,
dt: RightToLeft,
width: 1,
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
@ -1337,7 +1375,7 @@ func TestDiagonal(t *testing.T) {
desc: "left to right, area 4x4, width 2",
cellCanvas: image.Rect(0, 0, 2, 1),
ar: image.Rect(0, 0, 4, 4),
dt: DiagonalTypeLeftToRight,
dt: LeftToRight,
width: 2,
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
@ -1354,7 +1392,7 @@ func TestDiagonal(t *testing.T) {
desc: "right to left, area 4x4, width 2",
cellCanvas: image.Rect(0, 0, 2, 1),
ar: image.Rect(0, 0, 4, 4),
dt: DiagonalTypeRightToLeft,
dt: RightToLeft,
width: 2,
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
@ -1371,7 +1409,7 @@ func TestDiagonal(t *testing.T) {
desc: "left to right, area 4x4, width 3",
cellCanvas: image.Rect(0, 0, 2, 1),
ar: image.Rect(0, 0, 4, 4),
dt: DiagonalTypeLeftToRight,
dt: LeftToRight,
width: 3,
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
@ -1389,7 +1427,7 @@ func TestDiagonal(t *testing.T) {
desc: "right to left, area 4x4, width 3",
cellCanvas: image.Rect(0, 0, 2, 1),
ar: image.Rect(0, 0, 4, 4),
dt: DiagonalTypeRightToLeft,
dt: RightToLeft,
width: 3,
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
@ -1407,7 +1445,7 @@ func TestDiagonal(t *testing.T) {
desc: "left to right, area 8x4, width 3",
cellCanvas: image.Rect(0, 0, 4, 1),
ar: image.Rect(0, 0, 8, 4),
dt: DiagonalTypeLeftToRight,
dt: LeftToRight,
width: 3,
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
@ -1425,7 +1463,7 @@ func TestDiagonal(t *testing.T) {
desc: "right to left, area 8x4, width 3",
cellCanvas: image.Rect(0, 0, 4, 1),
ar: image.Rect(0, 0, 8, 4),
dt: DiagonalTypeRightToLeft,
dt: RightToLeft,
width: 3,
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
@ -1443,7 +1481,7 @@ func TestDiagonal(t *testing.T) {
desc: "left to right, area 4x8, width 3",
cellCanvas: image.Rect(0, 0, 2, 2),
ar: image.Rect(0, 0, 4, 8),
dt: DiagonalTypeLeftToRight,
dt: LeftToRight,
width: 3,
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
@ -1461,7 +1499,7 @@ func TestDiagonal(t *testing.T) {
desc: "right to left, area 4x8, width 3",
cellCanvas: image.Rect(0, 0, 2, 2),
ar: image.Rect(0, 0, 4, 8),
dt: DiagonalTypeRightToLeft,
dt: RightToLeft,
width: 3,
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
@ -1479,7 +1517,7 @@ func TestDiagonal(t *testing.T) {
desc: "left to right, area 4x4, width 4",
cellCanvas: image.Rect(0, 0, 2, 1),
ar: image.Rect(0, 0, 4, 4),
dt: DiagonalTypeLeftToRight,
dt: LeftToRight,
width: 4,
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
@ -1498,7 +1536,7 @@ func TestDiagonal(t *testing.T) {
desc: "right to left, area 4x4, width 4",
cellCanvas: image.Rect(0, 0, 2, 1),
ar: image.Rect(0, 0, 4, 4),
dt: DiagonalTypeRightToLeft,
dt: RightToLeft,
width: 4,
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
@ -1517,7 +1555,7 @@ func TestDiagonal(t *testing.T) {
desc: "left to right, area 4x4, width 5",
cellCanvas: image.Rect(0, 0, 2, 1),
ar: image.Rect(0, 0, 4, 4),
dt: DiagonalTypeLeftToRight,
dt: LeftToRight,
width: 5,
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
@ -1537,7 +1575,7 @@ func TestDiagonal(t *testing.T) {
desc: "right to left, area 4x4, width 5",
cellCanvas: image.Rect(0, 0, 2, 1),
ar: image.Rect(0, 0, 4, 4),
dt: DiagonalTypeRightToLeft,
dt: RightToLeft,
width: 5,
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
@ -1557,7 +1595,7 @@ func TestDiagonal(t *testing.T) {
desc: "left to right, area 4x4, width 6",
cellCanvas: image.Rect(0, 0, 2, 1),
ar: image.Rect(0, 0, 4, 4),
dt: DiagonalTypeLeftToRight,
dt: LeftToRight,
width: 6,
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
@ -1578,7 +1616,7 @@ func TestDiagonal(t *testing.T) {
desc: "right to left, area 4x4, width 6",
cellCanvas: image.Rect(0, 0, 2, 1),
ar: image.Rect(0, 0, 4, 4),
dt: DiagonalTypeRightToLeft,
dt: RightToLeft,
width: 6,
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
@ -1599,7 +1637,7 @@ func TestDiagonal(t *testing.T) {
desc: "left to right, area 4x4, width 7",
cellCanvas: image.Rect(0, 0, 2, 1),
ar: image.Rect(0, 0, 4, 4),
dt: DiagonalTypeLeftToRight,
dt: LeftToRight,
width: 7,
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
@ -1621,7 +1659,7 @@ func TestDiagonal(t *testing.T) {
desc: "right to left, area 4x4, width 7",
cellCanvas: image.Rect(0, 0, 2, 1),
ar: image.Rect(0, 0, 4, 4),
dt: DiagonalTypeRightToLeft,
dt: RightToLeft,
width: 7,
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
@ -1643,7 +1681,7 @@ func TestDiagonal(t *testing.T) {
desc: "left to right, fails when width is larger than area",
cellCanvas: image.Rect(0, 0, 2, 1),
ar: image.Rect(0, 0, 4, 4),
dt: DiagonalTypeLeftToRight,
dt: LeftToRight,
width: 8,
wantErr: true,
},
@ -1651,7 +1689,7 @@ func TestDiagonal(t *testing.T) {
desc: "right to left, fails when width is larger than area",
cellCanvas: image.Rect(0, 0, 2, 1),
ar: image.Rect(0, 0, 4, 4),
dt: DiagonalTypeRightToLeft,
dt: RightToLeft,
width: 8,
wantErr: true,
},
@ -1665,7 +1703,7 @@ func TestDiagonal(t *testing.T) {
},
cellCanvas: image.Rect(0, 0, 2, 1),
ar: image.Rect(0, 0, 4, 4),
dt: DiagonalTypeLeftToRight,
dt: LeftToRight,
width: 2,
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)

View File

@ -13,10 +13,11 @@
// limitations under the License.
/*
Package segdisp simulates a 16-segment display drawn on a canvas.
Package sixteen simulates a 16-segment display drawn on a canvas.
Given a canvas, determines the placement and size of the individual
segments and exposes API that can turn individual segments on and off.
segments and exposes API that can turn individual segments on and off or
display characters.
The following outlines segments in the display and their names.
@ -36,7 +37,7 @@ The following outlines segments in the display and their names.
------- -------
D1 D2
*/
package segdisp
package sixteen
import (
"errors"
@ -49,8 +50,8 @@ import (
"github.com/mum4k/termdash/canvas"
"github.com/mum4k/termdash/canvas/braille"
"github.com/mum4k/termdash/cell"
"github.com/mum4k/termdash/draw/segdisp/segment"
"github.com/mum4k/termdash/numbers"
"github.com/mum4k/termdash/segdisp/segment"
)
// Segment represents a single segment in the display.
@ -308,31 +309,32 @@ func (d *Display) Draw(cvs *canvas.Canvas, opts ...Option) error {
d2Ar := image.Rect(d1Ar.Max.X+ptp, botStart, d1Ar.Max.X+ptp+shortL, botStart+segW)
for _, segArg := range []struct {
s Segment
st segment.SegmentType
ar image.Rectangle
s Segment
st segment.SegmentType
ar image.Rectangle
opts []segment.Option
}{
{A1, segment.SegmentTypeHorizontal, a1Ar},
{A2, segment.SegmentTypeHorizontal, a2Ar},
{A1, segment.Horizontal, a1Ar, nil},
{A2, segment.Horizontal, a2Ar, nil},
{F, segment.SegmentTypeVertical, fAr},
{J, segment.SegmentTypeVertical, jAr},
{B, segment.SegmentTypeVertical, bAr},
{F, segment.Vertical, fAr, nil},
{J, segment.Vertical, jAr, []segment.Option{segment.SkipSlopesLTE(2)}},
{B, segment.Vertical, bAr, []segment.Option{segment.ReverseSlopes()}},
{G1, segment.SegmentTypeHorizontal, g1Ar},
{G2, segment.SegmentTypeHorizontal, g2Ar},
{G1, segment.Horizontal, g1Ar, []segment.Option{segment.SkipSlopesLTE(2)}},
{G2, segment.Horizontal, g2Ar, []segment.Option{segment.SkipSlopesLTE(2)}},
{E, segment.SegmentTypeVertical, eAr},
{M, segment.SegmentTypeVertical, mAr},
{C, segment.SegmentTypeVertical, cAr},
{E, segment.Vertical, eAr, nil},
{M, segment.Vertical, mAr, []segment.Option{segment.SkipSlopesLTE(2)}},
{C, segment.Vertical, cAr, []segment.Option{segment.ReverseSlopes()}},
{D1, segment.SegmentTypeHorizontal, d1Ar},
{D2, segment.SegmentTypeHorizontal, d2Ar},
{D1, segment.Horizontal, d1Ar, []segment.Option{segment.ReverseSlopes()}},
{D2, segment.Horizontal, d2Ar, []segment.Option{segment.ReverseSlopes()}},
} {
if !d.segments[segArg.s] {
continue
}
if err := segment.HV(bc, segArg.ar, segArg.st); err != nil {
if err := segment.HV(bc, segArg.ar, segArg.st, segArg.opts...); err != nil {
return fmt.Errorf("failed to draw segment %v, segment.HV => %v", segArg.s, err)
}
}
@ -366,10 +368,10 @@ func (d *Display) Draw(cvs *canvas.Canvas, opts ...Option) error {
dt segment.DiagonalType
ar image.Rectangle
}{
{H, segment.DiagonalTypeLeftToRight, hAr},
{K, segment.DiagonalTypeRightToLeft, kAr},
{N, segment.DiagonalTypeRightToLeft, nAr},
{L, segment.DiagonalTypeLeftToRight, lAr},
{H, segment.LeftToRight, hAr},
{K, segment.RightToLeft, kAr},
{N, segment.RightToLeft, nAr},
{L, segment.LeftToRight, lAr},
} {
if !d.segments[segArg.s] {
continue

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package segdisp
package sixteen
import (
"image"