diff --git a/TabTitleMenu/README.md b/TabTitleMenu/README.md
new file mode 100644
index 0000000..3f3d8d6
--- /dev/null
+++ b/TabTitleMenu/README.md
@@ -0,0 +1,10 @@
+Tabs Instead of Title for TUI Example
+===============
+see central box's tabs where the other box's titles are
+
+![screenshot](/screenshot.png?raw=true "screenshot")
+
+
+Thanks
+===============
+A MASSIVE thanks to @LoreleiAurora for helping with this!

diff --git a/TabTitleMenu/README.md b/TabTitleMenu/README.md
new file mode 100644
index 0000000..3f3d8d6
--- /dev/null
+++ b/TabTitleMenu/README.md
@@ -0,0 +1,10 @@
+Tabs Instead of Title for TUI Example
+===============
+see central box's tabs where the other box's titles are
+
+![screenshot](/screenshot.png?raw=true "screenshot")
+
+
+Thanks
+===============
+A MASSIVE thanks to @LoreleiAurora for helping with this!
diff --git a/TabTitleMenu/main.go b/TabTitleMenu/main.go
new file mode 100755
index 0000000..5919b14
--- /dev/null
+++ b/TabTitleMenu/main.go
@@ -0,0 +1,88 @@
+// Demo code for the TabbedPanels primitive.
+package main
+
+import (
+	"fmt"
+
+	//"github.com/rivo/tview"
+	"github.com/gdamore/tcell/v2"
+	"code.rocketnine.space/tslocum/cview"
+)
+
+const panelCount = 5
+
+
+func demoBox(title string) *cview.Box {
+		b := cview.NewBox()
+		b.SetBorder(true)
+		b.SetTitle(title)
+		return b
+	}
+
+
+func main() {
+
+	app := cview.NewApplication()
+	defer app.HandlePanic()
+	app.EnableMouse(true)
+
+	panels := NewTabbedPanels()
+
+	for panel := 0; panel < panelCount; panel++ {
+		func(panel int) {
+			form := cview.NewForm()
+			form.SetBorder(true)
+			form.SetDrawFunc(func(screen tcell.Screen, x int, y int, width int, height int) (int, int, int, int) {
+				//fix corners
+				screen.SetContent(x, y, cview.BoxDrawingsLightVertical, nil, tcell.StyleDefault.Background(tcell.Color16))
+				screen.SetContent(x+width-1, y, cview.BoxDrawingsLightVertical, nil, tcell.StyleDefault.Background(tcell.Color16))
+				// Draw nothing across the top of the box.
+			    for cx := x + 1; cx < x+width-1; cx++ {
+			      screen.SetContent(cx, y, ' ', nil, tcell.StyleDefault.Background(tcell.Color16))
+			    }
+			    // Space for other content.
+			    return x + 1, y, width - 2, height - y +1
+			})
+			//form.SetTitle(fmt.Sprintf("This is tab %d. Choose another tab.", panel+1))
+			form.AddButton("Next", func() {
+				panels.SetCurrentTab(fmt.Sprintf("panel-%d", (panel+1)%panelCount))
+			})
+			form.AddButton("Quit", func() {
+				app.Stop()
+			})
+			form.SetCancelFunc(func() {
+				app.Stop()
+			})
+
+			panels.AddTab(fmt.Sprintf("panel-%d", panel), fmt.Sprintf("Panel #%d", panel), form)
+		}(panel)
+	}
+
+	subFlex := cview.NewFlex()
+	subFlex.SetDirection(cview.FlexRow)
+	subFlex.AddItem(demoBox("Top"), 0, 1, false)
+	subFlex.AddItem(panels, 0, 3, false)
+	subFlex.AddItem(demoBox("Bottom (5 rows)"), 5, 1, false)
+
+	flex := cview.NewFlex()
+	flex.AddItem(demoBox("Left (1/2 x width of Top)"), 0, 1, false)
+	flex.AddItem(subFlex, 0, 2, false)
+	flex.AddItem(demoBox("Right (20 cols)"), 20, 1, false)
+
+	app.SetRoot(flex, true)
+	if err := app.Run(); err != nil {
+		panic(err)
+	}
+
+	//app := cview.NewApplication()
+	//defer app.HandlePanic()
+
+	
+
+	
+
+	//app.SetRoot(panels, true)
+	//if err := app.Run(); err != nil {
+	//	panic(err)
+	//}
+}
\ No newline at end of file

diff --git a/TabTitleMenu/README.md b/TabTitleMenu/README.md
new file mode 100644
index 0000000..3f3d8d6
--- /dev/null
+++ b/TabTitleMenu/README.md
@@ -0,0 +1,10 @@
+Tabs Instead of Title for TUI Example
+===============
+see central box's tabs where the other box's titles are
+
+![screenshot](/screenshot.png?raw=true "screenshot")
+
+
+Thanks
+===============
+A MASSIVE thanks to @LoreleiAurora for helping with this!
diff --git a/TabTitleMenu/main.go b/TabTitleMenu/main.go
new file mode 100755
index 0000000..5919b14
--- /dev/null
+++ b/TabTitleMenu/main.go
@@ -0,0 +1,88 @@
+// Demo code for the TabbedPanels primitive.
+package main
+
+import (
+	"fmt"
+
+	//"github.com/rivo/tview"
+	"github.com/gdamore/tcell/v2"
+	"code.rocketnine.space/tslocum/cview"
+)
+
+const panelCount = 5
+
+
+func demoBox(title string) *cview.Box {
+		b := cview.NewBox()
+		b.SetBorder(true)
+		b.SetTitle(title)
+		return b
+	}
+
+
+func main() {
+
+	app := cview.NewApplication()
+	defer app.HandlePanic()
+	app.EnableMouse(true)
+
+	panels := NewTabbedPanels()
+
+	for panel := 0; panel < panelCount; panel++ {
+		func(panel int) {
+			form := cview.NewForm()
+			form.SetBorder(true)
+			form.SetDrawFunc(func(screen tcell.Screen, x int, y int, width int, height int) (int, int, int, int) {
+				//fix corners
+				screen.SetContent(x, y, cview.BoxDrawingsLightVertical, nil, tcell.StyleDefault.Background(tcell.Color16))
+				screen.SetContent(x+width-1, y, cview.BoxDrawingsLightVertical, nil, tcell.StyleDefault.Background(tcell.Color16))
+				// Draw nothing across the top of the box.
+			    for cx := x + 1; cx < x+width-1; cx++ {
+			      screen.SetContent(cx, y, ' ', nil, tcell.StyleDefault.Background(tcell.Color16))
+			    }
+			    // Space for other content.
+			    return x + 1, y, width - 2, height - y +1
+			})
+			//form.SetTitle(fmt.Sprintf("This is tab %d. Choose another tab.", panel+1))
+			form.AddButton("Next", func() {
+				panels.SetCurrentTab(fmt.Sprintf("panel-%d", (panel+1)%panelCount))
+			})
+			form.AddButton("Quit", func() {
+				app.Stop()
+			})
+			form.SetCancelFunc(func() {
+				app.Stop()
+			})
+
+			panels.AddTab(fmt.Sprintf("panel-%d", panel), fmt.Sprintf("Panel #%d", panel), form)
+		}(panel)
+	}
+
+	subFlex := cview.NewFlex()
+	subFlex.SetDirection(cview.FlexRow)
+	subFlex.AddItem(demoBox("Top"), 0, 1, false)
+	subFlex.AddItem(panels, 0, 3, false)
+	subFlex.AddItem(demoBox("Bottom (5 rows)"), 5, 1, false)
+
+	flex := cview.NewFlex()
+	flex.AddItem(demoBox("Left (1/2 x width of Top)"), 0, 1, false)
+	flex.AddItem(subFlex, 0, 2, false)
+	flex.AddItem(demoBox("Right (20 cols)"), 20, 1, false)
+
+	app.SetRoot(flex, true)
+	if err := app.Run(); err != nil {
+		panic(err)
+	}
+
+	//app := cview.NewApplication()
+	//defer app.HandlePanic()
+
+	
+
+	
+
+	//app.SetRoot(panels, true)
+	//if err := app.Run(); err != nil {
+	//	panic(err)
+	//}
+}
\ No newline at end of file
diff --git a/TabTitleMenu/panels.go b/TabTitleMenu/panels.go
new file mode 100755
index 0000000..a3187f8
--- /dev/null
+++ b/TabTitleMenu/panels.go
@@ -0,0 +1,449 @@
+package main
+
+import (
+	"sync"
+
+	"github.com/gdamore/tcell/v2"
+	"code.rocketnine.space/tslocum/cview"
+)
+
+// panel represents a single panel of a Panels object.
+type panel struct {
+	Name    string    // The panel's name.
+	Item    cview.Primitive // The panel's cview.Primitive.
+	Resize  bool      // Whether or not to resize the panel when it is drawn.
+	Visible bool      // Whether or not this panel is visible.
+}
+
+// Panels is a container for other cview.Primitives often used as the application's
+// root cview.Primitive. It allows to easily switch the visibility of the contained
+// cview.Primitives.
+type Panels struct {
+	*cview.Box
+
+	// The contained panels. (Visible) panels are drawn from back to front.
+	panels []*panel
+
+	// We keep a reference to the function which allows us to set the focus to
+	// a newly visible panel.
+	setFocus func(p cview.Primitive)
+
+	// An optional handler which is called whenever the visibility or the order of
+	// panels changes.
+	changed func()
+
+	sync.RWMutex
+}
+
+// NewPanels returns a new Panels object.
+func NewPanels() *Panels {
+	p := &Panels{
+		Box: cview.NewBox(),
+	}
+	//p.focus = p
+	return p
+}
+
+// SetChangedFunc sets a handler which is called whenever the visibility or the
+// order of any visible panels changes. This can be used to redraw the panels.
+func (p *Panels) SetChangedFunc(handler func()) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.changed = handler
+}
+
+// GetPanelCount returns the number of panels currently stored in this object.
+func (p *Panels) GetPanelCount() int {
+	p.RLock()
+	defer p.RUnlock()
+
+	return len(p.panels)
+}
+
+// AddPanel adds a new panel with the given name and cview.Primitive. If there was
+// previously a panel with the same name, it is overwritten. Leaving the name
+// empty may cause conflicts in other functions so always specify a non-empty
+// name.
+//
+// Visible panels will be drawn in the order they were added (unless that order
+// was changed in one of the other functions). If "resize" is set to true, the
+// cview.Primitive will be set to the size available to the Panels cview.Primitive whenever
+// the panels are drawn.
+func (p *Panels) AddPanel(name string, item cview.Primitive, resize, visible bool) {
+	hasFocus := p.HasFocus()
+
+	p.Lock()
+	defer p.Unlock()
+
+	var added bool
+	for i, pg := range p.panels {
+		if pg.Name == name {
+			p.panels[i] = &panel{Item: item, Name: name, Resize: resize, Visible: visible}
+			added = true
+			break
+		}
+	}
+	if !added {
+		p.panels = append(p.panels, &panel{Item: item, Name: name, Resize: resize, Visible: visible})
+	}
+	if p.changed != nil {
+		p.Unlock()
+		p.changed()
+		p.Lock()
+	}
+	if hasFocus {
+		p.Unlock()
+		p.Focus(p.setFocus)
+		p.Lock()
+	}
+}
+
+// RemovePanel removes the panel with the given name. If that panel was the only
+// visible panel, visibility is assigned to the last panel.
+func (p *Panels) RemovePanel(name string) {
+	hasFocus := p.HasFocus()
+
+	p.Lock()
+	defer p.Unlock()
+
+	var isVisible bool
+	for index, panel := range p.panels {
+		if panel.Name == name {
+			isVisible = panel.Visible
+			p.panels = append(p.panels[:index], p.panels[index+1:]...)
+			if panel.Visible && p.changed != nil {
+				p.Unlock()
+				p.changed()
+				p.Lock()
+			}
+			break
+		}
+	}
+	if isVisible {
+		for index, panel := range p.panels {
+			if index < len(p.panels)-1 {
+				if panel.Visible {
+					break // There is a remaining visible panel.
+				}
+			} else {
+				panel.Visible = true // We need at least one visible panel.
+			}
+		}
+	}
+	if hasFocus {
+		p.Unlock()
+		p.Focus(p.setFocus)
+		p.Lock()
+	}
+}
+
+// HasPanel returns true if a panel with the given name exists in this object.
+func (p *Panels) HasPanel(name string) bool {
+	p.RLock()
+	defer p.RUnlock()
+
+	for _, panel := range p.panels {
+		if panel.Name == name {
+			return true
+		}
+	}
+	return false
+}
+
+// ShowPanel sets a panel's visibility to "true" (in addition to any other panels
+// which are already visible).
+func (p *Panels) ShowPanel(name string) {
+	hasFocus := p.HasFocus()
+
+	p.Lock()
+	defer p.Unlock()
+
+	for _, panel := range p.panels {
+		if panel.Name == name {
+			panel.Visible = true
+			if p.changed != nil {
+				p.Unlock()
+				p.changed()
+				p.Lock()
+			}
+			break
+		}
+	}
+	if hasFocus {
+		p.Unlock()
+		p.Focus(p.setFocus)
+		p.Lock()
+	}
+}
+
+// HidePanel sets a panel's visibility to "false".
+func (p *Panels) HidePanel(name string) {
+	hasFocus := p.HasFocus()
+
+	p.Lock()
+	defer p.Unlock()
+
+	for _, panel := range p.panels {
+		if panel.Name == name {
+			panel.Visible = false
+			if p.changed != nil {
+				p.Unlock()
+				p.changed()
+				p.Lock()
+			}
+			break
+		}
+	}
+	if hasFocus {
+		p.Unlock()
+		p.Focus(p.setFocus)
+		p.Lock()
+	}
+}
+
+// SetCurrentPanel sets a panel's visibility to "true" and all other panels'
+// visibility to "false".
+func (p *Panels) SetCurrentPanel(name string) {
+	hasFocus := p.HasFocus()
+
+	p.Lock()
+	defer p.Unlock()
+
+	for _, panel := range p.panels {
+		if panel.Name == name {
+			panel.Visible = true
+		} else {
+			panel.Visible = false
+		}
+	}
+	if p.changed != nil {
+		p.Unlock()
+		p.changed()
+		p.Lock()
+	}
+	if hasFocus {
+		p.Unlock()
+		p.Focus(p.setFocus)
+		p.Lock()
+	}
+}
+
+// SendToFront changes the order of the panels such that the panel with the given
+// name comes last, causing it to be drawn last with the next update (if
+// visible).
+func (p *Panels) SendToFront(name string) {
+	hasFocus := p.HasFocus()
+
+	p.Lock()
+	defer p.Unlock()
+
+	for index, panel := range p.panels {
+		if panel.Name == name {
+			if index < len(p.panels)-1 {
+				p.panels = append(append(p.panels[:index], p.panels[index+1:]...), panel)
+			}
+			if panel.Visible && p.changed != nil {
+				p.Unlock()
+				p.changed()
+				p.Lock()
+			}
+			break
+		}
+	}
+	if hasFocus {
+		p.Unlock()
+		p.Focus(p.setFocus)
+		p.Lock()
+	}
+}
+
+// SendToBack changes the order of the panels such that the panel with the given
+// name comes first, causing it to be drawn first with the next update (if
+// visible).
+func (p *Panels) SendToBack(name string) {
+	hasFocus := p.HasFocus()
+
+	p.Lock()
+	defer p.Unlock()
+
+	for index, pg := range p.panels {
+		if pg.Name == name {
+			if index > 0 {
+				p.panels = append(append([]*panel{pg}, p.panels[:index]...), p.panels[index+1:]...)
+			}
+			if pg.Visible && p.changed != nil {
+				p.Unlock()
+				p.changed()
+				p.Lock()
+			}
+			break
+		}
+	}
+	if hasFocus {
+		p.Unlock()
+		p.Focus(p.setFocus)
+		p.Lock()
+	}
+}
+
+// GetFrontPanel returns the front-most visible panel. If there are no visible
+// panels, ("", nil) is returned.
+func (p *Panels) GetFrontPanel() (name string, item cview.Primitive) {
+	p.RLock()
+	defer p.RUnlock()
+
+	for index := len(p.panels) - 1; index >= 0; index-- {
+		if p.panels[index].Visible {
+			return p.panels[index].Name, p.panels[index].Item
+		}
+	}
+	return
+}
+
+// HasFocus returns whether or not this cview.Primitive has focus.
+func (p *Panels) HasFocus() bool {
+	p.RLock()
+	defer p.RUnlock()
+
+	for _, panel := range p.panels {
+		if panel.Item.GetFocusable().HasFocus() {
+			return true
+		}
+	}
+	return false
+}
+
+// Focus is called by the application when the cview.Primitive receives focus.
+func (p *Panels) Focus(delegate func(p cview.Primitive)) {
+	p.Lock()
+	defer p.Unlock()
+
+	if delegate == nil {
+		return // We cannot delegate so we cannot focus.
+	}
+	p.setFocus = delegate
+	var topItem cview.Primitive
+	for _, panel := range p.panels {
+		if panel.Visible {
+			topItem = panel.Item
+		}
+	}
+	if topItem != nil {
+		p.Unlock()
+		delegate(topItem)
+		p.Lock()
+	}
+}
+
+// Draw draws this cview.Primitive onto the screen.
+func (p *Panels) Draw(screen tcell.Screen) {
+	if !p.GetVisible() {
+		return
+	}
+
+	p.Box.Draw(screen)
+
+	p.Lock()
+	defer p.Unlock()
+
+	x, y, width, height := p.GetInnerRect()
+
+	for _, panel := range p.panels {
+		if !panel.Visible {
+			continue
+		}
+		if panel.Resize {
+			panel.Item.SetRect(x, y, width, height)
+		}
+		panel.Item.Draw(screen)
+	}
+}
+
+// MouseHandler returns the mouse handler for this cview.Primitive.
+func (p *Panels) MouseHandler() func(action cview.MouseAction, event *tcell.EventMouse, setFocus func(p cview.Primitive)) (consumed bool, capture cview.Primitive) {
+	return p.WrapMouseHandler(func(action cview.MouseAction, event *tcell.EventMouse, setFocus func(p cview.Primitive)) (consumed bool, capture cview.Primitive) {
+		if !p.InRect(event.Position()) {
+			return false, nil
+		}
+
+		// Pass mouse events along to the last visible panel item that takes it.
+		for index := len(p.panels) - 1; index >= 0; index-- {
+			panel := p.panels[index]
+			if panel.Visible {
+				consumed, capture = panel.Item.MouseHandler()(action, event, setFocus)
+				if consumed {
+					return
+				}
+			}
+		}
+
+		return
+	})
+}
+
+// Support backwards compatibility with Pages.
+type page = panel
+
+// Pages is a wrapper around Panels.
+//
+// Deprecated: This type is provided for backwards compatibility.
+// Developers should use Panels instead.
+type Pages struct {
+	*Panels
+}
+
+// NewPages returns a new Panels object.
+//
+// Deprecated: This function is provided for backwards compatibility.
+// Developers should use NewPanels instead.
+func NewPages() *Pages {
+	return &Pages{NewPanels()}
+}
+
+// GetPageCount returns the number of panels currently stored in this object.
+func (p *Pages) GetPageCount() int {
+	return p.GetPanelCount()
+}
+
+// AddPage adds a new panel with the given name and cview.Primitive.
+func (p *Pages) AddPage(name string, item cview.Primitive, resize, visible bool) {
+	p.AddPanel(name, item, resize, visible)
+}
+
+// AddAndSwitchToPage calls Add(), then SwitchTo() on that newly added panel.
+func (p *Pages) AddAndSwitchToPage(name string, item cview.Primitive, resize bool) {
+	p.AddPanel(name, item, resize, true)
+	p.SetCurrentPanel(name)
+}
+
+// RemovePage removes the panel with the given name.
+func (p *Pages) RemovePage(name string) {
+	p.RemovePanel(name)
+}
+
+// HasPage returns true if a panel with the given name exists in this object.
+func (p *Pages) HasPage(name string) bool {
+	return p.HasPanel(name)
+}
+
+// ShowPage sets a panel's visibility to "true".
+func (p *Pages) ShowPage(name string) {
+	p.ShowPanel(name)
+}
+
+// HidePage sets a panel's visibility to "false".
+func (p *Pages) HidePage(name string) {
+	p.HidePanel(name)
+}
+
+// SwitchToPage sets a panel's visibility to "true" and all other panels'
+// visibility to "false".
+func (p *Pages) SwitchToPage(name string) {
+	p.SetCurrentPanel(name)
+}
+
+// GetFrontPage returns the front-most visible panel.
+func (p *Pages) GetFrontPage() (name string, item cview.Primitive) {
+	return p.GetFrontPanel()
+}

diff --git a/TabTitleMenu/README.md b/TabTitleMenu/README.md
new file mode 100644
index 0000000..3f3d8d6
--- /dev/null
+++ b/TabTitleMenu/README.md
@@ -0,0 +1,10 @@
+Tabs Instead of Title for TUI Example
+===============
+see central box's tabs where the other box's titles are
+
+![screenshot](/screenshot.png?raw=true "screenshot")
+
+
+Thanks
+===============
+A MASSIVE thanks to @LoreleiAurora for helping with this!
diff --git a/TabTitleMenu/main.go b/TabTitleMenu/main.go
new file mode 100755
index 0000000..5919b14
--- /dev/null
+++ b/TabTitleMenu/main.go
@@ -0,0 +1,88 @@
+// Demo code for the TabbedPanels primitive.
+package main
+
+import (
+	"fmt"
+
+	//"github.com/rivo/tview"
+	"github.com/gdamore/tcell/v2"
+	"code.rocketnine.space/tslocum/cview"
+)
+
+const panelCount = 5
+
+
+func demoBox(title string) *cview.Box {
+		b := cview.NewBox()
+		b.SetBorder(true)
+		b.SetTitle(title)
+		return b
+	}
+
+
+func main() {
+
+	app := cview.NewApplication()
+	defer app.HandlePanic()
+	app.EnableMouse(true)
+
+	panels := NewTabbedPanels()
+
+	for panel := 0; panel < panelCount; panel++ {
+		func(panel int) {
+			form := cview.NewForm()
+			form.SetBorder(true)
+			form.SetDrawFunc(func(screen tcell.Screen, x int, y int, width int, height int) (int, int, int, int) {
+				//fix corners
+				screen.SetContent(x, y, cview.BoxDrawingsLightVertical, nil, tcell.StyleDefault.Background(tcell.Color16))
+				screen.SetContent(x+width-1, y, cview.BoxDrawingsLightVertical, nil, tcell.StyleDefault.Background(tcell.Color16))
+				// Draw nothing across the top of the box.
+			    for cx := x + 1; cx < x+width-1; cx++ {
+			      screen.SetContent(cx, y, ' ', nil, tcell.StyleDefault.Background(tcell.Color16))
+			    }
+			    // Space for other content.
+			    return x + 1, y, width - 2, height - y +1
+			})
+			//form.SetTitle(fmt.Sprintf("This is tab %d. Choose another tab.", panel+1))
+			form.AddButton("Next", func() {
+				panels.SetCurrentTab(fmt.Sprintf("panel-%d", (panel+1)%panelCount))
+			})
+			form.AddButton("Quit", func() {
+				app.Stop()
+			})
+			form.SetCancelFunc(func() {
+				app.Stop()
+			})
+
+			panels.AddTab(fmt.Sprintf("panel-%d", panel), fmt.Sprintf("Panel #%d", panel), form)
+		}(panel)
+	}
+
+	subFlex := cview.NewFlex()
+	subFlex.SetDirection(cview.FlexRow)
+	subFlex.AddItem(demoBox("Top"), 0, 1, false)
+	subFlex.AddItem(panels, 0, 3, false)
+	subFlex.AddItem(demoBox("Bottom (5 rows)"), 5, 1, false)
+
+	flex := cview.NewFlex()
+	flex.AddItem(demoBox("Left (1/2 x width of Top)"), 0, 1, false)
+	flex.AddItem(subFlex, 0, 2, false)
+	flex.AddItem(demoBox("Right (20 cols)"), 20, 1, false)
+
+	app.SetRoot(flex, true)
+	if err := app.Run(); err != nil {
+		panic(err)
+	}
+
+	//app := cview.NewApplication()
+	//defer app.HandlePanic()
+
+	
+
+	
+
+	//app.SetRoot(panels, true)
+	//if err := app.Run(); err != nil {
+	//	panic(err)
+	//}
+}
\ No newline at end of file
diff --git a/TabTitleMenu/panels.go b/TabTitleMenu/panels.go
new file mode 100755
index 0000000..a3187f8
--- /dev/null
+++ b/TabTitleMenu/panels.go
@@ -0,0 +1,449 @@
+package main
+
+import (
+	"sync"
+
+	"github.com/gdamore/tcell/v2"
+	"code.rocketnine.space/tslocum/cview"
+)
+
+// panel represents a single panel of a Panels object.
+type panel struct {
+	Name    string    // The panel's name.
+	Item    cview.Primitive // The panel's cview.Primitive.
+	Resize  bool      // Whether or not to resize the panel when it is drawn.
+	Visible bool      // Whether or not this panel is visible.
+}
+
+// Panels is a container for other cview.Primitives often used as the application's
+// root cview.Primitive. It allows to easily switch the visibility of the contained
+// cview.Primitives.
+type Panels struct {
+	*cview.Box
+
+	// The contained panels. (Visible) panels are drawn from back to front.
+	panels []*panel
+
+	// We keep a reference to the function which allows us to set the focus to
+	// a newly visible panel.
+	setFocus func(p cview.Primitive)
+
+	// An optional handler which is called whenever the visibility or the order of
+	// panels changes.
+	changed func()
+
+	sync.RWMutex
+}
+
+// NewPanels returns a new Panels object.
+func NewPanels() *Panels {
+	p := &Panels{
+		Box: cview.NewBox(),
+	}
+	//p.focus = p
+	return p
+}
+
+// SetChangedFunc sets a handler which is called whenever the visibility or the
+// order of any visible panels changes. This can be used to redraw the panels.
+func (p *Panels) SetChangedFunc(handler func()) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.changed = handler
+}
+
+// GetPanelCount returns the number of panels currently stored in this object.
+func (p *Panels) GetPanelCount() int {
+	p.RLock()
+	defer p.RUnlock()
+
+	return len(p.panels)
+}
+
+// AddPanel adds a new panel with the given name and cview.Primitive. If there was
+// previously a panel with the same name, it is overwritten. Leaving the name
+// empty may cause conflicts in other functions so always specify a non-empty
+// name.
+//
+// Visible panels will be drawn in the order they were added (unless that order
+// was changed in one of the other functions). If "resize" is set to true, the
+// cview.Primitive will be set to the size available to the Panels cview.Primitive whenever
+// the panels are drawn.
+func (p *Panels) AddPanel(name string, item cview.Primitive, resize, visible bool) {
+	hasFocus := p.HasFocus()
+
+	p.Lock()
+	defer p.Unlock()
+
+	var added bool
+	for i, pg := range p.panels {
+		if pg.Name == name {
+			p.panels[i] = &panel{Item: item, Name: name, Resize: resize, Visible: visible}
+			added = true
+			break
+		}
+	}
+	if !added {
+		p.panels = append(p.panels, &panel{Item: item, Name: name, Resize: resize, Visible: visible})
+	}
+	if p.changed != nil {
+		p.Unlock()
+		p.changed()
+		p.Lock()
+	}
+	if hasFocus {
+		p.Unlock()
+		p.Focus(p.setFocus)
+		p.Lock()
+	}
+}
+
+// RemovePanel removes the panel with the given name. If that panel was the only
+// visible panel, visibility is assigned to the last panel.
+func (p *Panels) RemovePanel(name string) {
+	hasFocus := p.HasFocus()
+
+	p.Lock()
+	defer p.Unlock()
+
+	var isVisible bool
+	for index, panel := range p.panels {
+		if panel.Name == name {
+			isVisible = panel.Visible
+			p.panels = append(p.panels[:index], p.panels[index+1:]...)
+			if panel.Visible && p.changed != nil {
+				p.Unlock()
+				p.changed()
+				p.Lock()
+			}
+			break
+		}
+	}
+	if isVisible {
+		for index, panel := range p.panels {
+			if index < len(p.panels)-1 {
+				if panel.Visible {
+					break // There is a remaining visible panel.
+				}
+			} else {
+				panel.Visible = true // We need at least one visible panel.
+			}
+		}
+	}
+	if hasFocus {
+		p.Unlock()
+		p.Focus(p.setFocus)
+		p.Lock()
+	}
+}
+
+// HasPanel returns true if a panel with the given name exists in this object.
+func (p *Panels) HasPanel(name string) bool {
+	p.RLock()
+	defer p.RUnlock()
+
+	for _, panel := range p.panels {
+		if panel.Name == name {
+			return true
+		}
+	}
+	return false
+}
+
+// ShowPanel sets a panel's visibility to "true" (in addition to any other panels
+// which are already visible).
+func (p *Panels) ShowPanel(name string) {
+	hasFocus := p.HasFocus()
+
+	p.Lock()
+	defer p.Unlock()
+
+	for _, panel := range p.panels {
+		if panel.Name == name {
+			panel.Visible = true
+			if p.changed != nil {
+				p.Unlock()
+				p.changed()
+				p.Lock()
+			}
+			break
+		}
+	}
+	if hasFocus {
+		p.Unlock()
+		p.Focus(p.setFocus)
+		p.Lock()
+	}
+}
+
+// HidePanel sets a panel's visibility to "false".
+func (p *Panels) HidePanel(name string) {
+	hasFocus := p.HasFocus()
+
+	p.Lock()
+	defer p.Unlock()
+
+	for _, panel := range p.panels {
+		if panel.Name == name {
+			panel.Visible = false
+			if p.changed != nil {
+				p.Unlock()
+				p.changed()
+				p.Lock()
+			}
+			break
+		}
+	}
+	if hasFocus {
+		p.Unlock()
+		p.Focus(p.setFocus)
+		p.Lock()
+	}
+}
+
+// SetCurrentPanel sets a panel's visibility to "true" and all other panels'
+// visibility to "false".
+func (p *Panels) SetCurrentPanel(name string) {
+	hasFocus := p.HasFocus()
+
+	p.Lock()
+	defer p.Unlock()
+
+	for _, panel := range p.panels {
+		if panel.Name == name {
+			panel.Visible = true
+		} else {
+			panel.Visible = false
+		}
+	}
+	if p.changed != nil {
+		p.Unlock()
+		p.changed()
+		p.Lock()
+	}
+	if hasFocus {
+		p.Unlock()
+		p.Focus(p.setFocus)
+		p.Lock()
+	}
+}
+
+// SendToFront changes the order of the panels such that the panel with the given
+// name comes last, causing it to be drawn last with the next update (if
+// visible).
+func (p *Panels) SendToFront(name string) {
+	hasFocus := p.HasFocus()
+
+	p.Lock()
+	defer p.Unlock()
+
+	for index, panel := range p.panels {
+		if panel.Name == name {
+			if index < len(p.panels)-1 {
+				p.panels = append(append(p.panels[:index], p.panels[index+1:]...), panel)
+			}
+			if panel.Visible && p.changed != nil {
+				p.Unlock()
+				p.changed()
+				p.Lock()
+			}
+			break
+		}
+	}
+	if hasFocus {
+		p.Unlock()
+		p.Focus(p.setFocus)
+		p.Lock()
+	}
+}
+
+// SendToBack changes the order of the panels such that the panel with the given
+// name comes first, causing it to be drawn first with the next update (if
+// visible).
+func (p *Panels) SendToBack(name string) {
+	hasFocus := p.HasFocus()
+
+	p.Lock()
+	defer p.Unlock()
+
+	for index, pg := range p.panels {
+		if pg.Name == name {
+			if index > 0 {
+				p.panels = append(append([]*panel{pg}, p.panels[:index]...), p.panels[index+1:]...)
+			}
+			if pg.Visible && p.changed != nil {
+				p.Unlock()
+				p.changed()
+				p.Lock()
+			}
+			break
+		}
+	}
+	if hasFocus {
+		p.Unlock()
+		p.Focus(p.setFocus)
+		p.Lock()
+	}
+}
+
+// GetFrontPanel returns the front-most visible panel. If there are no visible
+// panels, ("", nil) is returned.
+func (p *Panels) GetFrontPanel() (name string, item cview.Primitive) {
+	p.RLock()
+	defer p.RUnlock()
+
+	for index := len(p.panels) - 1; index >= 0; index-- {
+		if p.panels[index].Visible {
+			return p.panels[index].Name, p.panels[index].Item
+		}
+	}
+	return
+}
+
+// HasFocus returns whether or not this cview.Primitive has focus.
+func (p *Panels) HasFocus() bool {
+	p.RLock()
+	defer p.RUnlock()
+
+	for _, panel := range p.panels {
+		if panel.Item.GetFocusable().HasFocus() {
+			return true
+		}
+	}
+	return false
+}
+
+// Focus is called by the application when the cview.Primitive receives focus.
+func (p *Panels) Focus(delegate func(p cview.Primitive)) {
+	p.Lock()
+	defer p.Unlock()
+
+	if delegate == nil {
+		return // We cannot delegate so we cannot focus.
+	}
+	p.setFocus = delegate
+	var topItem cview.Primitive
+	for _, panel := range p.panels {
+		if panel.Visible {
+			topItem = panel.Item
+		}
+	}
+	if topItem != nil {
+		p.Unlock()
+		delegate(topItem)
+		p.Lock()
+	}
+}
+
+// Draw draws this cview.Primitive onto the screen.
+func (p *Panels) Draw(screen tcell.Screen) {
+	if !p.GetVisible() {
+		return
+	}
+
+	p.Box.Draw(screen)
+
+	p.Lock()
+	defer p.Unlock()
+
+	x, y, width, height := p.GetInnerRect()
+
+	for _, panel := range p.panels {
+		if !panel.Visible {
+			continue
+		}
+		if panel.Resize {
+			panel.Item.SetRect(x, y, width, height)
+		}
+		panel.Item.Draw(screen)
+	}
+}
+
+// MouseHandler returns the mouse handler for this cview.Primitive.
+func (p *Panels) MouseHandler() func(action cview.MouseAction, event *tcell.EventMouse, setFocus func(p cview.Primitive)) (consumed bool, capture cview.Primitive) {
+	return p.WrapMouseHandler(func(action cview.MouseAction, event *tcell.EventMouse, setFocus func(p cview.Primitive)) (consumed bool, capture cview.Primitive) {
+		if !p.InRect(event.Position()) {
+			return false, nil
+		}
+
+		// Pass mouse events along to the last visible panel item that takes it.
+		for index := len(p.panels) - 1; index >= 0; index-- {
+			panel := p.panels[index]
+			if panel.Visible {
+				consumed, capture = panel.Item.MouseHandler()(action, event, setFocus)
+				if consumed {
+					return
+				}
+			}
+		}
+
+		return
+	})
+}
+
+// Support backwards compatibility with Pages.
+type page = panel
+
+// Pages is a wrapper around Panels.
+//
+// Deprecated: This type is provided for backwards compatibility.
+// Developers should use Panels instead.
+type Pages struct {
+	*Panels
+}
+
+// NewPages returns a new Panels object.
+//
+// Deprecated: This function is provided for backwards compatibility.
+// Developers should use NewPanels instead.
+func NewPages() *Pages {
+	return &Pages{NewPanels()}
+}
+
+// GetPageCount returns the number of panels currently stored in this object.
+func (p *Pages) GetPageCount() int {
+	return p.GetPanelCount()
+}
+
+// AddPage adds a new panel with the given name and cview.Primitive.
+func (p *Pages) AddPage(name string, item cview.Primitive, resize, visible bool) {
+	p.AddPanel(name, item, resize, visible)
+}
+
+// AddAndSwitchToPage calls Add(), then SwitchTo() on that newly added panel.
+func (p *Pages) AddAndSwitchToPage(name string, item cview.Primitive, resize bool) {
+	p.AddPanel(name, item, resize, true)
+	p.SetCurrentPanel(name)
+}
+
+// RemovePage removes the panel with the given name.
+func (p *Pages) RemovePage(name string) {
+	p.RemovePanel(name)
+}
+
+// HasPage returns true if a panel with the given name exists in this object.
+func (p *Pages) HasPage(name string) bool {
+	return p.HasPanel(name)
+}
+
+// ShowPage sets a panel's visibility to "true".
+func (p *Pages) ShowPage(name string) {
+	p.ShowPanel(name)
+}
+
+// HidePage sets a panel's visibility to "false".
+func (p *Pages) HidePage(name string) {
+	p.HidePanel(name)
+}
+
+// SwitchToPage sets a panel's visibility to "true" and all other panels'
+// visibility to "false".
+func (p *Pages) SwitchToPage(name string) {
+	p.SetCurrentPanel(name)
+}
+
+// GetFrontPage returns the front-most visible panel.
+func (p *Pages) GetFrontPage() (name string, item cview.Primitive) {
+	return p.GetFrontPanel()
+}
diff --git a/TabTitleMenu/screenshot.png b/TabTitleMenu/screenshot.png
new file mode 100755
index 0000000..a852a03
--- /dev/null
+++ b/TabTitleMenu/screenshot.png
Binary files differ

diff --git a/TabTitleMenu/README.md b/TabTitleMenu/README.md
new file mode 100644
index 0000000..3f3d8d6
--- /dev/null
+++ b/TabTitleMenu/README.md
@@ -0,0 +1,10 @@
+Tabs Instead of Title for TUI Example
+===============
+see central box's tabs where the other box's titles are
+
+![screenshot](/screenshot.png?raw=true "screenshot")
+
+
+Thanks
+===============
+A MASSIVE thanks to @LoreleiAurora for helping with this!
diff --git a/TabTitleMenu/main.go b/TabTitleMenu/main.go
new file mode 100755
index 0000000..5919b14
--- /dev/null
+++ b/TabTitleMenu/main.go
@@ -0,0 +1,88 @@
+// Demo code for the TabbedPanels primitive.
+package main
+
+import (
+	"fmt"
+
+	//"github.com/rivo/tview"
+	"github.com/gdamore/tcell/v2"
+	"code.rocketnine.space/tslocum/cview"
+)
+
+const panelCount = 5
+
+
+func demoBox(title string) *cview.Box {
+		b := cview.NewBox()
+		b.SetBorder(true)
+		b.SetTitle(title)
+		return b
+	}
+
+
+func main() {
+
+	app := cview.NewApplication()
+	defer app.HandlePanic()
+	app.EnableMouse(true)
+
+	panels := NewTabbedPanels()
+
+	for panel := 0; panel < panelCount; panel++ {
+		func(panel int) {
+			form := cview.NewForm()
+			form.SetBorder(true)
+			form.SetDrawFunc(func(screen tcell.Screen, x int, y int, width int, height int) (int, int, int, int) {
+				//fix corners
+				screen.SetContent(x, y, cview.BoxDrawingsLightVertical, nil, tcell.StyleDefault.Background(tcell.Color16))
+				screen.SetContent(x+width-1, y, cview.BoxDrawingsLightVertical, nil, tcell.StyleDefault.Background(tcell.Color16))
+				// Draw nothing across the top of the box.
+			    for cx := x + 1; cx < x+width-1; cx++ {
+			      screen.SetContent(cx, y, ' ', nil, tcell.StyleDefault.Background(tcell.Color16))
+			    }
+			    // Space for other content.
+			    return x + 1, y, width - 2, height - y +1
+			})
+			//form.SetTitle(fmt.Sprintf("This is tab %d. Choose another tab.", panel+1))
+			form.AddButton("Next", func() {
+				panels.SetCurrentTab(fmt.Sprintf("panel-%d", (panel+1)%panelCount))
+			})
+			form.AddButton("Quit", func() {
+				app.Stop()
+			})
+			form.SetCancelFunc(func() {
+				app.Stop()
+			})
+
+			panels.AddTab(fmt.Sprintf("panel-%d", panel), fmt.Sprintf("Panel #%d", panel), form)
+		}(panel)
+	}
+
+	subFlex := cview.NewFlex()
+	subFlex.SetDirection(cview.FlexRow)
+	subFlex.AddItem(demoBox("Top"), 0, 1, false)
+	subFlex.AddItem(panels, 0, 3, false)
+	subFlex.AddItem(demoBox("Bottom (5 rows)"), 5, 1, false)
+
+	flex := cview.NewFlex()
+	flex.AddItem(demoBox("Left (1/2 x width of Top)"), 0, 1, false)
+	flex.AddItem(subFlex, 0, 2, false)
+	flex.AddItem(demoBox("Right (20 cols)"), 20, 1, false)
+
+	app.SetRoot(flex, true)
+	if err := app.Run(); err != nil {
+		panic(err)
+	}
+
+	//app := cview.NewApplication()
+	//defer app.HandlePanic()
+
+	
+
+	
+
+	//app.SetRoot(panels, true)
+	//if err := app.Run(); err != nil {
+	//	panic(err)
+	//}
+}
\ No newline at end of file
diff --git a/TabTitleMenu/panels.go b/TabTitleMenu/panels.go
new file mode 100755
index 0000000..a3187f8
--- /dev/null
+++ b/TabTitleMenu/panels.go
@@ -0,0 +1,449 @@
+package main
+
+import (
+	"sync"
+
+	"github.com/gdamore/tcell/v2"
+	"code.rocketnine.space/tslocum/cview"
+)
+
+// panel represents a single panel of a Panels object.
+type panel struct {
+	Name    string    // The panel's name.
+	Item    cview.Primitive // The panel's cview.Primitive.
+	Resize  bool      // Whether or not to resize the panel when it is drawn.
+	Visible bool      // Whether or not this panel is visible.
+}
+
+// Panels is a container for other cview.Primitives often used as the application's
+// root cview.Primitive. It allows to easily switch the visibility of the contained
+// cview.Primitives.
+type Panels struct {
+	*cview.Box
+
+	// The contained panels. (Visible) panels are drawn from back to front.
+	panels []*panel
+
+	// We keep a reference to the function which allows us to set the focus to
+	// a newly visible panel.
+	setFocus func(p cview.Primitive)
+
+	// An optional handler which is called whenever the visibility or the order of
+	// panels changes.
+	changed func()
+
+	sync.RWMutex
+}
+
+// NewPanels returns a new Panels object.
+func NewPanels() *Panels {
+	p := &Panels{
+		Box: cview.NewBox(),
+	}
+	//p.focus = p
+	return p
+}
+
+// SetChangedFunc sets a handler which is called whenever the visibility or the
+// order of any visible panels changes. This can be used to redraw the panels.
+func (p *Panels) SetChangedFunc(handler func()) {
+	p.Lock()
+	defer p.Unlock()
+
+	p.changed = handler
+}
+
+// GetPanelCount returns the number of panels currently stored in this object.
+func (p *Panels) GetPanelCount() int {
+	p.RLock()
+	defer p.RUnlock()
+
+	return len(p.panels)
+}
+
+// AddPanel adds a new panel with the given name and cview.Primitive. If there was
+// previously a panel with the same name, it is overwritten. Leaving the name
+// empty may cause conflicts in other functions so always specify a non-empty
+// name.
+//
+// Visible panels will be drawn in the order they were added (unless that order
+// was changed in one of the other functions). If "resize" is set to true, the
+// cview.Primitive will be set to the size available to the Panels cview.Primitive whenever
+// the panels are drawn.
+func (p *Panels) AddPanel(name string, item cview.Primitive, resize, visible bool) {
+	hasFocus := p.HasFocus()
+
+	p.Lock()
+	defer p.Unlock()
+
+	var added bool
+	for i, pg := range p.panels {
+		if pg.Name == name {
+			p.panels[i] = &panel{Item: item, Name: name, Resize: resize, Visible: visible}
+			added = true
+			break
+		}
+	}
+	if !added {
+		p.panels = append(p.panels, &panel{Item: item, Name: name, Resize: resize, Visible: visible})
+	}
+	if p.changed != nil {
+		p.Unlock()
+		p.changed()
+		p.Lock()
+	}
+	if hasFocus {
+		p.Unlock()
+		p.Focus(p.setFocus)
+		p.Lock()
+	}
+}
+
+// RemovePanel removes the panel with the given name. If that panel was the only
+// visible panel, visibility is assigned to the last panel.
+func (p *Panels) RemovePanel(name string) {
+	hasFocus := p.HasFocus()
+
+	p.Lock()
+	defer p.Unlock()
+
+	var isVisible bool
+	for index, panel := range p.panels {
+		if panel.Name == name {
+			isVisible = panel.Visible
+			p.panels = append(p.panels[:index], p.panels[index+1:]...)
+			if panel.Visible && p.changed != nil {
+				p.Unlock()
+				p.changed()
+				p.Lock()
+			}
+			break
+		}
+	}
+	if isVisible {
+		for index, panel := range p.panels {
+			if index < len(p.panels)-1 {
+				if panel.Visible {
+					break // There is a remaining visible panel.
+				}
+			} else {
+				panel.Visible = true // We need at least one visible panel.
+			}
+		}
+	}
+	if hasFocus {
+		p.Unlock()
+		p.Focus(p.setFocus)
+		p.Lock()
+	}
+}
+
+// HasPanel returns true if a panel with the given name exists in this object.
+func (p *Panels) HasPanel(name string) bool {
+	p.RLock()
+	defer p.RUnlock()
+
+	for _, panel := range p.panels {
+		if panel.Name == name {
+			return true
+		}
+	}
+	return false
+}
+
+// ShowPanel sets a panel's visibility to "true" (in addition to any other panels
+// which are already visible).
+func (p *Panels) ShowPanel(name string) {
+	hasFocus := p.HasFocus()
+
+	p.Lock()
+	defer p.Unlock()
+
+	for _, panel := range p.panels {
+		if panel.Name == name {
+			panel.Visible = true
+			if p.changed != nil {
+				p.Unlock()
+				p.changed()
+				p.Lock()
+			}
+			break
+		}
+	}
+	if hasFocus {
+		p.Unlock()
+		p.Focus(p.setFocus)
+		p.Lock()
+	}
+}
+
+// HidePanel sets a panel's visibility to "false".
+func (p *Panels) HidePanel(name string) {
+	hasFocus := p.HasFocus()
+
+	p.Lock()
+	defer p.Unlock()
+
+	for _, panel := range p.panels {
+		if panel.Name == name {
+			panel.Visible = false
+			if p.changed != nil {
+				p.Unlock()
+				p.changed()
+				p.Lock()
+			}
+			break
+		}
+	}
+	if hasFocus {
+		p.Unlock()
+		p.Focus(p.setFocus)
+		p.Lock()
+	}
+}
+
+// SetCurrentPanel sets a panel's visibility to "true" and all other panels'
+// visibility to "false".
+func (p *Panels) SetCurrentPanel(name string) {
+	hasFocus := p.HasFocus()
+
+	p.Lock()
+	defer p.Unlock()
+
+	for _, panel := range p.panels {
+		if panel.Name == name {
+			panel.Visible = true
+		} else {
+			panel.Visible = false
+		}
+	}
+	if p.changed != nil {
+		p.Unlock()
+		p.changed()
+		p.Lock()
+	}
+	if hasFocus {
+		p.Unlock()
+		p.Focus(p.setFocus)
+		p.Lock()
+	}
+}
+
+// SendToFront changes the order of the panels such that the panel with the given
+// name comes last, causing it to be drawn last with the next update (if
+// visible).
+func (p *Panels) SendToFront(name string) {
+	hasFocus := p.HasFocus()
+
+	p.Lock()
+	defer p.Unlock()
+
+	for index, panel := range p.panels {
+		if panel.Name == name {
+			if index < len(p.panels)-1 {
+				p.panels = append(append(p.panels[:index], p.panels[index+1:]...), panel)
+			}
+			if panel.Visible && p.changed != nil {
+				p.Unlock()
+				p.changed()
+				p.Lock()
+			}
+			break
+		}
+	}
+	if hasFocus {
+		p.Unlock()
+		p.Focus(p.setFocus)
+		p.Lock()
+	}
+}
+
+// SendToBack changes the order of the panels such that the panel with the given
+// name comes first, causing it to be drawn first with the next update (if
+// visible).
+func (p *Panels) SendToBack(name string) {
+	hasFocus := p.HasFocus()
+
+	p.Lock()
+	defer p.Unlock()
+
+	for index, pg := range p.panels {
+		if pg.Name == name {
+			if index > 0 {
+				p.panels = append(append([]*panel{pg}, p.panels[:index]...), p.panels[index+1:]...)
+			}
+			if pg.Visible && p.changed != nil {
+				p.Unlock()
+				p.changed()
+				p.Lock()
+			}
+			break
+		}
+	}
+	if hasFocus {
+		p.Unlock()
+		p.Focus(p.setFocus)
+		p.Lock()
+	}
+}
+
+// GetFrontPanel returns the front-most visible panel. If there are no visible
+// panels, ("", nil) is returned.
+func (p *Panels) GetFrontPanel() (name string, item cview.Primitive) {
+	p.RLock()
+	defer p.RUnlock()
+
+	for index := len(p.panels) - 1; index >= 0; index-- {
+		if p.panels[index].Visible {
+			return p.panels[index].Name, p.panels[index].Item
+		}
+	}
+	return
+}
+
+// HasFocus returns whether or not this cview.Primitive has focus.
+func (p *Panels) HasFocus() bool {
+	p.RLock()
+	defer p.RUnlock()
+
+	for _, panel := range p.panels {
+		if panel.Item.GetFocusable().HasFocus() {
+			return true
+		}
+	}
+	return false
+}
+
+// Focus is called by the application when the cview.Primitive receives focus.
+func (p *Panels) Focus(delegate func(p cview.Primitive)) {
+	p.Lock()
+	defer p.Unlock()
+
+	if delegate == nil {
+		return // We cannot delegate so we cannot focus.
+	}
+	p.setFocus = delegate
+	var topItem cview.Primitive
+	for _, panel := range p.panels {
+		if panel.Visible {
+			topItem = panel.Item
+		}
+	}
+	if topItem != nil {
+		p.Unlock()
+		delegate(topItem)
+		p.Lock()
+	}
+}
+
+// Draw draws this cview.Primitive onto the screen.
+func (p *Panels) Draw(screen tcell.Screen) {
+	if !p.GetVisible() {
+		return
+	}
+
+	p.Box.Draw(screen)
+
+	p.Lock()
+	defer p.Unlock()
+
+	x, y, width, height := p.GetInnerRect()
+
+	for _, panel := range p.panels {
+		if !panel.Visible {
+			continue
+		}
+		if panel.Resize {
+			panel.Item.SetRect(x, y, width, height)
+		}
+		panel.Item.Draw(screen)
+	}
+}
+
+// MouseHandler returns the mouse handler for this cview.Primitive.
+func (p *Panels) MouseHandler() func(action cview.MouseAction, event *tcell.EventMouse, setFocus func(p cview.Primitive)) (consumed bool, capture cview.Primitive) {
+	return p.WrapMouseHandler(func(action cview.MouseAction, event *tcell.EventMouse, setFocus func(p cview.Primitive)) (consumed bool, capture cview.Primitive) {
+		if !p.InRect(event.Position()) {
+			return false, nil
+		}
+
+		// Pass mouse events along to the last visible panel item that takes it.
+		for index := len(p.panels) - 1; index >= 0; index-- {
+			panel := p.panels[index]
+			if panel.Visible {
+				consumed, capture = panel.Item.MouseHandler()(action, event, setFocus)
+				if consumed {
+					return
+				}
+			}
+		}
+
+		return
+	})
+}
+
+// Support backwards compatibility with Pages.
+type page = panel
+
+// Pages is a wrapper around Panels.
+//
+// Deprecated: This type is provided for backwards compatibility.
+// Developers should use Panels instead.
+type Pages struct {
+	*Panels
+}
+
+// NewPages returns a new Panels object.
+//
+// Deprecated: This function is provided for backwards compatibility.
+// Developers should use NewPanels instead.
+func NewPages() *Pages {
+	return &Pages{NewPanels()}
+}
+
+// GetPageCount returns the number of panels currently stored in this object.
+func (p *Pages) GetPageCount() int {
+	return p.GetPanelCount()
+}
+
+// AddPage adds a new panel with the given name and cview.Primitive.
+func (p *Pages) AddPage(name string, item cview.Primitive, resize, visible bool) {
+	p.AddPanel(name, item, resize, visible)
+}
+
+// AddAndSwitchToPage calls Add(), then SwitchTo() on that newly added panel.
+func (p *Pages) AddAndSwitchToPage(name string, item cview.Primitive, resize bool) {
+	p.AddPanel(name, item, resize, true)
+	p.SetCurrentPanel(name)
+}
+
+// RemovePage removes the panel with the given name.
+func (p *Pages) RemovePage(name string) {
+	p.RemovePanel(name)
+}
+
+// HasPage returns true if a panel with the given name exists in this object.
+func (p *Pages) HasPage(name string) bool {
+	return p.HasPanel(name)
+}
+
+// ShowPage sets a panel's visibility to "true".
+func (p *Pages) ShowPage(name string) {
+	p.ShowPanel(name)
+}
+
+// HidePage sets a panel's visibility to "false".
+func (p *Pages) HidePage(name string) {
+	p.HidePanel(name)
+}
+
+// SwitchToPage sets a panel's visibility to "true" and all other panels'
+// visibility to "false".
+func (p *Pages) SwitchToPage(name string) {
+	p.SetCurrentPanel(name)
+}
+
+// GetFrontPage returns the front-most visible panel.
+func (p *Pages) GetFrontPage() (name string, item cview.Primitive) {
+	return p.GetFrontPanel()
+}
diff --git a/TabTitleMenu/screenshot.png b/TabTitleMenu/screenshot.png
new file mode 100755
index 0000000..a852a03
--- /dev/null
+++ b/TabTitleMenu/screenshot.png
Binary files differ
diff --git a/TabTitleMenu/tabbedpanels.go b/TabTitleMenu/tabbedpanels.go
new file mode 100755
index 0000000..2b35f82
--- /dev/null
+++ b/TabTitleMenu/tabbedpanels.go
@@ -0,0 +1,433 @@
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"sync"
+	"strings"
+
+	"github.com/gdamore/tcell/v2"
+	"code.rocketnine.space/tslocum/cview"
+)
+
+// TabbedPanels is a tabbed container for other cview.Primitives. The tab switcher
+// may be positioned vertically or horizontally, before or after the content.
+type TabbedPanels struct {
+	*cview.Flex
+	Switcher *cview.TextView
+	panels   *Panels
+
+	tabLabels  map[string]string
+	currentTab string
+
+	dividerStart string
+	dividerMid   string
+	dividerEnd   string
+
+	switcherVertical     bool
+	switcherAfterContent bool
+	switcherHeight       int
+
+	width, lastWidth int
+
+	setFocus func(cview.Primitive)
+
+	sync.RWMutex
+}
+
+// NewTabbedPanels returns a new TabbedPanels object.
+func NewTabbedPanels() *TabbedPanels {
+	t := &TabbedPanels{
+		Flex:       cview.NewFlex(),
+		Switcher:   cview.NewTextView(),
+		panels:     NewPanels(),
+		dividerStart: string(cview.BoxDrawingsLightDownAndRight),
+		dividerMid: string("-"),
+		dividerEnd: string(cview.BoxDrawingsLightDownAndLeft),
+		tabLabels:  make(map[string]string),
+	}
+
+	s := t.Switcher
+	s.SetDynamicColors(true)
+	s.SetHighlightForegroundColor(tcell.Color226) // yellow
+	s.SetHighlightBackgroundColor(tcell.Color16) // black
+	s.SetRegions(true)
+	s.SetScrollable(true)
+	s.SetWrap(true)
+	s.SetWordWrap(true)
+	s.SetHighlightedFunc(func(added, removed, remaining []string) {
+		if len(added) == 0 {
+			return
+		}
+
+		s.ScrollToHighlight()
+		t.SetCurrentTab(added[0])
+		if t.setFocus != nil {
+			t.setFocus(t.panels)
+		}
+	})
+
+	t.rebuild()
+
+	return t
+}
+
+// SetChangedFunc sets a handler which is called whenever a tab is added,
+// selected, reordered or removed.
+func (t *TabbedPanels) SetChangedFunc(handler func()) {
+	t.panels.SetChangedFunc(handler)
+}
+
+// AddTab adds a new tab. Tab names should consist only of letters, numbers
+// and spaces.
+func (t *TabbedPanels) AddTab(name, label string, item cview.Primitive) {
+	t.Lock()
+	t.tabLabels[name] = label
+	t.Unlock()
+
+	t.panels.AddPanel(name, item, true, false)
+
+	t.updateAll()
+}
+
+// RemoveTab removes a tab.
+func (t *TabbedPanels) RemoveTab(name string) {
+	t.panels.RemovePanel(name)
+
+	t.updateAll()
+}
+
+// HasTab returns true if a tab with the given name exists in this object.
+func (t *TabbedPanels) HasTab(name string) bool {
+	t.RLock()
+	defer t.RUnlock()
+
+	for _, panel := range t.panels.panels {
+		if panel.Name == name {
+			return true
+		}
+	}
+	return false
+}
+
+// SetCurrentTab sets the currently visible tab.
+func (t *TabbedPanels) SetCurrentTab(name string) {
+	t.Lock()
+
+	if t.currentTab == name {
+		t.Unlock()
+		return
+	}
+
+	t.currentTab = name
+
+	t.updateAll()
+
+	t.Unlock()
+
+	h := t.Switcher.GetHighlights()
+	var found bool
+	for _, hl := range h {
+		if hl == name {
+			found = true
+			break
+		}
+	}
+	if !found {
+		t.Switcher.Highlight(t.currentTab)
+	}
+	t.Switcher.ScrollToHighlight()
+}
+
+// GetCurrentTab returns the currently visible tab.
+func (t *TabbedPanels) GetCurrentTab() string {
+	t.RLock()
+	defer t.RUnlock()
+	return t.currentTab
+}
+
+// SetTabLabel sets the label of a tab.
+func (t *TabbedPanels) SetTabLabel(name, label string) {
+	t.Lock()
+	defer t.Unlock()
+
+	if t.tabLabels[name] == label {
+		return
+	}
+
+	t.tabLabels[name] = label
+	t.updateTabLabels()
+}
+
+// SetTabTextColor sets the color of the tab text.
+func (t *TabbedPanels) SetTabTextColor(color tcell.Color) {
+	t.Switcher.SetTextColor(color)
+}
+
+// SetTabTextColorFocused sets the color of the tab text when the tab is in focus.
+func (t *TabbedPanels) SetTabTextColorFocused(color tcell.Color) {
+	t.Switcher.SetHighlightForegroundColor(color)
+}
+
+// SetTabBackgroundColor sets the background color of the tab.
+func (t *TabbedPanels) SetTabBackgroundColor(color tcell.Color) {
+	t.Switcher.SetBackgroundColor(color)
+}
+
+// SetTabBackgroundColorFocused sets the background color of the tab when the
+// tab is in focus.
+func (t *TabbedPanels) SetTabBackgroundColorFocused(color tcell.Color) {
+	t.Switcher.SetHighlightBackgroundColor(color)
+}
+
+// SetTabSwitcherDivider sets the tab switcher divider text. Color tags are supported.
+func (t *TabbedPanels) SetTabSwitcherDivider(start, mid, end string) {
+	t.Lock()
+	defer t.Unlock()
+	t.dividerStart, t.dividerMid, t.dividerEnd = start, mid, end
+}
+
+// SetTabSwitcherHeight sets the tab switcher height. This setting only applies
+// when rendering horizontally. A value of 0 (the default) indicates the height
+// should automatically adjust to fit all of the tab labels.
+func (t *TabbedPanels) SetTabSwitcherHeight(height int) {
+	t.Lock()
+	defer t.Unlock()
+
+	t.switcherHeight = height
+	t.rebuild()
+}
+
+// SetTabSwitcherVertical sets the orientation of the tab switcher.
+func (t *TabbedPanels) SetTabSwitcherVertical(vertical bool) {
+	t.Lock()
+	defer t.Unlock()
+	if t.switcherVertical == vertical {
+		return
+	}
+
+	t.switcherVertical = vertical
+	t.rebuild()
+}
+
+// SetTabSwitcherAfterContent sets whether the tab switcher is positioned after content.
+func (t *TabbedPanels) SetTabSwitcherAfterContent(after bool) {
+	t.Lock()
+	defer t.Unlock()
+
+	if t.switcherAfterContent == after {
+		return
+	}
+
+	t.switcherAfterContent = after
+	t.rebuild()
+}
+
+func (t *TabbedPanels) rebuild() {
+	f := t.Flex
+	if t.switcherVertical {
+		f.SetDirection(cview.FlexColumn)
+	} else {
+		f.SetDirection(cview.FlexRow)
+	}
+	f.RemoveItem(t.panels)
+	f.RemoveItem(t.Switcher)
+	if t.switcherAfterContent {
+		f.AddItem(t.panels, 0, 1, true)
+		f.AddItem(t.Switcher, 1, 1, false)
+	} else {
+		f.AddItem(t.Switcher, 1, 1, false)
+		f.AddItem(t.panels, 0, 1, true)
+	}
+
+	t.updateTabLabels()
+
+	t.Switcher.SetMaxLines(t.switcherHeight)
+}
+
+func (t *TabbedPanels) updateTabLabels() {
+	if len(t.panels.panels) == 0 {
+		t.Switcher.SetText("")
+		t.Flex.ResizeItem(t.Switcher, 0, 1)
+		return
+	}
+
+	maxWidth := 0
+	for _, panel := range t.panels.panels {
+		label := t.tabLabels[panel.Name]
+		if len(label) > maxWidth {
+			maxWidth = len(label)
+		}
+	}
+
+	var b bytes.Buffer
+	if !t.switcherVertical {
+		b.WriteString(t.dividerStart)
+	}
+	l := len(t.panels.panels)
+	spacer := []byte(" ")
+	for i, panel := range t.panels.panels {
+		if i > 0 && t.switcherVertical {
+			b.WriteRune('\n')
+		}
+
+		if t.switcherVertical && t.switcherAfterContent {
+			b.WriteString(t.dividerMid)
+			b.WriteRune(' ')
+		}
+
+		label := t.tabLabels[panel.Name]
+		if !t.switcherVertical {
+			label = " " + label
+		}
+
+		if t.switcherVertical {
+			spacer = bytes.Repeat([]byte(" "), maxWidth-len(label)+1)
+		}
+		b.WriteString(fmt.Sprintf(`["%s"]%s%s[""]`, panel.Name, label, spacer))
+		
+		if i == l-1 && !t.switcherVertical {
+			//fmt.Println("t.width", t.width, "maxwidth", maxWidth, "label", label, "l", l)
+			/***
+			 * This did not work! (trying to make when panel highlighted borders change)
+			 */
+			/*
+			spacer_char := ""
+			div_end := ""
+			if t.setFocus != nil { // not in focus!
+				spacer_char = string(cview.BoxDrawingsLightHorizontal)
+				div_end = t.dividerEnd
+			}else{
+				spacer_char = "[::b]"+string(cview.BoxDrawingsHeavyHorizontal)+"[::-]"
+				div_end = string(cview.BoxDrawingsHeavyDownAndLeft)
+			}
+			*/
+			spacer_char := string(cview.BoxDrawingsLightHorizontal)
+			div_end := t.dividerEnd
+
+			spacer_str := ""
+			if t.width > 0 {
+				spacer_len := 0
+				for _, panel_test := range t.panels.panels{
+					spacer_len += len(t.tabLabels[panel_test.Name])+2
+				}
+				
+				spacer_str = strings.Repeat(spacer_char, t.width-maxWidth-spacer_len+2)
+				
+			}else{
+				spacer_str = strings.Repeat("─", maxWidth+1)
+			}
+			b.WriteString(spacer_str + div_end)
+		} else if !t.switcherAfterContent {
+			b.WriteString(t.dividerMid)
+		}
+	}
+	t.Switcher.SetText(b.String())
+
+	var reqLines int
+	if t.switcherVertical {
+		reqLines = maxWidth + 2
+	} else {
+		if t.switcherHeight > 0 {
+			reqLines = t.switcherHeight
+		} else {
+			reqLines = len(cview.WordWrap(t.Switcher.GetText(true), t.width))
+			if reqLines < 1 {
+				reqLines = 1
+			}
+		}
+	}
+	t.Flex.ResizeItem(t.Switcher, reqLines, 1)
+}
+
+func (t *TabbedPanels) updateVisibleTabs() {
+	allPanels := t.panels.panels
+
+	var newTab string
+
+	var foundCurrent bool
+	for _, panel := range allPanels {
+		if panel.Name == t.currentTab {
+			newTab = panel.Name
+			foundCurrent = true
+			break
+		}
+	}
+	if !foundCurrent {
+		for _, panel := range allPanels {
+			if panel.Name != "" {
+				newTab = panel.Name
+				break
+			}
+		}
+	}
+
+	if t.currentTab != newTab {
+		t.SetCurrentTab(newTab)
+		return
+	}
+
+	for _, panel := range allPanels {
+		if panel.Name == t.currentTab {
+			t.panels.ShowPanel(panel.Name)
+		} else {
+			t.panels.HidePanel(panel.Name)
+		}
+	}
+}
+
+func (t *TabbedPanels) updateAll() {
+	t.updateTabLabels()
+	t.updateVisibleTabs()
+}
+
+// Draw draws this cview.Primitive onto the screen.
+func (t *TabbedPanels) Draw(screen tcell.Screen) {
+	if !t.GetVisible() {
+		return
+	}
+
+	t.Box.Draw(screen)
+
+	_, _, t.width, _ = t.GetInnerRect()
+	if t.width != t.lastWidth {
+		t.updateTabLabels()
+	}
+	t.lastWidth = t.width
+
+	t.Flex.Draw(screen)
+}
+
+// InputHandler returns the handler for this cview.Primitive.
+func (t *TabbedPanels) InputHandler() func(event *tcell.EventKey, setFocus func(p cview.Primitive)) {
+	return t.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p cview.Primitive)) {
+		if t.setFocus == nil {
+			t.setFocus = setFocus
+		}
+		t.Flex.InputHandler()(event, setFocus)
+	})
+}
+
+// MouseHandler returns the mouse handler for this cview.Primitive.
+func (t *TabbedPanels) MouseHandler() func(action cview.MouseAction, event *tcell.EventMouse, setFocus func(p cview.Primitive)) (consumed bool, capture cview.Primitive) {
+	return t.WrapMouseHandler(func(action cview.MouseAction, event *tcell.EventMouse, setFocus func(p cview.Primitive)) (consumed bool, capture cview.Primitive) {
+		if t.setFocus == nil {
+			t.setFocus = setFocus
+		}
+
+		x, y := event.Position()
+		if !t.InRect(x, y) {
+			return false, nil
+		}
+
+		if t.Switcher.InRect(x, y) {
+			if t.setFocus != nil {
+				defer t.setFocus(t.panels)
+			}
+			defer t.Switcher.MouseHandler()(action, event, setFocus)
+			return true, nil
+		}
+
+		return t.Flex.MouseHandler()(action, event, setFocus)
+	})
+}