diff --git a/tabbedcontainer.go b/tabbedcontainer.go new file mode 100644 index 0000000..ca0fbce --- /dev/null +++ b/tabbedcontainer.go @@ -0,0 +1,126 @@ +package objects + +import "git.tebibyte.media/tomo/tomo" +import "git.tebibyte.media/tomo/tomo/input" +import "git.tebibyte.media/tomo/objects/layouts" + +type TabbedContainer struct { + tomo.ContainerBox + + leftSpacer tomo.Box + rightSpacer tomo.Box + tabsRow tomo.ContainerBox + active string + tabs []*tab +} + +func NewTabbedContainer () *TabbedContainer { + container := &TabbedContainer { + ContainerBox: tomo.NewContainerBox(), + } + container.SetRole(tomo.R("objects", "TabbedContainer", "")) + container.SetLayout(layouts.Column { false, true } ) + + container.tabsRow = tomo.NewContainerBox() + container.tabsRow.SetRole(tomo.R("objects", "TabRow", "")) + container.Add(container.tabsRow) + + container.leftSpacer = tomo.NewBox() + container.leftSpacer.SetRole(tomo.R("objects", "TabSpacer", "left")) + container.rightSpacer = tomo.NewBox() + container.rightSpacer.SetRole(tomo.R("objects", "TabSpacer", "right")) + + container.ClearTabs() + container.setTabRowLayout() + return container +} + +func (this *TabbedContainer) Activate (name string) { + if _, tab := this.findTab(this.active); tab != nil { + tab.setActive(false) + this.Remove(tab.root) + } + if _, tab := this.findTab(name); tab != nil { + tab.setActive(true) + this.Add(tab.root) + } else { + name = "" + } + this.active = name +} + +func (this *TabbedContainer) AddTab (name string, root tomo.Object) { + tab := &tab { + TextBox: tomo.NewTextBox(), + name: name, + root: root, + } + tab.SetRole(tomo.R("objects", "Tab", "")) + tab.SetText(name) + tab.OnMouseDown(func (button input.Button) { + if button != input.ButtonLeft { return } + this.Activate(name) + }) + + this.tabs = append(this.tabs, tab) + this.tabsRow.Insert(tab, this.rightSpacer) + this.setTabRowLayout() + + // if the row was empty before, activate this tab + if len(this.tabs) == 1 { + this.Activate(name) + } +} + +func (this *TabbedContainer) RemoveTab (name string) { + index, tab := this.findTab(name) + if index < 0 { return } + nextIndex := index - 1 + + this.tabsRow.Remove(tab) + this.tabs = append(this.tabs[:index], this.tabs[index - 1:]...) + this.setTabRowLayout() + + if nextIndex < 0 { nextIndex = 0 } + if nextIndex >= len(this.tabs) { nextIndex = len(this.tabs) - 1 } + if nextIndex < 0 { + this.Activate("") + } else { + this.Activate(this.tabs[nextIndex].name) + } +} + +func (this *TabbedContainer) ClearTabs () { + this.tabs = nil + this.tabsRow.Clear() + this.tabsRow.Add(this.leftSpacer) + this.tabsRow.Add(this.rightSpacer) +} + +func (this *TabbedContainer) setTabRowLayout () { + row := make(layouts.Row, 1 + len(this.tabs) + 1) + row[len(row) - 1] = true + this.tabsRow.SetLayout(row) +} + +func (this *TabbedContainer) findTab (name string) (int, *tab) { + for index, tab := range this.tabs { + if tab.name == name { return index, tab } + } + return -1, nil +} + +type tab struct { + tomo.TextBox + name string + root tomo.Object +} + +func (this *tab) setActive (active bool) { + if active { + this.SetRole(tomo.R("objects", "Tab", "active")) + } else { + this.SetRole(tomo.R("objects", "Tab", "")) + } +} +