Hyprland/example/layouts/manual.lua
Vaxry 1681bea42d
config/lua: add simple layout API (#14258)
Adds a simple layout lua api
2026-05-06 13:56:12 +01:00

144 lines
3.8 KiB
Lua

local state = {
order = {},
split = {},
default_split = "h",
}
local function target_id(target)
local window = target.window
return window and tostring(window.stable_id) or tostring(target.index)
end
local function active_id(ctx)
for _, target in ipairs(ctx.targets) do
local window = target.window
if window and window.active then
return target_id(target)
end
end
return state.order[#state.order]
end
local function index_of(tbl, value)
for i, v in ipairs(tbl) do
if v == value then
return i
end
end
end
local function sync_order(ctx)
local present = {}
local targets = {}
for _, target in ipairs(ctx.targets) do
local id = target_id(target)
present[id] = true
targets[id] = target
end
local old_order = state.order
state.order = {}
for _, id in ipairs(old_order) do
if present[id] then
table.insert(state.order, id)
else
state.split[id] = nil
end
end
local focused = active_id(ctx)
for _, target in ipairs(ctx.targets) do
local id = target_id(target)
if not index_of(state.order, id) then
local after = focused and index_of(state.order, focused)
table.insert(state.order, after and (after + 1) or (#state.order + 1), id)
end
end
return targets
end
local function place_chain(ctx, targets, ids, area, i)
if i > #ids then
return
end
local target = targets[ids[i]]
if not target then
return
end
if i == #ids then
target:place(area)
return
end
local split = state.split[ids[i]] or state.default_split
if split == "v" then
target:place(ctx:split(area, "top", 0.5))
place_chain(ctx, targets, ids, ctx:split(area, "bottom", 0.5), i + 1)
else
target:place(ctx:split(area, "left", 0.5))
place_chain(ctx, targets, ids, ctx:split(area, "right", 0.5), i + 1)
end
end
local function move_active(ctx, delta)
local id = active_id(ctx)
local i = id and index_of(state.order, id)
local j = i and (i + delta)
if not i or j < 1 or j > #state.order then
return
end
state.order[i], state.order[j] = state.order[j], state.order[i]
end
hl.layout.register("manual", {
recalculate = function(ctx)
local targets = sync_order(ctx)
place_chain(ctx, targets, state.order, ctx.area, 1)
end,
layout_msg = function(ctx, msg)
local id = active_id(ctx)
local command = msg:match("^(%S+)")
if command == "splith" or command == "h" then
if id then
state.split[id] = "h"
end
elseif command == "splitv" or command == "v" then
if id then
state.split[id] = "v"
end
elseif command == "splittoggle" or command == "toggle" then
if id then
state.split[id] = state.split[id] == "v" and "h" or "v"
end
elseif command == "promote" then
local i = id and index_of(state.order, id)
if i then
table.remove(state.order, i)
table.insert(state.order, 1, id)
end
elseif command == "swapnext" then
move_active(ctx, 1)
elseif command == "swapprev" then
move_active(ctx, -1)
elseif command == "rotate" then
for k, v in pairs(state.split) do
state.split[k] = v == "v" and "h" or "v"
end
state.default_split = state.default_split == "v" and "h" or "v"
else
return "manual: expected splith, splitv, splittoggle, promote, swapnext, swapprev, or rotate"
end
return true
end,
})