4 "github.com/zyedidia/micro/cmd/micro/buffer"
5 "github.com/zyedidia/micro/cmd/micro/display"
6 "github.com/zyedidia/micro/cmd/micro/screen"
7 "github.com/zyedidia/micro/cmd/micro/views"
8 "github.com/zyedidia/tcell"
11 // The TabList is a list of tabs and a window to display the tab bar
12 // at the top of the screen
18 // NewTabList creates a TabList from a list of buffers by creating a Tab
20 func NewTabList(bufs []*buffer.Buffer) *TabList {
21 w, h := screen.Screen.Size()
23 tl.List = make([]*Tab, len(bufs))
25 for i, b := range bufs {
26 tl.List[i] = NewTabFromBuffer(0, 1, w, h-2, b)
29 tl.List[0] = NewTabFromBuffer(0, 0, w, h-1, bufs[0])
31 tl.TabWindow = display.NewTabWindow(w, 0)
32 tl.Names = make([]string, len(bufs))
37 // UpdateNames makes sure that the list of names the tab window has access to is
39 func (t *TabList) UpdateNames() {
41 for _, p := range t.List {
42 t.Names = append(t.Names, p.Panes[p.active].Name())
46 // AddTab adds a new tab to this TabList
47 func (t *TabList) AddTab(p *Tab) {
48 t.List = append(t.List, p)
53 // RemoveTab removes a tab with the given id from the TabList
54 func (t *TabList) RemoveTab(id uint64) {
55 for i, p := range t.List {
56 if len(p.Panes) == 0 {
59 if p.Panes[0].ID() == id {
60 copy(t.List[i:], t.List[i+1:])
61 t.List[len(t.List)-1] = nil
62 t.List = t.List[:len(t.List)-1]
63 if t.Active() >= len(t.List) {
64 t.SetActive(len(t.List) - 1)
73 // Resize resizes all elements within the tab list
74 // One thing to note is that when there is only 1 tab
75 // the tab bar should not be drawn so resizing must take
77 func (t *TabList) Resize() {
78 w, h := screen.Screen.Size()
79 InfoBar.Resize(w, h-1)
81 for _, p := range t.List {
86 } else if len(t.List) == 1 {
88 t.List[0].Node.Resize(w, h-1)
93 // HandleEvent checks for a resize event or a mouse event on the tab bar
94 // otherwise it will forward the event to the currently active tab
95 func (t *TabList) HandleEvent(event tcell.Event) {
96 switch e := event.(type) {
97 case *tcell.EventResize:
99 case *tcell.EventMouse:
100 mx, my := e.Position()
103 ind := t.GetMouseLoc(buffer.Loc{mx, my})
112 case tcell.WheelDown:
119 t.List[t.Active()].HandleEvent(event)
122 // Display updates the names and then displays the tab bar
123 func (t *TabList) Display() {
126 t.TabWindow.Display()
130 // Tabs is the global tab list
133 func InitTabs(bufs []*buffer.Buffer) {
134 Tabs = NewTabList(bufs)
137 func MainTab() *Tab {
138 return Tabs.List[Tabs.Active()]
141 // A Tab represents a single tab
142 // It consists of a list of edit panes (the open buffers),
143 // a split tree (stored as just the root node), and a uiwindow
144 // to display the UI elements like the borders between splits
151 resizing *views.Node // node currently being resized
154 // NewTabFromBuffer creates a new tab from the given buffer
155 func NewTabFromBuffer(x, y, width, height int, b *buffer.Buffer) *Tab {
157 t.Node = views.NewRoot(x, y, width, height)
158 t.UIWindow = display.NewUIWindow(t.Node)
160 e := NewBufEditPane(x, y, width, height, b)
163 t.Panes = append(t.Panes, e)
167 // HandleEvent takes a tcell event and usually dispatches it to the current
168 // active pane. However if the event is a resize or a mouse event where the user
169 // is interacting with the UI (resizing splits) then the event is consumed here
170 // If the event is a mouse event in a pane, that pane will become active and get
172 func (t *Tab) HandleEvent(event tcell.Event) {
173 switch e := event.(type) {
174 case *tcell.EventMouse:
175 mx, my := e.Position()
178 resizeID := t.GetMouseSplitID(buffer.Loc{mx, my})
179 if t.resizing != nil {
181 if t.resizing.Kind == views.STVert {
182 size = mx - t.resizing.X
184 size = my - t.resizing.Y + 1
186 t.resizing.ResizeSplit(size)
192 t.resizing = t.GetNode(uint64(resizeID))
196 for i, p := range t.Panes {
198 inpane := mx >= v.X && mx < v.X+v.Width && my >= v.Y && my < v.Y+v.Height
204 case tcell.ButtonNone:
207 for _, p := range t.Panes {
209 inpane := mx >= v.X && mx < v.X+v.Width && my >= v.Y && my < v.Y+v.Height
218 t.Panes[t.active].HandleEvent(event)
221 // SetActive changes the currently active pane to the specified index
222 func (t *Tab) SetActive(i int) {
224 for j, p := range t.Panes {
233 // GetPane returns the pane with the given split index
234 func (t *Tab) GetPane(splitid uint64) int {
235 for i, p := range t.Panes {
236 if p.ID() == splitid {
243 // Remove pane removes the pane with the given index
244 func (t *Tab) RemovePane(i int) {
245 copy(t.Panes[i:], t.Panes[i+1:])
246 t.Panes[len(t.Panes)-1] = nil
247 t.Panes = t.Panes[:len(t.Panes)-1]
250 // Resize resizes all panes according to their corresponding split nodes
251 func (t *Tab) Resize() {
252 for _, p := range t.Panes {
253 n := t.GetNode(p.ID())
259 pv.X, pv.Y = n.X+offset, n.Y
261 p.Resize(n.W-offset, n.H)
265 // CurPane returns the currently active pane
266 func (t *Tab) CurPane() Pane {
267 return t.Panes[t.active]