my personal dotfiles managed by dotbot, zinit
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.

190 lines
6.6 KiB

--- === ModalMgr ===
---
--- Modal keybindings environment management. Just an wrapper of `hs.hotkey.modal`.
---
--- Download: [https://github.com/Hammerspoon/Spoons/raw/master/Spoons/ModalMgr.spoon.zip](https://github.com/Hammerspoon/Spoons/raw/master/Spoons/ModalMgr.spoon.zip)
local obj = {}
obj.__index = obj
-- Metadata
obj.name = "ModalMgr"
obj.version = "1.0"
obj.author = "ashfinal <[email protected]>"
obj.homepage = "https://github.com/Hammerspoon/Spoons"
obj.license = "MIT - https://opensource.org/licenses/MIT"
obj.modal_tray = nil
obj.which_key = nil
obj.modal_list = {}
obj.active_list = {}
obj.supervisor = nil
function obj:init()
hsupervisor_keys = hsupervisor_keys or {{"cmd", "shift", "ctrl"}, "Q"}
obj.supervisor = hs.hotkey.modal.new(hsupervisor_keys[1], hsupervisor_keys[2], 'Initialize Modal Environment')
obj.supervisor:bind(hsupervisor_keys[1], hsupervisor_keys[2], "Reset Modal Environment", function() obj.supervisor:exit() end)
hshelp_keys = hshelp_keys or {{"alt", "shift"}, "/"}
obj.supervisor:bind(hshelp_keys[1], hshelp_keys[2], "Toggle Help Panel", function() obj:toggleCheatsheet({all=obj.supervisor}) end)
obj.modal_tray = hs.canvas.new({x = 0, y = 0, w = 0, h = 0})
obj.modal_tray:level(hs.canvas.windowLevels.tornOffMenu)
obj.modal_tray[1] = {
type = "circle",
action = "fill",
fillColor = {hex = "#FFFFFF", alpha = 0.7},
}
obj.which_key = hs.canvas.new({x = 0, y = 0, w = 0, h = 0})
obj.which_key:level(hs.canvas.windowLevels.tornOffMenu)
obj.which_key[1] = {
type = "rectangle",
action = "fill",
fillColor = {hex = "#EEEEEE", alpha = 0.95},
roundedRectRadii = {xRadius = 10, yRadius = 10},
}
end
--- ModalMgr:new(id)
--- Method
--- Create a new modal keybindings environment
---
--- Parameters:
--- * id - A string specifying ID of new modal keybindings
function obj:new(id)
obj.modal_list[id] = hs.hotkey.modal.new()
end
--- ModalMgr:toggleCheatsheet([idList], [force])
--- Method
--- Toggle the cheatsheet display of current modal environments's keybindings.
---
--- Parameters:
--- * iterList - An table specifying IDs of modal environments or active_list. Optional, defaults to all active environments.
--- * force - A optional boolean value to force show cheatsheet, defaults to `nil` (automatically).
function obj:toggleCheatsheet(iterList, force)
if obj.which_key:isShowing() and not force then
obj.which_key:hide()
else
local cscreen = hs.screen.mainScreen()
local cres = cscreen:fullFrame()
obj.which_key:frame({
x = cres.x + cres.w / 5,
y = cres.y + cres.h / 5,
w = cres.w / 5 * 3,
h = cres.h / 5 * 3
})
local keys_pool = {}
local tmplist = iterList or obj.active_list
for i, v in pairs(tmplist) do
if type(v) == "string" then
-- It appears to be idList
for _, m in ipairs(obj.modal_list[v].keys) do
table.insert(keys_pool, m.msg)
end
elseif type(i) == "string" then
-- It appears to be active_list
for _, m in pairs(v.keys) do
table.insert(keys_pool, m.msg)
end
end
end
for idx, val in ipairs(keys_pool) do
if idx % 2 == 1 then
obj.which_key[idx + 1] = {
type = "text",
text = keys_pool[idx],
textFont = "Courier-Bold",
textSize = 16,
textColor = {hex = "#2390FF", alpha = 1},
textAlignment = "left",
frame = {
x = tostring(40 / (cres.w / 5 * 3)),
y = tostring((30 + (idx - math.ceil(idx / 2)) * math.ceil((cres.h / 5 * 3 - 60) / #keys_pool) * 2) / (cres.h / 5 * 3)),
w = tostring((1 - 80 / (cres.w / 5 * 3)) / 2),
h = tostring(math.ceil((cres.h / 5 * 3 - 60) / #keys_pool) * 2 / (cres.h / 5 * 3))
}
}
else
obj.which_key[idx + 1] = {
type = "text",
text = keys_pool[idx],
textFont = "Courier-Bold",
textSize = 16,
textColor = {hex = "#2390FF"},
textAlignment = "right",
frame = {
x = "50%",
y = tostring((30 + (idx - math.ceil(idx / 2) - 1) * math.ceil((cres.h / 5 * 3 - 60) / #keys_pool) * 2) / (cres.h / 5 * 3)),
w = tostring((1 - 80 / (cres.w / 5 * 3)) / 2),
h = tostring(math.ceil((cres.h / 5 * 3 - 60) / #keys_pool) * 2 / (cres.h / 5 * 3))
}
}
end
end
obj.which_key:show()
end
end
--- ModalMgr:activate(idList, [trayColor], [showKeys])
--- Method
--- Activate all modal environment in `idList`.
---
--- Parameters:
--- * idList - An table specifying IDs of modal environments
--- * trayColor - An optional string (e.g. #000000) specifying the color of modalTray, defaults to `nil`.
--- * showKeys - A optional boolean value to show all available keybindings, defaults to `nil`.
function obj:activate(idList, trayColor, showKeys)
for _, val in ipairs(idList) do
obj.modal_list[val]:enter()
obj.active_list[val] = obj.modal_list[val]
end
if trayColor then
local cscreen = hs.screen.mainScreen()
local cres = cscreen:fullFrame()
local lcres = cscreen:absoluteToLocal(cres)
obj.modal_tray:frame(cscreen:localToAbsolute{
x = cres.w - 40,
y = cres.h - 40,
w = 20,
h = 20
})
obj.modal_tray[1].fillColor = {hex = trayColor, alpha = 0.7}
obj.modal_tray:show()
end
if showKeys then
obj:toggleCheatsheet(idList, true)
end
end
--- ModalMgr:deactivate(idList)
--- Method
--- Deactivate modal environments in `idList`.
---
--- Parameters:
--- * idList - An table specifying IDs of modal environments
function obj:deactivate(idList)
for _, val in ipairs(idList) do
obj.modal_list[val]:exit()
obj.active_list[val] = nil
end
obj.modal_tray:hide()
for i = 2, #obj.which_key do
obj.which_key:removeElement(2)
end
obj.which_key:hide()
end
--- ModalMgr:deactivateAll()
--- Method
--- Deactivate all active modal environments.
---
function obj:deactivateAll()
obj:deactivate(obj.active_list)
end
return obj