2018-03-27 19:01:35 +01:00
|
|
|
/*
|
|
|
|
Package container defines a type that wraps other containers or widgets.
|
|
|
|
|
|
|
|
The container supports splitting container into sub containers, defining
|
|
|
|
container styles and placing widgets. The container also creates and manages
|
|
|
|
canvases assigned to the placed widgets.
|
|
|
|
*/
|
|
|
|
package container
|
|
|
|
|
|
|
|
import (
|
2018-03-28 21:34:20 +03:00
|
|
|
"errors"
|
|
|
|
"image"
|
|
|
|
|
2018-03-27 19:01:35 +01:00
|
|
|
"github.com/mum4k/termdash/terminalapi"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Container wraps either sub containers or widgets and positions them on the
|
|
|
|
// terminal.
|
|
|
|
type Container struct {
|
|
|
|
// parent is the parent container, nil if this is the root container.
|
|
|
|
parent *Container
|
|
|
|
// The sub containers, if these aren't nil, the widget must be.
|
|
|
|
first *Container
|
|
|
|
second *Container
|
|
|
|
|
|
|
|
// term is the terminal this container is placed on.
|
2018-03-28 21:34:20 +03:00
|
|
|
// All containers in the tree share the same terminal.
|
2018-03-27 19:01:35 +01:00
|
|
|
term terminalapi.Terminal
|
|
|
|
|
2018-03-28 21:34:20 +03:00
|
|
|
// area is the area of the terminal this container has access to.
|
|
|
|
area image.Rectangle
|
2018-03-27 19:01:35 +01:00
|
|
|
|
2018-03-28 21:34:20 +03:00
|
|
|
// opts are the options provided to the container.
|
|
|
|
opts *options
|
2018-03-27 19:01:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// New returns a new root container that will use the provided terminal and
|
|
|
|
// applies the provided options.
|
|
|
|
func New(t terminalapi.Terminal, opts ...Option) *Container {
|
2018-03-28 21:34:20 +03:00
|
|
|
o := &options{}
|
|
|
|
for _, opt := range opts {
|
|
|
|
opt.set(o)
|
2018-03-27 19:01:35 +01:00
|
|
|
}
|
|
|
|
|
2018-03-28 21:34:20 +03:00
|
|
|
size := t.Size()
|
|
|
|
return &Container{
|
|
|
|
term: t,
|
|
|
|
// The root container has access to the entire terminal.
|
|
|
|
area: image.Rect(0, 0, size.X, size.Y),
|
|
|
|
opts: o,
|
2018-03-27 19:01:35 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the parent container of this container.
|
|
|
|
// Returns nil if this container is the root of the container tree.
|
|
|
|
func (c *Container) Parent(opts ...Option) *Container {
|
|
|
|
if c == nil || c.parent == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
p := c.parent
|
|
|
|
for _, opt := range opts {
|
2018-03-28 21:34:20 +03:00
|
|
|
opt.set(p.opts)
|
2018-03-27 19:01:35 +01:00
|
|
|
}
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
|
|
|
// First returns the first sub container of this container.
|
|
|
|
// This is the left sub container when using SplitVertical() or the top sub
|
|
|
|
// container when using SplitHorizontal().
|
|
|
|
// If this container doesn't have the first sub container yet, it will be
|
|
|
|
// created. Applies the provided options to the first sub container.
|
|
|
|
// Returns nil if this container contains a widget, containers with widgets
|
|
|
|
// cannot have sub containers.
|
|
|
|
func (c *Container) First(opts ...Option) *Container {
|
2018-03-28 21:34:20 +03:00
|
|
|
if c == nil || c.opts.widget != nil {
|
2018-03-27 19:01:35 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if child := c.first; child != nil {
|
|
|
|
for _, opt := range opts {
|
2018-03-28 21:34:20 +03:00
|
|
|
opt.set(child.opts)
|
2018-03-27 19:01:35 +01:00
|
|
|
}
|
|
|
|
return child
|
|
|
|
}
|
|
|
|
|
|
|
|
c.first = New(c.term, opts...)
|
|
|
|
c.first.parent = c
|
|
|
|
return c.first
|
|
|
|
}
|
|
|
|
|
|
|
|
// Second returns the second sub container of this container.
|
|
|
|
// This is the left sub container when using SplitVertical() or the top sub
|
|
|
|
// container when using SplitHorizontal().
|
|
|
|
// If this container doesn't have the second sub container yet, it will be
|
|
|
|
// created. Applies the provided options to the second sub container.
|
|
|
|
// Returns nil if this container contains a widget, containers with widgets
|
|
|
|
// cannot have sub containers.
|
|
|
|
func (c *Container) Second(opts ...Option) *Container {
|
2018-03-28 21:34:20 +03:00
|
|
|
if c == nil || c.opts.widget != nil {
|
2018-03-27 19:01:35 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if child := c.second; child != nil {
|
|
|
|
for _, opt := range opts {
|
2018-03-28 21:34:20 +03:00
|
|
|
opt.set(child.opts)
|
2018-03-27 19:01:35 +01:00
|
|
|
}
|
|
|
|
return child
|
|
|
|
}
|
|
|
|
|
|
|
|
c.second = New(c.term, opts...)
|
|
|
|
c.second.parent = c
|
|
|
|
return c.second
|
|
|
|
}
|
2018-03-28 21:34:20 +03:00
|
|
|
|
|
|
|
// Draw requests all widgets in this and all sub containers to draw on their
|
|
|
|
// respective canvases.
|
|
|
|
func (c *Container) Draw() error {
|
|
|
|
return errors.New("unimplemented")
|
|
|
|
}
|