diff --git a/lib/wibox/container/mirror.lua b/lib/wibox/container/mirror.lua
index 5bae08e5b..bad0a1067 100644
--- a/lib/wibox/container/mirror.lua
+++ b/lib/wibox/container/mirror.lua
@@ -96,9 +96,9 @@ end
--- Get the reflection of this mirror layout.
-- @property reflection
--- @param table reflection A table of booleans with the keys "horizontal", "vertical".
--- @param boolean reflection.horizontal
--- @param boolean reflection.vertical
+-- @tparam table reflection A table of booleans with the keys "horizontal", "vertical".
+-- @tparam boolean reflection.horizontal
+-- @tparam boolean reflection.vertical
function mirror:get_reflection()
return { horizontal = self._private.horizontal, vertical = self._private.vertical }
diff --git a/lib/wibox/layout/ratio.lua b/lib/wibox/layout/ratio.lua
index 86a22547d..a3a30f822 100644
--- a/lib/wibox/layout/ratio.lua
+++ b/lib/wibox/layout/ratio.lua
@@ -16,6 +16,7 @@ local pairs = pairs
local floor = math.floor
local gmath = require("gears.math")
local gtable = require("gears.table")
+local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1)
local ratio = {}
@@ -78,15 +79,19 @@ local function normalize(self)
assert(new_sum > 0.99 and new_sum < 1.01)
end
-function ratio:layout(_, width, height)
- local result = {}
+function ratio:layout(context, width, height)
+ local preliminary_results = {}
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
- local space
- local x, y, w, h
+ local space, is_void
+ 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]
x, y = 0, gmath.round(pos)
w, h = width, floor(space)
@@ -96,24 +101,84 @@ function ratio:layout(_, width, height)
w, h = floor(space), height
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
-- Make sure all widgets fit in the layout, if they aren't, something
-- went wrong
- if (self._private.dir == "y" and gmath.round(pos) >= height) or
- (self._private.dir ~= "y" and gmath.round(pos) >= width) then
+ if (dir == "y" and gmath.round(pos) >= height) or
+ (dir ~= "y" and gmath.round(pos) >= width) then
break
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
end
--- Increase the ratio of "widget"
-- If the increment produce an invalid ratio (not between 0 and 1), the method
-- do nothing.
+--
+--@DOC_wibox_layout_ratio_inc_ratio_EXAMPLE@
+--
-- @tparam number index The widget index to change
-- @tparam number increment An floating point value between -1 and 1 where the
-- end result is within 0 and 1
@@ -187,7 +252,10 @@ function ratio:set_widget_ratio(widget, percent)
end
--- Update all widgets to match a set of a ratio.
--- The sum of before, itself and after must be 1 or nothing will be done
+-- The sum of before, itself and after must be 1 or nothing will be done.
+--
+--@DOC_wibox_layout_ratio_ajust_ratio_EXAMPLE@
+--
-- @tparam number index The index of the widget to change
-- @tparam number before The sum of the ratio before the widget
-- @tparam number itself The ratio for "widget"
@@ -291,6 +359,44 @@ function ratio:insert(index, widget)
self:emit_signal("widget::inserted", widget, #self._private.widgets)
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 ret = flex[dir](widget1, ...)
diff --git a/lib/wibox/layout/stack.lua b/lib/wibox/layout/stack.lua
index 19149b25a..7592c44d9 100644
--- a/lib/wibox/layout/stack.lua
+++ b/lib/wibox/layout/stack.lua
@@ -51,7 +51,8 @@ local stack = {mt={}}
-- @name remove_widgets
-- @class function
---- Add spacing between each layout widgets
+--- Add spacing around the widget, similar to the margin container.
+--@DOC_wibox_layout_stack_spacing_EXAMPLE@
-- @property spacing
-- @tparam number spacing Spacing between widgets.
@@ -59,8 +60,14 @@ function stack:layout(_, width, height)
local result = {}
local spacing = self._private.spacing
+ width = width - math.abs(self._private.h_offset * #self._private.widgets) - 2*spacing
+ height = height - math.abs(self._private.v_offset * #self._private.widgets) - 2*spacing
+
+ local h_off, v_off = spacing, spacing
+
for _, v in pairs(self._private.widgets) do
- table.insert(result, base.place_widget_at(v, spacing, spacing, width - 2*spacing, height - 2*spacing))
+ table.insert(result, base.place_widget_at(v, h_off, v_off, width, height))
+ h_off, v_off = h_off + self._private.h_offset, v_off + self._private.v_offset
if self._private.top_only then break end
end
@@ -121,6 +128,35 @@ function stack:raise_widget(widget, recursive)
end
end
+--- Add an horizontal offset to each layers.
+--
+-- Note that this reduces the overall size of each widgets by the sum of all
+-- layers offsets.
+--
+--@DOC_wibox_layout_stack_offset_EXAMPLE@
+--
+-- @property horizontal_offset
+-- @param number
+
+--- Add an vertical offset to each layers.
+--
+-- Note that this reduces the overall size of each widgets by the sum of all
+-- layers offsets.
+--
+-- @property vertial_offset
+-- @param number
+-- @see horizontal_offset
+
+function stack:set_horizontal_offset(value)
+ self._private.h_offset = value
+ self:emit_signal("widget::layout_changed")
+end
+
+function stack:set_vertical_offset(value)
+ self._private.v_offset = value
+ self:emit_signal("widget::layout_changed")
+end
+
--- Create a new stack layout.
-- @function wibox.layout.stack
-- @treturn widget A new stack layout
@@ -130,6 +166,9 @@ local function new(...)
gtable.crush(ret, stack, true)
+ ret._private.h_offset = 0
+ ret._private.v_offset = 0
+
return ret
end
diff --git a/tests/examples/shims/drawin.lua b/tests/examples/shims/drawin.lua
index ed06e2e67..689aba322 100644
--- a/tests/examples/shims/drawin.lua
+++ b/tests/examples/shims/drawin.lua
@@ -4,7 +4,7 @@ local drawin, meta = awesome._shim_fake_class()
local function new_drawin(_, args)
local ret = gears_obj()
- ret.data = {}
+ ret.data = {drawable = gears_obj()}
for k, v in pairs(args) do
rawset(ret, k, v)
diff --git a/tests/examples/wibox/layout/ratio/ajust_ratio.lua b/tests/examples/wibox/layout/ratio/ajust_ratio.lua
new file mode 100644
index 000000000..4e18ef8b5
--- /dev/null
+++ b/tests/examples/wibox/layout/ratio/ajust_ratio.lua
@@ -0,0 +1,48 @@
+local generic_widget = ... --DOC_HIDE
+local wibox = require("wibox") --DOC_HIDE
+local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1) --DOC_HIDE
+
+local first, second, third = generic_widget("first"), --DOC_HIDE
+ generic_widget("second"), generic_widget("third") --DOC_HIDE
+
+local ret = wibox.layout.fixed.vertical()
+
+local function create() --DOC_HIDE
+
+local w = wibox.widget {
+ first,
+ second,
+ third,
+ force_width = 200, --DOC_HIDE
+ layout = wibox.layout.ratio.horizontal
+}
+
+ return w --DOC_HIDE
+end --DOC_HIDE
+
+local values = {
+ {0.25, 0.50, 0.25},
+ {0.33, 0.55, 0.12},
+ {0.123, 0.456, 0.789},
+ {0.123, 0, 0.789},
+ {0, 1, 0},
+}
+
+for i=1, 5 do
+ ret:add(wibox.widget { --DOC_HIDE
+ markup = "Set " .. i ..":", --DOC_HIDE
+ widget = wibox.widget.textbox --DOC_HIDE
+ }) --DOC_HIDE
+
+ local w = create() --DOC_HIDE
+
+ for _=1, i do --DOC_HIDE
+ w:ajust_ratio(2, unpack(values[i]))
+ end --DOC_HIDE
+
+ ret:add(w) --DOC_HIDE
+end
+
+return ret, 200, 200 --DOC_HIDE
+
+--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/tests/examples/wibox/layout/ratio/inc_ratio.lua b/tests/examples/wibox/layout/ratio/inc_ratio.lua
new file mode 100644
index 000000000..f430eab4f
--- /dev/null
+++ b/tests/examples/wibox/layout/ratio/inc_ratio.lua
@@ -0,0 +1,39 @@
+local generic_widget = ... --DOC_HIDE
+local wibox = require("wibox") --DOC_HIDE
+
+local first, second, third = generic_widget("first"), --DOC_HIDE
+ generic_widget("second"), generic_widget("third") --DOC_HIDE
+
+local ret = wibox.layout.fixed.vertical()
+
+local function create() --DOC_HIDE
+
+local w = wibox.widget {
+ first,
+ second,
+ third,
+ force_width = 200, --DOC_HIDE
+ layout = wibox.layout.ratio.horizontal
+}
+
+ return w --DOC_HIDE
+end --DOC_HIDE
+
+for i=1, 5 do
+ ret:add(wibox.widget { --DOC_HIDE
+ markup = "Iteration " .. i ..":", --DOC_HIDE
+ widget = wibox.widget.textbox --DOC_HIDE
+ }) --DOC_HIDE
+
+ local w = create() --DOC_HIDE
+
+ for _=1, i do --DOC_HIDE
+ w:inc_ratio(2, 0.1)
+ end --DOC_HIDE
+
+ ret:add(w) --DOC_HIDE
+end
+
+return ret, 200, 200 --DOC_HIDE
+
+--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/tests/examples/wibox/layout/ratio/strategy.lua b/tests/examples/wibox/layout/ratio/strategy.lua
new file mode 100644
index 000000000..3079b585e
--- /dev/null
+++ b/tests/examples/wibox/layout/ratio/strategy.lua
@@ -0,0 +1,36 @@
+local generic_widget = ... --DOC_HIDE_ALL
+local wibox = require("wibox")
+
+local empty_width = wibox.widget {
+ visible = false
+}
+local first, third, fourth = generic_widget("first"), generic_widget("third"), generic_widget("fourth")
+
+local function add(tab, name)
+ table.insert(tab, {
+ markup = ""..name..":",
+ widget = wibox.widget.textbox
+ })
+ table.insert(tab, {
+ first,
+ empty_width,
+ third,
+ fourth,
+ inner_fill_strategy = name,
+ force_width = 200,
+ layout = wibox.layout.ratio.horizontal
+ })
+end
+
+local ret = {layout = wibox.layout.fixed.vertical}
+add(ret, "default")
+add(ret, "center")
+add(ret, "justify")
+add(ret, "inner_spacing")
+add(ret, "spacing")
+add(ret, "left")
+add(ret, "right")
+
+return wibox.widget(ret), 200, 250
+
+--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/tests/examples/wibox/layout/stack/offset.lua b/tests/examples/wibox/layout/stack/offset.lua
new file mode 100644
index 000000000..e1ef3a5ee
--- /dev/null
+++ b/tests/examples/wibox/layout/stack/offset.lua
@@ -0,0 +1,15 @@
+local generic_widget = ... --DOC_HIDE
+local wibox = require("wibox") --DOC_HIDE
+
+return --DOC_HIDE
+wibox.widget {
+ generic_widget( "first" ),
+ generic_widget( "second" ),
+ generic_widget( "third" ),
+ horizontal_offset = 5,
+ vertical_offset = 5,
+ layout = wibox.layout.stack
+}
+, 200, 50 --DOC_HIDE
+
+--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/tests/examples/wibox/layout/stack/spacing.lua b/tests/examples/wibox/layout/stack/spacing.lua
new file mode 100644
index 000000000..a0a99c453
--- /dev/null
+++ b/tests/examples/wibox/layout/stack/spacing.lua
@@ -0,0 +1,13 @@
+local generic_widget = ... --DOC_HIDE
+local wibox = require("wibox") --DOC_HIDE
+
+return --DOC_HIDE
+wibox.widget {
+ generic_widget( "first" ),
+ generic_widget( "second" ),
+ generic_widget( "third" ),
+ spacing = 6,
+ layout = wibox.layout.stack
+}
+
+--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80