You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
141 lines
4.1 KiB
141 lines
4.1 KiB
local M = { dsp = {} }
|
|
|
|
local GAPS <const> = { left = 6, top = 6, right = 6, bottom = 6 }
|
|
-- TARGET_POS:
|
|
-- | 0 | 1 | 2 |
|
|
-- | 3 | 4 | 5 |
|
|
-- | 6 | 7 | 8 |
|
|
local TARGET_POS <const> = 2
|
|
|
|
local WINDOW_SIZE <const> = { 960, 480 }
|
|
|
|
local WS_HIDE <const> = 'special:dropdown'
|
|
local TAG_NEW <const> = 'dropdownNew'
|
|
|
|
local windows = {}
|
|
local window_pos_cache = {}
|
|
local new_id = nil
|
|
|
|
hl.on('window.open', function (window)
|
|
for _, v in ipairs(window.tags) do
|
|
if v == TAG_NEW .. '*' and new_id then
|
|
windows[new_id] = window
|
|
hl.dispatch(hl.dsp.window.tag { tag = '-' .. TAG_NEW .. '*', window = window })
|
|
new_id = nil
|
|
return
|
|
end
|
|
end
|
|
end)
|
|
|
|
---@param cmd string
|
|
---@return string
|
|
local function generate_id(cmd)
|
|
local id = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
|
|
|
local id_idx = 1
|
|
local id_len = #id
|
|
for i = 1, #cmd do
|
|
local byteVal = string.byte(cmd, i)
|
|
id[id_idx] = id[id_idx] ~ byteVal
|
|
id_idx = id_idx % id_len + 1
|
|
end
|
|
|
|
-- human-readable id
|
|
--local CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
|
--local CHARS_LEN = #CHARS
|
|
--for i = 1, id_len do
|
|
-- local pos = id[i] % CHARS_LEN + 1
|
|
-- id[i] = CHARS:sub(pos, pos)
|
|
--end
|
|
for i = 1, id_len do
|
|
id[i] = string.char(id[i])
|
|
end
|
|
|
|
return table.concat(id)
|
|
end
|
|
|
|
---@param absolute boolean
|
|
---@return table
|
|
local function get_pos(absolute)
|
|
local m = hl.get_active_monitor()
|
|
if not m then return { 0, 0 } end
|
|
|
|
local pos = window_pos_cache[m.name]
|
|
if not pos then
|
|
local r = m.reserved
|
|
local dis_pos = absolute and { m.x + r.left, m.y + r.top } or { r.left, r.top }
|
|
local dis_width = (m.transform % 2 == 0 and m.width or m.height) // m.scale - r.left - r.right
|
|
local dis_height = (m.transform % 2 == 0 and m.height or m.width) // m.scale - r.top - r.bottom
|
|
local targetX = TARGET_POS % 3
|
|
local targetY = TARGET_POS // 3
|
|
pos = {
|
|
targetX == 0 and dis_pos[1] + GAPS.left or (
|
|
targetX == 1 and dis_pos[1] + (dis_width - WINDOW_SIZE[1]) // 2 or
|
|
dis_pos[1] + dis_width - GAPS.right - WINDOW_SIZE[1]
|
|
),
|
|
targetY == 0 and dis_pos[2] + GAPS.top or (
|
|
targetY == 1 and dis_pos[2] + (dis_height - WINDOW_SIZE[2]) // 2 or
|
|
dis_pos[2] + dis_height - GAPS.bottom - WINDOW_SIZE[2]
|
|
),
|
|
}
|
|
window_pos_cache[m.name] = pos
|
|
end
|
|
return pos
|
|
end
|
|
|
|
---@param window HL.Window
|
|
local function hide_window(window)
|
|
hl.dispatch(hl.dsp.window.pin { action = 'off', window = window })
|
|
--hl.dispatch(hl.dsp.window.move { x = POSITION_X, y = HIDDEN_X, relative = false, window = window })
|
|
hl.dispatch(hl.dsp.window.move { workspace = WS_HIDE, follow = false, window = window })
|
|
end
|
|
|
|
---@param window HL.Window
|
|
local function hide_others_and_show(window)
|
|
for _, w in pairs(windows) do
|
|
if w == window then
|
|
local pos = get_pos(true)
|
|
hl.dispatch(hl.dsp.window.move { workspace = 'm+0', follow = true, window = w })
|
|
hl.dispatch(hl.dsp.window.move { x = pos[1], y = pos[2], relative = false, window = w })
|
|
hl.dispatch(hl.dsp.window.pin { action = 'on', window = w })
|
|
else
|
|
hide_window(w)
|
|
end
|
|
end
|
|
end
|
|
|
|
---@param cmd string
|
|
function M.dsp.toggle(cmd)
|
|
assert(cmd)
|
|
return function ()
|
|
if new_id then return end
|
|
|
|
local id = generate_id(cmd)
|
|
local window = windows[id]
|
|
if window then
|
|
if hl.get_window(window) then
|
|
if window.pinned and window.monitor == hl.get_active_monitor() then
|
|
hide_window(window)
|
|
else
|
|
hide_others_and_show(window)
|
|
end
|
|
return
|
|
else
|
|
windows[id] = nil
|
|
end
|
|
end
|
|
|
|
hide_others_and_show(nil)
|
|
new_id = id
|
|
hl.exec_cmd(cmd, {
|
|
float = true,
|
|
size = WINDOW_SIZE,
|
|
move = get_pos(false),
|
|
pin = true,
|
|
tag = TAG_NEW,
|
|
animation = 'slide',
|
|
})
|
|
end
|
|
end
|
|
|
|
return M
|
|
|