mirror of
https://github.com/mum4k/termdash.git
synced 2025-04-25 13:48:50 +08:00
Merge pull request #374 from mum4k/release-0-20-0
Releasing Termdash v0.20.0.
This commit is contained in:
commit
102df20a88
15
CHANGELOG.md
15
CHANGELOG.md
@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.20.0] - 10-Mar-2024
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Support for an alternative way of splitting containers where the size or
|
||||||
|
percentage is specified for the right (or bottom) container and the left (or
|
||||||
|
top) is calculated.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Bump github.com/gdamore/tcell/v2 from 2.7.0 to 2.7.4.
|
||||||
|
|
||||||
## [0.19.0] - 29-Jan-2024
|
## [0.19.0] - 29-Jan-2024
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
@ -531,7 +543,8 @@ identifiers shouldn't be used externally.
|
|||||||
- The Gauge widget.
|
- The Gauge widget.
|
||||||
- The Text widget.
|
- The Text widget.
|
||||||
|
|
||||||
[unreleased]: https://github.com/mum4k/termdash/compare/v0.19.0...devel
|
[unreleased]: https://github.com/mum4k/termdash/compare/v0.20.0...devel
|
||||||
|
[0.20.0]: https://github.com/mum4k/termdash/compare/v0.19.0...v0.20.0
|
||||||
[0.19.0]: https://github.com/mum4k/termdash/compare/v0.18.0...v0.19.0
|
[0.19.0]: https://github.com/mum4k/termdash/compare/v0.18.0...v0.19.0
|
||||||
[0.18.0]: https://github.com/mum4k/termdash/compare/v0.17.0...v0.18.0
|
[0.18.0]: https://github.com/mum4k/termdash/compare/v0.17.0...v0.18.0
|
||||||
[0.17.0]: https://github.com/mum4k/termdash/compare/v0.16.1...v0.17.0
|
[0.17.0]: https://github.com/mum4k/termdash/compare/v0.16.1...v0.17.0
|
||||||
|
@ -180,14 +180,26 @@ func (c *Container) split() (image.Rectangle, image.Rectangle, error) {
|
|||||||
}
|
}
|
||||||
if c.opts.splitFixed > DefaultSplitFixed {
|
if c.opts.splitFixed > DefaultSplitFixed {
|
||||||
if c.opts.split == splitTypeVertical {
|
if c.opts.split == splitTypeVertical {
|
||||||
|
if c.opts.splitReversed {
|
||||||
|
return area.VSplitCellsReversed(ar, c.opts.splitFixed)
|
||||||
|
}
|
||||||
return area.VSplitCells(ar, c.opts.splitFixed)
|
return area.VSplitCells(ar, c.opts.splitFixed)
|
||||||
}
|
}
|
||||||
|
if c.opts.splitReversed {
|
||||||
|
return area.HSplitCellsReversed(ar, c.opts.splitFixed)
|
||||||
|
}
|
||||||
return area.HSplitCells(ar, c.opts.splitFixed)
|
return area.HSplitCells(ar, c.opts.splitFixed)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.opts.split == splitTypeVertical {
|
if c.opts.split == splitTypeVertical {
|
||||||
|
if c.opts.splitReversed {
|
||||||
|
return area.VSplitReversed(ar, c.opts.splitPercent)
|
||||||
|
}
|
||||||
return area.VSplit(ar, c.opts.splitPercent)
|
return area.VSplit(ar, c.opts.splitPercent)
|
||||||
}
|
}
|
||||||
|
if c.opts.splitReversed {
|
||||||
|
return area.HSplitReversed(ar, c.opts.splitPercent)
|
||||||
|
}
|
||||||
return area.HSplit(ar, c.opts.splitPercent)
|
return area.HSplit(ar, c.opts.splitPercent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -713,7 +713,33 @@ func TestNew(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "horizontal unequal split",
|
desc: "horizontal, reversed unequal split",
|
||||||
|
termSize: image.Point{10, 20},
|
||||||
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
||||||
|
return New(
|
||||||
|
ft,
|
||||||
|
SplitHorizontal(
|
||||||
|
Top(
|
||||||
|
Border(linestyle.Light),
|
||||||
|
),
|
||||||
|
Bottom(
|
||||||
|
Border(linestyle.Light),
|
||||||
|
),
|
||||||
|
SplitPercentFromEnd(20),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
want: func(size image.Point) *faketerm.Terminal {
|
||||||
|
ft := faketerm.MustNew(size)
|
||||||
|
cvs := testcanvas.MustNew(ft.Area())
|
||||||
|
testdraw.MustBorder(cvs, image.Rect(0, 0, 10, 16))
|
||||||
|
testdraw.MustBorder(cvs, image.Rect(0, 16, 10, 20))
|
||||||
|
testcanvas.MustApply(cvs, ft)
|
||||||
|
return ft
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "horizontal fixed splits",
|
||||||
termSize: image.Point{10, 20},
|
termSize: image.Point{10, 20},
|
||||||
container: func(ft *faketerm.Terminal) (*Container, error) {
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
||||||
return New(
|
return New(
|
||||||
@ -738,6 +764,32 @@ func TestNew(t *testing.T) {
|
|||||||
return ft
|
return ft
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "horizontal, reversed fixed splits",
|
||||||
|
termSize: image.Point{10, 20},
|
||||||
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
||||||
|
return New(
|
||||||
|
ft,
|
||||||
|
SplitHorizontal(
|
||||||
|
Top(
|
||||||
|
Border(linestyle.Light),
|
||||||
|
),
|
||||||
|
Bottom(
|
||||||
|
Border(linestyle.Light),
|
||||||
|
),
|
||||||
|
SplitFixedFromEnd(4),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
want: func(size image.Point) *faketerm.Terminal {
|
||||||
|
ft := faketerm.MustNew(size)
|
||||||
|
cvs := testcanvas.MustNew(ft.Area())
|
||||||
|
testdraw.MustBorder(cvs, image.Rect(0, 0, 10, 16))
|
||||||
|
testdraw.MustBorder(cvs, image.Rect(0, 16, 10, 20))
|
||||||
|
testcanvas.MustApply(cvs, ft)
|
||||||
|
return ft
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "horizontal split, parent and children have borders",
|
desc: "horizontal split, parent and children have borders",
|
||||||
termSize: image.Point{10, 10},
|
termSize: image.Point{10, 10},
|
||||||
@ -864,6 +916,32 @@ func TestNew(t *testing.T) {
|
|||||||
return ft
|
return ft
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "vertical, reversed unequal split",
|
||||||
|
termSize: image.Point{20, 10},
|
||||||
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
||||||
|
return New(
|
||||||
|
ft,
|
||||||
|
SplitVertical(
|
||||||
|
Left(
|
||||||
|
Border(linestyle.Light),
|
||||||
|
),
|
||||||
|
Right(
|
||||||
|
Border(linestyle.Light),
|
||||||
|
),
|
||||||
|
SplitPercentFromEnd(20),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
want: func(size image.Point) *faketerm.Terminal {
|
||||||
|
ft := faketerm.MustNew(size)
|
||||||
|
cvs := testcanvas.MustNew(ft.Area())
|
||||||
|
testdraw.MustBorder(cvs, image.Rect(0, 0, 16, 10))
|
||||||
|
testdraw.MustBorder(cvs, image.Rect(16, 0, 20, 10))
|
||||||
|
testcanvas.MustApply(cvs, ft)
|
||||||
|
return ft
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "vertical fixed splits",
|
desc: "vertical fixed splits",
|
||||||
termSize: image.Point{20, 10},
|
termSize: image.Point{20, 10},
|
||||||
@ -890,6 +968,32 @@ func TestNew(t *testing.T) {
|
|||||||
return ft
|
return ft
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "vertical, reversed fixed splits",
|
||||||
|
termSize: image.Point{20, 10},
|
||||||
|
container: func(ft *faketerm.Terminal) (*Container, error) {
|
||||||
|
return New(
|
||||||
|
ft,
|
||||||
|
SplitVertical(
|
||||||
|
Left(
|
||||||
|
Border(linestyle.Light),
|
||||||
|
),
|
||||||
|
Right(
|
||||||
|
Border(linestyle.Light),
|
||||||
|
),
|
||||||
|
SplitFixedFromEnd(4),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
want: func(size image.Point) *faketerm.Terminal {
|
||||||
|
ft := faketerm.MustNew(size)
|
||||||
|
cvs := testcanvas.MustNew(ft.Area())
|
||||||
|
testdraw.MustBorder(cvs, image.Rect(0, 0, 16, 10))
|
||||||
|
testdraw.MustBorder(cvs, image.Rect(16, 0, 20, 10))
|
||||||
|
testcanvas.MustApply(cvs, ft)
|
||||||
|
return ft
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "vertical split, parent and children have borders",
|
desc: "vertical split, parent and children have borders",
|
||||||
termSize: image.Point{10, 10},
|
termSize: image.Point{10, 10},
|
||||||
|
@ -108,9 +108,10 @@ type options struct {
|
|||||||
inherited inherited
|
inherited inherited
|
||||||
|
|
||||||
// split identifies how is this container split.
|
// split identifies how is this container split.
|
||||||
split splitType
|
split splitType
|
||||||
splitPercent int
|
splitReversed bool
|
||||||
splitFixed int
|
splitPercent int
|
||||||
|
splitFixed int
|
||||||
|
|
||||||
// widget is the widget in the container.
|
// widget is the widget in the container.
|
||||||
// A container can have either two sub containers (left and right) or a
|
// A container can have either two sub containers (left and right) or a
|
||||||
@ -247,10 +248,11 @@ func newOptions(parent *options) *options {
|
|||||||
inherited: inherited{
|
inherited: inherited{
|
||||||
focusedColor: cell.ColorYellow,
|
focusedColor: cell.ColorYellow,
|
||||||
},
|
},
|
||||||
hAlign: align.HorizontalCenter,
|
hAlign: align.HorizontalCenter,
|
||||||
vAlign: align.VerticalMiddle,
|
vAlign: align.VerticalMiddle,
|
||||||
splitPercent: DefaultSplitPercent,
|
splitReversed: DefaultSplitReversed,
|
||||||
splitFixed: DefaultSplitFixed,
|
splitPercent: DefaultSplitPercent,
|
||||||
|
splitFixed: DefaultSplitFixed,
|
||||||
}
|
}
|
||||||
if parent != nil {
|
if parent != nil {
|
||||||
opts.global = parent.global
|
opts.global = parent.global
|
||||||
@ -281,13 +283,17 @@ func (so splitOption) setSplit(opts *options) error {
|
|||||||
return so(opts)
|
return so(opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DefaultSplitReversed is the default value for the SplitReversed option.
|
||||||
|
const DefaultSplitReversed = false
|
||||||
|
|
||||||
// DefaultSplitPercent is the default value for the SplitPercent option.
|
// DefaultSplitPercent is the default value for the SplitPercent option.
|
||||||
const DefaultSplitPercent = 50
|
const DefaultSplitPercent = 50
|
||||||
|
|
||||||
// DefaultSplitFixed is the default value for the SplitFixed option.
|
// DefaultSplitFixed is the default value for the SplitFixed option.
|
||||||
const DefaultSplitFixed = -1
|
const DefaultSplitFixed = -1
|
||||||
|
|
||||||
// SplitPercent sets the relative size of the split as percentage of the available space.
|
// SplitPercent sets the relative size of the split as percentage of the
|
||||||
|
// available space.
|
||||||
// When using SplitVertical, the provided size is applied to the new left
|
// When using SplitVertical, the provided size is applied to the new left
|
||||||
// container, the new right container gets the reminder of the size.
|
// container, the new right container gets the reminder of the size.
|
||||||
// When using SplitHorizontal, the provided size is applied to the new top
|
// When using SplitHorizontal, the provided size is applied to the new top
|
||||||
@ -304,6 +310,25 @@ func SplitPercent(p int) SplitOption {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SplitPercentFromEnd sets the relative size of the split as percentage of the
|
||||||
|
// available space.
|
||||||
|
// When using SplitVertical, the provided size is applied to the new right
|
||||||
|
// container, the new left container gets the reminder of the size.
|
||||||
|
// When using SplitHorizontal, the provided size is applied to the new bottom
|
||||||
|
// container, the new top container gets the reminder of the size.
|
||||||
|
// The provided value must be a positive number in the range 0 < p < 100.
|
||||||
|
// If not provided, defaults to using SplitPercent with DefaultSplitPercent.
|
||||||
|
func SplitPercentFromEnd(p int) SplitOption {
|
||||||
|
return splitOption(func(opts *options) error {
|
||||||
|
if min, max := 0, 100; p <= min || p >= max {
|
||||||
|
return fmt.Errorf("invalid split percentage %d, must be in range %d < p < %d", p, min, max)
|
||||||
|
}
|
||||||
|
opts.splitReversed = true
|
||||||
|
opts.splitPercent = p
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// SplitFixed sets the size of the first container to be a fixed value
|
// SplitFixed sets the size of the first container to be a fixed value
|
||||||
// and makes the second container take up the remaining space.
|
// and makes the second container take up the remaining space.
|
||||||
// When using SplitVertical, the provided size is applied to the new left
|
// When using SplitVertical, the provided size is applied to the new left
|
||||||
@ -311,8 +336,9 @@ func SplitPercent(p int) SplitOption {
|
|||||||
// When using SplitHorizontal, the provided size is applied to the new top
|
// When using SplitHorizontal, the provided size is applied to the new top
|
||||||
// container, the new bottom container gets the reminder of the size.
|
// container, the new bottom container gets the reminder of the size.
|
||||||
// The provided value must be a positive number in the range 0 <= cells.
|
// The provided value must be a positive number in the range 0 <= cells.
|
||||||
// If SplitFixed() is not specified, it defaults to SplitPercent() and its given value.
|
// If SplitFixed* or SplitPercent* is not specified, it defaults to
|
||||||
// Only one of SplitFixed() and SplitPercent() can be specified per container.
|
// SplitPercent() and its given value.
|
||||||
|
// Only one SplitFixed* or SplitPercent* may be specified per container.
|
||||||
func SplitFixed(cells int) SplitOption {
|
func SplitFixed(cells int) SplitOption {
|
||||||
return splitOption(func(opts *options) error {
|
return splitOption(func(opts *options) error {
|
||||||
if cells < 0 {
|
if cells < 0 {
|
||||||
@ -323,6 +349,27 @@ func SplitFixed(cells int) SplitOption {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SplitFixedFromEnd sets the size of the second container to be a fixed value
|
||||||
|
// and makes the first container take up the remaining space.
|
||||||
|
// When using SplitVertical, the provided size is applied to the new right
|
||||||
|
// container, the new left container gets the reminder of the size.
|
||||||
|
// When using SplitHorizontal, the provided size is applied to the new bottom
|
||||||
|
// container, the new top container gets the reminder of the size.
|
||||||
|
// The provided value must be a positive number in the range 0 <= cells.
|
||||||
|
// If SplitFixed* or SplitPercent* is not specified, it defaults to
|
||||||
|
// SplitPercent() and its given value.
|
||||||
|
// Only one SplitFixed* or SplitPercent* may be specified per container.
|
||||||
|
func SplitFixedFromEnd(cells int) SplitOption {
|
||||||
|
return splitOption(func(opts *options) error {
|
||||||
|
if cells < 0 {
|
||||||
|
return fmt.Errorf("invalid fixed value %d, must be in range %d <= cells", cells, 0)
|
||||||
|
}
|
||||||
|
opts.splitFixed = cells
|
||||||
|
opts.splitReversed = true
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// SplitVertical splits the container along the vertical axis into two sub
|
// SplitVertical splits the container along the vertical axis into two sub
|
||||||
// containers. The use of this option removes any widget placed at this
|
// containers. The use of this option removes any widget placed at this
|
||||||
// container, containers with sub containers cannot contain widgets.
|
// container, containers with sub containers cannot contain widgets.
|
||||||
|
6
go.mod
6
go.mod
@ -3,7 +3,7 @@ module github.com/mum4k/termdash
|
|||||||
go 1.21
|
go 1.21
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gdamore/tcell/v2 v2.7.0
|
github.com/gdamore/tcell/v2 v2.7.4
|
||||||
github.com/kylelemons/godebug v1.1.0
|
github.com/kylelemons/godebug v1.1.0
|
||||||
github.com/mattn/go-runewidth v0.0.15
|
github.com/mattn/go-runewidth v0.0.15
|
||||||
github.com/nsf/termbox-go v1.1.1
|
github.com/nsf/termbox-go v1.1.1
|
||||||
@ -13,7 +13,7 @@ require (
|
|||||||
github.com/gdamore/encoding v1.0.0 // indirect
|
github.com/gdamore/encoding v1.0.0 // indirect
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||||
github.com/rivo/uniseg v0.4.3 // indirect
|
github.com/rivo/uniseg v0.4.3 // indirect
|
||||||
golang.org/x/sys v0.15.0 // indirect
|
golang.org/x/sys v0.17.0 // indirect
|
||||||
golang.org/x/term v0.15.0 // indirect
|
golang.org/x/term v0.17.0 // indirect
|
||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/text v0.14.0 // indirect
|
||||||
)
|
)
|
||||||
|
12
go.sum
12
go.sum
@ -1,7 +1,7 @@
|
|||||||
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
|
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
|
||||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||||
github.com/gdamore/tcell/v2 v2.7.0 h1:I5LiGTQuwrysAt1KS9wg1yFfOI3arI3ucFrxtd/xqaA=
|
github.com/gdamore/tcell/v2 v2.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU=
|
||||||
github.com/gdamore/tcell/v2 v2.7.0/go.mod h1:hl/KtAANGBecfIPxk+FzKvThTqI84oplgbPEmVX60b8=
|
github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg=
|
||||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||||
@ -32,13 +32,13 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
||||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
|
||||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
@ -38,92 +38,210 @@ func FromSize(size image.Point) (image.Rectangle, error) {
|
|||||||
return image.Rect(0, 0, size.X, size.Y), nil
|
return image.Rect(0, 0, size.X, size.Y), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HSplit returns two new areas created by splitting the provided area at the
|
// hSplit returns two new areas created by splitting the provided area at the
|
||||||
// specified percentage of its width. The percentage must be in the range
|
// specified percentage of its height, applying the percentage to the top or
|
||||||
// 0 <= heightPerc <= 100.
|
// bottom area, depending on the reversed flag. The percentage must be in the
|
||||||
|
// range 0 <= heightPerc <= 100.
|
||||||
// Can return zero size areas.
|
// Can return zero size areas.
|
||||||
func HSplit(area image.Rectangle, heightPerc int) (top image.Rectangle, bottom image.Rectangle, err error) {
|
func hSplit(area image.Rectangle, heightPerc int, reversed bool) (top image.Rectangle, bottom image.Rectangle, err error) {
|
||||||
if min, max := 0, 100; heightPerc < min || heightPerc > max {
|
if min, max := 0, 100; heightPerc < min || heightPerc > max {
|
||||||
return image.ZR, image.ZR, fmt.Errorf("invalid heightPerc %d, must be in range %d <= heightPerc <= %d", heightPerc, min, max)
|
return image.ZR, image.ZR, fmt.Errorf("invalid heightPerc %d, must be in range %d <= heightPerc <= %d", heightPerc, min, max)
|
||||||
}
|
}
|
||||||
|
|
||||||
height := area.Dy() * heightPerc / 100
|
height := area.Dy() * heightPerc / 100
|
||||||
top = image.Rect(area.Min.X, area.Min.Y, area.Max.X, area.Min.Y+height)
|
|
||||||
|
if reversed {
|
||||||
|
top = image.Rect(area.Min.X, area.Min.Y, area.Max.X, area.Max.Y-height)
|
||||||
|
bottom = image.Rect(area.Min.X, area.Max.Y-height, area.Max.X, area.Max.Y)
|
||||||
|
} else {
|
||||||
|
top = image.Rect(area.Min.X, area.Min.Y, area.Max.X, area.Min.Y+height)
|
||||||
|
bottom = image.Rect(area.Min.X, area.Min.Y+height, area.Max.X, area.Max.Y)
|
||||||
|
}
|
||||||
|
|
||||||
if top.Dy() == 0 {
|
if top.Dy() == 0 {
|
||||||
top = image.ZR
|
top = image.ZR
|
||||||
}
|
}
|
||||||
bottom = image.Rect(area.Min.X, area.Min.Y+height, area.Max.X, area.Max.Y)
|
|
||||||
if bottom.Dy() == 0 {
|
if bottom.Dy() == 0 {
|
||||||
bottom = image.ZR
|
bottom = image.ZR
|
||||||
}
|
}
|
||||||
|
|
||||||
return top, bottom, nil
|
return top, bottom, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// VSplit returns two new areas created by splitting the provided area at the
|
// HSplit returns two new areas created by splitting the provided area at the
|
||||||
// specified percentage of its width. The percentage must be in the range
|
// specified percentage of its height, applying the percentage to the top area.
|
||||||
// 0 <= widthPerc <= 100.
|
// The percentage must be in the range 0 <= heightPerc <= 100.
|
||||||
// Can return zero size areas.
|
// Can return zero size areas.
|
||||||
func VSplit(area image.Rectangle, widthPerc int) (left image.Rectangle, right image.Rectangle, err error) {
|
func HSplit(area image.Rectangle, heightPerc int) (top image.Rectangle, bottom image.Rectangle, err error) {
|
||||||
|
return hSplit(area, heightPerc, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HSplitReversed returns two new areas created by splitting the provided area
|
||||||
|
// at the specified percentage of its height, applying the percentage to the
|
||||||
|
// bottom area. The percentage must be in the range 0 <= heightPerc <= 100.
|
||||||
|
// Can return zero size areas.
|
||||||
|
func HSplitReversed(area image.Rectangle, heightPerc int) (top image.Rectangle, bottom image.Rectangle, err error) {
|
||||||
|
return hSplit(area, heightPerc, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// vSplit returns two new areas created by splitting the provided area at the
|
||||||
|
// specified percentage of its width, applying the percentage to the left or
|
||||||
|
// right area, depending on the reversed flag. The percentage must be in the
|
||||||
|
// range 0 <= widthPerc <= 100.
|
||||||
|
// Can return zero size areas.
|
||||||
|
func vSplit(area image.Rectangle, widthPerc int, reversed bool) (left image.Rectangle, right image.Rectangle, err error) {
|
||||||
if min, max := 0, 100; widthPerc < min || widthPerc > max {
|
if min, max := 0, 100; widthPerc < min || widthPerc > max {
|
||||||
return image.ZR, image.ZR, fmt.Errorf("invalid widthPerc %d, must be in range %d <= widthPerc <= %d", widthPerc, min, max)
|
return image.ZR, image.ZR, fmt.Errorf("invalid widthPerc %d, must be in range %d <= widthPerc <= %d", widthPerc, min, max)
|
||||||
}
|
}
|
||||||
|
|
||||||
width := area.Dx() * widthPerc / 100
|
width := area.Dx() * widthPerc / 100
|
||||||
left = image.Rect(area.Min.X, area.Min.Y, area.Min.X+width, area.Max.Y)
|
|
||||||
|
if reversed {
|
||||||
|
left = image.Rect(area.Min.X, area.Min.Y, area.Max.X-width, area.Max.Y)
|
||||||
|
right = image.Rect(area.Max.X-width, area.Min.Y, area.Max.X, area.Max.Y)
|
||||||
|
} else {
|
||||||
|
left = image.Rect(area.Min.X, area.Min.Y, area.Min.X+width, area.Max.Y)
|
||||||
|
right = image.Rect(area.Min.X+width, area.Min.Y, area.Max.X, area.Max.Y)
|
||||||
|
}
|
||||||
|
|
||||||
if left.Dx() == 0 {
|
if left.Dx() == 0 {
|
||||||
left = image.ZR
|
left = image.ZR
|
||||||
}
|
}
|
||||||
right = image.Rect(area.Min.X+width, area.Min.Y, area.Max.X, area.Max.Y)
|
|
||||||
if right.Dx() == 0 {
|
if right.Dx() == 0 {
|
||||||
right = image.ZR
|
right = image.ZR
|
||||||
}
|
}
|
||||||
|
|
||||||
return left, right, nil
|
return left, right, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// VSplitCells returns two new areas created by splitting the provided area
|
// VSplit returns two new areas created by splitting the provided area at the
|
||||||
// after the specified amount of cells of its width. The number of cells must
|
// specified percentage of its width, applying the percentage to the left area.
|
||||||
// be a zero or a positive integer. Providing a zero returns left=image.ZR,
|
// The percentage must be in the range 0 <= widthPerc <= 100.
|
||||||
|
// Can return zero size areas.
|
||||||
|
func VSplit(area image.Rectangle, widthPerc int) (left image.Rectangle, right image.Rectangle, err error) {
|
||||||
|
return vSplit(area, widthPerc, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VSplitReversed returns two new areas created by splitting the provided area
|
||||||
|
// at the specified percentage of its width, applying the percentage to the
|
||||||
|
// right area. The percentage must be in the range 0 <= widthPerc <= 100.
|
||||||
|
// Can return zero size areas.
|
||||||
|
func VSplitReversed(area image.Rectangle, widthPerc int) (left image.Rectangle, right image.Rectangle, err error) {
|
||||||
|
return vSplit(area, widthPerc, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// vSplitCells returns two new areas created by splitting the provided area
|
||||||
|
// after the specified amount of cells of its width, applied to the left or
|
||||||
|
// right area, depending on the reversed flag. The number of cells must be a
|
||||||
|
// zero or a positive integer. Providing a zero returns left=image.ZR,
|
||||||
// right=area. Providing a number equal or larger to area's width returns
|
// right=area. Providing a number equal or larger to area's width returns
|
||||||
// left=area, right=image.ZR.
|
// left=area, right=image.ZR.
|
||||||
func VSplitCells(area image.Rectangle, cells int) (left image.Rectangle, right image.Rectangle, err error) {
|
func vSplitCells(area image.Rectangle, cells int, reversed bool) (left image.Rectangle, right image.Rectangle, err error) {
|
||||||
if min := 0; cells < min {
|
if min := 0; cells < min {
|
||||||
return image.ZR, image.ZR, fmt.Errorf("invalid cells %d, must be a positive integer", cells)
|
return image.ZR, image.ZR, fmt.Errorf("invalid cells %d, must be a positive integer", cells)
|
||||||
}
|
}
|
||||||
if cells == 0 {
|
if cells == 0 {
|
||||||
|
if reversed {
|
||||||
|
return area, image.ZR, nil
|
||||||
|
}
|
||||||
return image.ZR, area, nil
|
return image.ZR, area, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
width := area.Dx()
|
width := area.Dx()
|
||||||
if cells >= width {
|
if cells >= width {
|
||||||
|
if reversed {
|
||||||
|
return image.ZR, area, nil
|
||||||
|
}
|
||||||
return area, image.ZR, nil
|
return area, image.ZR, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
left = image.Rect(area.Min.X, area.Min.Y, area.Min.X+cells, area.Max.Y)
|
splitX := area.Min.X
|
||||||
right = image.Rect(area.Min.X+cells, area.Min.Y, area.Max.X, area.Max.Y)
|
if reversed {
|
||||||
|
splitX = area.Max.X - cells
|
||||||
|
} else {
|
||||||
|
splitX = area.Min.X + cells
|
||||||
|
}
|
||||||
|
|
||||||
|
left = image.Rect(area.Min.X, area.Min.Y, splitX, area.Max.Y)
|
||||||
|
right = image.Rect(splitX, area.Min.Y, area.Max.X, area.Max.Y)
|
||||||
|
|
||||||
return left, right, nil
|
return left, right, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HSplitCells returns two new areas created by splitting the provided area
|
// VSplitCells returns two new areas created by splitting the provided area
|
||||||
// after the specified amount of cells of its height. The number of cells must
|
// after the specified amount of cells of its width, as applied to the left
|
||||||
// be a zero or a positive integer. Providing a zero returns top=image.ZR,
|
// area. The number of cells must be a zero or a positive integer. Providing a
|
||||||
|
// zero returns left=image.ZR, right=area. Providing a number equal or larger to
|
||||||
|
// area's width returns left=area, right=image.ZR.
|
||||||
|
func VSplitCells(area image.Rectangle, cells int) (left image.Rectangle, right image.Rectangle, err error) {
|
||||||
|
return vSplitCells(area, cells, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VSplitCellsReversed returns two new areas created by splitting the provided
|
||||||
|
// area after the specified amount of cells of its width, as applied to the
|
||||||
|
// right area. The number of cells must be a zero or a positive integer.
|
||||||
|
// Providing a zero returns left=image.ZR, right=area. Providing a number equal
|
||||||
|
// or larger to area's width returns left=area, right=image.ZR.
|
||||||
|
func VSplitCellsReversed(area image.Rectangle, cells int) (left image.Rectangle, right image.Rectangle, err error) {
|
||||||
|
return vSplitCells(area, cells, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// hSplitCells returns two new areas created by splitting the provided area
|
||||||
|
// after the specified amount of cells of its height, applied to the top or
|
||||||
|
// bottom area, depending on the reversed flag. The number of cells must be a
|
||||||
|
// zero or a positive integer. Providing a zero returns top=image.ZR,
|
||||||
// bottom=area. Providing a number equal or larger to area's height returns
|
// bottom=area. Providing a number equal or larger to area's height returns
|
||||||
// top=area, bottom=image.ZR.
|
// top=area, bottom=image.ZR.
|
||||||
func HSplitCells(area image.Rectangle, cells int) (top image.Rectangle, bottom image.Rectangle, err error) {
|
func hSplitCells(area image.Rectangle, cells int, reversed bool) (top image.Rectangle, bottom image.Rectangle, err error) {
|
||||||
if min := 0; cells < min {
|
if min := 0; cells < min {
|
||||||
return image.ZR, image.ZR, fmt.Errorf("invalid cells %d, must be a positive integer", cells)
|
return image.ZR, image.ZR, fmt.Errorf("invalid cells %d, must be a positive integer", cells)
|
||||||
}
|
}
|
||||||
if cells == 0 {
|
if cells == 0 {
|
||||||
|
if reversed {
|
||||||
|
return area, image.ZR, nil
|
||||||
|
}
|
||||||
return image.ZR, area, nil
|
return image.ZR, area, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
height := area.Dy()
|
height := area.Dy()
|
||||||
if cells >= height {
|
if cells >= height {
|
||||||
|
if reversed {
|
||||||
|
return image.ZR, area, nil
|
||||||
|
}
|
||||||
return area, image.ZR, nil
|
return area, image.ZR, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
top = image.Rect(area.Min.X, area.Min.Y, area.Max.X, area.Min.Y+cells)
|
splitY := area.Min.Y
|
||||||
bottom = image.Rect(area.Min.X, area.Min.Y+cells, area.Max.X, area.Max.Y)
|
if reversed {
|
||||||
|
splitY = area.Max.Y - cells
|
||||||
|
} else {
|
||||||
|
splitY = area.Min.Y + cells
|
||||||
|
}
|
||||||
|
|
||||||
|
top = image.Rect(area.Min.X, area.Min.Y, area.Max.X, splitY)
|
||||||
|
bottom = image.Rect(area.Min.X, splitY, area.Max.X, area.Max.Y)
|
||||||
|
|
||||||
return top, bottom, nil
|
return top, bottom, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HSplitCells returns two new areas created by splitting the provided area
|
||||||
|
// after the specified amount of cells of its height, as applied to the top
|
||||||
|
// area. The number of cells must be a zero or a positive integer. Providing a
|
||||||
|
// zero returns top=image.ZR, bottom=area. Providing a number equal or larger to
|
||||||
|
// area's height returns top=area, bottom=image.ZR.
|
||||||
|
func HSplitCells(area image.Rectangle, cells int) (top image.Rectangle, bottom image.Rectangle, err error) {
|
||||||
|
return hSplitCells(area, cells, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HSplitCellsReversed returns two new areas created by splitting the provided
|
||||||
|
// area after the specified amount of cells of its height, as applied to the
|
||||||
|
// bottom area. The number of cells must be a zero or a positive integer.
|
||||||
|
// Providing a zero returns top=area, bottom=image.ZR. Providing a number equal
|
||||||
|
// or larger to area's height returns top=image.ZR, bottom=area.
|
||||||
|
func HSplitCellsReversed(area image.Rectangle, cells int) (top image.Rectangle, bottom image.Rectangle, err error) {
|
||||||
|
return hSplitCells(area, cells, true)
|
||||||
|
}
|
||||||
|
|
||||||
// ExcludeBorder returns a new area created by subtracting a border around the
|
// ExcludeBorder returns a new area created by subtracting a border around the
|
||||||
// provided area. Return the zero area if there isn't enough space to exclude
|
// provided area. Return the zero area if there isn't enough space to exclude
|
||||||
// the border.
|
// the border.
|
||||||
|
@ -198,6 +198,87 @@ func TestHSplit(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHSplitReversed(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
desc string
|
||||||
|
area image.Rectangle
|
||||||
|
heightPerc int
|
||||||
|
wantTop image.Rectangle
|
||||||
|
wantBot image.Rectangle
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "fails on heightPerc too small",
|
||||||
|
area: image.Rect(1, 1, 2, 2),
|
||||||
|
heightPerc: -1,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "fails on heightPerc too large",
|
||||||
|
area: image.Rect(1, 1, 2, 2),
|
||||||
|
heightPerc: 101,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "zero area to begin with",
|
||||||
|
area: image.ZR,
|
||||||
|
heightPerc: 50,
|
||||||
|
wantTop: image.ZR,
|
||||||
|
wantBot: image.ZR,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "splitting results in zero height area on the bottom",
|
||||||
|
area: image.Rect(1, 1, 2, 2),
|
||||||
|
heightPerc: 0,
|
||||||
|
wantTop: image.Rect(1, 1, 2, 2),
|
||||||
|
wantBot: image.ZR,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "splitting results in 100 height area on the top",
|
||||||
|
area: image.Rect(1, 1, 2, 2),
|
||||||
|
heightPerc: 100,
|
||||||
|
wantTop: image.ZR,
|
||||||
|
wantBot: image.Rect(1, 1, 2, 2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "splits area with even height",
|
||||||
|
area: image.Rect(1, 1, 3, 3),
|
||||||
|
heightPerc: 50,
|
||||||
|
wantTop: image.Rect(1, 1, 3, 2),
|
||||||
|
wantBot: image.Rect(1, 2, 3, 3),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "splits area with odd height",
|
||||||
|
area: image.Rect(1, 1, 4, 4),
|
||||||
|
heightPerc: 50,
|
||||||
|
wantTop: image.Rect(1, 1, 4, 3),
|
||||||
|
wantBot: image.Rect(1, 3, 4, 4),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "splits to unequal areas",
|
||||||
|
area: image.Rect(0, 0, 4, 4),
|
||||||
|
heightPerc: 25,
|
||||||
|
wantTop: image.Rect(0, 0, 4, 3),
|
||||||
|
wantBot: image.Rect(0, 3, 4, 4),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
|
gotTop, gotBot, err := HSplitReversed(tc.area, tc.heightPerc)
|
||||||
|
if (err != nil) != tc.wantErr {
|
||||||
|
t.Errorf("VSplit => unexpected error:%v, wantErr:%v", err, tc.wantErr)
|
||||||
|
}
|
||||||
|
if diff := pretty.Compare(tc.wantTop, gotTop); diff != "" {
|
||||||
|
t.Errorf("HSplit => first value unexpected diff (-want, +got):\n%s", diff)
|
||||||
|
}
|
||||||
|
if diff := pretty.Compare(tc.wantBot, gotBot); diff != "" {
|
||||||
|
t.Errorf("HSplit => second value unexpected diff (-want, +got):\n%s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestVSplit(t *testing.T) {
|
func TestVSplit(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
desc string
|
desc string
|
||||||
@ -282,6 +363,90 @@ func TestVSplit(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVSplitReversed(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
desc string
|
||||||
|
area image.Rectangle
|
||||||
|
widthPerc int
|
||||||
|
wantLeft image.Rectangle
|
||||||
|
wantRight image.Rectangle
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "fails on widthPerc too small",
|
||||||
|
area: image.Rect(1, 1, 2, 2),
|
||||||
|
widthPerc: -1,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "fails on widthPerc too large",
|
||||||
|
area: image.Rect(1, 1, 2, 2),
|
||||||
|
widthPerc: 101,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "zero area to begin with",
|
||||||
|
area: image.ZR,
|
||||||
|
widthPerc: 50,
|
||||||
|
wantLeft: image.ZR,
|
||||||
|
wantRight: image.ZR,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "splitting results in zero width area on the right",
|
||||||
|
area: image.Rect(1, 1, 2, 2),
|
||||||
|
widthPerc: 0,
|
||||||
|
wantLeft: image.Rect(1, 1, 2, 2),
|
||||||
|
wantRight: image.ZR,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "splitting results in zero width area on the left",
|
||||||
|
area: image.Rect(1, 1, 2, 2),
|
||||||
|
widthPerc: 100,
|
||||||
|
wantLeft: image.ZR,
|
||||||
|
wantRight: image.Rect(1, 1, 2, 2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "splits area with even width",
|
||||||
|
area: image.Rect(1, 1, 3, 3),
|
||||||
|
widthPerc: 50,
|
||||||
|
wantLeft: image.Rect(1, 1, 2, 3),
|
||||||
|
wantRight: image.Rect(2, 1, 3, 3),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "splits area with odd width",
|
||||||
|
area: image.Rect(1, 1, 4, 4),
|
||||||
|
widthPerc: 50,
|
||||||
|
wantLeft: image.Rect(1, 1, 3, 4),
|
||||||
|
wantRight: image.Rect(3, 1, 4, 4),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "splits to unequal areas",
|
||||||
|
area: image.Rect(0, 0, 4, 4),
|
||||||
|
widthPerc: 25,
|
||||||
|
wantLeft: image.Rect(0, 0, 3, 4),
|
||||||
|
wantRight: image.Rect(3, 0, 4, 4),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
|
gotLeft, gotRight, err := VSplitReversed(tc.area, tc.widthPerc)
|
||||||
|
if (err != nil) != tc.wantErr {
|
||||||
|
t.Errorf("VSplit => unexpected error:%v, wantErr:%v", err, tc.wantErr)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if diff := pretty.Compare(tc.wantLeft, gotLeft); diff != "" {
|
||||||
|
t.Errorf("VSplit => left value unexpected diff (-want, +got):\n%s", diff)
|
||||||
|
}
|
||||||
|
if diff := pretty.Compare(tc.wantRight, gotRight); diff != "" {
|
||||||
|
t.Errorf("VSplit => right value unexpected diff (-want, +got):\n%s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestVSplitCells(t *testing.T) {
|
func TestVSplitCells(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
desc string
|
desc string
|
||||||
@ -367,6 +532,91 @@ func TestVSplitCells(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVSplitCellsReversed(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
desc string
|
||||||
|
area image.Rectangle
|
||||||
|
cells int
|
||||||
|
wantLeft image.Rectangle
|
||||||
|
wantRight image.Rectangle
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "fails on negative cells",
|
||||||
|
area: image.Rect(1, 1, 2, 2),
|
||||||
|
cells: -1,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "returns area as left on cells too large",
|
||||||
|
area: image.Rect(1, 1, 2, 2),
|
||||||
|
cells: 2,
|
||||||
|
wantLeft: image.ZR,
|
||||||
|
wantRight: image.Rect(1, 1, 2, 2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "returns area as left on cells equal area width",
|
||||||
|
area: image.Rect(1, 1, 2, 2),
|
||||||
|
cells: 1,
|
||||||
|
wantLeft: image.ZR,
|
||||||
|
wantRight: image.Rect(1, 1, 2, 2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "returns area as right on zero cells",
|
||||||
|
area: image.Rect(1, 1, 2, 2),
|
||||||
|
cells: 0,
|
||||||
|
wantRight: image.ZR,
|
||||||
|
wantLeft: image.Rect(1, 1, 2, 2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "zero area to begin with",
|
||||||
|
area: image.ZR,
|
||||||
|
cells: 0,
|
||||||
|
wantLeft: image.ZR,
|
||||||
|
wantRight: image.ZR,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "splits area with even width",
|
||||||
|
area: image.Rect(1, 1, 3, 3),
|
||||||
|
cells: 1,
|
||||||
|
wantLeft: image.Rect(1, 1, 2, 3),
|
||||||
|
wantRight: image.Rect(2, 1, 3, 3),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "splits area with odd width",
|
||||||
|
area: image.Rect(1, 1, 4, 4),
|
||||||
|
cells: 1,
|
||||||
|
wantLeft: image.Rect(1, 1, 3, 4),
|
||||||
|
wantRight: image.Rect(3, 1, 4, 4),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "splits to unequal areas",
|
||||||
|
area: image.Rect(0, 0, 4, 4),
|
||||||
|
cells: 3,
|
||||||
|
wantLeft: image.Rect(0, 0, 1, 4),
|
||||||
|
wantRight: image.Rect(1, 0, 4, 4),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
|
gotLeft, gotRight, err := VSplitCellsReversed(tc.area, tc.cells)
|
||||||
|
if (err != nil) != tc.wantErr {
|
||||||
|
t.Errorf("VSplitCells => unexpected error:%v, wantErr:%v", err, tc.wantErr)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if diff := pretty.Compare(tc.wantLeft, gotLeft); diff != "" {
|
||||||
|
t.Errorf("VSplitCells => left value unexpected diff (-want, +got):\n%s", diff)
|
||||||
|
}
|
||||||
|
if diff := pretty.Compare(tc.wantRight, gotRight); diff != "" {
|
||||||
|
t.Errorf("VSplitCells => right value unexpected diff (-want, +got):\n%s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestHSplitCells(t *testing.T) {
|
func TestHSplitCells(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
desc string
|
desc string
|
||||||
@ -452,6 +702,91 @@ func TestHSplitCells(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHSplitCellsReversed(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
desc string
|
||||||
|
area image.Rectangle
|
||||||
|
cells int
|
||||||
|
wantTop image.Rectangle
|
||||||
|
wantBottom image.Rectangle
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "fails on negative cells",
|
||||||
|
area: image.Rect(1, 1, 2, 2),
|
||||||
|
cells: -1,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "returns area as bottom on cells too large",
|
||||||
|
area: image.Rect(1, 1, 2, 2),
|
||||||
|
cells: 2,
|
||||||
|
wantTop: image.ZR,
|
||||||
|
wantBottom: image.Rect(1, 1, 2, 2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "returns area as bottom on cells equal area width",
|
||||||
|
area: image.Rect(1, 1, 2, 2),
|
||||||
|
cells: 1,
|
||||||
|
wantTop: image.ZR,
|
||||||
|
wantBottom: image.Rect(1, 1, 2, 2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "returns area as top on zero cells",
|
||||||
|
area: image.Rect(1, 1, 2, 2),
|
||||||
|
cells: 0,
|
||||||
|
wantBottom: image.ZR,
|
||||||
|
wantTop: image.Rect(1, 1, 2, 2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "zero area to begin with",
|
||||||
|
area: image.ZR,
|
||||||
|
cells: 0,
|
||||||
|
wantTop: image.ZR,
|
||||||
|
wantBottom: image.ZR,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "splits area with even height",
|
||||||
|
area: image.Rect(1, 1, 3, 3),
|
||||||
|
cells: 1,
|
||||||
|
wantTop: image.Rect(1, 1, 3, 2),
|
||||||
|
wantBottom: image.Rect(1, 2, 3, 3),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "splits area with odd width",
|
||||||
|
area: image.Rect(1, 1, 4, 4),
|
||||||
|
cells: 1,
|
||||||
|
wantTop: image.Rect(1, 1, 4, 3),
|
||||||
|
wantBottom: image.Rect(1, 3, 4, 4),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "splits to unequal areas",
|
||||||
|
area: image.Rect(0, 0, 4, 4),
|
||||||
|
cells: 3,
|
||||||
|
wantTop: image.Rect(0, 0, 4, 1),
|
||||||
|
wantBottom: image.Rect(0, 1, 4, 4),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
|
gotTop, gotBottom, err := HSplitCellsReversed(tc.area, tc.cells)
|
||||||
|
if (err != nil) != tc.wantErr {
|
||||||
|
t.Errorf("HSplitCells => unexpected error:%v, wantErr:%v", err, tc.wantErr)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if diff := pretty.Compare(tc.wantTop, gotTop); diff != "" {
|
||||||
|
t.Errorf("HSplitCells => left value unexpected diff (-want, +got):\n%s", diff)
|
||||||
|
}
|
||||||
|
if diff := pretty.Compare(tc.wantBottom, gotBottom); diff != "" {
|
||||||
|
t.Errorf("HSplitCells => right value unexpected diff (-want, +got):\n%s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestExcludeBorder(t *testing.T) {
|
func TestExcludeBorder(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
desc string
|
desc string
|
||||||
|
Loading…
x
Reference in New Issue
Block a user