-
Notifications
You must be signed in to change notification settings - Fork 2
/
notebook.lua
190 lines (162 loc) · 4.54 KB
/
notebook.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
--
-- NoteBook Widget.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local style = require "core.style"
local Widget = require "widget"
local Button = require "widget.button"
local HSPACING = 2
local VSPACING = 2
---Represents a notebook pane
---@class widget.notebook.pane
---@field public name string
---@field public tab widget.button
---@field public container widget
local NoteBookPane = {}
---@class widget.notebook : widget
---@overload fun(parent?:widget):widget.notebook
---@field public panes widget.notebook.pane[]
---@field public active_pane widget.notebook.pane
local NoteBook = Widget:extend()
---Notebook constructor
---@param parent widget
function NoteBook:new(parent)
NoteBook.super.new(self, parent)
self.type_name = "widget.notebook"
self.panes = {}
self.active_pane = nil
end
---Called when a tab is clicked.
---@param pane widget.notebook.pane
---@diagnostic disable-next-line
function NoteBook:on_tab_click(pane) end
---Adds a new pane to the notebook and returns a container widget where
---you can add more child elements.
---@param name string
---@param label string
---@return widget container
function NoteBook:add_pane(name, label)
---@type widget.button
local tab = Button(self, label)
tab.border.width = 0
if #self.panes > 0 then
tab:set_position(self.panes[#self.panes].tab:get_right() + HSPACING, 0)
end
local container = Widget(self)
container.scrollable = true
container:set_position(0, tab:get_bottom() + VSPACING)
container:set_size(
self:get_width(),
self:get_height() - tab:get_height() - VSPACING
)
local pane = {
name = name,
tab = tab,
container = container
}
if not self.active_pane then
self.active_pane = pane
self:schedule_update()
end
tab.on_click = function()
self.active_pane = pane
self:on_tab_click(pane)
end
table.insert(self.panes, pane)
return container
end
---Search the pane for the given name and return it.
---@param name string
---@return widget.notebook.pane | nil
function NoteBook:get_pane(name)
for _, pane in pairs(self.panes) do
if pane.name == name then
return pane
end
end
return nil
end
---Activates the given pane.
---@param name string
---@return boolean
function NoteBook:set_pane(name)
local pane = self:get_pane(name)
if pane then
self.active_pane = pane
return true
end
return false
end
---Change the tab label of the given pane.
---@param name string
---@param label string
function NoteBook:set_pane_label(name, label)
local pane = self:get_pane(name)
if pane then
pane.tab:set_label(label)
return true
end
return false
end
---Set or remove the icon for the given pane.
---@param name string
---@param icon? string|nil
---@param color? renderer.color|nil
---@param hover_color? renderer.color|nil
function NoteBook:set_pane_icon(name, icon, color, hover_color)
local pane = self:get_pane(name)
if pane then
pane.tab:set_icon(icon, color, hover_color)
return true
end
return false
end
---Recalculate the position of the elements on resizing or position
---changes and also make changes to properly render active pane.
function NoteBook:update()
if not NoteBook.super.update(self) then return false end
for pos, pane in pairs(self.panes) do
if pos ~= 1 then
pane.tab:set_position(
self.panes[pos-1].tab:get_right() + HSPACING, 0
)
else
pane.tab:set_position(0, 0)
end
if pane ~= self.active_pane then
if pane.container.visible then
pane.tab.background_color = style.background
pane.tab.foreground_color = style.text
pane.container:hide()
end
elseif not pane.container.visible then
pane.container:show()
self:schedule_update()
end
end
if self.active_pane then
self.active_pane.tab.foreground_color = style.accent
self.active_pane.container:set_position(
0, self.active_pane.tab:get_bottom() + VSPACING
)
self.active_pane.container:set_size(
self:get_width(),
self:get_height() - self.active_pane.tab:get_height() - VSPACING
)
self.active_pane.container.border.color = style.divider
end
return true
end
---Here we draw the bottom line on the tab of active pane.
function NoteBook:draw()
if not NoteBook.super.draw(self) then return false end
if self.active_pane then
local x = self.active_pane.tab.position.x
local y = self.active_pane.tab.position.y + self.active_pane.tab:get_bottom()
local w = self.active_pane.tab:get_width()
renderer.draw_rect(x, y, w, HSPACING, style.caret)
end
return true
end
return NoteBook