-
Notifications
You must be signed in to change notification settings - Fork 2
/
init.xl.lua
253 lines (213 loc) · 7.46 KB
/
init.xl.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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
local core = require "core"
local config = require "core.config"
local common = require "core.common"
local command = require "core.command"
local View = require "core.view"
local style = require "core.style"
local RootView = require "core.rootview"
config.nagbar = true
config.nagbar_color = { common.color "#FF0000" }
config.nagbar_text_color = { common.color "#FFFFFF" }
config.nagbar_dim_color = { common.color "rgba(0, 0, 0, 0.45)" }
local BORDER_WIDTH = common.round(2 * SCALE)
local BORDER_PADDING = common.round(5 * SCALE)
local noop = function() end
local NagView = View:extend()
function NagView:new()
NagView.super.new(self)
self.size.y = 0
self.title = "Warning"
self.message = ""
self.options = {}
self.submit = noop
end
function NagView:get_title()
return self.title
end
function NagView:each_option()
return coroutine.wrap(function()
for i = #self.options, 1, -1 do
coroutine.yield(i, self.options[i])
end
end)
end
function NagView:get_options_height()
local max = 0
for _, opt in ipairs(self.options) do
local lh = style.font:get_height(opt.text)
if lh > max then max = lh end
end
return max
end
function NagView:get_line_height()
local maxlh = math.max(style.font:get_height(self.message), self:get_options_height())
return 2 * BORDER_WIDTH + 2 * BORDER_PADDING + maxlh + 2 * style.padding.y
end
function NagView:update()
NagView.super.update(self)
local dest = core.active_view == self and self:get_line_height() or 0
self:move_towards(self.size, "y", dest)
end
function NagView:draw_overlay()
local ox, oy = self:get_content_offset()
oy = oy + self.size.y
local w, h = core.root_view.size.x, core.root_view.size.y - oy
core.root_view:defer_draw(function()
renderer.draw_rect(ox, oy, w, h, config.nagbar_dim_color)
end)
end
function NagView:each_visible_option()
return coroutine.wrap(function()
local halfh = math.floor(self.size.y / 2)
local ox, oy = self:get_content_offset()
ox = ox + self.size.x - style.padding.x
for i, opt in self:each_option() do
local lw, lh = opt.font:get_width(opt.text), opt.font:get_height(opt.text)
local bw, bh = (lw + 2 * BORDER_WIDTH + 2 * BORDER_PADDING), (lh + 2 * BORDER_WIDTH + 2 * BORDER_PADDING)
local halfbh = math.floor(bh / 2)
local bx, by = math.max(0, ox - bw), math.max(0, oy + halfh - halfbh)
local fw, fh = bw - 2 * BORDER_WIDTH, bh - 2 * BORDER_WIDTH
local fx, fy = bx + BORDER_WIDTH, by + BORDER_WIDTH
coroutine.yield(i, opt, bx,by,bw,bh, fx,fy,fw,fh)
ox = ox - bw - style.padding.x
end
end)
end
function NagView:on_mouse_moved(mx, my, ...)
NagView.super.on_mouse_moved(self, mx, my, ...)
local selected = false
for i, _, x,y,w,h in self:each_visible_option() do
if mx >= x and my >= y and mx < x + w and my < y + h then
self.selected = i
selected = true
break
end
end
if not selected then self.selected = nil end
end
function NagView:on_mouse_pressed(...)
if not NagView.super.on_mouse_pressed(self, ...) and self.selected then
core.set_active_view(core.last_active_view, true)
self.submit(self.options[self.selected])
end
end
function NagView:draw()
if self.size.y <= 0 then return end
self:draw_overlay()
self:draw_background(config.nagbar_color)
-- draw message
local ox, oy = self:get_content_offset()
common.draw_text(style.font, config.nagbar_text_color, self.message, "left", ox + style.padding.x, oy, self.size.x, self.size.y)
-- draw buttons
for i, opt, bx,by,bw,bh, fx,fy,fw,fh in self:each_visible_option() do
local fill = i == self.selected and config.nagbar_text_color or config.nagbar_color
local text_color = i == self.selected and config.nagbar_color or config.nagbar_text_color
renderer.draw_rect(bx,by,bw,bh, config.nagbar_text_color)
if i ~= self.selected then
renderer.draw_rect(fx,fy,fw,fh, fill)
end
common.draw_text(opt.font, text_color, opt.text, "center", fx,fy,fw,fh)
end
end
function NagView:show(title, message, options, on_select, on_cancel)
self.title = title or "Warning"
self.message = message or "Empty?"
self.options = options or {}
if on_cancel then table.insert(options, { key = "cancel", font = style.icon_font, text = "x" }) end
self.submit = function(item)
self.submit = noop
if item.key == "cancel" and on_cancel then
on_cancel()
elseif on_select then
on_select(item)
end
end
core.set_active_view(self)
end
core.nagview = NagView()
function core.root_view:on_mouse_moved(...)
RootView.on_mouse_moved(self, ...)
if config.nagbar then
system.set_cursor("arrow")
end
end
function core.root_view:on_mouse_pressed(...)
if not config.nagbar then return RootView.on_mouse_pressed(self, ...) end
if core.active_view == core.nagview then
-- redirect all mouse click to nagview
core.nagview:on_mouse_pressed(...)
else
RootView.on_mouse_pressed(self, ...)
end
end
local last_view = core.active_view
-- this method prevents splitting non-leaf node error while preserving the tree structure
local node = RootView().root_node -- Node is not exported so we have to get it this way ;-;
node.is_primary_node = true
node:split("up", core.nagview, { y = true })
node.b:consume(core.root_view.root_node.a)
core.root_view.root_node.a = node
core.set_active_view(last_view)
local set_active_view = core.set_active_view
function core.set_active_view(view, override)
if not config.nagbar then return set_active_view(view) end
if core.active_view == core.nagview and not override then return end -- prevent stealing focus
set_active_view(view)
end
local function try_get_upvalue(fn, target)
local i = 1
while true do
local name, value = debug.getupvalue(fn, i)
if not name then break end
if name == target then return value end
i = i + 1
end
end
local run_threads = try_get_upvalue(core.run, "run_threads") or noop
local function step(idle_iterations, frame_duration) -- copied from lite-xl
core.frame_start = system.get_time()
local did_redraw = core.step()
local need_more_work = run_threads()
if core.restart_request then return end
if not did_redraw and not need_more_work then
idle_iterations = idle_iterations + 1
-- do not wait of events at idle_iterations = 1 to give a chance at core.step to run
-- and set "redraw" flag.
if idle_iterations > 1 then
if system.window_has_focus() then
-- keep running even with no events to make the cursor blinks
system.wait_event(frame_duration)
else
system.wait_event()
end
end
else
idle_iterations = 0
local elapsed = system.get_time() - core.frame_start
system.sleep(math.max(0, frame_duration - elapsed))
end
return idle_iterations
end
local show_confirm_dialog = system.show_confirm_dialog
function system.show_confirm_dialog(title, msg)
if not config.nagbar then return show_confirm_dialog(title, msg) end
local res
local opt = {
{ font = style.font, text = "Yes" },
{ font = style.font, text = "No" }
}
core.nagview:show(title, msg, opt, function(item)
res = item.text == "Yes"
end)
local idle_iterations, frame_duration = 0, 1 / config.fps
while res == nil do
idle_iterations = step(idle_iterations, frame_duration)
if not idle_iterations then return false end
end
return res
end
command.add(nil, {
["nagbar:disable"] = function() config.nagbar = false end,
["nagbar:enable"] = function() config.nagbar = true end,
["nagbar:toggle"] = function() config.nagbar = not config.nagbar end
})