summaryrefslogtreecommitdiff
path: root/awesome/lib/wibox/layout/align.lua
diff options
context:
space:
mode:
Diffstat (limited to 'awesome/lib/wibox/layout/align.lua')
-rw-r--r--awesome/lib/wibox/layout/align.lua526
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