From 22d656903563f75678f3634964731ccf93355dfd Mon Sep 17 00:00:00 2001 From: ache Date: Mon, 13 Mar 2017 23:17:19 +0100 Subject: Init commit --- lib/wibox/layout/align.lua | 526 ++++++++++++++++++++++++++++++++++++ lib/wibox/layout/constraint.lua | 17 ++ lib/wibox/layout/fixed.lua | 585 ++++++++++++++++++++++++++++++++++++++++ lib/wibox/layout/flex.lua | 429 +++++++++++++++++++++++++++++ lib/wibox/layout/init.lua | 23 ++ lib/wibox/layout/margin.lua | 17 ++ lib/wibox/layout/mirror.lua | 17 ++ lib/wibox/layout/ratio.lua | 583 +++++++++++++++++++++++++++++++++++++++ lib/wibox/layout/rotate.lua | 17 ++ lib/wibox/layout/scroll.lua | 16 ++ lib/wibox/layout/stack.lua | 402 +++++++++++++++++++++++++++ 11 files changed, 2632 insertions(+) create mode 100644 lib/wibox/layout/align.lua create mode 100644 lib/wibox/layout/constraint.lua create mode 100644 lib/wibox/layout/fixed.lua create mode 100644 lib/wibox/layout/flex.lua create mode 100644 lib/wibox/layout/init.lua create mode 100644 lib/wibox/layout/margin.lua create mode 100644 lib/wibox/layout/mirror.lua create mode 100644 lib/wibox/layout/ratio.lua create mode 100644 lib/wibox/layout/rotate.lua create mode 100644 lib/wibox/layout/scroll.lua create mode 100644 lib/wibox/layout/stack.lua (limited to 'lib/wibox/layout') diff --git a/lib/wibox/layout/align.lua b/lib/wibox/layout/align.lua new file mode 100644 index 0000000..92a5582 --- /dev/null +++ b/lib/wibox/layout/align.lua @@ -0,0 +1,526 @@ +--------------------------------------------------------------------------- +-- +-- +-- +--![Usage example](../images/AUTOGEN_wibox_layout_defaults_align.svg) +-- +-- @usage +--wibox.widget { +-- generic_widget( 'first' ), +-- generic_widget( 'second' ), +-- generic_widget( 'third' ), +-- layout = wibox.layout.align.horizontal +--} +-- @author Uli Schlachter +-- @copyright 2010 Uli Schlachter +-- @classmod wibox.layout.align +--------------------------------------------------------------------------- + +local table = table +local pairs = pairs +local type = type +local floor = math.floor +local util = require("awful.util") +local base = require("wibox.widget.base") + +local align = {} + +-- Calculate the layout of an align layout. +-- @param context The context in which we are drawn. +-- @param width The available width. +-- @param height The available height. +function align:layout(context, width, height) + local result = {} + + -- Draw will have to deal with all three align modes and should work in a + -- way that makes sense if one or two of the widgets are missing (if they + -- are all missing, it won't draw anything.) It should also handle the case + -- where the fit something that isn't set to expand (for instance the + -- outside widgets when the expand mode is "inside" or any of the widgets + -- when the expand mode is "none" wants to take up more space than is + -- allowed. + local size_first = 0 + -- start with all the space given by the parent, subtract as we go along + local size_remains = self._private.dir == "y" and height or width + -- This is only set & used if expand ~= "inside" and we have second width. + -- It contains the size allocated to the second widget. + local size_second + + -- we will prioritize the middle widget unless the expand mode is "inside" + -- if it is, we prioritize the first widget by not doing this block also, + -- if the second widget doesn't exist, we will prioritise the first one + -- instead + if self._private.expand ~= "inside" and self._private.second then + local w, h = base.fit_widget(self, context, self._private.second, width, height) + size_second = self._private.dir == "y" and h or w + -- if all the space is taken, skip the rest, and draw just the middle + -- widget + if size_second >= size_remains then + return { base.place_widget_at(self._private.second, 0, 0, width, height) } + else + -- the middle widget is sized first, the outside widgets are given + -- the remaining space if available we will draw later + size_remains = floor((size_remains - size_second) / 2) + end + end + if self._private.first then + local w, h, _ = width, height, nil + -- we use the fit function for the "inside" and "none" modes, but + -- ignore it for the "outside" mode, which will force it to expand + -- into the remaining space + if self._private.expand ~= "outside" then + if self._private.dir == "y" then + _, h = base.fit_widget(self, context, self._private.first, width, size_remains) + size_first = h + -- for "inside", the third widget will get a chance to use the + -- remaining space, then the middle widget. For "none" we give + -- the third widget the remaining space if there was no second + -- widget to take up any space (as the first if block is skipped + -- if this is the case) + if self._private.expand == "inside" or not self._private.second then + size_remains = size_remains - h + end + else + w, _ = base.fit_widget(self, context, self._private.first, size_remains, height) + size_first = w + if self._private.expand == "inside" or not self._private.second then + size_remains = size_remains - w + end + end + else + if self._private.dir == "y" then + h = size_remains + else + w = size_remains + end + end + table.insert(result, base.place_widget_at(self._private.first, 0, 0, w, h)) + end + -- size_remains will be <= 0 if first used all the space + if self._private.third and size_remains > 0 then + local w, h, _ = width, height, nil + if self._private.expand ~= "outside" then + if self._private.dir == "y" then + _, h = base.fit_widget(self, context, self._private.third, width, size_remains) + -- give the middle widget the rest of the space for "inside" mode + if self._private.expand == "inside" then + size_remains = size_remains - h + end + else + w, _ = base.fit_widget(self, context, self._private.third, size_remains, height) + if self._private.expand == "inside" then + size_remains = size_remains - w + end + end + else + if self._private.dir == "y" then + h = size_remains + else + w = size_remains + end + end + local x, y = width - w, height - h + table.insert(result, base.place_widget_at(self._private.third, x, y, w, h)) + end + -- here we either draw the second widget in the space set aside for it + -- in the beginning, or in the remaining space, if it is "inside" + if self._private.second and size_remains > 0 then + local x, y, w, h = 0, 0, width, height + if self._private.expand == "inside" then + if self._private.dir == "y" then + h = size_remains + x, y = 0, size_first + else + w = size_remains + x, y = size_first, 0 + end + else + local _ + if self._private.dir == "y" then + _, h = base.fit_widget(self, context, self._private.second, width, size_second) + y = floor( (height - h)/2 ) + else + w, _ = base.fit_widget(self, context, self._private.second, size_second, height) + x = floor( (width -w)/2 ) + end + end + table.insert(result, base.place_widget_at(self._private.second, x, y, w, h)) + end + return result +end + +--- Set the layout's first widget. +-- This is the widget that is at the left/top +-- @property first + +function align:set_first(widget) + if self._private.first == widget then + return + end + self._private.first = widget + self:emit_signal("widget::layout_changed") +end + +--- Set the layout's second widget. This is the centered one. +-- @property second + +function align:set_second(widget) + if self._private.second == widget then + return + end + self._private.second = widget + self:emit_signal("widget::layout_changed") +end + +--- Set the layout's third widget. +-- This is the widget that is at the right/bottom +-- @property third + +function align:set_third(widget) + if self._private.third == widget then + return + end + self._private.third = widget + self:emit_signal("widget::layout_changed") +end + +for _, prop in ipairs {"first", "second", "third", "expand" } do + align["get_"..prop] = function(self) + return self._private[prop] + end +end + +--- All direct children of this layout. +-- This can be used to replace all 3 widgets at once. +-- @treturn table a list of all widgets +-- @property children + +function align:get_children() + return util.from_sparse {self._private.first, self._private.second, self._private.third} +end + +function align:set_children(children) + self:set_first(children[1]) + self:set_second(children[2]) + self:set_third(children[3]) +end + +-- Fit the align layout into the given space. The align layout will +-- ask for the sum of the sizes of its sub-widgets in its direction +-- and the largest sized sub widget in the other direction. +-- @param context The context in which we are fit. +-- @param orig_width The available width. +-- @param orig_height The available height. +function align:fit(context, orig_width, orig_height) + local used_in_dir = 0 + local used_in_other = 0 + + for _, v in pairs{self._private.first, self._private.second, self._private.third} do + local w, h = base.fit_widget(self, context, v, orig_width, orig_height) + + local max = self._private.dir == "y" and w or h + if max > used_in_other then + used_in_other = max + end + + used_in_dir = used_in_dir + (self._private.dir == "y" and h or w) + end + + if self._private.dir == "y" then + return used_in_other, used_in_dir + end + return used_in_dir, used_in_other +end + +--- Set the expand mode which determines how sub widgets expand to take up +-- unused space. +-- +-- @tparam[opt=inside] string mode How to use unused space. +-- +-- * "inside" - Default option. Size of outside widgets is determined using +-- their fit function. Second, middle, or center widget expands to fill +-- remaining space. +-- * "outside" - Center widget is sized using its fit function and placed in +-- the center of the allowed space. Outside widgets expand (or contract) to +-- fill remaining space on their side. +-- * "none" - All widgets are sized using their fit function, drawn to only the +-- returned space, or remaining space, whichever is smaller. Center widget +-- gets priority. +-- @property expand + +function align:set_expand(mode) + if mode == "none" or mode == "outside" then + self._private.expand = mode + else + self._private.expand = "inside" + end + self:emit_signal("widget::layout_changed") +end + +function align:reset() + for _, v in pairs({ "first", "second", "third" }) do + self[v] = nil + end + self:emit_signal("widget::layout_changed") +end + +local function get_layout(dir, first, second, third) + local ret = base.make_widget(nil, nil, {enable_properties = true}) + ret._private.dir = dir + + for k, v in pairs(align) do + if type(v) == "function" then + rawset(ret, k, v) + end + end + + ret:set_expand("inside") + ret:set_first(first) + ret:set_second(second) + ret:set_third(third) + + -- An align layout allow set_children to have empty entries + ret.allow_empty_widget = true + + return ret +end + +--- Returns a new horizontal align layout. An align layout can display up to +-- three widgets. The widget set via :set_left() is left-aligned. :set_right() +-- sets a widget which will be right-aligned. The remaining space between those +-- two will be given to the widget set via :set_middle(). +-- @tparam[opt] widget left Widget to be put to the left. +-- @tparam[opt] widget middle Widget to be put to the middle. +-- @tparam[opt] widget right Widget to be put to the right. +function align.horizontal(left, middle, right) + local ret = get_layout("x", left, middle, right) + + rawset(ret, "set_left" , ret.set_first ) + rawset(ret, "set_middle", ret.set_second ) + rawset(ret, "set_right" , ret.set_third ) + + return ret +end + +--- Returns a new vertical align layout. An align layout can display up to +-- three widgets. The widget set via :set_top() is top-aligned. :set_bottom() +-- sets a widget which will be bottom-aligned. The remaining space between those +-- two will be given to the widget set via :set_middle(). +-- @tparam[opt] widget top Widget to be put to the top. +-- @tparam[opt] widget middle Widget to be put to the middle. +-- @tparam[opt] widget bottom Widget to be put to the right. +function align.vertical(top, middle, bottom) + local ret = get_layout("y", top, middle, bottom) + + rawset(ret, "set_top" , ret.set_first ) + rawset(ret, "set_middle", ret.set_second ) + rawset(ret, "set_bottom", ret.set_third ) + + return ret +end + +--Imported documentation + + +--- Get a widex index. +-- @param widget The widget to look for +-- @param[opt] recursive Also check sub-widgets +-- @param[opt] ... Aditional widgets to add at the end of the \"path\" +-- @return The index +-- @return The parent layout +-- @return The path between \"self\" and \"widget\" +-- @function index + +--- Get all direct and indirect children widgets. +-- This will scan all containers recursively to find widgets +-- Warning: This method it prone to stack overflow id the widget, or any of its +-- children, contain (directly or indirectly) itself. +-- @treturn table The children +-- @function get_all_children + +--- Set a declarative widget hierarchy description. +-- See [The declarative layout system](../documentation/03-declarative-layout.md.html) +-- @param args An array containing the widgets disposition +-- @function setup + +--- Force a widget height. +-- @property forced_height +-- @tparam number|nil height The height (`nil` for automatic) + +--- Force a widget width. +-- @property forced_width +-- @tparam number|nil width The width (`nil` for automatic) + +--- The widget opacity (transparency). +-- @property opacity +-- @tparam[opt=1] number opacity The opacity (between 0 and 1) + +--- The widget visibility. +-- @property visible +-- @param boolean + +--- Set/get a widget's buttons. +-- @param _buttons The table of buttons that should bind to the widget. +-- @function buttons + +--- Emit a signal and ensure all parent widgets in the hierarchies also +-- forward the signal. This is useful to track signals when there is a dynamic +-- set of containers and layouts wrapping the widget. +-- @tparam string signal_name +-- @param ... Other arguments +-- @function emit_signal_recursive + +--- When the layout (size) change. +-- This signal is emitted when the previous results of `:layout()` and `:fit()` +-- are no longer valid. Unless this signal is emitted, `:layout()` and `:fit()` +-- must return the same result when called with the same arguments. +-- @signal widget::layout_changed +-- @see widget::redraw_needed + +--- When the widget content changed. +-- This signal is emitted when the content of the widget changes. The widget will +-- be redrawn, it is not re-layouted. Put differently, it is assumed that +-- `:layout()` and `:fit()` would still return the same results as before. +-- @signal widget::redraw_needed +-- @see widget::layout_changed + +--- When a mouse button is pressed over the widget. +-- @signal button::press +-- @tparam number lx The horizontal position relative to the (0,0) position in +-- the widget. +-- @tparam number ly The vertical position relative to the (0,0) position in the +-- widget. +-- @tparam number button The button number. +-- @tparam table mods The modifiers (mod4, mod1 (alt), Control, Shift) +-- @tparam table find_widgets_result The entry from the result of +-- @{wibox.drawable:find_widgets} for the position that the mouse hit. +-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing +-- the widget. +-- @tparam widget find_widgets_result.widget The widget being displayed. +-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy +-- managing the widget's geometry. +-- @tparam number find_widgets_result.x An approximation of the X position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.y An approximation of the Y position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.width An approximation of the width that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.height An approximation of the height that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.widget_width The exact width of the widget +-- in its local coordinate system. +-- @tparam number find_widgets_result.widget_height The exact height of the widget +-- in its local coordinate system. +-- @see mouse + +--- When a mouse button is released over the widget. +-- @signal button::release +-- @tparam number lx The horizontal position relative to the (0,0) position in +-- the widget. +-- @tparam number ly The vertical position relative to the (0,0) position in the +-- widget. +-- @tparam number button The button number. +-- @tparam table mods The modifiers (mod4, mod1 (alt), Control, Shift) +-- @tparam table find_widgets_result The entry from the result of +-- @{wibox.drawable:find_widgets} for the position that the mouse hit. +-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing +-- the widget. +-- @tparam widget find_widgets_result.widget The widget being displayed. +-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy +-- managing the widget's geometry. +-- @tparam number find_widgets_result.x An approximation of the X position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.y An approximation of the Y position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.width An approximation of the width that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.height An approximation of the height that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.widget_width The exact width of the widget +-- in its local coordinate system. +-- @tparam number find_widgets_result.widget_height The exact height of the widget +-- in its local coordinate system. +-- @see mouse + +--- When the mouse enter a widget. +-- @signal mouse::enter +-- @tparam table find_widgets_result The entry from the result of +-- @{wibox.drawable:find_widgets} for the position that the mouse hit. +-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing +-- the widget. +-- @tparam widget find_widgets_result.widget The widget being displayed. +-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy +-- managing the widget's geometry. +-- @tparam number find_widgets_result.x An approximation of the X position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.y An approximation of the Y position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.width An approximation of the width that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.height An approximation of the height that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.widget_width The exact width of the widget +-- in its local coordinate system. +-- @tparam number find_widgets_result.widget_height The exact height of the widget +-- in its local coordinate system. +-- @see mouse + +--- When the mouse leave a widget. +-- @signal mouse::leave +-- @tparam table find_widgets_result The entry from the result of +-- @{wibox.drawable:find_widgets} for the position that the mouse hit. +-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing +-- the widget. +-- @tparam widget find_widgets_result.widget The widget being displayed. +-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy +-- managing the widget's geometry. +-- @tparam number find_widgets_result.x An approximation of the X position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.y An approximation of the Y position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.width An approximation of the width that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.height An approximation of the height that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.widget_width The exact width of the widget +-- in its local coordinate system. +-- @tparam number find_widgets_result.widget_height The exact height of the widget +-- in its local coordinate system. +-- @see mouse + + +--Imported documentation + + +--- Disconnect to a signal. +-- @tparam string name The name of the signal +-- @tparam function func The callback that should be disconnected +-- @function disconnect_signal + +--- Emit a signal. +-- +-- @tparam string name The name of the signal +-- @param ... Extra arguments for the callback functions. Each connected +-- function receives the object as first argument and then any extra arguments +-- that are given to emit_signal() +-- @function emit_signal + +--- Connect to a signal. +-- @tparam string name The name of the signal +-- @tparam function func The callback to call when the signal is emitted +-- @function connect_signal + +--- Connect to a signal weakly. This allows the callback function to be garbage +-- collected and automatically disconnects the signal when that happens. +-- +-- **Warning:** +-- Only use this function if you really, really, really know what you +-- are doing. +-- @tparam string name The name of the signal +-- @tparam function func The callback to call when the signal is emitted +-- @function weak_connect_signal + + +return align + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/lib/wibox/layout/constraint.lua b/lib/wibox/layout/constraint.lua new file mode 100644 index 0000000..5333b38 --- /dev/null +++ b/lib/wibox/layout/constraint.lua @@ -0,0 +1,17 @@ +--------------------------------------------------------------------------- +-- This class has been moved to `wibox.container.` +-- +-- @author Lukáš Hrázký +-- @copyright 2012 Lukáš Hrázký +-- @classmod wibox.layout.constraint +--------------------------------------------------------------------------- + +local util = require("awful.util") + +return util.deprecate_class( + require("wibox.container.constraint"), + "wibox.layout.constraint", + "wibox.container.constraint" +) + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/lib/wibox/layout/fixed.lua b/lib/wibox/layout/fixed.lua new file mode 100644 index 0000000..7258438 --- /dev/null +++ b/lib/wibox/layout/fixed.lua @@ -0,0 +1,585 @@ +--------------------------------------------------------------------------- +-- +-- +-- +--![Usage example](../images/AUTOGEN_wibox_layout_defaults_fixed.svg) +-- +-- @usage +--wibox.widget { +-- generic_widget( 'first' ), +-- generic_widget( 'second' ), +-- generic_widget( 'third' ), +-- layout = wibox.layout.fixed.horizontal +--} +-- @author Uli Schlachter +-- @copyright 2010 Uli Schlachter +-- @classmod wibox.layout.fixed +--------------------------------------------------------------------------- + +local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1) +local base = require("wibox.widget.base") +local table = table +local pairs = pairs +local util = require("awful.util") + +local fixed = {} + +--Imported documentation + +--- Set a widget at a specific index, replace the current one. +-- **Signal:** widget::replaced The argument is the new widget and the old one +-- and the index. +-- @tparam number index A widget or a widget index +-- @param widget2 The widget to take the place of the first one +-- @treturn boolean If the operation is successful +-- @name set +-- @class function + +--- Replace the first instance of `widget` in the layout with `widget2`. +-- **Signal:** widget::replaced The argument is the new widget and the old one +-- and the index. +-- @param widget The widget to replace +-- @param widget2 The widget to replace `widget` with +-- @tparam[opt=false] boolean recursive Digg in all compatible layouts to find the widget. +-- @treturn boolean If the operation is successful +-- @name replace_widget +-- @class function + +--- Swap 2 widgets in a layout. +-- **Signal:** widget::swapped The arguments are both widgets and both (new) indexes. +-- @tparam number index1 The first widget index +-- @tparam number index2 The second widget index +-- @treturn boolean If the operation is successful +-- @name swap +-- @class function + +--- Swap 2 widgets in a layout. +-- If widget1 is present multiple time, only the first instance is swapped +-- **Signal:** widget::swapped The arguments are both widgets and both (new) indexes. +-- if the layouts not the same, then only `widget::replaced` will be emitted. +-- @param widget1 The first widget +-- @param widget2 The second widget +-- @tparam[opt=false] boolean recursive Digg in all compatible layouts to find the widget. +-- @treturn boolean If the operation is successful +-- @name swap_widgets +-- @class function + +--- Get all direct children of this layout. +-- @param layout The layout you are modifying. +-- @property children + +--- Reset a ratio layout. This removes all widgets from the layout. +-- **Signal:** widget::reset +-- @param layout The layout you are modifying. +-- @name reset +-- @class function + + +-- Layout a fixed layout. Each widget gets just the space it asks for. +-- @param context The context in which we are drawn. +-- @param width The available width. +-- @param height The available height. +function fixed:layout(context, width, height) + local result = {} + local pos,spacing = 0, self._private.spacing + + for k, v in pairs(self._private.widgets) do + local x, y, w, h, _ + if self._private.dir == "y" then + x, y = 0, pos + w, h = width, height - pos + if k ~= #self._private.widgets or not self._private.fill_space then + _, h = base.fit_widget(self, context, v, w, h); + end + pos = pos + h + spacing + else + x, y = pos, 0 + w, h = width - pos, height + if k ~= #self._private.widgets or not self._private.fill_space then + w, _ = base.fit_widget(self, context, v, w, h); + end + pos = pos + w + spacing + end + + if (self._private.dir == "y" and pos-spacing > height) or + (self._private.dir ~= "y" and pos-spacing > width) then + break + end + table.insert(result, base.place_widget_at(v, x, y, w, h)) + end + return result +end + +--- Add some widgets to the given fixed layout +-- @param ... Widgets that should be added (must at least be one) +function fixed:add(...) + -- No table.pack in Lua 5.1 :-( + local args = { n=select('#', ...), ... } + assert(args.n > 0, "need at least one widget to add") + for i=1, args.n do + base.check_widget(args[i]) + table.insert(self._private.widgets, args[i]) + end + self:emit_signal("widget::layout_changed") +end + + +--- Remove a widget from the layout +-- @tparam number index The widget index to remove +-- @treturn boolean index If the operation is successful +function fixed:remove(index) + if not index or index < 1 or index > #self._private.widgets then return false end + + table.remove(self._private.widgets, index) + + self:emit_signal("widget::layout_changed") + + return true +end + +--- Remove one or more widgets from the layout +-- The last parameter can be a boolean, forcing a recursive seach of the +-- widget(s) to remove. +-- @param widget ... Widgets that should be removed (must at least be one) +-- @treturn boolean If the operation is successful +function fixed:remove_widgets(...) + local args = { ... } + + local recursive = type(args[#args]) == "boolean" and args[#args] + + local ret = true + for k, rem_widget in ipairs(args) do + if recursive and k == #args then break end + + local idx, l = self:index(rem_widget, recursive) + + if idx and l and l.remove then + l:remove(idx, false) + else + ret = false + end + + end + + return #args > (recursive and 1 or 0) and ret +end + +function fixed:get_children() + return self._private.widgets +end + +function fixed:set_children(children) + self:reset() + if #children > 0 then + self:add(unpack(children)) + end +end + +--- Replace the first instance of `widget` in the layout with `widget2` +-- @param widget The widget to replace +-- @param widget2 The widget to replace `widget` with +-- @tparam[opt=false] boolean recursive Digg in all compatible layouts to find the widget. +-- @treturn boolean If the operation is successful +function fixed:replace_widget(widget, widget2, recursive) + local idx, l = self:index(widget, recursive) + + if idx and l then + l:set(idx, widget2) + return true + end + + return false +end + +function fixed:swap(index1, index2) + if not index1 or not index2 or index1 > #self._private.widgets + or index2 > #self._private.widgets then + return false + end + + local widget1, widget2 = self._private.widgets[index1], self._private.widgets[index2] + + self:set(index1, widget2) + self:set(index2, widget1) + + self:emit_signal("widget::swapped", widget1, widget2, index2, index1) + + return true +end + +function fixed:swap_widgets(widget1, widget2, recursive) + base.check_widget(widget1) + base.check_widget(widget2) + + local idx1, l1 = self:index(widget1, recursive) + local idx2, l2 = self:index(widget2, recursive) + + if idx1 and l1 and idx2 and l2 and (l1.set or l1.set_widget) and (l2.set or l2.set_widget) then + if l1.set then + l1:set(idx1, widget2) + if l1 == self then + self:emit_signal("widget::swapped", widget1, widget2, idx2, idx1) + end + elseif l1.set_widget then + l1:set_widget(widget2) + end + if l2.set then + l2:set(idx2, widget1) + if l2 == self then + self:emit_signal("widget::swapped", widget1, widget2, idx2, idx1) + end + elseif l2.set_widget then + l2:set_widget(widget1) + end + + return true + end + + return false +end + +function fixed:set(index, widget2) + if (not widget2) or (not self._private.widgets[index]) then return false end + + base.check_widget(widget2) + + local w = self._private.widgets[index] + + self._private.widgets[index] = widget2 + + self:emit_signal("widget::layout_changed") + self:emit_signal("widget::replaced", widget2, w, index) + + return true +end + +--- Insert a new widget in the layout at position `index` +-- **Signal:** widget::inserted The arguments are the widget and the index +-- @tparam number index The position +-- @param widget The widget +-- @treturn boolean If the operation is successful +function fixed:insert(index, widget) + if not index or index < 1 or index > #self._private.widgets + 1 then return false end + + base.check_widget(widget) + table.insert(self._private.widgets, index, widget) + self:emit_signal("widget::layout_changed") + self:emit_signal("widget::inserted", widget, #self._private.widgets) + + return true +end + +-- Fit the fixed layout into the given space +-- @param context The context in which we are fit. +-- @param orig_width The available width. +-- @param orig_height The available height. +function fixed:fit(context, orig_width, orig_height) + local width, height = orig_width, orig_height + local used_in_dir, used_max = 0, 0 + + for _, v in pairs(self._private.widgets) do + local w, h = base.fit_widget(self, context, v, width, height) + local in_dir, max + if self._private.dir == "y" then + max, in_dir = w, h + height = height - in_dir + else + in_dir, max = w, h + width = width - in_dir + end + if max > used_max then + used_max = max + end + used_in_dir = used_in_dir + in_dir + + if width <= 0 or height <= 0 then + if self._private.dir == "y" then + used_in_dir = orig_height + else + used_in_dir = orig_width + end + break + end + end + + local spacing = self._private.spacing * (#self._private.widgets-1) + + if self._private.dir == "y" then + return used_max, used_in_dir + spacing + end + return used_in_dir + spacing, used_max +end + +function fixed:reset() + self._private.widgets = {} + self:emit_signal("widget::layout_changed") + self:emit_signal("widget::reseted") +end + +--- Set the layout's fill_space property. If this property is true, the last +-- widget will get all the space that is left. If this is false, the last widget +-- won't be handled specially and there can be space left unused. +-- @property fill_space + +function fixed:fill_space(val) + if self._private.fill_space ~= val then + self._private.fill_space = not not val + self:emit_signal("widget::layout_changed") + end +end + +local function get_layout(dir, widget1, ...) + local ret = base.make_widget(nil, nil, {enable_properties = true}) + + util.table.crush(ret, fixed, true) + + ret._private.dir = dir + ret._private.widgets = {} + ret:set_spacing(0) + ret:fill_space(false) + + if widget1 then + ret:add(widget1, ...) + end + + return ret +end + +--- Returns a new horizontal fixed layout. Each widget will get as much space as it +-- asks for and each widget will be drawn next to its neighboring widget. +-- Widgets can be added via :add() or as arguments to this function. +-- @tparam widget ... Widgets that should be added to the layout. +-- @function wibox.layout.fixed.horizontal +function fixed.horizontal(...) + return get_layout("x", ...) +end + +--- Returns a new vertical fixed layout. Each widget will get as much space as it +-- asks for and each widget will be drawn next to its neighboring widget. +-- Widgets can be added via :add() or as arguments to this function. +-- @tparam widget ... Widgets that should be added to the layout. +-- @function wibox.layout.fixed.vertical +function fixed.vertical(...) + return get_layout("y", ...) +end + +--- Add spacing between each layout widgets +-- @property spacing +-- @tparam number spacing Spacing between widgets. + +function fixed:set_spacing(spacing) + if self._private.spacing ~= spacing then + self._private.spacing = spacing + self:emit_signal("widget::layout_changed") + end +end + +function fixed:get_spacing() + return self._private.spacing or 0 +end + +--Imported documentation + + +--- Get a widex index. +-- @param widget The widget to look for +-- @param[opt] recursive Also check sub-widgets +-- @param[opt] ... Aditional widgets to add at the end of the \"path\" +-- @return The index +-- @return The parent layout +-- @return The path between \"self\" and \"widget\" +-- @function index + +--- Get all direct and indirect children widgets. +-- This will scan all containers recursively to find widgets +-- Warning: This method it prone to stack overflow id the widget, or any of its +-- children, contain (directly or indirectly) itself. +-- @treturn table The children +-- @function get_all_children + +--- Set a declarative widget hierarchy description. +-- See [The declarative layout system](../documentation/03-declarative-layout.md.html) +-- @param args An array containing the widgets disposition +-- @function setup + +--- Force a widget height. +-- @property forced_height +-- @tparam number|nil height The height (`nil` for automatic) + +--- Force a widget width. +-- @property forced_width +-- @tparam number|nil width The width (`nil` for automatic) + +--- The widget opacity (transparency). +-- @property opacity +-- @tparam[opt=1] number opacity The opacity (between 0 and 1) + +--- The widget visibility. +-- @property visible +-- @param boolean + +--- Set/get a widget's buttons. +-- @param _buttons The table of buttons that should bind to the widget. +-- @function buttons + +--- Emit a signal and ensure all parent widgets in the hierarchies also +-- forward the signal. This is useful to track signals when there is a dynamic +-- set of containers and layouts wrapping the widget. +-- @tparam string signal_name +-- @param ... Other arguments +-- @function emit_signal_recursive + +--- When the layout (size) change. +-- This signal is emitted when the previous results of `:layout()` and `:fit()` +-- are no longer valid. Unless this signal is emitted, `:layout()` and `:fit()` +-- must return the same result when called with the same arguments. +-- @signal widget::layout_changed +-- @see widget::redraw_needed + +--- When the widget content changed. +-- This signal is emitted when the content of the widget changes. The widget will +-- be redrawn, it is not re-layouted. Put differently, it is assumed that +-- `:layout()` and `:fit()` would still return the same results as before. +-- @signal widget::redraw_needed +-- @see widget::layout_changed + +--- When a mouse button is pressed over the widget. +-- @signal button::press +-- @tparam number lx The horizontal position relative to the (0,0) position in +-- the widget. +-- @tparam number ly The vertical position relative to the (0,0) position in the +-- widget. +-- @tparam number button The button number. +-- @tparam table mods The modifiers (mod4, mod1 (alt), Control, Shift) +-- @tparam table find_widgets_result The entry from the result of +-- @{wibox.drawable:find_widgets} for the position that the mouse hit. +-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing +-- the widget. +-- @tparam widget find_widgets_result.widget The widget being displayed. +-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy +-- managing the widget's geometry. +-- @tparam number find_widgets_result.x An approximation of the X position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.y An approximation of the Y position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.width An approximation of the width that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.height An approximation of the height that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.widget_width The exact width of the widget +-- in its local coordinate system. +-- @tparam number find_widgets_result.widget_height The exact height of the widget +-- in its local coordinate system. +-- @see mouse + +--- When a mouse button is released over the widget. +-- @signal button::release +-- @tparam number lx The horizontal position relative to the (0,0) position in +-- the widget. +-- @tparam number ly The vertical position relative to the (0,0) position in the +-- widget. +-- @tparam number button The button number. +-- @tparam table mods The modifiers (mod4, mod1 (alt), Control, Shift) +-- @tparam table find_widgets_result The entry from the result of +-- @{wibox.drawable:find_widgets} for the position that the mouse hit. +-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing +-- the widget. +-- @tparam widget find_widgets_result.widget The widget being displayed. +-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy +-- managing the widget's geometry. +-- @tparam number find_widgets_result.x An approximation of the X position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.y An approximation of the Y position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.width An approximation of the width that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.height An approximation of the height that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.widget_width The exact width of the widget +-- in its local coordinate system. +-- @tparam number find_widgets_result.widget_height The exact height of the widget +-- in its local coordinate system. +-- @see mouse + +--- When the mouse enter a widget. +-- @signal mouse::enter +-- @tparam table find_widgets_result The entry from the result of +-- @{wibox.drawable:find_widgets} for the position that the mouse hit. +-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing +-- the widget. +-- @tparam widget find_widgets_result.widget The widget being displayed. +-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy +-- managing the widget's geometry. +-- @tparam number find_widgets_result.x An approximation of the X position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.y An approximation of the Y position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.width An approximation of the width that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.height An approximation of the height that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.widget_width The exact width of the widget +-- in its local coordinate system. +-- @tparam number find_widgets_result.widget_height The exact height of the widget +-- in its local coordinate system. +-- @see mouse + +--- When the mouse leave a widget. +-- @signal mouse::leave +-- @tparam table find_widgets_result The entry from the result of +-- @{wibox.drawable:find_widgets} for the position that the mouse hit. +-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing +-- the widget. +-- @tparam widget find_widgets_result.widget The widget being displayed. +-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy +-- managing the widget's geometry. +-- @tparam number find_widgets_result.x An approximation of the X position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.y An approximation of the Y position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.width An approximation of the width that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.height An approximation of the height that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.widget_width The exact width of the widget +-- in its local coordinate system. +-- @tparam number find_widgets_result.widget_height The exact height of the widget +-- in its local coordinate system. +-- @see mouse + + +--Imported documentation + + +--- Disconnect to a signal. +-- @tparam string name The name of the signal +-- @tparam function func The callback that should be disconnected +-- @function disconnect_signal + +--- Emit a signal. +-- +-- @tparam string name The name of the signal +-- @param ... Extra arguments for the callback functions. Each connected +-- function receives the object as first argument and then any extra arguments +-- that are given to emit_signal() +-- @function emit_signal + +--- Connect to a signal. +-- @tparam string name The name of the signal +-- @tparam function func The callback to call when the signal is emitted +-- @function connect_signal + +--- Connect to a signal weakly. This allows the callback function to be garbage +-- collected and automatically disconnects the signal when that happens. +-- +-- **Warning:** +-- Only use this function if you really, really, really know what you +-- are doing. +-- @tparam string name The name of the signal +-- @tparam function func The callback to call when the signal is emitted +-- @function weak_connect_signal + + +return fixed + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/lib/wibox/layout/flex.lua b/lib/wibox/layout/flex.lua new file mode 100644 index 0000000..1326f31 --- /dev/null +++ b/lib/wibox/layout/flex.lua @@ -0,0 +1,429 @@ +--------------------------------------------------------------------------- +-- +-- +-- +--![Usage example](../images/AUTOGEN_wibox_layout_defaults_flex.svg) +-- +-- @usage +--wibox.widget { +-- generic_widget( 'first' ), +-- generic_widget( 'second' ), +-- generic_widget( 'third' ), +-- layout = wibox.layout.flex.horizontal +--} +-- @author Uli Schlachter +-- @copyright 2010 Uli Schlachter +-- @classmod wibox.layout.flex +--------------------------------------------------------------------------- + +local base = require("wibox.widget.base") +local fixed = require("wibox.layout.fixed") +local table = table +local pairs = pairs +local floor = math.floor +local util = require("awful.util") + +local flex = {} + +--Imported documentation + +--- Set a widget at a specific index, replace the current one. +-- **Signal:** widget::replaced The argument is the new widget and the old one +-- and the index. +-- @tparam number index A widget or a widget index +-- @param widget2 The widget to take the place of the first one +-- @treturn boolean If the operation is successful +-- @name set +-- @class function + +--- Replace the first instance of `widget` in the layout with `widget2`. +-- **Signal:** widget::replaced The argument is the new widget and the old one +-- and the index. +-- @param widget The widget to replace +-- @param widget2 The widget to replace `widget` with +-- @tparam[opt=false] boolean recursive Digg in all compatible layouts to find the widget. +-- @treturn boolean If the operation is successful +-- @name replace_widget +-- @class function + +--- Swap 2 widgets in a layout. +-- **Signal:** widget::swapped The arguments are both widgets and both (new) indexes. +-- @tparam number index1 The first widget index +-- @tparam number index2 The second widget index +-- @treturn boolean If the operation is successful +-- @name swap +-- @class function + +--- Swap 2 widgets in a layout. +-- If widget1 is present multiple time, only the first instance is swapped +-- **Signal:** widget::swapped The arguments are both widgets and both (new) indexes. +-- if the layouts not the same, then only `widget::replaced` will be emitted. +-- @param widget1 The first widget +-- @param widget2 The second widget +-- @tparam[opt=false] boolean recursive Digg in all compatible layouts to find the widget. +-- @treturn boolean If the operation is successful +-- @name swap_widgets +-- @class function + +--- Get all direct children of this layout. +-- @param layout The layout you are modifying. +-- @property children + +--- Reset a ratio layout. This removes all widgets from the layout. +-- **Signal:** widget::reset +-- @param layout The layout you are modifying. +-- @name reset +-- @class function + + +--- Replace the layout children +-- @tparam table children A table composed of valid widgets +-- @name set_children +-- @class function + +--- Add some widgets to the given fixed layout +-- @param layout The layout you are modifying. +-- @tparam widget ... Widgets that should be added (must at least be one) +-- @name add +-- @class function + +--- Remove a widget from the layout +-- @tparam index The widget index to remove +-- @treturn boolean index If the operation is successful +-- @name remove +-- @class function + +--- Remove one or more widgets from the layout +-- The last parameter can be a boolean, forcing a recursive seach of the +-- widget(s) to remove. +-- @param widget ... Widgets that should be removed (must at least be one) +-- @treturn boolean If the operation is successful +-- @name remove_widgets +-- @class function + +--- Insert a new widget in the layout at position `index` +-- @tparam number index The position +-- @param widget The widget +-- @treturn boolean If the operation is successful +-- @name insert +-- @class function + +function flex:layout(_, width, height) + local result = {} + local pos,spacing = 0, self._private.spacing + local num = #self._private.widgets + local total_spacing = (spacing*(num-1)) + + local space_per_item + if self._private.dir == "y" then + space_per_item = height / num - total_spacing/num + else + space_per_item = width / num - total_spacing/num + end + + if self._private.max_widget_size then + space_per_item = math.min(space_per_item, self._private.max_widget_size) + end + + for _, v in pairs(self._private.widgets) do + local x, y, w, h + if self._private.dir == "y" then + x, y = 0, util.round(pos) + w, h = width, floor(space_per_item) + else + x, y = util.round(pos), 0 + w, h = floor(space_per_item), height + end + + table.insert(result, base.place_widget_at(v, x, y, w, h)) + + pos = pos + space_per_item + spacing + + if (self._private.dir == "y" and pos-spacing >= height) or + (self._private.dir ~= "y" and pos-spacing >= width) then + break + end + end + + return result +end + +-- Fit the flex layout into the given space. +-- @param context The context in which we are fit. +-- @param orig_width The available width. +-- @param orig_height The available height. +function flex:fit(context, orig_width, orig_height) + local used_in_dir = 0 + local used_in_other = 0 + + -- Figure out the maximum size we can give out to sub-widgets + local sub_height = self._private.dir == "x" and orig_height or orig_height / #self._private.widgets + local sub_width = self._private.dir == "y" and orig_width or orig_width / #self._private.widgets + + for _, v in pairs(self._private.widgets) do + local w, h = base.fit_widget(self, context, v, sub_width, sub_height) + + local max = self._private.dir == "y" and w or h + if max > used_in_other then + used_in_other = max + end + + used_in_dir = used_in_dir + (self._private.dir == "y" and h or w) + end + + if self._private.max_widget_size then + used_in_dir = math.min(used_in_dir, + #self._private.widgets * self._private.max_widget_size) + end + + local spacing = self._private.spacing * (#self._private.widgets-1) + + if self._private.dir == "y" then + return used_in_other, used_in_dir + spacing + end + return used_in_dir + spacing, used_in_other +end + +--- Set the maximum size the widgets in this layout will take. +--That is, maximum width for horizontal and maximum height for vertical. +-- @property max_widget_size +-- @param number + +function flex:set_max_widget_size(val) + if self._private.max_widget_size ~= val then + self._private.max_widget_size = val + self:emit_signal("widget::layout_changed") + end +end + +local function get_layout(dir, widget1, ...) + local ret = fixed[dir](widget1, ...) + + util.table.crush(ret, flex, true) + + ret._private.fill_space = nil + + return ret +end + +--- Returns a new horizontal flex layout. A flex layout shares the available space +-- equally among all widgets. Widgets can be added via :add(widget). +-- @tparam widget ... Widgets that should be added to the layout. +-- @function wibox.layout.flex.horizontal +function flex.horizontal(...) + return get_layout("horizontal", ...) +end + +--- Returns a new vertical flex layout. A flex layout shares the available space +-- equally among all widgets. Widgets can be added via :add(widget). +-- @tparam widget ... Widgets that should be added to the layout. +-- @function wibox.layout.flex.vertical +function flex.vertical(...) + return get_layout("vertical", ...) +end + +--Imported documentation + + +--- Get a widex index. +-- @param widget The widget to look for +-- @param[opt] recursive Also check sub-widgets +-- @param[opt] ... Aditional widgets to add at the end of the \"path\" +-- @return The index +-- @return The parent layout +-- @return The path between \"self\" and \"widget\" +-- @function index + +--- Get all direct and indirect children widgets. +-- This will scan all containers recursively to find widgets +-- Warning: This method it prone to stack overflow id the widget, or any of its +-- children, contain (directly or indirectly) itself. +-- @treturn table The children +-- @function get_all_children + +--- Set a declarative widget hierarchy description. +-- See [The declarative layout system](../documentation/03-declarative-layout.md.html) +-- @param args An array containing the widgets disposition +-- @function setup + +--- Force a widget height. +-- @property forced_height +-- @tparam number|nil height The height (`nil` for automatic) + +--- Force a widget width. +-- @property forced_width +-- @tparam number|nil width The width (`nil` for automatic) + +--- The widget opacity (transparency). +-- @property opacity +-- @tparam[opt=1] number opacity The opacity (between 0 and 1) + +--- The widget visibility. +-- @property visible +-- @param boolean + +--- Set/get a widget's buttons. +-- @param _buttons The table of buttons that should bind to the widget. +-- @function buttons + +--- Emit a signal and ensure all parent widgets in the hierarchies also +-- forward the signal. This is useful to track signals when there is a dynamic +-- set of containers and layouts wrapping the widget. +-- @tparam string signal_name +-- @param ... Other arguments +-- @function emit_signal_recursive + +--- When the layout (size) change. +-- This signal is emitted when the previous results of `:layout()` and `:fit()` +-- are no longer valid. Unless this signal is emitted, `:layout()` and `:fit()` +-- must return the same result when called with the same arguments. +-- @signal widget::layout_changed +-- @see widget::redraw_needed + +--- When the widget content changed. +-- This signal is emitted when the content of the widget changes. The widget will +-- be redrawn, it is not re-layouted. Put differently, it is assumed that +-- `:layout()` and `:fit()` would still return the same results as before. +-- @signal widget::redraw_needed +-- @see widget::layout_changed + +--- When a mouse button is pressed over the widget. +-- @signal button::press +-- @tparam number lx The horizontal position relative to the (0,0) position in +-- the widget. +-- @tparam number ly The vertical position relative to the (0,0) position in the +-- widget. +-- @tparam number button The button number. +-- @tparam table mods The modifiers (mod4, mod1 (alt), Control, Shift) +-- @tparam table find_widgets_result The entry from the result of +-- @{wibox.drawable:find_widgets} for the position that the mouse hit. +-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing +-- the widget. +-- @tparam widget find_widgets_result.widget The widget being displayed. +-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy +-- managing the widget's geometry. +-- @tparam number find_widgets_result.x An approximation of the X position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.y An approximation of the Y position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.width An approximation of the width that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.height An approximation of the height that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.widget_width The exact width of the widget +-- in its local coordinate system. +-- @tparam number find_widgets_result.widget_height The exact height of the widget +-- in its local coordinate system. +-- @see mouse + +--- When a mouse button is released over the widget. +-- @signal button::release +-- @tparam number lx The horizontal position relative to the (0,0) position in +-- the widget. +-- @tparam number ly The vertical position relative to the (0,0) position in the +-- widget. +-- @tparam number button The button number. +-- @tparam table mods The modifiers (mod4, mod1 (alt), Control, Shift) +-- @tparam table find_widgets_result The entry from the result of +-- @{wibox.drawable:find_widgets} for the position that the mouse hit. +-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing +-- the widget. +-- @tparam widget find_widgets_result.widget The widget being displayed. +-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy +-- managing the widget's geometry. +-- @tparam number find_widgets_result.x An approximation of the X position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.y An approximation of the Y position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.width An approximation of the width that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.height An approximation of the height that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.widget_width The exact width of the widget +-- in its local coordinate system. +-- @tparam number find_widgets_result.widget_height The exact height of the widget +-- in its local coordinate system. +-- @see mouse + +--- When the mouse enter a widget. +-- @signal mouse::enter +-- @tparam table find_widgets_result The entry from the result of +-- @{wibox.drawable:find_widgets} for the position that the mouse hit. +-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing +-- the widget. +-- @tparam widget find_widgets_result.widget The widget being displayed. +-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy +-- managing the widget's geometry. +-- @tparam number find_widgets_result.x An approximation of the X position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.y An approximation of the Y position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.width An approximation of the width that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.height An approximation of the height that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.widget_width The exact width of the widget +-- in its local coordinate system. +-- @tparam number find_widgets_result.widget_height The exact height of the widget +-- in its local coordinate system. +-- @see mouse + +--- When the mouse leave a widget. +-- @signal mouse::leave +-- @tparam table find_widgets_result The entry from the result of +-- @{wibox.drawable:find_widgets} for the position that the mouse hit. +-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing +-- the widget. +-- @tparam widget find_widgets_result.widget The widget being displayed. +-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy +-- managing the widget's geometry. +-- @tparam number find_widgets_result.x An approximation of the X position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.y An approximation of the Y position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.width An approximation of the width that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.height An approximation of the height that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.widget_width The exact width of the widget +-- in its local coordinate system. +-- @tparam number find_widgets_result.widget_height The exact height of the widget +-- in its local coordinate system. +-- @see mouse + + +--Imported documentation + + +--- Disconnect to a signal. +-- @tparam string name The name of the signal +-- @tparam function func The callback that should be disconnected +-- @function disconnect_signal + +--- Emit a signal. +-- +-- @tparam string name The name of the signal +-- @param ... Extra arguments for the callback functions. Each connected +-- function receives the object as first argument and then any extra arguments +-- that are given to emit_signal() +-- @function emit_signal + +--- Connect to a signal. +-- @tparam string name The name of the signal +-- @tparam function func The callback to call when the signal is emitted +-- @function connect_signal + +--- Connect to a signal weakly. This allows the callback function to be garbage +-- collected and automatically disconnects the signal when that happens. +-- +-- **Warning:** +-- Only use this function if you really, really, really know what you +-- are doing. +-- @tparam string name The name of the signal +-- @tparam function func The callback to call when the signal is emitted +-- @function weak_connect_signal + + +return flex + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/lib/wibox/layout/init.lua b/lib/wibox/layout/init.lua new file mode 100644 index 0000000..4a9b006 --- /dev/null +++ b/lib/wibox/layout/init.lua @@ -0,0 +1,23 @@ +--------------------------------------------------------------------------- +--- Collection of layouts that can be used in widget boxes +-- +-- @author Uli Schlachter +-- @copyright 2010 Uli Schlachter +-- @classmod wibox.layout +--------------------------------------------------------------------------- +local base = require("wibox.widget.base") + +return setmetatable({ + fixed = require("wibox.layout.fixed"); + align = require("wibox.layout.align"); + flex = require("wibox.layout.flex"); + rotate = require("wibox.layout.rotate"); + margin = require("wibox.layout.margin"); + mirror = require("wibox.layout.mirror"); + constraint = require("wibox.layout.constraint"); + scroll = require("wibox.layout.scroll"); + ratio = require("wibox.layout.ratio"); + stack = require("wibox.layout.stack"); +}, {__call = function(_, args) return base.make_widget_declarative(args) end}) + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/lib/wibox/layout/margin.lua b/lib/wibox/layout/margin.lua new file mode 100644 index 0000000..8d2eba2 --- /dev/null +++ b/lib/wibox/layout/margin.lua @@ -0,0 +1,17 @@ +--------------------------------------------------------------------------- +-- This class has been moved to `wibox.container.margin` +-- +-- @author Uli Schlachter +-- @copyright 2010 Uli Schlachter +-- @classmod wibox.layout.margin +--------------------------------------------------------------------------- + +local util = require("awful.util") + +return util.deprecate_class( + require("wibox.container.margin"), + "wibox.layout.margin", + "wibox.container.margin" +) + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/lib/wibox/layout/mirror.lua b/lib/wibox/layout/mirror.lua new file mode 100644 index 0000000..16be754 --- /dev/null +++ b/lib/wibox/layout/mirror.lua @@ -0,0 +1,17 @@ +--------------------------------------------------------------------------- +-- This class has been moved to `wibox.container.mirror` +-- +-- @author dodo +-- @copyright 2012 dodo +-- @classmod wibox.layout.mirror +--------------------------------------------------------------------------- + +local util = require("awful.util") + +return util.deprecate_class( + require("wibox.container.mirror"), + "wibox.layout.mirror", + "wibox.container.mirror" +) + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/lib/wibox/layout/ratio.lua b/lib/wibox/layout/ratio.lua new file mode 100644 index 0000000..bcae443 --- /dev/null +++ b/lib/wibox/layout/ratio.lua @@ -0,0 +1,583 @@ +--------------------------------------------------------------------------- +--- A layout filling all the available space. Each widget is assigned a +-- ratio (percentage) of the total space. Multiple methods are available to +-- ajust this ratio. +-- +-- +-- +--![Usage example](../images/AUTOGEN_wibox_layout_defaults_ratio.svg) +-- +-- @usage +--local w = wibox.widget { +-- generic_widget( 'first' ), +-- generic_widget( 'second' ), +-- generic_widget( 'third' ), +-- layout = wibox.layout.ratio.horizontal +--} +--w:ajust_ratio(2, 0.44, 0.33, 0.22) +-- @author Emmanuel Lepage Vallee +-- @copyright 2016 Emmanuel Lepage Vallee +-- @classmod wibox.layout.ratio +--------------------------------------------------------------------------- + +local base = require("wibox.widget.base" ) +local flex = require("wibox.layout.flex" ) +local table = table +local pairs = pairs +local floor = math.floor +local util = require("awful.util") + +local ratio = {} + +--Imported documentation + +--- Set a widget at a specific index, replace the current one. +-- **Signal:** widget::replaced The argument is the new widget and the old one +-- and the index. +-- @tparam number index A widget or a widget index +-- @param widget2 The widget to take the place of the first one +-- @treturn boolean If the operation is successful +-- @name set +-- @class function + +--- Replace the first instance of `widget` in the layout with `widget2`. +-- **Signal:** widget::replaced The argument is the new widget and the old one +-- and the index. +-- @param widget The widget to replace +-- @param widget2 The widget to replace `widget` with +-- @tparam[opt=false] boolean recursive Digg in all compatible layouts to find the widget. +-- @treturn boolean If the operation is successful +-- @name replace_widget +-- @class function + +--- Swap 2 widgets in a layout. +-- **Signal:** widget::swapped The arguments are both widgets and both (new) indexes. +-- @tparam number index1 The first widget index +-- @tparam number index2 The second widget index +-- @treturn boolean If the operation is successful +-- @name swap +-- @class function + +--- Swap 2 widgets in a layout. +-- If widget1 is present multiple time, only the first instance is swapped +-- **Signal:** widget::swapped The arguments are both widgets and both (new) indexes. +-- if the layouts not the same, then only `widget::replaced` will be emitted. +-- @param widget1 The first widget +-- @param widget2 The second widget +-- @tparam[opt=false] boolean recursive Digg in all compatible layouts to find the widget. +-- @treturn boolean If the operation is successful +-- @name swap_widgets +-- @class function + +--- Get all direct children of this layout. +-- @param layout The layout you are modifying. +-- @property children + +--- Reset a ratio layout. This removes all widgets from the layout. +-- **Signal:** widget::reset +-- @param layout The layout you are modifying. +-- @name reset +-- @class function + + +-- Compute the sum of all ratio (ideally, it should be 1) +local function gen_sum(self, i_s, i_e) + local sum, new_w = 0,0 + + for i = i_s or 1, i_e or #self._private.widgets do + if self._private.ratios[i] then + sum = sum + self._private.ratios[i] + else + new_w = new_w + 1 + end + end + + return sum, new_w +end + +-- The ratios are expressed as percentages. For this to work, the sum of all +-- ratio must be 1. This function attempt to ajust them. Space can be taken +-- from or added to a ratio when widgets are being added or removed. If a +-- specific ratio must be enforced for a widget, it has to be done with the +-- `ajust_ratio` method after each insertion or deletion +local function normalize(self) + local count = #self._private.widgets + if count == 0 then return end + + -- Instead of adding "if" everywhere, just handle this common case + if count == 1 then + self._private.ratios = { 1 } + return + end + + local sum, new_w = gen_sum(self) + local old_count = #self._private.widgets - new_w + + local to_add = (sum == 0) and 1 or (sum / old_count) + + -- Make sure all widgets have a ratio + for i=1, #self._private.widgets do + if not self._private.ratios[i] then + self._private.ratios[i] = to_add + end + end + + sum = sum + to_add*new_w + + local delta, new_sum = (1 - sum) / count,0 + + -- Increase or decrease each ratio so it the sum become 1 + for i=1, #self._private.widgets do + self._private.ratios[i] = self._private.ratios[i] + delta + new_sum = new_sum + self._private.ratios[i] + end + + -- Floating points is not an exact science, but it should still be close + -- to 1.00. + assert(new_sum > 0.99 and new_sum < 1.01) +end + +function ratio:layout(_, width, height) + local result = {} + local pos,spacing = 0, self._private.spacing + + for k, v in ipairs(self._private.widgets) do + local space + local x, y, w, h + + if self._private.dir == "y" then + space = height * self._private.ratios[k] + x, y = 0, util.round(pos) + w, h = width, floor(space) + else + space = width * self._private.ratios[k] + x, y = util.round(pos), 0 + w, h = floor(space), height + end + + table.insert(result, base.place_widget_at(v, x, y, w, h)) + + 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 util.round(pos) >= height) or + (self._private.dir ~= "y" and util.round(pos) >= width) then + break + end + 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. +-- @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 +function ratio:inc_ratio(index, increment) + if #self._private.widgets == 1 or (not index) or (not self._private.ratios[index]) + or increment < -1 or increment > 1 then + return + end + + assert(self._private.ratios[index]) + + self:set_ratio(index, self._private.ratios[index] + increment) +end + +--- Increment the ratio of the first instance of `widget` +-- If the increment produce an invalid ratio (not between 0 and 1), the method +-- do nothing. +-- @param widget The widget to ajust +-- @tparam number increment An floating point value between -1 and 1 where the +-- end result is within 0 and 1 +function ratio:inc_widget_ratio(widget, increment) + if not widget or not increment then return end + + local index = self:index(widget) + + self:inc_ratio(index, increment) +end + +--- Set the ratio of the widget at position `index` +-- @tparam number index The index of the widget to change +-- @tparam number percent An floating point value between 0 and 1 +function ratio:set_ratio(index, percent) + if not percent or #self._private.widgets == 1 or not index or not self._private.widgets[index] + or percent < 0 or percent > 1 then + return + end + + local old = self._private.ratios[index] + + -- Remove what has to be cleared from all widget + local delta = ( (percent-old) / (#self._private.widgets-1) ) + + for k in pairs(self._private.widgets) do + self._private.ratios[k] = self._private.ratios[k] - delta + end + + -- Set the new ratio + self._private.ratios[index] = percent + + -- As some widgets may now have a slightly negative ratio, normalize again + normalize(self) + + self:emit_signal("widget::layout_changed") +end + +--- Get the ratio at `index`. +-- @tparam number index The widget index to query +-- @treturn number The index (between 0 and 1) +function ratio:get_ratio(index) + if not index then return end + return self._private.ratios[index] +end + +--- Set the ratio of `widget` to `percent`. +-- @tparam widget widget The widget to ajust. +-- @tparam number percent A floating point value between 0 and 1. +function ratio:set_widget_ratio(widget, percent) + local index = self:index(widget) + + self:set_ratio(index, 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 +-- @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" +-- @tparam number after The sum of the ratio after the widget +function ratio:ajust_ratio(index, before, itself, after) + if not self._private.widgets[index] or not before or not itself or not after then + return + end + + local sum = before + itself + after + + -- As documented, it is the caller job to come up with valid numbers + if math.min(before, itself, after) < 0 then return end + if sum > 1.01 or sum < -0.99 then return end + + -- Compute the before and after offset to be applied to each widgets + local before_count, after_count = index-1, #self._private.widgets - index + + local b, a = gen_sum(self, 1, index-1), gen_sum(self, index+1) + + local db, da = (before - b)/before_count, (after - a)/after_count + + -- Apply the new ratio + self._private.ratios[index] = itself + + -- Equality split the delta among widgets before and after + for i = 1, index -1 do + self._private.ratios[i] = self._private.ratios[i] + db + end + for i = index+1, #self._private.widgets do + self._private.ratios[i] = self._private.ratios[i] + da + end + + -- Remove potential negative ratio + normalize(self) + + self:emit_signal("widget::layout_changed") +end + +--- Update all widgets to match a set of a ratio +-- @param widget The widget to ajust +-- @tparam number before The sum of the ratio before the widget +-- @tparam number itself The ratio for "widget" +-- @tparam number after The sum of the ratio after the widget +function ratio:ajust_widget_ratio(widget, before, itself, after) + local index = self:index(widget) + self:ajust_ratio(index, before, itself, after) +end + +--- Add some widgets to the given fixed layout +-- **Signal:** widget::added The argument are the widgets +-- @tparam widget ... Widgets that should be added (must at least be one) +function ratio:add(...) + -- No table.pack in Lua 5.1 :-( + local args = { n=select('#', ...), ... } + assert(args.n > 0, "need at least one widget to add") + for i=1, args.n do + base.check_widget(args[i]) + table.insert(self._private.widgets, args[i]) + end + + normalize(self) + self:emit_signal("widget::layout_changed") + self:emit_signal("widget::added", ...) +end + +--- Remove a widget from the layout +-- **Signal:** widget::removed The arguments are the widget and the index +-- @tparam number index The widget index to remove +-- @treturn boolean index If the operation is successful +function ratio:remove(index) + if not index or not self._private.widgets[index] then return false end + + local w = self._private.widgets[index] + + table.remove(self._private.ratios, index) + table.remove(self._private.widgets, index) + + normalize(self) + + self:emit_signal("widget::layout_changed") + self:emit_signal("widget::removed", w, index) + + return true +end + +--- Insert a new widget in the layout at position `index` +-- **Signal:** widget::inserted The arguments are the widget and the index +-- @tparam number index The position +-- @param widget The widget +function ratio:insert(index, widget) + if not index or index < 1 or index > #self._private.widgets + 1 then return false end + + base.check_widget(widget) + + table.insert(self._private.widgets, index, widget) + + normalize(self) + + self:emit_signal("widget::layout_changed") + self:emit_signal("widget::inserted", widget, #self._private.widgets) +end + +local function get_layout(dir, widget1, ...) + local ret = flex[dir](widget1, ...) + + util.table.crush(ret, ratio, true) + + ret._private.fill_space = nil + + ret._private.ratios = {} + + return ret +end + +--- Returns a new horizontal ratio layout. A ratio layout shares the available space +-- equally among all widgets. Widgets can be added via :add(widget). +-- @tparam widget ... Widgets that should be added to the layout. +function ratio.horizontal(...) + return get_layout("horizontal", ...) +end + +--- Returns a new vertical ratio layout. A ratio layout shares the available space +-- equally among all widgets. Widgets can be added via :add(widget). +-- @tparam widget ... Widgets that should be added to the layout. +function ratio.vertical(...) + return get_layout("vertical", ...) +end + +--Imported documentation + + +--- Get a widex index. +-- @param widget The widget to look for +-- @param[opt] recursive Also check sub-widgets +-- @param[opt] ... Aditional widgets to add at the end of the \"path\" +-- @return The index +-- @return The parent layout +-- @return The path between \"self\" and \"widget\" +-- @function index + +--- Get all direct and indirect children widgets. +-- This will scan all containers recursively to find widgets +-- Warning: This method it prone to stack overflow id the widget, or any of its +-- children, contain (directly or indirectly) itself. +-- @treturn table The children +-- @function get_all_children + +--- Set a declarative widget hierarchy description. +-- See [The declarative layout system](../documentation/03-declarative-layout.md.html) +-- @param args An array containing the widgets disposition +-- @function setup + +--- Force a widget height. +-- @property forced_height +-- @tparam number|nil height The height (`nil` for automatic) + +--- Force a widget width. +-- @property forced_width +-- @tparam number|nil width The width (`nil` for automatic) + +--- The widget opacity (transparency). +-- @property opacity +-- @tparam[opt=1] number opacity The opacity (between 0 and 1) + +--- The widget visibility. +-- @property visible +-- @param boolean + +--- Set/get a widget's buttons. +-- @param _buttons The table of buttons that should bind to the widget. +-- @function buttons + +--- Emit a signal and ensure all parent widgets in the hierarchies also +-- forward the signal. This is useful to track signals when there is a dynamic +-- set of containers and layouts wrapping the widget. +-- @tparam string signal_name +-- @param ... Other arguments +-- @function emit_signal_recursive + +--- When the layout (size) change. +-- This signal is emitted when the previous results of `:layout()` and `:fit()` +-- are no longer valid. Unless this signal is emitted, `:layout()` and `:fit()` +-- must return the same result when called with the same arguments. +-- @signal widget::layout_changed +-- @see widget::redraw_needed + +--- When the widget content changed. +-- This signal is emitted when the content of the widget changes. The widget will +-- be redrawn, it is not re-layouted. Put differently, it is assumed that +-- `:layout()` and `:fit()` would still return the same results as before. +-- @signal widget::redraw_needed +-- @see widget::layout_changed + +--- When a mouse button is pressed over the widget. +-- @signal button::press +-- @tparam number lx The horizontal position relative to the (0,0) position in +-- the widget. +-- @tparam number ly The vertical position relative to the (0,0) position in the +-- widget. +-- @tparam number button The button number. +-- @tparam table mods The modifiers (mod4, mod1 (alt), Control, Shift) +-- @tparam table find_widgets_result The entry from the result of +-- @{wibox.drawable:find_widgets} for the position that the mouse hit. +-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing +-- the widget. +-- @tparam widget find_widgets_result.widget The widget being displayed. +-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy +-- managing the widget's geometry. +-- @tparam number find_widgets_result.x An approximation of the X position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.y An approximation of the Y position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.width An approximation of the width that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.height An approximation of the height that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.widget_width The exact width of the widget +-- in its local coordinate system. +-- @tparam number find_widgets_result.widget_height The exact height of the widget +-- in its local coordinate system. +-- @see mouse + +--- When a mouse button is released over the widget. +-- @signal button::release +-- @tparam number lx The horizontal position relative to the (0,0) position in +-- the widget. +-- @tparam number ly The vertical position relative to the (0,0) position in the +-- widget. +-- @tparam number button The button number. +-- @tparam table mods The modifiers (mod4, mod1 (alt), Control, Shift) +-- @tparam table find_widgets_result The entry from the result of +-- @{wibox.drawable:find_widgets} for the position that the mouse hit. +-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing +-- the widget. +-- @tparam widget find_widgets_result.widget The widget being displayed. +-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy +-- managing the widget's geometry. +-- @tparam number find_widgets_result.x An approximation of the X position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.y An approximation of the Y position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.width An approximation of the width that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.height An approximation of the height that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.widget_width The exact width of the widget +-- in its local coordinate system. +-- @tparam number find_widgets_result.widget_height The exact height of the widget +-- in its local coordinate system. +-- @see mouse + +--- When the mouse enter a widget. +-- @signal mouse::enter +-- @tparam table find_widgets_result The entry from the result of +-- @{wibox.drawable:find_widgets} for the position that the mouse hit. +-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing +-- the widget. +-- @tparam widget find_widgets_result.widget The widget being displayed. +-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy +-- managing the widget's geometry. +-- @tparam number find_widgets_result.x An approximation of the X position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.y An approximation of the Y position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.width An approximation of the width that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.height An approximation of the height that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.widget_width The exact width of the widget +-- in its local coordinate system. +-- @tparam number find_widgets_result.widget_height The exact height of the widget +-- in its local coordinate system. +-- @see mouse + +--- When the mouse leave a widget. +-- @signal mouse::leave +-- @tparam table find_widgets_result The entry from the result of +-- @{wibox.drawable:find_widgets} for the position that the mouse hit. +-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing +-- the widget. +-- @tparam widget find_widgets_result.widget The widget being displayed. +-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy +-- managing the widget's geometry. +-- @tparam number find_widgets_result.x An approximation of the X position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.y An approximation of the Y position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.width An approximation of the width that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.height An approximation of the height that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.widget_width The exact width of the widget +-- in its local coordinate system. +-- @tparam number find_widgets_result.widget_height The exact height of the widget +-- in its local coordinate system. +-- @see mouse + + +--Imported documentation + + +--- Disconnect to a signal. +-- @tparam string name The name of the signal +-- @tparam function func The callback that should be disconnected +-- @function disconnect_signal + +--- Emit a signal. +-- +-- @tparam string name The name of the signal +-- @param ... Extra arguments for the callback functions. Each connected +-- function receives the object as first argument and then any extra arguments +-- that are given to emit_signal() +-- @function emit_signal + +--- Connect to a signal. +-- @tparam string name The name of the signal +-- @tparam function func The callback to call when the signal is emitted +-- @function connect_signal + +--- Connect to a signal weakly. This allows the callback function to be garbage +-- collected and automatically disconnects the signal when that happens. +-- +-- **Warning:** +-- Only use this function if you really, really, really know what you +-- are doing. +-- @tparam string name The name of the signal +-- @tparam function func The callback to call when the signal is emitted +-- @function weak_connect_signal + + +return ratio + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/lib/wibox/layout/rotate.lua b/lib/wibox/layout/rotate.lua new file mode 100644 index 0000000..a6b5d7a --- /dev/null +++ b/lib/wibox/layout/rotate.lua @@ -0,0 +1,17 @@ +--------------------------------------------------------------------------- +-- This class has been moved to `wibox.container.rotate` +-- +-- @author Uli Schlachter +-- @copyright 2010 Uli Schlachter +-- @classmod wibox.layout.rotate +--------------------------------------------------------------------------- + +local util = require("awful.util") + +return util.deprecate_class( + require("wibox.container.rotate"), + "wibox.layout.rotate", + "wibox.container.rotate" +) + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/lib/wibox/layout/scroll.lua b/lib/wibox/layout/scroll.lua new file mode 100644 index 0000000..e0be79f --- /dev/null +++ b/lib/wibox/layout/scroll.lua @@ -0,0 +1,16 @@ +--------------------------------------------------------------------------- +-- This class has been moved to `wibox.container.scroll` +-- +-- @author Uli Schlachter (based on ideas from Saleur Geoffrey) +-- @copyright 2015 Uli Schlachter +-- @classmod wibox.layout.scroll +--------------------------------------------------------------------------- +local util = require("awful.util") + +return util.deprecate_class( + require("wibox.container.scroll"), + "wibox.layout.scroll", + "wibox.container.scroll" +) + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/lib/wibox/layout/stack.lua b/lib/wibox/layout/stack.lua new file mode 100644 index 0000000..bd28703 --- /dev/null +++ b/lib/wibox/layout/stack.lua @@ -0,0 +1,402 @@ +--------------------------------------------------------------------------- +-- A stacked layout. +-- +-- This layout display widgets on top of each other. It can be used to overlay +-- a `wibox.widget.textbox` on top of a `awful.widget.progressbar` or manage +-- "pages" where only one is visible at any given moment. +-- +-- The indices are going from 1 (the bottom of the stack) up to the top of +-- the stack. The order can be changed either using `:swap` or `:raise`. +-- +-- +-- +--![Usage example](../images/AUTOGEN_wibox_layout_defaults_stack.svg) +-- +-- @usage +--wibox.widget { +-- generic_widget( 'first' ), +-- generic_widget( 'second' ), +-- generic_widget( 'third' ), +-- layout = wibox.layout.stack +--} +-- @author Emmanuel Lepage Vallee +-- @copyright 2016 Emmanuel Lepage Vallee +-- @classmod wibox.layout.stack +--------------------------------------------------------------------------- + +local base = require("wibox.widget.base" ) +local fixed = require("wibox.layout.fixed") +local table = table +local pairs = pairs +local util = require("awful.util") + +local stack = {mt={}} + +--Imported documentation + +--- Set a widget at a specific index, replace the current one. +-- **Signal:** widget::replaced The argument is the new widget and the old one +-- and the index. +-- @tparam number index A widget or a widget index +-- @param widget2 The widget to take the place of the first one +-- @treturn boolean If the operation is successful +-- @name set +-- @class function + +--- Replace the first instance of `widget` in the layout with `widget2`. +-- **Signal:** widget::replaced The argument is the new widget and the old one +-- and the index. +-- @param widget The widget to replace +-- @param widget2 The widget to replace `widget` with +-- @tparam[opt=false] boolean recursive Digg in all compatible layouts to find the widget. +-- @treturn boolean If the operation is successful +-- @name replace_widget +-- @class function + +--- Swap 2 widgets in a layout. +-- **Signal:** widget::swapped The arguments are both widgets and both (new) indexes. +-- @tparam number index1 The first widget index +-- @tparam number index2 The second widget index +-- @treturn boolean If the operation is successful +-- @name swap +-- @class function + +--- Swap 2 widgets in a layout. +-- If widget1 is present multiple time, only the first instance is swapped +-- **Signal:** widget::swapped The arguments are both widgets and both (new) indexes. +-- if the layouts not the same, then only `widget::replaced` will be emitted. +-- @param widget1 The first widget +-- @param widget2 The second widget +-- @tparam[opt=false] boolean recursive Digg in all compatible layouts to find the widget. +-- @treturn boolean If the operation is successful +-- @name swap_widgets +-- @class function + +--- Get all direct children of this layout. +-- @param layout The layout you are modifying. +-- @property children + +--- Reset a ratio layout. This removes all widgets from the layout. +-- **Signal:** widget::reset +-- @param layout The layout you are modifying. +-- @name reset +-- @class function + + +--- Add some widgets to the given stack layout +-- @param layout The layout you are modifying. +-- @tparam widget ... Widgets that should be added (must at least be one) +-- @name add +-- @class function + +--- Remove a widget from the layout +-- @tparam index The widget index to remove +-- @treturn boolean index If the operation is successful +-- @name remove +-- @class function + +--- Insert a new widget in the layout at position `index` +-- @tparam number index The position +-- @param widget The widget +-- @treturn boolean If the operation is successful +-- @name insert +-- @class function + +--- Remove one or more widgets from the layout +-- The last parameter can be a boolean, forcing a recursive seach of the +-- widget(s) to remove. +-- @param widget ... Widgets that should be removed (must at least be one) +-- @treturn boolean If the operation is successful +-- @name remove_widgets +-- @class function + +--- Add spacing between each layout widgets +-- @property spacing +-- @tparam number spacing Spacing between widgets. + +function stack:layout(_, width, height) + local result = {} + local spacing = self._private.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)) + if self._private.top_only then break end + end + + return result +end + +function stack:fit(context, orig_width, orig_height) + local max_w, max_h = 0,0 + local spacing = self._private.spacing + + for _, v in pairs(self._private.widgets) do + local w, h = base.fit_widget(self, context, v, orig_width, orig_height) + max_w, max_h = math.max(max_w, w+2*spacing), math.max(max_h, h+2*spacing) + end + + return math.min(max_w, orig_width), math.min(max_h, orig_height) +end + +--- If only the first stack widget is drawn +-- @property top_only + +function stack:get_top_only() + return self._private.top_only +end + +function stack:set_top_only(top_only) + self._private.top_only = top_only +end + +--- Raise a widget at `index` to the top of the stack +-- @tparam number index the widget index to raise +function stack:raise(index) + if (not index) or self._private.widgets[index] then return end + + local w = self._private.widgets[index] + table.remove(self._private.widgets, index) + table.insert(self._private.widgets, w) + + self:emit_signal("widget::layout_changed") +end + +--- Raise the first instance of `widget` +-- @param widget The widget to raise +-- @tparam[opt=false] boolean recursive Also look deeper in the hierarchy to +-- find the widget +function stack:raise_widget(widget, recursive) + local idx, layout = self:index(widget, recursive) + + if not idx or not layout then return end + + -- Bubble up in the stack until the right index is found + while layout and layout ~= self do + idx, layout = self:index(layout, recursive) + end + + if layout == self and idx ~= 1 then + self:raise(idx) + end +end + +--- Create a new stack layout. +-- @function wibox.layout.stack +-- @treturn widget A new stack layout + +local function new(...) + local ret = fixed.horizontal(...) + + util.table.crush(ret, stack, true) + + return ret +end + +function stack.mt:__call(_, ...) + return new(...) +end + +--Imported documentation + + +--- Get a widex index. +-- @param widget The widget to look for +-- @param[opt] recursive Also check sub-widgets +-- @param[opt] ... Aditional widgets to add at the end of the \"path\" +-- @return The index +-- @return The parent layout +-- @return The path between \"self\" and \"widget\" +-- @function index + +--- Get all direct and indirect children widgets. +-- This will scan all containers recursively to find widgets +-- Warning: This method it prone to stack overflow id the widget, or any of its +-- children, contain (directly or indirectly) itself. +-- @treturn table The children +-- @function get_all_children + +--- Set a declarative widget hierarchy description. +-- See [The declarative layout system](../documentation/03-declarative-layout.md.html) +-- @param args An array containing the widgets disposition +-- @function setup + +--- Force a widget height. +-- @property forced_height +-- @tparam number|nil height The height (`nil` for automatic) + +--- Force a widget width. +-- @property forced_width +-- @tparam number|nil width The width (`nil` for automatic) + +--- The widget opacity (transparency). +-- @property opacity +-- @tparam[opt=1] number opacity The opacity (between 0 and 1) + +--- The widget visibility. +-- @property visible +-- @param boolean + +--- Set/get a widget's buttons. +-- @param _buttons The table of buttons that should bind to the widget. +-- @function buttons + +--- Emit a signal and ensure all parent widgets in the hierarchies also +-- forward the signal. This is useful to track signals when there is a dynamic +-- set of containers and layouts wrapping the widget. +-- @tparam string signal_name +-- @param ... Other arguments +-- @function emit_signal_recursive + +--- When the layout (size) change. +-- This signal is emitted when the previous results of `:layout()` and `:fit()` +-- are no longer valid. Unless this signal is emitted, `:layout()` and `:fit()` +-- must return the same result when called with the same arguments. +-- @signal widget::layout_changed +-- @see widget::redraw_needed + +--- When the widget content changed. +-- This signal is emitted when the content of the widget changes. The widget will +-- be redrawn, it is not re-layouted. Put differently, it is assumed that +-- `:layout()` and `:fit()` would still return the same results as before. +-- @signal widget::redraw_needed +-- @see widget::layout_changed + +--- When a mouse button is pressed over the widget. +-- @signal button::press +-- @tparam number lx The horizontal position relative to the (0,0) position in +-- the widget. +-- @tparam number ly The vertical position relative to the (0,0) position in the +-- widget. +-- @tparam number button The button number. +-- @tparam table mods The modifiers (mod4, mod1 (alt), Control, Shift) +-- @tparam table find_widgets_result The entry from the result of +-- @{wibox.drawable:find_widgets} for the position that the mouse hit. +-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing +-- the widget. +-- @tparam widget find_widgets_result.widget The widget being displayed. +-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy +-- managing the widget's geometry. +-- @tparam number find_widgets_result.x An approximation of the X position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.y An approximation of the Y position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.width An approximation of the width that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.height An approximation of the height that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.widget_width The exact width of the widget +-- in its local coordinate system. +-- @tparam number find_widgets_result.widget_height The exact height of the widget +-- in its local coordinate system. +-- @see mouse + +--- When a mouse button is released over the widget. +-- @signal button::release +-- @tparam number lx The horizontal position relative to the (0,0) position in +-- the widget. +-- @tparam number ly The vertical position relative to the (0,0) position in the +-- widget. +-- @tparam number button The button number. +-- @tparam table mods The modifiers (mod4, mod1 (alt), Control, Shift) +-- @tparam table find_widgets_result The entry from the result of +-- @{wibox.drawable:find_widgets} for the position that the mouse hit. +-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing +-- the widget. +-- @tparam widget find_widgets_result.widget The widget being displayed. +-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy +-- managing the widget's geometry. +-- @tparam number find_widgets_result.x An approximation of the X position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.y An approximation of the Y position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.width An approximation of the width that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.height An approximation of the height that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.widget_width The exact width of the widget +-- in its local coordinate system. +-- @tparam number find_widgets_result.widget_height The exact height of the widget +-- in its local coordinate system. +-- @see mouse + +--- When the mouse enter a widget. +-- @signal mouse::enter +-- @tparam table find_widgets_result The entry from the result of +-- @{wibox.drawable:find_widgets} for the position that the mouse hit. +-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing +-- the widget. +-- @tparam widget find_widgets_result.widget The widget being displayed. +-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy +-- managing the widget's geometry. +-- @tparam number find_widgets_result.x An approximation of the X position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.y An approximation of the Y position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.width An approximation of the width that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.height An approximation of the height that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.widget_width The exact width of the widget +-- in its local coordinate system. +-- @tparam number find_widgets_result.widget_height The exact height of the widget +-- in its local coordinate system. +-- @see mouse + +--- When the mouse leave a widget. +-- @signal mouse::leave +-- @tparam table find_widgets_result The entry from the result of +-- @{wibox.drawable:find_widgets} for the position that the mouse hit. +-- @tparam wibox.drawable find_widgets_result.drawable The drawable containing +-- the widget. +-- @tparam widget find_widgets_result.widget The widget being displayed. +-- @tparam wibox.hierarchy find_widgets_result.hierarchy The hierarchy +-- managing the widget's geometry. +-- @tparam number find_widgets_result.x An approximation of the X position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.y An approximation of the Y position that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.width An approximation of the width that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.height An approximation of the height that +-- the widget is visible at on the surface. +-- @tparam number find_widgets_result.widget_width The exact width of the widget +-- in its local coordinate system. +-- @tparam number find_widgets_result.widget_height The exact height of the widget +-- in its local coordinate system. +-- @see mouse + + +--Imported documentation + + +--- Disconnect to a signal. +-- @tparam string name The name of the signal +-- @tparam function func The callback that should be disconnected +-- @function disconnect_signal + +--- Emit a signal. +-- +-- @tparam string name The name of the signal +-- @param ... Extra arguments for the callback functions. Each connected +-- function receives the object as first argument and then any extra arguments +-- that are given to emit_signal() +-- @function emit_signal + +--- Connect to a signal. +-- @tparam string name The name of the signal +-- @tparam function func The callback to call when the signal is emitted +-- @function connect_signal + +--- Connect to a signal weakly. This allows the callback function to be garbage +-- collected and automatically disconnects the signal when that happens. +-- +-- **Warning:** +-- Only use this function if you really, really, really know what you +-- are doing. +-- @tparam string name The name of the signal +-- @tparam function func The callback to call when the signal is emitted +-- @function weak_connect_signal + + +return setmetatable(stack, stack.mt) +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 -- cgit v1.2.3-54-g00ecf