termdash/container/options.go

314 lines
7.9 KiB
Go

package container
// options.go defines container options.
import (
"github.com/mum4k/termdash/draw"
"github.com/mum4k/termdash/widget"
)
// applyOptions applies the options to the container.
func applyOptions(c *Container, opts ...Option) {
for _, opt := range opts {
opt.set(c)
}
}
// Option is used to provide options to a container.
type Option interface {
// set sets the provided option.
set(*Container)
}
// options stores the options provided to the container.
type options struct {
// split identifies how is this container split.
split splitType
// widget is the widget in the container.
// A container can have either two sub containers (left and right) or a
// widget. But not both.
widget widget.Widget
// Alignment of the widget if present.
hAlign hAlignType
vAlign vAlignType
// border is the border around the container.
border draw.LineStyle
}
// option implements Option.
type option func(*Container)
// set implements Option.set.
func (o option) set(c *Container) {
o(c)
}
// SplitVertical splits the container along the vertical axis into two sub
// containers. The use of this option removes any widget placed at this
// container, containers with sub containers cannot contain widgets.
func SplitVertical(l LeftOption, r RightOption) Option {
return option(func(c *Container) {
c.opts.split = splitTypeVertical
c.opts.widget = nil
applyOptions(c.createFirst(), l.lOpts()...)
applyOptions(c.createSecond(), r.rOpts()...)
})
}
// SplitHorizontal splits the container along the horizontal axis into two sub
// containers. The use of this option removes any widget placed at this
// container, containers with sub containers cannot contain widgets.
func SplitHorizontal(t TopOption, b BottomOption) Option {
return option(func(c *Container) {
c.opts.split = splitTypeHorizontal
c.opts.widget = nil
applyOptions(c.createFirst(), t.tOpts()...)
applyOptions(c.createSecond(), b.bOpts()...)
})
}
// PlaceWidget places the provided widget into the container.
// The use of this option removes any sub containers. Containers with sub
// containers cannot have widgets.
func PlaceWidget(w widget.Widget) Option {
return option(func(c *Container) {
c.opts.widget = w
c.first = nil
c.second = nil
})
}
// HorizontalAlignLeft aligns the placed widget on the left of the
// container along the horizontal axis. Has no effect if the container contains
// no widget. This is the default horizontal alignment if no other is specified.
func HorizontalAlignLeft() Option {
return option(func(c *Container) {
c.opts.hAlign = hAlignTypeLeft
})
}
// HorizontalAlignCenter aligns the placed widget in the center of the
// container along the horizontal axis. Has no effect if the container contains
// no widget.
func HorizontalAlignCenter() Option {
return option(func(c *Container) {
c.opts.hAlign = hAlignTypeCenter
})
}
// HorizontalAlignRight aligns the placed widget on the right of the
// container along the horizontal axis. Has no effect if the container contains
// no widget.
func HorizontalAlignRight() Option {
return option(func(c *Container) {
c.opts.hAlign = hAlignTypeRight
})
}
// VerticalAlignTop aligns the placed widget on the top of the
// container along the vertical axis. Has no effect if the container contains
// no widget. This is the default vertical alignment if no other is specified.
func VerticalAlignTop() Option {
return option(func(c *Container) {
c.opts.vAlign = vAlignTypeTop
})
}
// VerticalAlignMiddle aligns the placed widget in the middle of the
// container along the vertical axis. Has no effect if the container contains
// no widget.
func VerticalAlignMiddle() Option {
return option(func(c *Container) {
c.opts.vAlign = vAlignTypeMiddle
})
}
// VerticalAlignBottom aligns the placed widget at the bottom of the
// container along the vertical axis. Has no effect if the container contains
// no widget.
func VerticalAlignBottom() Option {
return option(func(c *Container) {
c.opts.vAlign = vAlignTypeBottom
})
}
// Border configures the container to have a border of the specified style.
func Border(ls draw.LineStyle) Option {
return option(func(c *Container) {
c.opts.border = ls
})
}
// splitType identifies how a container is split.
type splitType int
// String implements fmt.Stringer()
func (st splitType) String() string {
if n, ok := splitTypeNames[st]; ok {
return n
}
return "splitTypeUnknown"
}
// splitTypeNames maps splitType values to human readable names.
var splitTypeNames = map[splitType]string{
splitTypeVertical: "splitTypeVertical",
splitTypeHorizontal: "splitTypeHorizontal",
}
const (
splitTypeVertical splitType = iota
splitTypeHorizontal
)
// hAlignType indicates the horizontal alignment of the widget in the container.
type hAlignType int
// String implements fmt.Stringer()
func (hat hAlignType) String() string {
if n, ok := hAlignTypeNames[hat]; ok {
return n
}
return "hAlignTypeUnknown"
}
// hAlignTypeNames maps hAlignType values to human readable names.
var hAlignTypeNames = map[hAlignType]string{
hAlignTypeLeft: "hAlignTypeLeft",
hAlignTypeCenter: "hAlignTypeCenter",
hAlignTypeRight: "hAlignTypeRight",
}
const (
hAlignTypeLeft hAlignType = iota
hAlignTypeCenter
hAlignTypeRight
)
// vAlignType represents
type vAlignType int
// String implements fmt.Stringer()
func (vat vAlignType) String() string {
if n, ok := vAlignTypeNames[vat]; ok {
return n
}
return "vAlignTypeUnknown"
}
// vAlignTypeNames maps vAlignType values to human readable names.
var vAlignTypeNames = map[vAlignType]string{
vAlignTypeTop: "vAlignTypeTop",
vAlignTypeMiddle: "vAlignTypeMiddle",
vAlignTypeBottom: "vAlignTypeBottom",
}
const (
vAlignTypeTop vAlignType = iota
vAlignTypeMiddle
vAlignTypeBottom
)
// LeftOption is used to provide options to the left sub container after a
// vertical split of the parent.
type LeftOption interface {
// lOpts returns the options.
lOpts() []Option
}
// leftOption implements LeftOption.
type leftOption func() []Option
// lOpts implements LeftOption.lOpts.
func (lo leftOption) lOpts() []Option {
if lo == nil {
return nil
}
return lo()
}
// Left applies options to the left sub container after a vertical split of the parent.
func Left(opts ...Option) LeftOption {
return leftOption(func() []Option {
return opts
})
}
// RightOption is used to provide options to the right sub container after a
// vertical split of the parent.
type RightOption interface {
// rOpts returns the options.
rOpts() []Option
}
// rightOption implements RightOption.
type rightOption func() []Option
// rOpts implements RightOption.rOpts.
func (lo rightOption) rOpts() []Option {
if lo == nil {
return nil
}
return lo()
}
// Right applies options to the right sub container after a vertical split of the parent.
func Right(opts ...Option) RightOption {
return rightOption(func() []Option {
return opts
})
}
// TopOption is used to provide options to the top sub container after a
// horizontal split of the parent.
type TopOption interface {
// tOpts returns the options.
tOpts() []Option
}
// topOption implements TopOption.
type topOption func() []Option
// tOpts implements TopOption.tOpts.
func (lo topOption) tOpts() []Option {
if lo == nil {
return nil
}
return lo()
}
// Top applies options to the top sub container after a horizontal split of the parent.
func Top(opts ...Option) TopOption {
return topOption(func() []Option {
return opts
})
}
// BottomOption is used to provide options to the bottom sub container after a
// horizontal split of the parent.
type BottomOption interface {
// bOpts returns the options.
bOpts() []Option
}
// bottomOption implements BottomOption.
type bottomOption func() []Option
// bOpts implements BottomOption.bOpts.
func (lo bottomOption) bOpts() []Option {
if lo == nil {
return nil
}
return lo()
}
// Bottom applies options to the bottom sub container after a horizontal split of the parent.
func Bottom(opts ...Option) BottomOption {
return bottomOption(func() []Option {
return opts
})
}