clui/control_base.go

293 lines
8.0 KiB
Go
Raw Normal View History

2015-10-16 10:27:43 -07:00
package clui
import (
"fmt"
term "github.com/nsf/termbox-go"
"log"
)
2015-10-27 17:45:03 -07:00
// ControlBase is a base for all visible controls.
// Every new control must inherit it or implement
// the same set of methods
2015-10-16 10:27:43 -07:00
type ControlBase struct {
2015-10-19 15:09:25 -07:00
title string
x, y int
width, height int
minW, minH int
scale int
fg, bg term.Attribute
fgActive term.Attribute
bgActive term.Attribute
tabSkip bool
disabled bool
align Align
parent Control
view View
active bool
padX, padY int
padTop, padSide int
2015-10-16 10:27:43 -07:00
}
2015-10-27 17:45:03 -07:00
// Title returns the current title or text of the control
2015-10-16 10:27:43 -07:00
func (c *ControlBase) Title() string {
return c.title
}
2015-10-27 17:45:03 -07:00
// SetTitle changes control text or title
2015-10-16 10:27:43 -07:00
func (c *ControlBase) SetTitle(title string) {
c.title = title
}
2015-10-27 17:45:03 -07:00
// Size returns current control width and height
2015-10-16 10:27:43 -07:00
func (c *ControlBase) Size() (int, int) {
return c.width, c.height
}
2015-10-27 17:45:03 -07:00
// SetSize changes control size. Constant DoNotChange can be
// used as placeholder to indicate that the control attrubute
// should be unchanged.
// Method panics if new size is less than minimal size
2015-10-16 10:27:43 -07:00
func (c *ControlBase) SetSize(width, height int) {
if width != DoNotChange && (width > 1000 || width < c.minW) {
panic(fmt.Sprintf("Invalid width: %v", width))
}
if height != DoNotChange && (height > 200 || height < c.minH) {
panic(fmt.Sprintf("Invalid height: %v", height))
}
if width != DoNotChange {
c.width = width
}
if height != DoNotChange {
c.height = height
}
}
2015-10-27 17:45:03 -07:00
// Pos returns the current control position: X and Y.
// For View the position's origin is top left corner of console window,
// for other controls the origin is top left corner of View that hold
// the control
2015-10-16 10:27:43 -07:00
func (c *ControlBase) Pos() (int, int) {
return c.x, c.y
}
2015-10-27 17:45:03 -07:00
// SetPos changes contols position. Manual call of the method does not
// make sense for any control except View because control positions
// inside of container always recalculated after View resizes
2015-10-16 10:27:43 -07:00
func (c *ControlBase) SetPos(x, y int) {
c.x = x
c.y = y
}
2015-10-27 17:47:53 -07:00
// applyConstraints checks if the current size fits minimal size.
2015-10-27 17:45:03 -07:00
// Contol size is increased if its size is less than the current
// contol minimal size
2015-10-27 17:47:53 -07:00
func (c *ControlBase) applyConstraints() {
2015-10-16 10:27:43 -07:00
w, h := c.Size()
wM, hM := c.Constraints()
newW, newH := w, h
if w < wM {
newW = wM
}
if h < hM {
newH = hM
}
if newW != w || newH != h {
c.SetSize(newW, newH)
}
}
2015-10-27 17:45:03 -07:00
// SetConstraints sets new minimal size of control.
// If minimal size of the control is greater than the current
// control size then the control size is changed to fit minimal values
2015-10-16 10:27:43 -07:00
func (c *ControlBase) SetConstraints(width, height int) {
if width >= 1 {
c.minW = width
}
if height >= 1 {
c.minH = height
}
2015-10-27 17:47:53 -07:00
c.applyConstraints()
2015-10-16 10:27:43 -07:00
}
2015-10-27 17:45:03 -07:00
// Constraints return minimal control widht and height
2015-10-16 10:27:43 -07:00
func (c *ControlBase) Constraints() (int, int) {
return c.minW, c.minH
}
2015-10-27 17:45:03 -07:00
// Scale return scale coefficient that is used to calculate
// new control size after its parent resizes.
// DoNotScale means the controls never changes its size.
// Any positive value is a real coefficient of scaling.
// How the scaling works: after resizing, parent control
// calculates the difference between minimal and current sizes,
// then divides the difference between controls that has
// positive scale depending on a scale value. The more scale,
// the larger control after resizing. Example: if you have
// two controls with scales 1 and 2, then after every resizing
// the latter controls expands by 100% more than the first one.
2015-10-16 10:27:43 -07:00
func (c *ControlBase) Scale() int {
return c.scale
}
2015-10-27 17:45:03 -07:00
// SetScale sets a scale coefficient for the control.
// See Scale method for details
2015-10-16 10:27:43 -07:00
func (c *ControlBase) SetScale(scale int) {
c.scale = scale
}
2015-10-27 17:45:03 -07:00
// Pack returns direction in which a container packs
// its children: horizontal or vertical
2015-10-16 10:27:43 -07:00
func (c *ControlBase) Pack() PackType {
return Vertical
}
2015-10-27 17:45:03 -07:00
// SetPack changes the direction of children packing
2015-10-16 10:27:43 -07:00
func (c *ControlBase) SetPack(pk PackType) {
}
2015-10-27 17:45:03 -07:00
// AddChild adds a new child to a container. For the most
// of controls the method is just a stub that panics
// because not every control can be a container
2015-10-16 10:27:43 -07:00
func (c *ControlBase) AddChild(ctrl Control, scale int) {
2015-10-20 16:00:35 -07:00
panic("This control cannot have children")
2015-10-16 10:27:43 -07:00
}
2015-10-27 17:45:03 -07:00
// Children returns the list of container child controls
2015-10-16 10:27:43 -07:00
func (c *ControlBase) Children() []Control {
return make([]Control, 0)
}
2015-10-27 17:45:03 -07:00
// Colors return the basic attrubutes for the controls: text
// attribute and background one. Some controls inroduce their
// own additional controls: see ProgressBar
2015-10-16 10:27:43 -07:00
func (c *ControlBase) Colors() (term.Attribute, term.Attribute) {
return c.fg, c.bg
}
2015-10-27 17:45:03 -07:00
// SetTextColor changes text color of the control
2015-10-19 12:05:43 -07:00
func (c *ControlBase) SetTextColor(clr term.Attribute) {
2015-10-16 10:27:43 -07:00
c.fg = clr
}
2015-10-27 17:45:03 -07:00
// SetBackColor changes background color of the control
2015-10-19 12:05:43 -07:00
func (c *ControlBase) SetBackColor(clr term.Attribute) {
c.bg = clr
}
2015-10-27 17:45:03 -07:00
// ActiveColors return the attrubutes for the controls when it
// is active: text and background colors
2015-10-19 12:05:43 -07:00
func (c *ControlBase) ActiveColors() (term.Attribute, term.Attribute) {
return c.fg, c.bg
}
2015-10-27 17:45:03 -07:00
// SetActiveTextColor changes text color of the active control
2015-10-19 12:05:43 -07:00
func (c *ControlBase) SetActiveTextColor(clr term.Attribute) {
c.fg = clr
}
2015-10-27 17:45:03 -07:00
// SetActiveBackColor changes background color of the active control
2015-10-19 12:05:43 -07:00
func (c *ControlBase) SetActiveBackColor(clr term.Attribute) {
2015-10-16 10:27:43 -07:00
c.bg = clr
}
2015-10-27 17:45:03 -07:00
// TabStop returns if a control can be selected by traversing
// controls using TAB key
2015-10-16 10:27:43 -07:00
func (c *ControlBase) TabStop() bool {
return !c.tabSkip
}
2015-10-27 17:45:03 -07:00
// SetTabStop sets if a control can be selected by pressing
// TAB key
2015-10-16 10:27:43 -07:00
func (c *ControlBase) SetTabStop(skip bool) {
c.tabSkip = !skip
}
2015-10-27 17:45:03 -07:00
// Enabled returns if controls is enabled. Disabled controls
// do not process events and usually have different look
2015-10-16 10:27:43 -07:00
func (c *ControlBase) Enabled() bool {
return !c.disabled
}
2015-10-27 17:45:03 -07:00
// SetEnabled enables or disables control
2015-10-16 10:27:43 -07:00
func (c *ControlBase) SetEnabled(enable bool) {
c.disabled = !enable
}
2015-10-27 17:45:03 -07:00
// SetAlign sets text alignment for some controls(Label, CheckBox etc)
2015-10-16 10:27:43 -07:00
func (c *ControlBase) SetAlign(align Align) {
c.align = align
}
2015-10-27 17:45:03 -07:00
// Align return text alignment
func (c *ControlBase) Align() Align {
2015-10-16 10:27:43 -07:00
return c.align
}
2015-10-27 17:45:03 -07:00
// Active returns if a control is active. Only active controls can
// process keyboard events. Parent View looks for active controls to
// make sure that there is only one active control at a time
2015-10-16 10:27:43 -07:00
func (c *ControlBase) Active() bool {
return c.active
}
2015-10-27 17:45:03 -07:00
// SetActive activates and deactivates control
2015-10-16 10:27:43 -07:00
func (c *ControlBase) SetActive(active bool) {
c.active = active
}
2015-10-27 17:45:03 -07:00
// ProcessEvent processes all events come from the control parent. If a control
// processes an event it should return true. If the method returns false it means
// that the control do not want or cannot process the event and the caller sends
// the event to the control parent
2015-10-16 10:27:43 -07:00
func (c *ControlBase) ProcessEvent(ev Event) bool {
return false
}
2015-10-27 17:45:03 -07:00
// Parent return control's container or nil if there is no parent container
2015-10-16 10:27:43 -07:00
func (c *ControlBase) Parent() Control {
return c.parent
}
2015-10-27 17:45:03 -07:00
// RecalculateConstraints used by containers to recalculate new minimal size
// depending on its children constraints after a new child is added
2015-10-17 01:16:19 -07:00
func (c *ControlBase) RecalculateConstraints() {
}
2015-10-27 17:45:03 -07:00
// Paddings returns a number of spaces used to auto-arrange children inside
// a container: indent from left and right sides, indent from top and bottom
// sides, horizontal space between controls, vertical space between controls.
// Horizontal space is used in case of PackType is horizontal, and vertical
// in other case
2015-10-19 15:09:25 -07:00
func (c *ControlBase) Paddings() (int, int, int, int) {
return c.padSide, c.padTop, c.padX, c.padY
}
2015-10-27 17:45:03 -07:00
// SetPaddings changes indents for the container. Use DoNotChange as a placeholder
// if you do not want to touch a parameter
2015-10-19 15:09:25 -07:00
func (c *ControlBase) SetPaddings(side, top, dx, dy int) {
if side >= 0 {
c.padSide = side
}
if top >= 0 {
c.padTop = top
}
if dx >= 0 {
c.padX = dx
}
if dy >= 0 {
c.padY = dy
}
}
2015-10-16 10:27:43 -07:00
//---------- debug ----------------
func (c *ControlBase) Logger() *log.Logger {
if c.parent == nil {
return nil
}
2015-10-26 13:58:54 -07:00
return c.parent.Logger()
2015-10-16 10:27:43 -07:00
}