feat(columns): open a workspace's first window in the middle column
least_col() now breaks count ties by nearness to the middle column, so the first window of a workspace (every column still empty) lands centred instead of pinned to the left edge, and a restored batch fans out from the middle. reflow() keeps a lone window in the middle too, so the menu's column stepper doesn't shove it back to the left. Applied identically to hyprlua and hyprdrive. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>main
parent
d5da519c9b
commit
d6cb0909ae
|
|
@ -17,6 +17,11 @@
|
|||
-- SCROLLS. Resizing up/down retunes the focused window's height weight.
|
||||
-- Weights and per-column pan persist across relayouts.
|
||||
--
|
||||
-- A workspace's FIRST window opens in the middle column (an even column count has no
|
||||
-- true middle — it takes the left of the two), so a lone window is centred rather than
|
||||
-- stuck against the left edge; further windows stack into the column you're working in
|
||||
-- and otherwise fill outward from the middle.
|
||||
--
|
||||
-- This is a real custom layout (hl.layout.register), not the built-in scrolling engine —
|
||||
-- that one has a single shared tape; this pans each column apart.
|
||||
--
|
||||
|
|
@ -123,6 +128,11 @@ local function ws_state(wsid, area)
|
|||
return s
|
||||
end
|
||||
|
||||
-- The MIDDLE column — where a workspace's first window lands, and the tie-break for
|
||||
-- every "emptiest column" pick, so a lone window sits centred on screen instead of pinned
|
||||
-- to the left edge. An even column count has no true middle; take the left of the two.
|
||||
local function mid_col(s) return math.floor((s.ncols + 1) / 2) end
|
||||
|
||||
-- Reflow every window evenly across the current column count, by insertion order.
|
||||
local function reflow(s, targets)
|
||||
local addrs = {}
|
||||
|
|
@ -131,7 +141,13 @@ local function reflow(s, targets)
|
|||
if ok and addr then addrs[#addrs + 1] = addr end
|
||||
end
|
||||
table.sort(addrs, function(a, b) return (s.seq[a] or 0) < (s.seq[b] or 0) end)
|
||||
for i, addr in ipairs(addrs) do s.assign[addr] = ((i - 1) % s.ncols) + 1 end
|
||||
if #addrs == 1 then
|
||||
-- a lone window keeps the middle (changing the column count from the menu
|
||||
-- shouldn't shove it to the left edge).
|
||||
s.assign[addrs[1]] = mid_col(s)
|
||||
else
|
||||
for i, addr in ipairs(addrs) do s.assign[addr] = ((i - 1) % s.ncols) + 1 end
|
||||
end
|
||||
for k in pairs(s.pair) do s.pair[k] = nil end -- a redistribute breaks parked pairs
|
||||
end
|
||||
|
||||
|
|
@ -177,9 +193,18 @@ local function columnize(s, targets)
|
|||
end
|
||||
local fresh = {}
|
||||
for addr in pairs(present) do if not s.assign[addr] then fresh[#fresh + 1] = addr end end
|
||||
-- emptiest column, ties broken by nearness to the middle — so the first window of a
|
||||
-- workspace (every column still empty) opens in the middle column, and a fresh batch
|
||||
-- fills outward from there rather than left-to-right.
|
||||
local function least_col()
|
||||
local best, bestn = 1, math.huge
|
||||
for c = 1, s.ncols do if counts[c] < bestn then best, bestn = c, counts[c] end end
|
||||
local mid = mid_col(s)
|
||||
local best, bestn, bestd = mid, math.huge, math.huge
|
||||
for c = 1, s.ncols do
|
||||
local d = math.abs(c - mid)
|
||||
if counts[c] < bestn or (counts[c] == bestn and d < bestd) then
|
||||
best, bestn, bestd = c, counts[c], d
|
||||
end
|
||||
end
|
||||
return best
|
||||
end
|
||||
if #fresh == 1 and next(s.assign) ~= nil then
|
||||
|
|
|
|||
|
|
@ -17,6 +17,11 @@
|
|||
-- SCROLLS. Resizing up/down retunes the focused window's height weight.
|
||||
-- Weights and per-column pan persist across relayouts.
|
||||
--
|
||||
-- A workspace's FIRST window opens in the middle column (an even column count has no
|
||||
-- true middle — it takes the left of the two), so a lone window is centred rather than
|
||||
-- stuck against the left edge; further windows stack into the column you're working in
|
||||
-- and otherwise fill outward from the middle.
|
||||
--
|
||||
-- This is a real custom layout (hl.layout.register), not the built-in scrolling engine —
|
||||
-- that one has a single shared tape; this pans each column apart.
|
||||
--
|
||||
|
|
@ -123,6 +128,11 @@ local function ws_state(wsid, area)
|
|||
return s
|
||||
end
|
||||
|
||||
-- The MIDDLE column — where a workspace's first window lands, and the tie-break for
|
||||
-- every "emptiest column" pick, so a lone window sits centred on screen instead of pinned
|
||||
-- to the left edge. An even column count has no true middle; take the left of the two.
|
||||
local function mid_col(s) return math.floor((s.ncols + 1) / 2) end
|
||||
|
||||
-- Reflow every window evenly across the current column count, by insertion order.
|
||||
local function reflow(s, targets)
|
||||
local addrs = {}
|
||||
|
|
@ -131,7 +141,13 @@ local function reflow(s, targets)
|
|||
if ok and addr then addrs[#addrs + 1] = addr end
|
||||
end
|
||||
table.sort(addrs, function(a, b) return (s.seq[a] or 0) < (s.seq[b] or 0) end)
|
||||
for i, addr in ipairs(addrs) do s.assign[addr] = ((i - 1) % s.ncols) + 1 end
|
||||
if #addrs == 1 then
|
||||
-- a lone window keeps the middle (changing the column count from the menu
|
||||
-- shouldn't shove it to the left edge).
|
||||
s.assign[addrs[1]] = mid_col(s)
|
||||
else
|
||||
for i, addr in ipairs(addrs) do s.assign[addr] = ((i - 1) % s.ncols) + 1 end
|
||||
end
|
||||
for k in pairs(s.pair) do s.pair[k] = nil end -- a redistribute breaks parked pairs
|
||||
end
|
||||
|
||||
|
|
@ -177,9 +193,18 @@ local function columnize(s, targets)
|
|||
end
|
||||
local fresh = {}
|
||||
for addr in pairs(present) do if not s.assign[addr] then fresh[#fresh + 1] = addr end end
|
||||
-- emptiest column, ties broken by nearness to the middle — so the first window of a
|
||||
-- workspace (every column still empty) opens in the middle column, and a fresh batch
|
||||
-- fills outward from there rather than left-to-right.
|
||||
local function least_col()
|
||||
local best, bestn = 1, math.huge
|
||||
for c = 1, s.ncols do if counts[c] < bestn then best, bestn = c, counts[c] end end
|
||||
local mid = mid_col(s)
|
||||
local best, bestn, bestd = mid, math.huge, math.huge
|
||||
for c = 1, s.ncols do
|
||||
local d = math.abs(c - mid)
|
||||
if counts[c] < bestn or (counts[c] == bestn and d < bestd) then
|
||||
best, bestn, bestd = c, counts[c], d
|
||||
end
|
||||
end
|
||||
return best
|
||||
end
|
||||
if #fresh == 1 and next(s.assign) ~= nil then
|
||||
|
|
|
|||
Loading…
Reference in New Issue