ratio: Add a fill strategy for empty entries
This allows, for example, to imeplement the tag `master_fill_policy` and simplify the client layouts by not having to hardcode empty columns and rows in each layouts.
This commit is contained in:
parent
731099ba4d
commit
0430f55257
|
@ -16,6 +16,7 @@ local pairs = pairs
|
||||||
local floor = math.floor
|
local floor = math.floor
|
||||||
local gmath = require("gears.math")
|
local gmath = require("gears.math")
|
||||||
local gtable = require("gears.table")
|
local gtable = require("gears.table")
|
||||||
|
local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1)
|
||||||
|
|
||||||
local ratio = {}
|
local ratio = {}
|
||||||
|
|
||||||
|
@ -78,15 +79,19 @@ local function normalize(self)
|
||||||
assert(new_sum > 0.99 and new_sum < 1.01)
|
assert(new_sum > 0.99 and new_sum < 1.01)
|
||||||
end
|
end
|
||||||
|
|
||||||
function ratio:layout(_, width, height)
|
function ratio:layout(context, width, height)
|
||||||
local result = {}
|
local preliminary_results = {}
|
||||||
local pos,spacing = 0, self._private.spacing
|
local pos,spacing = 0, self._private.spacing
|
||||||
|
local strategy = self:get_inner_fill_strategy()
|
||||||
|
local has_stragety = strategy ~= "default"
|
||||||
|
local to_redistribute, void_count = 0, 0
|
||||||
|
local dir = self._private.dir or "x"
|
||||||
|
|
||||||
for k, v in ipairs(self._private.widgets) do
|
for k, v in ipairs(self._private.widgets) do
|
||||||
local space
|
local space, is_void
|
||||||
local x, y, w, h
|
local x, y, w, h, fit_h, fit_w
|
||||||
|
|
||||||
if self._private.dir == "y" then
|
if dir == "y" then
|
||||||
space = height * self._private.ratios[k]
|
space = height * self._private.ratios[k]
|
||||||
x, y = 0, gmath.round(pos)
|
x, y = 0, gmath.round(pos)
|
||||||
w, h = width, floor(space)
|
w, h = width, floor(space)
|
||||||
|
@ -96,18 +101,75 @@ function ratio:layout(_, width, height)
|
||||||
w, h = floor(space), height
|
w, h = floor(space), height
|
||||||
end
|
end
|
||||||
|
|
||||||
table.insert(result, base.place_widget_at(v, x, y, w, h))
|
-- Keep track of the unused entries
|
||||||
|
if has_stragety then
|
||||||
|
fit_h, fit_w = base.fit_widget(
|
||||||
|
self, context, v,
|
||||||
|
dir == "x" and floor(space) or w,
|
||||||
|
dir == "y" and floor(space) or h
|
||||||
|
)
|
||||||
|
|
||||||
|
is_void = (v.visible == false)
|
||||||
|
or (dir == "x" and fit_w == 0)
|
||||||
|
or (dir == "y" and fit_h == 0)
|
||||||
|
|
||||||
|
if is_void then
|
||||||
|
to_redistribute = to_redistribute + space + spacing
|
||||||
|
void_count = void_count + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(preliminary_results, {v, x, y, w, h, is_void})
|
||||||
|
|
||||||
pos = pos + space + spacing
|
pos = pos + space + spacing
|
||||||
|
|
||||||
-- Make sure all widgets fit in the layout, if they aren't, something
|
-- Make sure all widgets fit in the layout, if they aren't, something
|
||||||
-- went wrong
|
-- went wrong
|
||||||
if (self._private.dir == "y" and gmath.round(pos) >= height) or
|
if (dir == "y" and gmath.round(pos) >= height) or
|
||||||
(self._private.dir ~= "y" and gmath.round(pos) >= width) then
|
(dir ~= "y" and gmath.round(pos) >= width) then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local active = #preliminary_results - void_count
|
||||||
|
local result, real_pos, space_front = {}, 0, strategy == "right" and
|
||||||
|
to_redistribute or (
|
||||||
|
strategy == "center" and math.floor(to_redistribute/2) or 0
|
||||||
|
)
|
||||||
|
|
||||||
|
-- The number of spaces between `n` element is `n-1`, if there is spaces
|
||||||
|
-- outside, then it is `n+1`
|
||||||
|
if strategy == "spacing" then
|
||||||
|
space_front = (space_front+to_redistribute/(active + 1))
|
||||||
|
to_redistribute = (to_redistribute/(active + 1))*(active - 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
spacing = strategy:match("spacing")
|
||||||
|
and to_redistribute/(active - 1) or 0
|
||||||
|
|
||||||
|
-- Only the `justify` strategy changes the original widget size.
|
||||||
|
to_redistribute = (strategy == "justify") and to_redistribute or 0
|
||||||
|
|
||||||
|
for _, entry in ipairs(preliminary_results) do
|
||||||
|
local v, x, y, w, h, is_void = unpack(entry)
|
||||||
|
|
||||||
|
-- Redistribute the space or move the widgets
|
||||||
|
if strategy ~= "default" then
|
||||||
|
if dir == "y" then
|
||||||
|
h = is_void and 0 or h + (to_redistribute / (active))
|
||||||
|
y = space_front + real_pos
|
||||||
|
real_pos = real_pos + h + (is_void and 0 or spacing)
|
||||||
|
|
||||||
|
else
|
||||||
|
w = is_void and 0 or w + (to_redistribute / (active))
|
||||||
|
x = space_front + real_pos
|
||||||
|
real_pos = real_pos + w + (is_void and 0 or spacing)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(result, base.place_widget_at(v, x, y, w, h))
|
||||||
|
end
|
||||||
|
|
||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -291,6 +353,44 @@ function ratio:insert(index, widget)
|
||||||
self:emit_signal("widget::inserted", widget, #self._private.widgets)
|
self:emit_signal("widget::inserted", widget, #self._private.widgets)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set how the space of invisible or `0x0` sized widget is redistributed.
|
||||||
|
--
|
||||||
|
-- Possible values:
|
||||||
|
--
|
||||||
|
-- * "default": Honor the ratio and do not redistribute the space.
|
||||||
|
-- * "justify": Distribute the space among remaining widgets.
|
||||||
|
-- * "center": Squash remaining widgets and leave equal space on both side.
|
||||||
|
-- * "inner_spacing": Add equal spacing between all widgets.
|
||||||
|
-- * "spacing": Add equal spacing between all widgets and on the outside.
|
||||||
|
-- * "left": Squash remaining widgets and leave empty space on the left.
|
||||||
|
-- * "right": Squash remaining widgets and leave empty space on the right.
|
||||||
|
--
|
||||||
|
--@DOC_wibox_layout_ratio_strategy_EXAMPLE@
|
||||||
|
--
|
||||||
|
-- @property inner_fill_strategy
|
||||||
|
-- @tparam string inner_fill_strategy One of the value listed above.
|
||||||
|
|
||||||
|
function ratio:get_inner_fill_strategy()
|
||||||
|
return self._private.inner_fill_strategy or "default"
|
||||||
|
end
|
||||||
|
|
||||||
|
local valid_strategies = {
|
||||||
|
default = true,
|
||||||
|
justify = true,
|
||||||
|
center = true,
|
||||||
|
inner_spacing = true,
|
||||||
|
spacing = true,
|
||||||
|
left = true,
|
||||||
|
right = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function ratio:set_inner_fill_strategy(strategy)
|
||||||
|
assert(valid_strategies[strategy] ~= nil, "Invalid strategy: "..(strategy or ""))
|
||||||
|
|
||||||
|
self._private.inner_fill_strategy = strategy
|
||||||
|
self:emit_signal("widget::layout_changed")
|
||||||
|
end
|
||||||
|
|
||||||
local function get_layout(dir, widget1, ...)
|
local function get_layout(dir, widget1, ...)
|
||||||
local ret = flex[dir](widget1, ...)
|
local ret = flex[dir](widget1, ...)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue