diff --git a/dot_config/hypr/hyprland.d.lua/keybinds.lua.tmpl b/dot_config/hypr/hyprland.d.lua/keybinds.lua.tmpl index ae36117..3af29ed 100644 --- a/dot_config/hypr/hyprland.d.lua/keybinds.lua.tmpl +++ b/dot_config/hypr/hyprland.d.lua/keybinds.lua.tmpl @@ -86,7 +86,20 @@ hl.bind(mainMod .. " + SHIFT + O", hl.dsp.workspace.move({ monitor = "r" })) -- ─── Workspace layout state ─────────────────────────────────────────────────── local ws_layouts = {} -local ws_cycle_order = { "dwindle", "master", "scrolling", "monocle" } +_G._hl_ws_layouts = ws_layouts +local ws_cycle_order = { + "master", + "lua:master-scroll", + "lua:slave-master-scroll", + "lua:center-master-scroll", + "lua:top-master-scroll", + "lua:center-master-scroll-v", + "lua:master-swap", + "lua:slave-master-swap", + "lua:top-master-swap", + "scrolling", + "monocle", +} local function active_ws_id() local w = hl.get_active_window() @@ -107,7 +120,10 @@ local function set_ws_layout(layout) end local function ws_toggle_ms() - set_ws_layout(cur_ws_layout() == "master" and "scrolling" or "master") + local cur = cur_ws_layout() + -- Any master variant → scrolling; scrolling/monocle → master + local next = (cur == "scrolling" or cur == "monocle") and "master" or "scrolling" + set_ws_layout(next) end local function ws_cycle() diff --git a/dot_config/hypr/hyprland.d.lua/layout.lua b/dot_config/hypr/hyprland.d.lua/layout.lua index 68c5bb1..27b1dbc 100644 --- a/dot_config/hypr/hyprland.d.lua/layout.lua +++ b/dot_config/hypr/hyprland.d.lua/layout.lua @@ -401,41 +401,48 @@ hl.layout.register("center-master-scroll-v", { }) -- ─── Swap-on-focus layouts ──────────────────────────────────────────────────── --- Focusing any window promotes it to master; old master drops to slave area. --- One address slot per layout; all updated on every focus event (only the --- active layout's recalculate runs, so cross-pollution is harmless). +-- Focusing any window promotes it to master. recalculate reads the active +-- window directly via hl.get_active_window() — no external address tracking. -local swap_master_addr = nil -- shared: only one swap layout active at a time - -local function find_master_idx(targets, addr) - if addr then +local function swap_master_idx(targets) + local aw = hl.get_active_window() + if aw and aw.address then for i = 1, #targets do local w = targets[i].window - if w and w.address == addr then return i end + if w and w.address == aw.address then return i end end end return 1 end --- ─── master-swap: master left, slaves right ─────────────────────────────────── -hl.layout.register("master-swap", { - recalculate = function(ctx) - local targets = ctx.targets - local n = #targets - if n == 0 then return end - if n == 1 then targets[1]:place(ctx.area); return end - - local midx = find_master_idx(targets, swap_master_addr) - local slave_area = ctx:split(ctx.area, "right", 1.0 - mfact) - local master_area = { x=ctx.area.x, y=ctx.area.y, w=slave_area.x-ctx.area.x, h=ctx.area.h } - targets[midx]:place(master_area) - - local sidx = {} - for i = 1, n do if i ~= midx then sidx[#sidx+1] = i end end +local function swap_place_slaves(targets, midx, slave_area, vertical) + local sidx = {} + for i = 1, #targets do if i ~= midx then sidx[#sidx+1] = i end end + if #sidx == 0 then return end + if vertical then local h = slave_area.h / #sidx for j, si in ipairs(sidx) do targets[si]:place({ x=slave_area.x, y=slave_area.y+(j-1)*h, w=slave_area.w, h=h }) end + else + local w = slave_area.w / #sidx + for j, si in ipairs(sidx) do + targets[si]:place({ x=slave_area.x+(j-1)*w, y=slave_area.y, w=w, h=slave_area.h }) + end + end +end + +-- ─── master-swap: master left, slaves right ─────────────────────────────────── +hl.layout.register("master-swap", { + recalculate = function(ctx) + local targets, n = ctx.targets, #ctx.targets + if n == 0 then return end + if n == 1 then targets[1]:place(ctx.area); return end + local midx = swap_master_idx(targets) + local slave_area = ctx:split(ctx.area, "right", 1.0 - mfact) + local master_area = { x=ctx.area.x, y=ctx.area.y, w=slave_area.x-ctx.area.x, h=ctx.area.h } + targets[midx]:place(master_area) + swap_place_slaves(targets, midx, slave_area, true) end, layout_msg = function(_, msg) if msg == "recalc" then return true end @@ -447,25 +454,14 @@ hl.layout.register("master-swap", { -- ─── slave-master-swap: slaves left, master right ───────────────────────────── hl.layout.register("slave-master-swap", { recalculate = function(ctx) - local targets = ctx.targets - local n = #targets + local targets, n = ctx.targets, #ctx.targets if n == 0 then return end if n == 1 then targets[1]:place(ctx.area); return end - - local midx = find_master_idx(targets, swap_master_addr) - local slave_area = ctx:split(ctx.area, "left", 1.0 - mfact) - local master_area = { - x = slave_area.x + slave_area.w, y = ctx.area.y, - w = ctx.area.w - slave_area.w, h = ctx.area.h, - } + local midx = swap_master_idx(targets) + local slave_area = ctx:split(ctx.area, "left", 1.0 - mfact) + local master_area = { x=slave_area.x+slave_area.w, y=ctx.area.y, w=ctx.area.w-slave_area.w, h=ctx.area.h } targets[midx]:place(master_area) - - local sidx = {} - for i = 1, n do if i ~= midx then sidx[#sidx+1] = i end end - local h = slave_area.h / #sidx - for j, si in ipairs(sidx) do - targets[si]:place({ x=slave_area.x, y=slave_area.y+(j-1)*h, w=slave_area.w, h=h }) - end + swap_place_slaves(targets, midx, slave_area, true) end, layout_msg = function(_, msg) if msg == "recalc" then return true end @@ -477,22 +473,14 @@ hl.layout.register("slave-master-swap", { -- ─── top-master-swap: master top, slaves bottom row ─────────────────────────── hl.layout.register("top-master-swap", { recalculate = function(ctx) - local targets = ctx.targets - local n = #targets + local targets, n = ctx.targets, #ctx.targets if n == 0 then return end if n == 1 then targets[1]:place(ctx.area); return end - - local midx = find_master_idx(targets, swap_master_addr) - local slave_area = ctx:split(ctx.area, "bottom", 1.0 - mfact_v) + local midx = swap_master_idx(targets) + local slave_area = ctx:split(ctx.area, "bottom", 1.0 - mfact_v) local master_area = { x=ctx.area.x, y=ctx.area.y, w=ctx.area.w, h=slave_area.y-ctx.area.y } targets[midx]:place(master_area) - - local sidx = {} - for i = 1, n do if i ~= midx then sidx[#sidx+1] = i end end - local w = slave_area.w / #sidx - for j, si in ipairs(sidx) do - targets[si]:place({ x=slave_area.x+(j-1)*w, y=slave_area.y, w=w, h=slave_area.h }) - end + swap_place_slaves(targets, midx, slave_area, false) end, layout_msg = function(_, msg) if msg == "recalc" then return true end @@ -507,9 +495,6 @@ local all_col_states = { ms, sm, cm_left, cm_right, tm, cm_vtop, cm_vbot } hl.on("window.active", function(w) if w == nil or w.address == nil then return end - -- Promote focused window to master in any active swap layout - swap_master_addr = w.address - -- Auto-scroll: if the focused window is a peek slot, slide it into view for _, state in ipairs(all_col_states) do if w.address == state.peek_bottom_addr then @@ -519,9 +504,10 @@ hl.on("window.active", function(w) end end - -- For swap layouts (no scroll dispatched), trigger a recalculate. - -- Guard by name so built-in layouts never receive an unknown message. - local cur = hl.get_config("general.layout") + -- Trigger recalc for swap layouts so the focused window becomes master. + -- _G._hl_ws_layouts is set by keybinds.lua and tracks per-workspace layout. + local ws_id = w.workspace and w.workspace.id + local cur = ws_id and _G._hl_ws_layouts and _G._hl_ws_layouts[ws_id] if cur == "lua:master-swap" or cur == "lua:slave-master-swap" or cur == "lua:top-master-swap" then hl.dispatch(hl.dsp.layout("recalc")) end