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.
|
-- SCROLLS. Resizing up/down retunes the focused window's height weight.
|
||||||
-- Weights and per-column pan persist across relayouts.
|
-- 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 —
|
-- 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.
|
-- that one has a single shared tape; this pans each column apart.
|
||||||
--
|
--
|
||||||
|
|
@ -123,6 +128,11 @@ local function ws_state(wsid, area)
|
||||||
return s
|
return s
|
||||||
end
|
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.
|
-- Reflow every window evenly across the current column count, by insertion order.
|
||||||
local function reflow(s, targets)
|
local function reflow(s, targets)
|
||||||
local addrs = {}
|
local addrs = {}
|
||||||
|
|
@ -131,7 +141,13 @@ local function reflow(s, targets)
|
||||||
if ok and addr then addrs[#addrs + 1] = addr end
|
if ok and addr then addrs[#addrs + 1] = addr end
|
||||||
end
|
end
|
||||||
table.sort(addrs, function(a, b) return (s.seq[a] or 0) < (s.seq[b] or 0) 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
|
for k in pairs(s.pair) do s.pair[k] = nil end -- a redistribute breaks parked pairs
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -177,9 +193,18 @@ local function columnize(s, targets)
|
||||||
end
|
end
|
||||||
local fresh = {}
|
local fresh = {}
|
||||||
for addr in pairs(present) do if not s.assign[addr] then fresh[#fresh + 1] = addr end end
|
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 function least_col()
|
||||||
local best, bestn = 1, math.huge
|
local mid = mid_col(s)
|
||||||
for c = 1, s.ncols do if counts[c] < bestn then best, bestn = c, counts[c] end end
|
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
|
return best
|
||||||
end
|
end
|
||||||
if #fresh == 1 and next(s.assign) ~= nil then
|
if #fresh == 1 and next(s.assign) ~= nil then
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,11 @@
|
||||||
-- SCROLLS. Resizing up/down retunes the focused window's height weight.
|
-- SCROLLS. Resizing up/down retunes the focused window's height weight.
|
||||||
-- Weights and per-column pan persist across relayouts.
|
-- 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 —
|
-- 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.
|
-- that one has a single shared tape; this pans each column apart.
|
||||||
--
|
--
|
||||||
|
|
@ -123,6 +128,11 @@ local function ws_state(wsid, area)
|
||||||
return s
|
return s
|
||||||
end
|
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.
|
-- Reflow every window evenly across the current column count, by insertion order.
|
||||||
local function reflow(s, targets)
|
local function reflow(s, targets)
|
||||||
local addrs = {}
|
local addrs = {}
|
||||||
|
|
@ -131,7 +141,13 @@ local function reflow(s, targets)
|
||||||
if ok and addr then addrs[#addrs + 1] = addr end
|
if ok and addr then addrs[#addrs + 1] = addr end
|
||||||
end
|
end
|
||||||
table.sort(addrs, function(a, b) return (s.seq[a] or 0) < (s.seq[b] or 0) 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
|
for k in pairs(s.pair) do s.pair[k] = nil end -- a redistribute breaks parked pairs
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -177,9 +193,18 @@ local function columnize(s, targets)
|
||||||
end
|
end
|
||||||
local fresh = {}
|
local fresh = {}
|
||||||
for addr in pairs(present) do if not s.assign[addr] then fresh[#fresh + 1] = addr end end
|
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 function least_col()
|
||||||
local best, bestn = 1, math.huge
|
local mid = mid_col(s)
|
||||||
for c = 1, s.ncols do if counts[c] < bestn then best, bestn = c, counts[c] end end
|
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
|
return best
|
||||||
end
|
end
|
||||||
if #fresh == 1 and next(s.assign) ~= nil then
|
if #fresh == 1 and next(s.assign) ~= nil then
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue