diff --git a/barchart.go b/barchart.go index b04e3fa..d6933ac 100644 --- a/barchart.go +++ b/barchart.go @@ -79,6 +79,7 @@ control should keep its original size. */ func CreateBarChart(parent Control, w, h int, scale int) *BarChart { c := new(BarChart) + c.BaseControl = NewBaseControl() if w == AutoSize { w = 10 diff --git a/base_control.go b/base_control.go index 719e817..c96cc64 100644 --- a/base_control.go +++ b/base_control.go @@ -3,12 +3,14 @@ package clui import ( term "github.com/nsf/termbox-go" "sync" + "sync/atomic" ) // BaseControl is a base for all visible controls. // Every new control must inherit it or implement // the same set of methods type BaseControl struct { + refID int64 title string x, y int width, height int @@ -31,6 +33,22 @@ type BaseControl struct { mtx sync.RWMutex } +var ( + globalRefId int64 +) + +func nextRefId() int64 { + return atomic.AddInt64(&globalRefId, 1) +} + +func NewBaseControl() BaseControl { + return BaseControl{refID: nextRefId()} +} + +func (c *BaseControl) RefID() int64 { + return c.refID +} + func (c *BaseControl) Title() string { return c.title } @@ -524,3 +542,25 @@ func (c *BaseControl) SetActiveTextColor(clr term.Attribute) { func (c *BaseControl) SetActiveBackColor(clr term.Attribute) { c.bgActive = clr } + +func (c *BaseControl) removeChild(control Control) { + children := []Control{} + + for _, child := range c.children { + if child.RefID() == control.RefID() { + continue + } + + children = append(children, child) + } + c.children = nil + + for _, child := range children { + c.AddChild(child) + } +} + +// Destroy removes an object from its parental chain +func (c *BaseControl) Destroy() { + c.parent.removeChild(c) +} diff --git a/button.go b/button.go index dbae036..48e7c25 100644 --- a/button.go +++ b/button.go @@ -31,6 +31,7 @@ control should keep its original size. */ func CreateButton(parent Control, width, height int, title string, scale int) *Button { b := new(Button) + b.BaseControl = NewBaseControl() b.parent = parent b.align = AlignCenter diff --git a/checkbox.go b/checkbox.go index 4f4c7e2..828e4e3 100644 --- a/checkbox.go +++ b/checkbox.go @@ -28,6 +28,7 @@ CheckBox state can be changed using mouse or pressing space on keyboard while th */ func CreateCheckBox(parent Control, width int, title string, scale int) *CheckBox { c := new(CheckBox) + c.BaseControl = NewBaseControl() c.parent = parent if width == AutoSize { diff --git a/control_intf.go b/control_intf.go index 96125d3..89104fb 100644 --- a/control_intf.go +++ b/control_intf.go @@ -147,4 +147,14 @@ type Control interface { // that the control do not want or cannot process the event and the caller sends // the event to the control parent ProcessEvent(ev Event) bool + // RefID returns the controls internal reference id + RefID() int64 + // removeChild removes a child from a container + // It's used to "destroy" controls whenever a control is no longer used + // by the user + removeChild(control Control) + // Destroy is the public interface to remove an object from its parental chain + // it implies this control will stop receiving events and will not be drawn nor + // will impact on other objects position and size calculation + Destroy() } diff --git a/edit_osx.go b/edit_osx.go index cedeb4a..4ae0e32 100644 --- a/edit_osx.go +++ b/edit_osx.go @@ -44,6 +44,7 @@ type EditField struct { // control should keep its original size. func CreateEditField(parent Control, width int, text string, scale int) *EditField { e := new(EditField) + e.BaseControl = NewBaseControl() e.onChange = nil e.SetTitle(text) e.SetEnabled(true) diff --git a/edit_other.go b/edit_other.go index bd0b4ed..6c2276c 100644 --- a/edit_other.go +++ b/edit_other.go @@ -40,6 +40,7 @@ type EditField struct { // control should keep its original size. func CreateEditField(parent Control, width int, text string, scale int) *EditField { e := new(EditField) + e.BaseControl = NewBaseControl() e.onChange = nil e.SetTitle(text) e.SetEnabled(true) diff --git a/frame.go b/frame.go index 6f13964..76d7b38 100644 --- a/frame.go +++ b/frame.go @@ -28,6 +28,7 @@ control should keep its original size. */ func CreateFrame(parent Control, width, height int, bs BorderStyle, scale int) *Frame { f := new(Frame) + f.BaseControl = NewBaseControl() if width == AutoSize { width = 5 diff --git a/label.go b/label.go index ee05496..d5794a2 100644 --- a/label.go +++ b/label.go @@ -29,6 +29,7 @@ control should keep its original size. */ func CreateLabel(parent Control, w, h int, title string, scale int) *Label { c := new(Label) + c.BaseControl = NewBaseControl() if w == AutoSize { w = xs.Len(title) diff --git a/listbox.go b/listbox.go index 57eaaa6..06c9a58 100644 --- a/listbox.go +++ b/listbox.go @@ -38,6 +38,7 @@ control should keep its original size. */ func CreateListBox(parent Control, width, height int, scale int) *ListBox { l := new(ListBox) + l.BaseControl = NewBaseControl() if height == AutoSize { height = 3 diff --git a/progressbar.go b/progressbar.go index b1e7632..823ab3d 100644 --- a/progressbar.go +++ b/progressbar.go @@ -32,6 +32,7 @@ control should keep its original size. */ func CreateProgressBar(parent Control, width, height int, scale int) *ProgressBar { b := new(ProgressBar) + b.BaseControl = NewBaseControl() if height == AutoSize { height = 1 diff --git a/radio.go b/radio.go index 1333d33..32fed29 100644 --- a/radio.go +++ b/radio.go @@ -26,6 +26,7 @@ control should keep its original size. */ func CreateRadio(parent Control, width int, title string, scale int) *Radio { c := new(Radio) + c.BaseControl = NewBaseControl() if width == AutoSize { width = xs.Len(title) + 4 diff --git a/sparkchart.go b/sparkchart.go index 0ee051e..4887039 100644 --- a/sparkchart.go +++ b/sparkchart.go @@ -45,6 +45,7 @@ control should keep its original size. */ func CreateSparkChart(parent Control, w, h int, scale int) *SparkChart { c := new(SparkChart) + c.BaseControl = NewBaseControl() if w == AutoSize { w = 10 diff --git a/tableview.go b/tableview.go index 2e68e49..f75e603 100644 --- a/tableview.go +++ b/tableview.go @@ -127,6 +127,7 @@ control should keep its original size. */ func CreateTableView(parent Control, width, height int, scale int) *TableView { l := new(TableView) + l.BaseControl = NewBaseControl() if height == AutoSize { height = 3 diff --git a/textreader.go b/textreader.go index 33b01f0..e01ad32 100644 --- a/textreader.go +++ b/textreader.go @@ -17,6 +17,7 @@ type TextReader struct { func CreateTextReader(parent Control, width, height int, scale int) *TextReader { l := new(TextReader) + l.BaseControl = NewBaseControl() if height == AutoSize { height = 10 @@ -260,10 +261,10 @@ func (l *TextReader) TopLine() int { func (l *TextReader) SetTopLine(top int) { if top < l.lineCount { - l.topLine = top + l.topLine = top - if l.onPositionChanged != nil { - l.onPositionChanged(l.topLine, l.lineCount) - } - } + if l.onPositionChanged != nil { + l.onPositionChanged(l.topLine, l.lineCount) + } + } } diff --git a/textview.go b/textview.go index 78be754..f4bd52c 100644 --- a/textview.go +++ b/textview.go @@ -46,6 +46,7 @@ control should keep its original size. */ func CreateTextView(parent Control, width, height int, scale int) *TextView { l := new(TextView) + l.BaseControl = NewBaseControl() if height == AutoSize { height = 3 diff --git a/window.go b/window.go index 74660f2..9a2f750 100644 --- a/window.go +++ b/window.go @@ -27,6 +27,8 @@ type Window struct { func CreateWindow(x, y, w, h int, title string) *Window { wnd := new(Window) + wnd.BaseControl = NewBaseControl() + if w == AutoSize || w < 1 || w > 1000 { w = 10 }