-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathfoldingbook.lua
216 lines (184 loc) · 5.2 KB
/
foldingbook.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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
--
-- FoldingBook Widget.
-- @copyright Jefferson Gonzalez
-- @license MIT
--
local style = require "core.style"
local Widget = require "libraries.widget"
local Button = require "libraries.widget.button"
---Represents a foldingbook pane
---@class widget.foldingbook.pane
---@field public name string
---@field public tab widget.button
---@field public container widget
---@field public expanded boolean
local FoldingBookPane = {}
---@class widget.foldingbook : widget
---@overload fun(parent:widget?):widget.foldingbook
---@field public panes widget.foldingbook.pane[]
local FoldingBook = Widget:extend()
---FoldingBook constructor
---@param parent widget
function FoldingBook:new(parent)
FoldingBook.super.new(self, parent)
self.type_name = "widget.foldingbook"
self.panes = {}
self.scrollable = true
end
---@param pane widget.foldingbook.pane
function FoldingBook:on_tab_click(pane)
pane.expanded = not pane.expanded
end
---Adds a new pane to the foldingbook and returns a container widget where
---you can add more child elements.
---@param name string
---@param label string
---@return widget container
function FoldingBook:add_pane(name, label)
---@type widget.button
local tab = Button(self, label)
tab.border.width = 0
tab:toggle_expand(true)
tab:set_icon("+")
if #self.panes > 0 then
if self.panes[#self.panes].expanded then
tab:set_position(0, self.panes[#self.panes].container:get_bottom() + 2)
else
tab:set_position(0, self.panes[#self.panes].tab:get_bottom() + 2)
end
else
tab:set_position(0, 10)
end
local container = Widget(self)
container:set_position(0, tab:get_bottom() + 4)
container:set_size(self:get_width(), 0)
local pane = {
name = name,
tab = tab,
container = container,
expanded = false
}
tab.on_click = function()
self:on_tab_click(pane)
end
table.insert(self.panes, pane)
return container
end
---@param name string
---@return widget.foldingbook.pane | nil
function FoldingBook:get_pane(name)
for _, pane in pairs(self.panes) do
if pane.name == name then
return pane
end
end
return nil
end
---Delete a pane and all its childs from the folding book.
---@param name string
---@return boolean deleted
function FoldingBook:delete_pane(name)
for idx, pane in ipairs(self.panes) do
if pane.name == name then
self:remove_child(pane.tab)
self:remove_child(pane.container)
table.remove(self.panes, idx)
return true
end
end
return false
end
---Activates the given pane
---@param name string
---@param visible boolean | nil
function FoldingBook:toggle_pane(name, visible)
local pane = self:get_pane(name)
if pane then
if type(visible) == "boolean" then
pane.expanded = visible
else
pane.expanded = not pane.expanded
end
end
end
---Change the tab label of the given pane.
---@param name string
---@param label string
function FoldingBook: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
---@param color? renderer.color|nil
---@param hover_color? renderer.color|nil
function FoldingBook: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.
function FoldingBook:update()
if not FoldingBook.super.update(self) then return false end
---@type widget.foldingbook.pane
local prev_pane = nil
for _, pane in ipairs(self.panes) do
local tx, ty = 0, 10
local cx, cy = 0, 0
local cw, ch = 0, 0
if prev_pane then
if prev_pane and prev_pane.container:is_visible() then
ty = prev_pane.container:get_bottom() + 2
else
ty = prev_pane.tab:get_bottom() + 2
end
end
pane.tab:set_position(tx, ty)
cy = pane.tab:get_bottom() + 4
cw = self:get_width()
if #pane.container.childs > 0 then
ch = pane.container:get_real_height() + 10
end
pane.container.border.color = style.divider
if pane.expanded and not pane.container.hiding then
pane.container:set_position(cx, cy)
pane.container:set_size(cw)
if not pane.container.visible then
pane.container:set_size(cw, ch)
pane.container:show_animated(true)
pane.tab:set_icon("-")
pane.container.hiding = false
end
elseif pane.container.visible and not pane.container.hiding then
pane.tab:set_icon("+")
pane.container.hiding = true
pane.container:hide_animated(true, false, {
on_complete = function()
pane.container.hiding = false
end
})
end
prev_pane = pane
end
return true
end
---Here we draw the bottom line on each tab.
function FoldingBook:draw()
if not FoldingBook.super.draw(self) then return false end
for _, pane in ipairs(self.panes) do
local x = pane.tab.position.x
local y = pane.tab.position.y + pane.tab:get_height()
local w = self:get_width()
renderer.draw_rect(x, y, w, 2, style.selection)
end
return true
end
return FoldingBook