mirror of https://github.com/mum4k/termdash.git
Refactor `SplitFixed()` to use SplitCells
* Add basic tests to `SplitFixed()` * Panic when both `SplitFixed()` and `SplitPercent()` are used * Refactor `validateOptions()` into two smaller functions
This commit is contained in:
parent
4aa60fe8e7
commit
70a5255d5e
|
@ -171,10 +171,17 @@ func (c *Container) split() (image.Rectangle, image.Rectangle, error) {
|
|||
if err != nil {
|
||||
return image.ZR, image.ZR, err
|
||||
}
|
||||
if c.opts.split == splitTypeVertical {
|
||||
return area.VSplit(ar, c.opts.splitPercent, c.opts.splitFixed)
|
||||
if c.opts.splitFixed > -1 {
|
||||
if c.opts.split == splitTypeVertical {
|
||||
return area.VSplitCells(ar, c.opts.splitFixed)
|
||||
}
|
||||
return area.HSplitCells(ar, c.opts.splitFixed)
|
||||
}
|
||||
return area.HSplit(ar, c.opts.splitPercent, c.opts.splitFixed)
|
||||
|
||||
if c.opts.split == splitTypeVertical {
|
||||
return area.VSplit(ar, c.opts.splitPercent)
|
||||
}
|
||||
return area.HSplit(ar, c.opts.splitPercent)
|
||||
}
|
||||
|
||||
// createFirst creates and returns the first sub container of this container.
|
||||
|
|
|
@ -490,6 +490,26 @@ func TestNew(t *testing.T) {
|
|||
},
|
||||
wantContainerErr: true,
|
||||
},
|
||||
{
|
||||
desc: "fails when both SplitFixed and SplitPercent are specified",
|
||||
termSize: image.Point{10, 10},
|
||||
container: func(ft *faketerm.Terminal) (*Container, error) {
|
||||
return New(
|
||||
ft,
|
||||
SplitHorizontal(
|
||||
Top(
|
||||
Border(linestyle.Light),
|
||||
),
|
||||
Bottom(
|
||||
Border(linestyle.Light),
|
||||
),
|
||||
SplitFixed(4),
|
||||
SplitPercent(20),
|
||||
),
|
||||
)
|
||||
},
|
||||
wantContainerErr: true,
|
||||
},
|
||||
{
|
||||
desc: "empty container",
|
||||
termSize: image.Point{10, 10},
|
||||
|
@ -616,6 +636,32 @@ func TestNew(t *testing.T) {
|
|||
return ft
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "horizontal 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),
|
||||
),
|
||||
SplitFixed(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, 4))
|
||||
testdraw.MustBorder(cvs, image.Rect(0, 4, 10, 20))
|
||||
testcanvas.MustApply(cvs, ft)
|
||||
return ft
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "horizontal split, parent and children have borders",
|
||||
termSize: image.Point{10, 10},
|
||||
|
@ -742,6 +788,32 @@ func TestNew(t *testing.T) {
|
|||
return ft
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "vertical 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),
|
||||
),
|
||||
SplitFixed(4),
|
||||
),
|
||||
)
|
||||
},
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
ft := faketerm.MustNew(size)
|
||||
cvs := testcanvas.MustNew(ft.Area())
|
||||
testdraw.MustBorder(cvs, image.Rect(0, 0, 4, 10))
|
||||
testdraw.MustBorder(cvs, image.Rect(4, 0, 20, 10))
|
||||
testcanvas.MustApply(cvs, ft)
|
||||
return ft
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "vertical split, parent and children have borders",
|
||||
termSize: image.Point{10, 10},
|
||||
|
|
|
@ -127,7 +127,7 @@ func mirror() *fakewidget.Mirror {
|
|||
|
||||
// mustHSplit splits the area or panics.
|
||||
func mustHSplit(ar image.Rectangle, heightPerc int) (top image.Rectangle, bottom image.Rectangle) {
|
||||
t, b, err := area.HSplit(ar, heightPerc, -1)
|
||||
t, b, err := area.HSplit(ar, heightPerc)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ func mustHSplit(ar image.Rectangle, heightPerc int) (top image.Rectangle, bottom
|
|||
|
||||
// mustVSplit splits the area or panics.
|
||||
func mustVSplit(ar image.Rectangle, widthPerc int) (left image.Rectangle, right image.Rectangle) {
|
||||
l, r, err := area.VSplit(ar, widthPerc, -1)
|
||||
l, r, err := area.VSplit(ar, widthPerc)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -38,9 +38,8 @@ func applyOptions(c *Container, opts ...Option) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// validateOptions validates options set in the container tree.
|
||||
func validateOptions(c *Container) error {
|
||||
// ensure all the container identifiers are either empty or unique.
|
||||
// ensure all the container identifiers are either empty or unique.
|
||||
func validateIds(c *Container) error {
|
||||
var errStr string
|
||||
seenID := map[string]bool{}
|
||||
preOrder(c, &errStr, func(c *Container) error {
|
||||
|
@ -60,6 +59,43 @@ func validateOptions(c *Container) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ensure all the container only have one split modifier.
|
||||
func validateSplits(c *Container) error {
|
||||
var errStr string
|
||||
preOrder(c, &errStr, func(c *Container) error {
|
||||
if c.opts.splitFixed > -1 && c.opts.splitPercent != 50 {
|
||||
return fmt.Errorf(
|
||||
"only one of splitFixed `%v` and splitPercent `%v` is allowed to be set per container",
|
||||
c.opts.splitFixed,
|
||||
c.opts.splitPercent,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if errStr != "" {
|
||||
return errors.New(errStr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateOptions validates options set in the container tree.
|
||||
func validateOptions(c *Container) error {
|
||||
// ensure all the container identifiers are either empty or unique.
|
||||
errIds := validateIds(c)
|
||||
if errIds != nil {
|
||||
return errIds
|
||||
}
|
||||
|
||||
// ensure that max one split modifier is used per container
|
||||
errSplits := validateSplits(c)
|
||||
if errSplits != nil {
|
||||
return errSplits
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Option is used to provide options to a container.
|
||||
type Option interface {
|
||||
// set sets the provided option.
|
||||
|
@ -218,8 +254,8 @@ func SplitPercent(p int) SplitOption {
|
|||
})
|
||||
}
|
||||
|
||||
// SplitFixed sets the heights of the top and the bottom containers.
|
||||
// The first container will be fixed and the second one will fill the rest of the space.
|
||||
// SplitFixed sets the size as a fixed value of the available space.
|
||||
// FIXME: More comments
|
||||
// Allows values greater or equal to zero.
|
||||
func SplitFixed(cells int) SplitOption {
|
||||
return splitOption(func(opts *options) error {
|
||||
|
|
|
@ -45,23 +45,14 @@ func FromSize(size image.Point) (image.Rectangle, error) {
|
|||
//
|
||||
// The fixed value must by in the range -1 <= heightFixed.
|
||||
// If fixed value is -1 (default value), heightPerc is used instead.
|
||||
func HSplit(area image.Rectangle, heightPerc int, heightFixed int) (top image.Rectangle, bottom image.Rectangle, err error) {
|
||||
func HSplit(area image.Rectangle, heightPerc int) (top image.Rectangle, bottom image.Rectangle, err error) {
|
||||
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)
|
||||
}
|
||||
if heightFixed < -1 {
|
||||
return image.ZR, image.ZR, fmt.Errorf("invalid heightFixed %d, must be in range %d <= heightFixed", heightFixed, -1)
|
||||
}
|
||||
|
||||
// Prioritize `SplitFixed()` over `SplitPercent()`.
|
||||
if heightFixed >= 0 {
|
||||
top = image.Rect(area.Min.X, area.Min.Y, area.Max.X, area.Min.Y+heightFixed)
|
||||
bottom = image.Rect(area.Min.X, area.Min.Y+heightFixed, area.Max.X, area.Max.Y)
|
||||
} else {
|
||||
height := area.Dy() * heightPerc / 100
|
||||
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)
|
||||
}
|
||||
height := area.Dy() * heightPerc / 100
|
||||
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 {
|
||||
top = image.ZR
|
||||
}
|
||||
|
@ -78,23 +69,14 @@ func HSplit(area image.Rectangle, heightPerc int, heightFixed int) (top image.Re
|
|||
//
|
||||
// The fixed value must by in the range -1 <= heightFixed.
|
||||
// If fixed value is -1 (default value), heightPerc is used instead.
|
||||
func VSplit(area image.Rectangle, widthPerc int, widthFixed int) (left image.Rectangle, right image.Rectangle, err error) {
|
||||
func VSplit(area image.Rectangle, widthPerc int) (left image.Rectangle, right image.Rectangle, err error) {
|
||||
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)
|
||||
}
|
||||
if widthFixed < -1 {
|
||||
return image.ZR, image.ZR, fmt.Errorf("invalid widthFixed %d, must be in range %d <= widthFixed", widthFixed, -1)
|
||||
}
|
||||
|
||||
// Prioritize `SplitFixed()` over `SplitPercent()`.
|
||||
if widthFixed >= 0 {
|
||||
left = image.Rect(area.Min.X, area.Min.Y, area.Min.X+widthFixed, area.Max.Y)
|
||||
right = image.Rect(area.Min.X+widthFixed, area.Min.Y, area.Max.X, area.Max.Y)
|
||||
} else {
|
||||
width := area.Dx() * widthPerc / 100
|
||||
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)
|
||||
}
|
||||
width := area.Dx() * widthPerc / 100
|
||||
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 {
|
||||
left = image.ZR
|
||||
}
|
||||
|
|
|
@ -184,7 +184,7 @@ func TestHSplit(t *testing.T) {
|
|||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
gotTop, gotBot, err := HSplit(tc.area, tc.heightPerc, -1)
|
||||
gotTop, gotBot, err := HSplit(tc.area, tc.heightPerc)
|
||||
if (err != nil) != tc.wantErr {
|
||||
t.Errorf("VSplit => unexpected error:%v, wantErr:%v", err, tc.wantErr)
|
||||
}
|
||||
|
@ -265,7 +265,7 @@ func TestVSplit(t *testing.T) {
|
|||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
gotLeft, gotRight, err := VSplit(tc.area, tc.widthPerc, -1)
|
||||
gotLeft, gotRight, err := VSplit(tc.area, tc.widthPerc)
|
||||
if (err != nil) != tc.wantErr {
|
||||
t.Errorf("VSplit => unexpected error:%v, wantErr:%v", err, tc.wantErr)
|
||||
}
|
||||
|
|
|
@ -330,7 +330,7 @@ func split(cvsAr image.Rectangle, label string, widthPerc *int) (labelAr, textAr
|
|||
switch {
|
||||
case widthPerc != nil:
|
||||
splitP := 100 - *widthPerc
|
||||
labelAr, textAr, err := area.VSplit(cvsAr, splitP, -1)
|
||||
labelAr, textAr, err := area.VSplit(cvsAr, splitP)
|
||||
if err != nil {
|
||||
return image.ZR, image.ZR, err
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue