#84 - add new Control property Visible

This commit is contained in:
Vladimir Markelov 2018-03-13 22:14:40 -07:00
parent d1b209b51f
commit 77ee1b7531
20 changed files with 227 additions and 25 deletions

View File

@ -106,6 +106,10 @@ func CreateBarChart(parent Control, w, h int, scale int) *BarChart {
// Repaint draws the control on its View surface
func (b *BarChart) Draw() {
if b.hidden {
return
}
b.mtx.RLock()
defer b.mtx.RUnlock()

View File

@ -19,6 +19,7 @@ type BaseControl struct {
bgActive term.Attribute
tabSkip bool
disabled bool
hidden bool
align Align
parent Control
inactive bool
@ -118,6 +119,34 @@ func (c *BaseControl) SetEnabled(enabled bool) {
c.disabled = !enabled
}
func (c *BaseControl) Visible() bool {
c.mtx.RLock()
defer c.mtx.RUnlock()
return !c.hidden
}
func (c *BaseControl) SetVisible(visible bool) {
c.mtx.Lock()
defer c.mtx.Unlock()
if visible == !c.hidden {
return
}
c.hidden = !visible
if c.parent == nil {
return
}
p := c.Parent()
for p.Parent() != nil {
p = p.Parent()
}
go PutEvent(Event{Type: EventLayout, Target: p})
}
func (c *BaseControl) Parent() Control {
return c.parent
}
@ -204,23 +233,39 @@ func (c *BaseControl) SetBackColor(clr term.Attribute) {
c.bg = clr
}
func (c *BaseControl) childCount() int {
cnt := 0
for _, child := range c.children {
if child.Visible() {
cnt++
}
}
return cnt
}
func (c *BaseControl) ResizeChildren() {
if len(c.children) == 0 {
children := c.childCount()
if children == 0 {
return
}
fullWidth := c.width - 2*c.padX
fullHeight := c.height - 2*c.padY
if c.pack == Horizontal {
fullWidth -= (len(c.children) - 1) * c.gapX
fullWidth -= (children - 1) * c.gapX
} else {
fullHeight -= (len(c.children) - 1) * c.gapY
fullHeight -= (children - 1) * c.gapY
}
totalSc := c.ChildrenScale()
minWidth := 0
minHeight := 0
for _, child := range c.children {
if !child.Visible() {
continue
}
cw, ch := child.MinimalSize()
if c.pack == Horizontal {
minWidth += cw
@ -239,6 +284,10 @@ func (c *BaseControl) ResizeChildren() {
}
for _, ctrl := range c.children {
if !ctrl.Visible() {
continue
}
tw, th := ctrl.MinimalSize()
sc := ctrl.Scale()
d := int(ctrl.Scale() * aStep)
@ -332,20 +381,23 @@ func (c *BaseControl) ChildExists(control Control) bool {
}
func (c *BaseControl) ChildrenScale() int {
if len(c.children) == 0 {
if c.childCount() == 0 {
return c.scale
}
total := 0
for _, ctrl := range c.children {
if ctrl.Visible() {
total += ctrl.Scale()
}
}
return total
}
func (c *BaseControl) MinimalSize() (w int, h int) {
if len(c.children) == 0 {
children := c.childCount()
if children == 0 {
return c.minW, c.minH
}
@ -353,12 +405,15 @@ func (c *BaseControl) MinimalSize() (w int, h int) {
totalY := 2 * c.padY
if c.pack == Vertical {
totalY += (len(c.children) - 1) * c.gapY
totalY += (children - 1) * c.gapY
} else {
totalX += (len(c.children) - 1) * c.gapX
totalX += (children - 1) * c.gapX
}
for _, ctrl := range c.children {
if !ctrl.Visible() {
continue
}
ww, hh := ctrl.MinimalSize()
if c.pack == Vertical {
totalY += hh
@ -388,6 +443,10 @@ func (c *BaseControl) Draw() {
}
func (c *BaseControl) DrawChildren() {
if c.hidden {
return
}
PushClip()
defer PopClip()
@ -422,14 +481,18 @@ func (c *BaseControl) ProcessEvent(ev Event) bool {
}
func (c *BaseControl) PlaceChildren() {
if c.children == nil || len(c.children) == 0 {
children := c.childCount()
if c.children == nil || children == 0 {
return
}
xx, yy := c.x+c.padX, c.y+c.padY
for _, ctrl := range c.children {
ctrl.SetPos(xx, yy)
if !ctrl.Visible() {
continue
}
ctrl.SetPos(xx, yy)
ww, hh := ctrl.Size()
if c.pack == Vertical {
yy += c.gapY + hh

View File

@ -3,8 +3,8 @@ package clui
import (
xs "github.com/huandu/xstrings"
term "github.com/nsf/termbox-go"
"time"
"sync/atomic"
"time"
)
/*
@ -63,6 +63,10 @@ func CreateButton(parent Control, width, height int, title string, scale int) *B
// Repaint draws the control on its View surface
func (b *Button) Draw() {
if b.hidden {
return
}
b.mtx.RLock()
defer b.mtx.RUnlock()
PushAttributes()

View File

@ -1,4 +1,15 @@
2018-01-26 - version 0.7.0
2018-03-13 - version 0.8.0-RC1
[+] Added new property for all controls: Visible. It makes possible to show
and hide any control with its children(if there are any).
New Control interface methods: Visible and SetVisible
[+] A new event to support hiding/displaying controls: EventLayout with one
argument - Control that should handle the event. On receiving the event
the Control must recalculate and reposition all its children.
At this moment only Windows handle this event. Other kinds of Control
never receieves the event
[+] Add a new simple demo to play with Control visiblity: demos/visible
2018-01-26 - version 0.7.0
[+] Added new event handler for Window: set a callback OnScreenResize if you
want to handle terminal resize event

View File

@ -52,6 +52,10 @@ func CreateCheckBox(parent Control, width int, title string, scale int) *CheckBo
// Repaint draws the control on its View surface
func (c *CheckBox) Draw() {
if c.hidden {
return
}
c.mtx.RLock()
defer c.mtx.RUnlock()

View File

@ -696,5 +696,13 @@ func ProcessEvent(ev Event) {
comp.processKey(ev)
case EventMouse:
comp.processMouse(ev)
case EventLayout:
for _, c := range comp.windows {
if c == ev.Target {
c.ResizeChildren()
c.PlaceChildren()
break
}
}
}
}

View File

@ -85,6 +85,7 @@ type Event struct {
// For resize event - new terminal size
Width int
Height int
Target Control
}
// BorderStyle constants
@ -288,6 +289,8 @@ const (
EventQuit
// Close top window - or application is there is only one window
EventCloseWindow
// Make a control (Target field of Event structure) to recalculate and reposition all its children
EventLayout
)
// ConfirmationDialog and SelectDialog exit codes

View File

@ -38,6 +38,9 @@ type Control interface {
// Enable return if a control can process keyboard and mouse events
Enabled() bool
SetEnabled(enabled bool)
// Visible return if a control is visible
Visible() bool
SetVisible(enabled bool)
// Parent return control's container or nil if there is no parent container
// that is true for Windows
Parent() Control

View File

@ -211,7 +211,7 @@ func _nextControl(parent Control, curr, prev Control, foundPrev, next bool) (boo
}
}
if ctrl.Enabled() && ctrl.TabStop() {
if ctrl.Enabled() && ctrl.TabStop() && ctrl.Visible() {
if found {
return found, ctrl
} else if !next {
@ -233,7 +233,7 @@ func _nextControl(parent Control, curr, prev Control, foundPrev, next bool) (boo
// that has tab-stop feature on. Used by library when processing TAB key
func NextControl(parent Control, curr Control, next bool) Control {
fnTab := func(c Control) bool {
return c.TabStop()
return c.TabStop() && c.Visible()
}
var defControl Control

62
demos/visible/visible.go Normal file
View File

@ -0,0 +1,62 @@
package main
import (
ui "github.com/VladimirMarkelov/clui"
)
func main() {
ui.InitLibrary()
defer ui.DeinitLibrary()
view := ui.AddWindow(0, 0, 10, 7, "Hello World!")
view.SetPack(ui.Vertical)
frmResize := ui.CreateFrame(view, 8, 6, ui.BorderNone, ui.Fixed)
frmResize.SetTitle("FrameTop")
frmResize.SetPack(ui.Horizontal)
btn1 := ui.CreateButton(frmResize, 8, 5, "Button 1", 1)
btn2 := ui.CreateButton(frmResize, 8, 5, "Button 2", 1)
btn3 := ui.CreateButton(frmResize, 8, 5, "Button 3", 1)
frmBtns := ui.CreateFrame(view, 8, 5, ui.BorderNone, ui.Fixed)
frmBtns.SetPack(ui.Horizontal)
frmBtns.SetTitle("FrameBottom")
btnHide1 := ui.CreateButton(frmBtns, 8, 4, "Hide 1", 1)
btnHide1.OnClick(func(ev ui.Event) {
if btn1.Visible() {
btnHide1.SetTitle("Show 1")
btn1.SetVisible(false)
} else {
btnHide1.SetTitle("Hide 1")
btn1.SetVisible(true)
}
})
btnHide2 := ui.CreateButton(frmBtns, 8, 4, "Hide 2", 1)
btnHide2.OnClick(func(ev ui.Event) {
if btn2.Visible() {
btnHide2.SetTitle("Show 2")
btn2.SetVisible(false)
} else {
btnHide2.SetTitle("Hide 2")
btn2.SetVisible(true)
}
})
btnHide3 := ui.CreateButton(frmBtns, 8, 4, "Hide 3", 1)
btnHide3.OnClick(func(ev ui.Event) {
if btn3.Visible() {
btnHide3.SetTitle("Show 3")
btn3.SetVisible(false)
} else {
btnHide3.SetTitle("Hide 3")
btn3.SetVisible(true)
}
})
btnQuit := ui.CreateButton(frmBtns, 8, 4, "Quit", 1)
btnQuit.OnClick(func(ev ui.Event) {
go ui.Stop()
})
ui.MainLoop()
}

View File

@ -32,6 +32,10 @@ func (e *EditField) SetTitle(title string) {
// Repaint draws the control on its View surface
func (e *EditField) Draw() {
if e.hidden {
return
}
PushAttributes()
defer PopAttributes()

View File

@ -59,6 +59,10 @@ func CreateFrame(parent Control, width, height int, bs BorderStyle, scale int) *
// Repaint draws the control on its View surface
func (f *Frame) Draw() {
if f.hidden {
return
}
PushAttributes()
defer PopAttributes()

View File

@ -63,6 +63,10 @@ func (l *Label) SetDirection(dir Direction) {
}
func (l *Label) Draw() {
if l.hidden {
return
}
PushAttributes()
defer PopAttributes()

View File

@ -111,6 +111,10 @@ func (l *ListBox) drawItems() {
// Repaint draws the control on its View surface
func (l *ListBox) Draw() {
if l.hidden {
return
}
PushAttributes()
defer PopAttributes()

View File

@ -71,6 +71,10 @@ func CreateProgressBar(parent Control, width, height int, scale int) *ProgressBa
// pb.SetTitle("{{value}} of {{max}}")
// pb.SetTitle("{{percent}}%")
func (b *ProgressBar) Draw() {
if b.hidden {
return
}
b.mtx.RLock()
defer b.mtx.RUnlock()
if b.max <= b.min {

View File

@ -48,6 +48,10 @@ func CreateRadio(parent Control, width int, title string, scale int) *Radio {
// Repaint draws the control on its View surface
func (c *Radio) Draw() {
if c.hidden {
return
}
PushAttributes()
defer PopAttributes()

View File

@ -72,6 +72,10 @@ func CreateSparkChart(parent Control, w, h int, scale int) *SparkChart {
// Repaint draws the control on its View surface
func (b *SparkChart) Draw() {
if b.hidden {
return
}
b.mtx.RLock()
defer b.mtx.RUnlock()

View File

@ -348,6 +348,10 @@ func (l *TableView) drawCells() {
// Repaint draws the control on its View surface
func (l *TableView) Draw() {
if l.hidden {
return
}
l.mtx.RLock()
defer l.mtx.RUnlock()
PushAttributes()

View File

@ -80,6 +80,10 @@ func (l *TextReader) drawText() {
// Repaint draws the control on its View surface
func (l *TextReader) Draw() {
if l.hidden {
return
}
PushAttributes()
defer PopAttributes()

View File

@ -166,6 +166,10 @@ func (l *TextView) drawText() {
// Repaint draws the control on its View surface
func (l *TextView) Draw() {
if l.hidden {
return
}
PushAttributes()
defer PopAttributes()