mirror of
https://github.com/VladimirMarkelov/clui.git
synced 2025-04-26 13:49:01 +08:00
#84 - add new Control property Visible
This commit is contained in:
parent
d1b209b51f
commit
77ee1b7531
@ -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()
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
13
changelog
13
changelog
@ -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
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
62
demos/visible/visible.go
Normal 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()
|
||||
}
|
4
edit.go
4
edit.go
@ -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()
|
||||
|
||||
|
4
frame.go
4
frame.go
@ -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()
|
||||
|
||||
|
4
label.go
4
label.go
@ -63,6 +63,10 @@ func (l *Label) SetDirection(dir Direction) {
|
||||
}
|
||||
|
||||
func (l *Label) Draw() {
|
||||
if l.hidden {
|
||||
return
|
||||
}
|
||||
|
||||
PushAttributes()
|
||||
defer PopAttributes()
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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 {
|
||||
|
4
radio.go
4
radio.go
@ -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()
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user