"github.com/zyedidia/tcell"
)
+// The TabList is a list of tabs and a window to display the tab bar
+// at the top of the screen
type TabList struct {
*display.TabWindow
- List []*TabPane
+ List []*Tab
}
+// NewTabList creates a TabList from a list of buffers by creating a Tab
+// for each buffer
func NewTabList(bufs []*buffer.Buffer) *TabList {
w, h := screen.Screen.Size()
tl := new(TabList)
- tl.List = make([]*TabPane, len(bufs))
+ tl.List = make([]*Tab, len(bufs))
if len(bufs) > 1 {
for i, b := range bufs {
- tl.List[i] = NewTabPane(0, 1, w, h-2, b)
+ tl.List[i] = NewTabFromBuffer(0, 1, w, h-2, b)
}
} else {
- tl.List[0] = NewTabPane(0, 0, w, h-1, bufs[0])
+ tl.List[0] = NewTabFromBuffer(0, 0, w, h-1, bufs[0])
}
tl.TabWindow = display.NewTabWindow(w, 0)
tl.Names = make([]string, len(bufs))
- tl.UpdateNames()
return tl
}
+// UpdateNames makes sure that the list of names the tab window has access to is
+// correct
func (t *TabList) UpdateNames() {
t.Names = t.Names[:0]
for _, p := range t.List {
- t.Names = append(t.Names, p.Panes[p.active].Buf.GetName())
+ t.Names = append(t.Names, p.Panes[p.active].Name())
}
}
+// AddTab adds a new tab to this TabList
+func (t *TabList) AddTab(p *Tab) {
+ t.List = append(t.List, p)
+ t.Resize()
+ t.UpdateNames()
+}
+
+// RemoveTab removes a tab with the given id from the TabList
+func (t *TabList) RemoveTab(id uint64) {
+ for i, p := range t.List {
+ if len(p.Panes) == 0 {
+ continue
+ }
+ if p.Panes[0].ID() == id {
+ copy(t.List[i:], t.List[i+1:])
+ t.List[len(t.List)-1] = nil
+ t.List = t.List[:len(t.List)-1]
+ if t.Active() >= len(t.List) {
+ t.SetActive(len(t.List) - 1)
+ }
+ t.Resize()
+ t.UpdateNames()
+ return
+ }
+ }
+}
+
+// Resize resizes all elements within the tab list
+// One thing to note is that when there is only 1 tab
+// the tab bar should not be drawn so resizing must take
+// that into account
+func (t *TabList) Resize() {
+ w, h := screen.Screen.Size()
+ InfoBar.Resize(w, h-1)
+ if len(t.List) > 1 {
+ for _, p := range t.List {
+ p.Y = 1
+ p.Node.Resize(w, h-2)
+ p.Resize()
+ }
+ } else if len(t.List) == 1 {
+ t.List[0].Y = 0
+ t.List[0].Node.Resize(w, h-1)
+ t.List[0].Resize()
+ }
+}
+
+// HandleEvent checks for a resize event or a mouse event on the tab bar
+// otherwise it will forward the event to the currently active tab
func (t *TabList) HandleEvent(event tcell.Event) {
switch e := event.(type) {
case *tcell.EventResize:
- w, h := screen.Screen.Size()
- InfoBar.Resize(w, h-1)
- if len(t.List) > 1 {
- for _, p := range t.List {
- p.Node.Resize(w, h-2)
- p.Resize()
- }
- } else {
- t.List[0].Node.Resize(w, h-1)
- t.List[0].Resize()
- }
+ t.Resize()
case *tcell.EventMouse:
mx, my := e.Position()
switch e.Buttons() {
case tcell.Button1:
ind := t.GetMouseLoc(buffer.Loc{mx, my})
if ind != -1 {
- t.Active = ind
+ t.SetActive(ind)
}
case tcell.WheelUp:
if my == t.Y {
}
}
}
- t.List[t.Active].HandleEvent(event)
+ t.List[t.Active()].HandleEvent(event)
}
+// Display updates the names and then displays the tab bar
func (t *TabList) Display() {
+ t.UpdateNames()
if len(t.List) > 1 {
t.TabWindow.Display()
}
}
+// Tabs is the global tab list
var Tabs *TabList
func InitTabs(bufs []*buffer.Buffer) {
Tabs = NewTabList(bufs)
}
-func MainTab() *TabPane {
- return Tabs.List[Tabs.Active]
+func MainTab() *Tab {
+ return Tabs.List[Tabs.Active()]
}
-// A TabPane represents a single tab
+// A Tab represents a single tab
// It consists of a list of edit panes (the open buffers),
// a split tree (stored as just the root node), and a uiwindow
// to display the UI elements like the borders between splits
-type TabPane struct {
+type Tab struct {
*views.Node
*display.UIWindow
- Panes []*EditPane
+ Panes []Pane
active int
resizing *views.Node // node currently being resized
}
+// NewTabFromBuffer creates a new tab from the given buffer
+func NewTabFromBuffer(x, y, width, height int, b *buffer.Buffer) *Tab {
+ t := new(Tab)
+ t.Node = views.NewRoot(x, y, width, height)
+ t.UIWindow = display.NewUIWindow(t.Node)
+
+ e := NewBufEditPane(x, y, width, height, b)
+ e.splitID = t.ID()
+
+ t.Panes = append(t.Panes, e)
+ return t
+}
+
// HandleEvent takes a tcell event and usually dispatches it to the current
// active pane. However if the event is a resize or a mouse event where the user
// is interacting with the UI (resizing splits) then the event is consumed here
// If the event is a mouse event in a pane, that pane will become active and get
// the event
-func (t *TabPane) HandleEvent(event tcell.Event) {
+func (t *Tab) HandleEvent(event tcell.Event) {
switch e := event.(type) {
case *tcell.EventMouse:
mx, my := e.Position()
v := p.GetView()
inpane := mx >= v.X && mx < v.X+v.Width && my >= v.Y && my < v.Y+v.Height
if inpane {
- t.active = i
- p.SetActive(true)
- } else {
- p.SetActive(false)
+ t.SetActive(i)
+ break
}
}
case tcell.ButtonNone:
}
// SetActive changes the currently active pane to the specified index
-func (t *TabPane) SetActive(i int) {
+func (t *Tab) SetActive(i int) {
t.active = i
for j, p := range t.Panes {
if j == i {
}
// GetPane returns the pane with the given split index
-func (t *TabPane) GetPane(splitid uint64) int {
+func (t *Tab) GetPane(splitid uint64) int {
for i, p := range t.Panes {
- if p.splitID == splitid {
+ if p.ID() == splitid {
return i
}
}
}
// Remove pane removes the pane with the given index
-func (t *TabPane) RemovePane(i int) {
+func (t *Tab) RemovePane(i int) {
copy(t.Panes[i:], t.Panes[i+1:])
- t.Panes[len(t.Panes)-1] = nil // or the zero value of T
+ t.Panes[len(t.Panes)-1] = nil
t.Panes = t.Panes[:len(t.Panes)-1]
}
// Resize resizes all panes according to their corresponding split nodes
-func (t *TabPane) Resize() {
+func (t *Tab) Resize() {
for _, p := range t.Panes {
- n := t.GetNode(p.splitID)
+ n := t.GetNode(p.ID())
pv := p.GetView()
offset := 0
if n.X != 0 {
}
// CurPane returns the currently active pane
-func (t *TabPane) CurPane() *EditPane {
+func (t *Tab) CurPane() Pane {
return t.Panes[t.active]
}