diff options
Diffstat (limited to 'awesome/lib/wibox/layout/align.lua')
-rw-r--r-- | awesome/lib/wibox/layout/align.lua | 526 |
1 files changed, 526 insertions, 0 deletions
diff --git a/awesome/lib/wibox/layout/align.lua b/awesome/lib/wibox/layout/align.lua new file mode 100644 index 0000000..92a5582 --- /dev/null +++ b/awesome/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 |