4 "github.com/zyedidia/micro/v2/internal/buffer"
5 "github.com/zyedidia/micro/v2/internal/config"
6 "github.com/zyedidia/micro/v2/internal/display"
7 "github.com/zyedidia/micro/v2/internal/screen"
8 "github.com/zyedidia/micro/v2/internal/views"
9 "github.com/zyedidia/tcell"
12 // The TabList is a list of tabs and a window to display the tab bar
13 // at the top of the screen
19 // NewTabList creates a TabList from a list of buffers by creating a Tab
21 func NewTabList(bufs []*buffer.Buffer) *TabList {
22 w, h := screen.Screen.Size()
23 iOffset := config.GetInfoBarOffset()
25 tl.List = make([]*Tab, len(bufs))
27 for i, b := range bufs {
28 tl.List[i] = NewTabFromBuffer(0, 1, w, h-1-iOffset, b)
31 tl.List[0] = NewTabFromBuffer(0, 0, w, h-iOffset, bufs[0])
33 tl.TabWindow = display.NewTabWindow(w, 0)
34 tl.Names = make([]string, len(bufs))
39 // UpdateNames makes sure that the list of names the tab window has access to is
41 func (t *TabList) UpdateNames() {
43 for _, p := range t.List {
44 t.Names = append(t.Names, p.Panes[p.active].Name())
48 // AddTab adds a new tab to this TabList
49 func (t *TabList) AddTab(p *Tab) {
50 t.List = append(t.List, p)
55 // RemoveTab removes a tab with the given id from the TabList
56 func (t *TabList) RemoveTab(id uint64) {
57 for i, p := range t.List {
58 if len(p.Panes) == 0 {
61 if p.Panes[0].ID() == id {
62 copy(t.List[i:], t.List[i+1:])
63 t.List[len(t.List)-1] = nil
64 t.List = t.List[:len(t.List)-1]
65 if t.Active() >= len(t.List) {
66 t.SetActive(len(t.List) - 1)
75 // Resize resizes all elements within the tab list
76 // One thing to note is that when there is only 1 tab
77 // the tab bar should not be drawn so resizing must take
79 func (t *TabList) Resize() {
80 w, h := screen.Screen.Size()
81 iOffset := config.GetInfoBarOffset()
82 InfoBar.Resize(w, h-1)
84 for _, p := range t.List {
86 p.Node.Resize(w, h-1-iOffset)
89 } else if len(t.List) == 1 {
91 t.List[0].Node.Resize(w, h-iOffset)
94 t.TabWindow.Resize(w, h)
97 // HandleEvent checks for a resize event or a mouse event on the tab bar
98 // otherwise it will forward the event to the currently active tab
99 func (t *TabList) HandleEvent(event tcell.Event) {
100 switch e := event.(type) {
101 case *tcell.EventResize:
103 case *tcell.EventMouse:
104 mx, my := e.Position()
107 if my == t.Y && mx == 0 {
110 } else if my == t.Y && mx == t.Width-1 {
115 ind := t.LocFromVisual(buffer.Loc{mx, my})
129 case tcell.WheelDown:
136 t.List[t.Active()].HandleEvent(event)
139 // Display updates the names and then displays the tab bar
140 func (t *TabList) Display() {
143 t.TabWindow.Display()
147 // Tabs is the global tab list
150 func InitTabs(bufs []*buffer.Buffer) {
151 Tabs = NewTabList(bufs)
154 func MainTab() *Tab {
155 return Tabs.List[Tabs.Active()]
158 // A Tab represents a single tab
159 // It consists of a list of edit panes (the open buffers),
160 // a split tree (stored as just the root node), and a uiwindow
161 // to display the UI elements like the borders between splits
168 resizing *views.Node // node currently being resized
169 // captures whether the mouse is released
173 // NewTabFromBuffer creates a new tab from the given buffer
174 func NewTabFromBuffer(x, y, width, height int, b *buffer.Buffer) *Tab {
176 t.Node = views.NewRoot(x, y, width, height)
177 t.UIWindow = display.NewUIWindow(t.Node)
180 e := NewBufPaneFromBuf(b, t)
183 t.Panes = append(t.Panes, e)
187 func NewTabFromPane(x, y, width, height int, pane Pane) *Tab {
189 t.Node = views.NewRoot(x, y, width, height)
190 t.UIWindow = display.NewUIWindow(t.Node)
195 t.Panes = append(t.Panes, pane)
199 // HandleEvent takes a tcell event and usually dispatches it to the current
200 // active pane. However if the event is a resize or a mouse event where the user
201 // is interacting with the UI (resizing splits) then the event is consumed here
202 // If the event is a mouse event in a pane, that pane will become active and get
204 func (t *Tab) HandleEvent(event tcell.Event) {
205 switch e := event.(type) {
206 case *tcell.EventMouse:
207 mx, my := e.Position()
210 wasReleased := t.release
212 if t.resizing != nil {
214 if t.resizing.Kind == views.STVert {
215 size = mx - t.resizing.X
217 size = my - t.resizing.Y + 1
219 t.resizing.ResizeSplit(size)
225 t.resizing = t.GetMouseSplitNode(buffer.Loc{mx, my})
226 if t.resizing != nil {
230 for i, p := range t.Panes {
232 inpane := mx >= v.X && mx < v.X+v.Width && my >= v.Y && my < v.Y+v.Height
239 case tcell.ButtonNone:
243 for _, p := range t.Panes {
245 inpane := mx >= v.X && mx < v.X+v.Width && my >= v.Y && my < v.Y+v.Height
254 t.Panes[t.active].HandleEvent(event)
257 // SetActive changes the currently active pane to the specified index
258 func (t *Tab) SetActive(i int) {
260 for j, p := range t.Panes {
269 // GetPane returns the pane with the given split index
270 func (t *Tab) GetPane(splitid uint64) int {
271 for i, p := range t.Panes {
272 if p.ID() == splitid {
279 // Remove pane removes the pane with the given index
280 func (t *Tab) RemovePane(i int) {
281 copy(t.Panes[i:], t.Panes[i+1:])
282 t.Panes[len(t.Panes)-1] = nil
283 t.Panes = t.Panes[:len(t.Panes)-1]
286 // Resize resizes all panes according to their corresponding split nodes
287 func (t *Tab) Resize() {
288 for _, p := range t.Panes {
289 n := t.GetNode(p.ID())
295 pv.X, pv.Y = n.X+offset, n.Y
297 p.Resize(n.W-offset, n.H)
301 // CurPane returns the currently active pane
302 func (t *Tab) CurPane() *BufPane {
303 p, ok := t.Panes[t.active].(*BufPane)