Merge branch 'new_widget_system3'
This commit is contained in:
commit
ca9242da4b
|
@ -195,7 +195,7 @@ local function add_value(_graph, value, group)
|
||||||
table.remove(values, 1)
|
table.remove(values, 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
_graph:emit_signal("widget::updated")
|
_graph:emit_signal("widget::redraw_needed")
|
||||||
return _graph
|
return _graph
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -205,7 +205,7 @@ end
|
||||||
function graph:set_height(height)
|
function graph:set_height(height)
|
||||||
if height >= 5 then
|
if height >= 5 then
|
||||||
data[self].height = height
|
data[self].height = height
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
@ -215,7 +215,7 @@ end
|
||||||
function graph:set_width(width)
|
function graph:set_width(width)
|
||||||
if width >= 5 then
|
if width >= 5 then
|
||||||
data[self].width = width
|
data[self].width = width
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
@ -226,7 +226,7 @@ for _, prop in ipairs(properties) do
|
||||||
graph["set_" .. prop] = function(_graph, value)
|
graph["set_" .. prop] = function(_graph, value)
|
||||||
if data[_graph][prop] ~= value then
|
if data[_graph][prop] ~= value then
|
||||||
data[_graph][prop] = value
|
data[_graph][prop] = value
|
||||||
_graph:emit_signal("widget::updated")
|
_graph:emit_signal("widget::redraw_needed")
|
||||||
end
|
end
|
||||||
return _graph
|
return _graph
|
||||||
end
|
end
|
||||||
|
|
|
@ -164,7 +164,7 @@ function progressbar:set_value(value)
|
||||||
local value = value or 0
|
local value = value or 0
|
||||||
local max_value = data[self].max_value
|
local max_value = data[self].max_value
|
||||||
data[self].value = math.min(max_value, math.max(0, value))
|
data[self].value = math.min(max_value, math.max(0, value))
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::redraw_needed")
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ end
|
||||||
-- @param height The height to set.
|
-- @param height The height to set.
|
||||||
function progressbar:set_height(height)
|
function progressbar:set_height(height)
|
||||||
data[self].height = height
|
data[self].height = height
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::layout_changed")
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ end
|
||||||
-- @param width The width to set.
|
-- @param width The width to set.
|
||||||
function progressbar:set_width(width)
|
function progressbar:set_width(width)
|
||||||
data[self].width = width
|
data[self].width = width
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::layout_changed")
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -189,7 +189,7 @@ for _, prop in ipairs(properties) do
|
||||||
if not progressbar["set_" .. prop] then
|
if not progressbar["set_" .. prop] then
|
||||||
progressbar["set_" .. prop] = function(pbar, value)
|
progressbar["set_" .. prop] = function(pbar, value)
|
||||||
data[pbar][prop] = value
|
data[pbar][prop] = value
|
||||||
pbar:emit_signal("widget::updated")
|
pbar:emit_signal("widget::redraw_needed")
|
||||||
return pbar
|
return pbar
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,6 +20,9 @@ local object = require("gears.object")
|
||||||
local sort = require("gears.sort")
|
local sort = require("gears.sort")
|
||||||
local surface = require("gears.surface")
|
local surface = require("gears.surface")
|
||||||
local timer = require("gears.timer")
|
local timer = require("gears.timer")
|
||||||
|
local matrix = require("gears.matrix")
|
||||||
|
local hierarchy = require("wibox.hierarchy")
|
||||||
|
local base = require("wibox.widget.base")
|
||||||
|
|
||||||
local drawables = setmetatable({}, { __mode = 'k' })
|
local drawables = setmetatable({}, { __mode = 'k' })
|
||||||
local wallpaper = nil
|
local wallpaper = nil
|
||||||
|
@ -69,6 +72,36 @@ local function do_redraw(self)
|
||||||
local geom = self.drawable:geometry();
|
local geom = self.drawable:geometry();
|
||||||
local x, y, width, height = geom.x, geom.y, geom.width, geom.height
|
local x, y, width, height = geom.x, geom.y, geom.width, geom.height
|
||||||
|
|
||||||
|
-- Relayout
|
||||||
|
if self._need_relayout then
|
||||||
|
self._need_relayout = false
|
||||||
|
local old_hierarchy = self._widget_hierarchy
|
||||||
|
self._widget_hierarchy_callback_arg = {}
|
||||||
|
self._widget_hierarchy = self.widget and
|
||||||
|
hierarchy.new(get_widget_context(self), self.widget, width, height,
|
||||||
|
self._redraw_callback, self._layout_callback, self._widget_hierarchy_callback_arg)
|
||||||
|
|
||||||
|
if old_hierarchy == nil or self._widget_hierarchy == nil or self._need_complete_repaint then
|
||||||
|
self._need_complete_repaint = false
|
||||||
|
self._dirty_area:union_rectangle(cairo.RectangleInt{
|
||||||
|
x = 0, y = 0, width = width, height = height
|
||||||
|
})
|
||||||
|
else
|
||||||
|
self._dirty_area:union(self._widget_hierarchy:find_differences(old_hierarchy))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Clip to the dirty area
|
||||||
|
if self._dirty_area:is_empty() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
for i = 0, self._dirty_area:num_rectangles() - 1 do
|
||||||
|
local rect = self._dirty_area:get_rectangle(i)
|
||||||
|
cr:rectangle(rect.x, rect.y, rect.width, rect.height)
|
||||||
|
end
|
||||||
|
self._dirty_area = cairo.Region.create()
|
||||||
|
cr:clip()
|
||||||
|
|
||||||
-- Draw the background
|
-- Draw the background
|
||||||
cr:save()
|
cr:save()
|
||||||
|
|
||||||
|
@ -93,21 +126,9 @@ local function do_redraw(self)
|
||||||
cr:restore()
|
cr:restore()
|
||||||
|
|
||||||
-- Draw the widget
|
-- Draw the widget
|
||||||
self._widget_geometries = {}
|
if self._widget_hierarchy then
|
||||||
if self.widget and self.widget.visible then
|
|
||||||
cr:set_source(self.foreground_color)
|
cr:set_source(self.foreground_color)
|
||||||
|
self._widget_hierarchy:draw(get_widget_context(self), cr)
|
||||||
if self.widget.opacity ~= 1 then
|
|
||||||
cr:push_group()
|
|
||||||
end
|
|
||||||
self.widget:draw(get_widget_context(self), cr, width, height)
|
|
||||||
if self.widget.opacity ~= 1 then
|
|
||||||
cr:pop_group_to_source()
|
|
||||||
cr.operator = cairo.Operator.OVER
|
|
||||||
cr:paint_with_alpha(self.widget.opacity)
|
|
||||||
end
|
|
||||||
|
|
||||||
self:widget_at(self.widget, 0, 0, width, height)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
self.drawable:refresh()
|
self.drawable:refresh()
|
||||||
|
@ -115,16 +136,33 @@ local function do_redraw(self)
|
||||||
debug.assert(cr.status == "SUCCESS", "Cairo context entered error state: " .. cr.status)
|
debug.assert(cr.status == "SUCCESS", "Cairo context entered error state: " .. cr.status)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Register a widget's position.
|
local function find_widgets(drawable, result, hierarchy, x, y)
|
||||||
-- This is internal, don't call it yourself! Only wibox.layout.base.draw_widget
|
local m = hierarchy:get_matrix_from_device()
|
||||||
-- is allowed to call this.
|
|
||||||
function drawable:widget_at(widget, x, y, width, height)
|
-- Is (x,y) inside of this hierarchy or any child (aka the draw extents)
|
||||||
local t = {
|
local x1, y1 = m:transform_point(x, y)
|
||||||
widget = widget,
|
local x2, y2, width, height = hierarchy:get_draw_extents()
|
||||||
x = x, y = y,drawable = self,
|
if x1 < x2 or x1 >= x2 + width then
|
||||||
width = width, height = height
|
return
|
||||||
}
|
end
|
||||||
table.insert(self._widget_geometries, t)
|
if y1 < y2 or y1 >= y2 + height then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Is (x,y) inside of this widget?
|
||||||
|
local width, height = hierarchy:get_size()
|
||||||
|
if x1 >= 0 and y1 >= 0 and x1 <= width and y1 <= height then
|
||||||
|
-- Get the extents of this widget in the device space
|
||||||
|
local x2, y2, w2, h2 = matrix.transform_rectangle(hierarchy:get_matrix_to_device(),
|
||||||
|
0, 0, width, height)
|
||||||
|
table.insert(result, {
|
||||||
|
x = x2, y = y2, width = w2, height = h2,
|
||||||
|
drawable = drawable, widget = hierarchy:get_widget()
|
||||||
|
})
|
||||||
|
end
|
||||||
|
for _, child in ipairs(hierarchy:get_children()) do
|
||||||
|
find_widgets(drawable, result, child, x, y)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Find a widget by a point.
|
--- Find a widget by a point.
|
||||||
|
@ -134,43 +172,20 @@ end
|
||||||
-- @return A sorted table with all widgets that contain the given point. The
|
-- @return A sorted table with all widgets that contain the given point. The
|
||||||
-- widgets are sorted by relevance.
|
-- widgets are sorted by relevance.
|
||||||
function drawable:find_widgets(x, y)
|
function drawable:find_widgets(x, y)
|
||||||
local matches = {}
|
local result = {}
|
||||||
-- Find all widgets that contain the point
|
if self._widget_hierarchy then
|
||||||
for k, v in pairs(self._widget_geometries) do
|
find_widgets(self, result, self._widget_hierarchy, x, y)
|
||||||
local match = true
|
|
||||||
if v.x > x or v.x + v.width <= x then match = false end
|
|
||||||
if v.y > y or v.y + v.height <= y then match = false end
|
|
||||||
if match then
|
|
||||||
table.insert(matches, v)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
return result
|
||||||
-- Sort the matches by area, the assumption here is that widgets don't
|
|
||||||
-- overlap and so smaller widgets are "more specific".
|
|
||||||
local function cmp(a, b)
|
|
||||||
local area_a = a.width * a.height
|
|
||||||
local area_b = b.width * b.height
|
|
||||||
return area_a < area_b
|
|
||||||
end
|
|
||||||
sort(matches, cmp)
|
|
||||||
|
|
||||||
return matches
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set the widget that the drawable displays
|
--- Set the widget that the drawable displays
|
||||||
function drawable:set_widget(widget)
|
function drawable:set_widget(widget)
|
||||||
if self.widget then
|
|
||||||
-- Disconnect from the old widget so that we aren't updated due to it
|
|
||||||
self.widget:disconnect_signal("widget::updated", self.draw)
|
|
||||||
end
|
|
||||||
|
|
||||||
self.widget = widget
|
self.widget = widget
|
||||||
if widget then
|
|
||||||
widget:weak_connect_signal("widget::updated", self.draw)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Make sure the widget gets drawn
|
-- Make sure the widget gets drawn
|
||||||
|
self._need_relayout = true
|
||||||
self.draw()
|
self.draw()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -192,16 +207,16 @@ function drawable:set_bg(c)
|
||||||
if self._redraw_on_move ~= redraw_on_move then
|
if self._redraw_on_move ~= redraw_on_move then
|
||||||
self._redraw_on_move = redraw_on_move
|
self._redraw_on_move = redraw_on_move
|
||||||
if redraw_on_move then
|
if redraw_on_move then
|
||||||
self.drawable:connect_signal("property::x", self.draw)
|
self.drawable:connect_signal("property::x", self._do_complete_repaint)
|
||||||
self.drawable:connect_signal("property::y", self.draw)
|
self.drawable:connect_signal("property::y", self._do_complete_repaint)
|
||||||
else
|
else
|
||||||
self.drawable:disconnect_signal("property::x", self.draw)
|
self.drawable:disconnect_signal("property::x", self._do_complete_repaint)
|
||||||
self.drawable:disconnect_signal("property::y", self.draw)
|
self.drawable:disconnect_signal("property::y", self._do_complete_repaint)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self.background_color = c
|
self.background_color = c
|
||||||
self.draw()
|
self._do_complete_repaint()
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the foreground of the drawable
|
--- Set the foreground of the drawable
|
||||||
|
@ -213,7 +228,7 @@ function drawable:set_fg(c)
|
||||||
c = color(c)
|
c = color(c)
|
||||||
end
|
end
|
||||||
self.foreground_color = c
|
self.foreground_color = c
|
||||||
self.draw()
|
self._do_complete_repaint()
|
||||||
end
|
end
|
||||||
|
|
||||||
local function emit_difference(name, list, skip)
|
local function emit_difference(name, list, skip)
|
||||||
|
@ -280,6 +295,9 @@ function drawable.new(d, widget_context_skeleton, drawable_name)
|
||||||
local ret = object()
|
local ret = object()
|
||||||
ret.drawable = d
|
ret.drawable = d
|
||||||
ret._widget_context_skeleton = widget_context_skeleton
|
ret._widget_context_skeleton = widget_context_skeleton
|
||||||
|
ret._need_complete_repaint = true
|
||||||
|
ret._need_relayout = true
|
||||||
|
ret._dirty_area = cairo.Region.create()
|
||||||
setup_signals(ret)
|
setup_signals(ret)
|
||||||
|
|
||||||
for k, v in pairs(drawable) do
|
for k, v in pairs(drawable) do
|
||||||
|
@ -302,8 +320,12 @@ function drawable.new(d, widget_context_skeleton, drawable_name)
|
||||||
ret._redraw_pending = true
|
ret._redraw_pending = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
drawables[ret.draw] = true
|
ret._do_complete_repaint = function()
|
||||||
d:connect_signal("property::surface", ret.draw)
|
ret._need_complete_repaint = true
|
||||||
|
ret:draw()
|
||||||
|
end
|
||||||
|
drawables[ret._do_complete_repaint] = true
|
||||||
|
d:connect_signal("property::surface", ret._do_complete_repaint)
|
||||||
|
|
||||||
-- Currently we aren't redrawing on move (signals not connected).
|
-- Currently we aren't redrawing on move (signals not connected).
|
||||||
-- :set_bg() will later recompute this.
|
-- :set_bg() will later recompute this.
|
||||||
|
@ -314,7 +336,6 @@ function drawable.new(d, widget_context_skeleton, drawable_name)
|
||||||
ret:set_fg(beautiful.fg_normal)
|
ret:set_fg(beautiful.fg_normal)
|
||||||
|
|
||||||
-- Initialize internals
|
-- Initialize internals
|
||||||
ret._widget_geometries = {}
|
|
||||||
ret._widgets_under_mouse = {}
|
ret._widgets_under_mouse = {}
|
||||||
|
|
||||||
local function button_signal(name)
|
local function button_signal(name)
|
||||||
|
@ -334,6 +355,28 @@ function drawable.new(d, widget_context_skeleton, drawable_name)
|
||||||
d:connect_signal("mouse::move", function(_, x, y) handle_motion(ret, x, y) end)
|
d:connect_signal("mouse::move", function(_, x, y) handle_motion(ret, x, y) end)
|
||||||
d:connect_signal("mouse::leave", function() handle_leave(ret) end)
|
d:connect_signal("mouse::leave", function() handle_leave(ret) end)
|
||||||
|
|
||||||
|
-- Set up our callbacks for repaints
|
||||||
|
ret._redraw_callback = function(hierarchy, arg)
|
||||||
|
if ret._widget_hierarchy_callback_arg ~= arg then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local m = hierarchy:get_matrix_to_device()
|
||||||
|
local x, y, width, height = matrix.transform_rectangle(m, hierarchy:get_draw_extents())
|
||||||
|
local x1, y1 = math.floor(x), math.floor(y)
|
||||||
|
local x2, y2 = math.ceil(x + width), math.ceil(y + height)
|
||||||
|
ret._dirty_area:union_rectangle(cairo.RectangleInt{
|
||||||
|
x = x1, y = y1, width = x2 - x1, height = y2 - y1
|
||||||
|
})
|
||||||
|
ret:draw()
|
||||||
|
end
|
||||||
|
ret._layout_callback = function(hierarchy, arg)
|
||||||
|
if ret._widget_hierarchy_callback_arg ~= arg then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
ret._need_relayout = true
|
||||||
|
ret:draw()
|
||||||
|
end
|
||||||
|
|
||||||
-- Add __tostring method to metatable.
|
-- Add __tostring method to metatable.
|
||||||
ret.drawable_name = drawable_name or object.modulename(3)
|
ret.drawable_name = drawable_name or object.modulename(3)
|
||||||
local mt = {}
|
local mt = {}
|
||||||
|
@ -344,7 +387,7 @@ function drawable.new(d, widget_context_skeleton, drawable_name)
|
||||||
ret = setmetatable(ret, mt)
|
ret = setmetatable(ret, mt)
|
||||||
|
|
||||||
-- Make sure the drawable is drawn at least once
|
-- Make sure the drawable is drawn at least once
|
||||||
ret.draw()
|
ret._do_complete_repaint()
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,260 @@
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
-- Management of widget hierarchies. Each widget hierarchy object has a widget
|
||||||
|
-- for which it saves e.g. size and transformation in its parent. Also, each
|
||||||
|
-- widget has a number of children.
|
||||||
|
--
|
||||||
|
-- @author Uli Schlachter
|
||||||
|
-- @copyright 2015 Uli Schlachter
|
||||||
|
-- @release @AWESOME_VERSION@
|
||||||
|
-- @module wibox.hierarchy
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
local matrix = require("gears.matrix")
|
||||||
|
local cairo = require("lgi").cairo
|
||||||
|
local base = require("wibox.widget.base")
|
||||||
|
|
||||||
|
local hierarchy = {}
|
||||||
|
|
||||||
|
local function hierarchy_new(context, widget, width, height, redraw_callback, layout_callback, callback_arg,
|
||||||
|
matrix_to_parent, matrix_to_device)
|
||||||
|
local children = base.layout_widget(context, widget, width, height)
|
||||||
|
local draws_x1, draws_y1, draws_x2, draws_y2 = 0, 0, width, height
|
||||||
|
local result = {
|
||||||
|
_matrix = matrix_to_parent,
|
||||||
|
_matrix_to_device = matrix_to_device,
|
||||||
|
_widget = widget,
|
||||||
|
_size = {
|
||||||
|
width = width,
|
||||||
|
height = height
|
||||||
|
},
|
||||||
|
_draw_extents = nil,
|
||||||
|
_children = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
result._redraw = function() redraw_callback(result, callback_arg) end
|
||||||
|
result._layout = function() layout_callback(result, callback_arg) end
|
||||||
|
widget:weak_connect_signal("widget::redraw_needed", result._redraw)
|
||||||
|
widget:weak_connect_signal("widget::layout_changed", result._layout)
|
||||||
|
|
||||||
|
for _, w in ipairs(children or {}) do
|
||||||
|
local to_dev = cairo.Matrix.create_identity()
|
||||||
|
to_dev:multiply(matrix_to_device, w._matrix)
|
||||||
|
|
||||||
|
local r = hierarchy_new(context, w._widget, w._width, w._height, redraw_callback, layout_callback,
|
||||||
|
callback_arg, matrix.copy(w._matrix), to_dev)
|
||||||
|
table.insert(result._children, r)
|
||||||
|
|
||||||
|
-- Update our drawing extents
|
||||||
|
local s = r._draw_extents
|
||||||
|
local px, py, pwidth, pheight = matrix.transform_rectangle(r._matrix,
|
||||||
|
s.x, s.y, s.width, s.height)
|
||||||
|
local px2, py2 = px + pwidth, py + pheight
|
||||||
|
draws_x1 = math.min(draws_x1, px)
|
||||||
|
draws_y1 = math.min(draws_y1, py)
|
||||||
|
draws_x2 = math.max(draws_x2, px2)
|
||||||
|
draws_y2 = math.max(draws_y2, py2)
|
||||||
|
end
|
||||||
|
result._draw_extents = {
|
||||||
|
x = draws_x1,
|
||||||
|
y = draws_y1,
|
||||||
|
width = draws_x2 - draws_x1,
|
||||||
|
height = draws_y2 - draws_y1
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, f in pairs(hierarchy) do
|
||||||
|
if type(f) == "function" then
|
||||||
|
result[k] = f
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Create a new widget hierarchy that has no parent.
|
||||||
|
-- @param context The context in which we are laid out.
|
||||||
|
-- @param widget The widget that is at the base of the hierarchy.
|
||||||
|
-- @param width The available width for this hierarchy.
|
||||||
|
-- @param height The available height for this hierarchy.
|
||||||
|
-- @param redraw_callback Callback that is called with the corresponding widget
|
||||||
|
-- hierarchy on widget::redraw_needed on some widget.
|
||||||
|
-- @param layout_callback Callback that is called with the corresponding widget
|
||||||
|
-- hierarchy on widget::layout_changed on some widget.
|
||||||
|
-- @param callback_arg A second argument that is given to the above callbacks.
|
||||||
|
-- @return A new widget hierarchy
|
||||||
|
function hierarchy.new(context, widget, width, height, redraw_callback, layout_callback, callback_arg)
|
||||||
|
return hierarchy_new(context, widget, width, height, redraw_callback, layout_callback, callback_arg,
|
||||||
|
cairo.Matrix.create_identity(), cairo.Matrix.create_identity())
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the widget that this hierarchy manages.
|
||||||
|
function hierarchy:get_widget()
|
||||||
|
return self._widget
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get a cairo matrix that transforms to the parent's coordinate space from
|
||||||
|
-- this hierarchy's coordinate system.
|
||||||
|
-- @return A cairo matrix describing the transformation.
|
||||||
|
function hierarchy:get_matrix_to_parent()
|
||||||
|
return matrix.copy(self._matrix)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get a cairo matrix that transforms to the base of this hierarchy's
|
||||||
|
-- coordinate system (aka the coordinate system of the device that this
|
||||||
|
-- hierarchy is applied upon) from this hierarchy's coordinate system.
|
||||||
|
-- @return A cairo matrix describing the transformation.
|
||||||
|
function hierarchy:get_matrix_to_device()
|
||||||
|
return matrix.copy(self._matrix_to_device)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get a cairo matrix that transforms from the parent's coordinate space into
|
||||||
|
-- this hierarchy's coordinate system.
|
||||||
|
-- @return A cairo matrix describing the transformation.
|
||||||
|
function hierarchy:get_matrix_from_parent()
|
||||||
|
local m = self:get_matrix_to_parent()
|
||||||
|
m:invert()
|
||||||
|
return m
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get a cairo matrix that transforms from the base of this hierarchy's
|
||||||
|
-- coordinate system (aka the coordinate system of the device that this
|
||||||
|
-- hierarchy is applied upon) into this hierarchy's coordinate system.
|
||||||
|
-- @return A cairo matrix describing the transformation.
|
||||||
|
function hierarchy:get_matrix_from_device()
|
||||||
|
local m = self:get_matrix_to_device()
|
||||||
|
m:invert()
|
||||||
|
return m
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the extents that this hierarchy possibly draws to (in the current coordinate space).
|
||||||
|
-- This includes the size of this element plus the size of all children
|
||||||
|
-- (after applying the corresponding transformation).
|
||||||
|
-- @return x, y, width, height
|
||||||
|
function hierarchy:get_draw_extents()
|
||||||
|
local ext = self._draw_extents
|
||||||
|
return ext.x, ext.y, ext.width, ext.height
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the size that this hierarchy logically covers (in the current coordinate space).
|
||||||
|
-- @return width, height
|
||||||
|
function hierarchy:get_size()
|
||||||
|
local ext = self._size
|
||||||
|
return ext.width, ext.height
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get a list of all children.
|
||||||
|
-- @return List of all children hierarchies.
|
||||||
|
function hierarchy:get_children()
|
||||||
|
return self._children
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Compare two widget hierarchies and compute a cairo Region that contains all
|
||||||
|
-- rectangles that aren't the same between both hierarchies.
|
||||||
|
-- @param other The hierarchy to compare with
|
||||||
|
-- @return A cairo Region containing the differences.
|
||||||
|
function hierarchy:find_differences(other)
|
||||||
|
local region = cairo.Region.create()
|
||||||
|
local function needs_redraw(h)
|
||||||
|
local m = h:get_matrix_to_device()
|
||||||
|
local p = h._draw_extents
|
||||||
|
local x, y, width, height = matrix.transform_rectangle(m, p.x, p.y, p.width, p.height)
|
||||||
|
local x1, y1 = math.floor(x), math.floor(y)
|
||||||
|
local x2, y2 = math.ceil(x + width), math.ceil(y + height)
|
||||||
|
region:union_rectangle(cairo.RectangleInt({
|
||||||
|
x = x1, y = y1, width = x2 - x1, height = y2 - y1
|
||||||
|
}))
|
||||||
|
end
|
||||||
|
local compare
|
||||||
|
compare = function(self, other)
|
||||||
|
local s_size, o_size = self._size, other._size
|
||||||
|
if s_size.width ~= o_size.width or s_size.height ~= o_size.height or
|
||||||
|
#self._children ~= #other._children or self._widget ~= other._widget or
|
||||||
|
not matrix.equals(self._matrix, other._matrix) then
|
||||||
|
needs_redraw(self)
|
||||||
|
needs_redraw(other)
|
||||||
|
else
|
||||||
|
for i = 1, #self._children do
|
||||||
|
compare(self._children[i], other._children[i])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
compare(self, other)
|
||||||
|
return region
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Does the given cairo context have an empty clip (aka "no drawing possible")?
|
||||||
|
local function empty_clip(cr)
|
||||||
|
local x, y, width, height = cr:clip_extents()
|
||||||
|
return width == 0 or height == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Draw a hierarchy to some cairo context.
|
||||||
|
-- This function draws the widgets in this widget hierarchy to the given cairo
|
||||||
|
-- context. The context's clip is used to skip parts that aren't visible.
|
||||||
|
-- @param context The context in which widgets are drawn.
|
||||||
|
-- @param cr The cairo context that is used for drawing.
|
||||||
|
function hierarchy:draw(context, cr)
|
||||||
|
local widget = self:get_widget()
|
||||||
|
if not widget.visible then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
cr:save()
|
||||||
|
cr:transform(self:get_matrix_to_parent())
|
||||||
|
|
||||||
|
-- Clip to the draw extents
|
||||||
|
cr:rectangle(self:get_draw_extents())
|
||||||
|
cr:clip()
|
||||||
|
|
||||||
|
-- Draw if needed
|
||||||
|
if not empty_clip(cr) then
|
||||||
|
local opacity = widget.opacity
|
||||||
|
local function call(func, extra_arg1, extra_arg2)
|
||||||
|
if not func then return end
|
||||||
|
local function error_function(err)
|
||||||
|
print(debug.traceback("Error while drawing widget: " .. tostring(err), 2))
|
||||||
|
end
|
||||||
|
if not extra_arg2 then
|
||||||
|
xpcall(function()
|
||||||
|
func(widget, context, cr, self:get_size())
|
||||||
|
end, error_function)
|
||||||
|
else
|
||||||
|
xpcall(function()
|
||||||
|
func(widget, context, extra_arg1, extra_arg2, cr, self:get_size())
|
||||||
|
end, error_function)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Prepare opacity handling
|
||||||
|
if opacity ~= 1 then
|
||||||
|
cr:push_group()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Draw the widget
|
||||||
|
cr:save()
|
||||||
|
cr:rectangle(0, 0, self:get_size())
|
||||||
|
cr:clip()
|
||||||
|
call(widget.draw)
|
||||||
|
cr:restore()
|
||||||
|
|
||||||
|
-- Draw its children (We already clipped to the draw extents above)
|
||||||
|
call(widget.before_draw_children)
|
||||||
|
for i, wi in ipairs(self:get_children()) do
|
||||||
|
call(widget.before_draw_child, i, wi:get_widget())
|
||||||
|
wi:draw(context, cr)
|
||||||
|
call(widget.after_draw_child, i, wi:get_widget())
|
||||||
|
end
|
||||||
|
call(widget.after_draw_children)
|
||||||
|
|
||||||
|
-- Apply opacity
|
||||||
|
if opacity ~= 1 then
|
||||||
|
cr:pop_group_to_source()
|
||||||
|
cr.operator = cairo.Operator.OVER
|
||||||
|
cr:paint_with_alpha(opacity)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
cr:restore()
|
||||||
|
end
|
||||||
|
|
||||||
|
return hierarchy
|
||||||
|
|
||||||
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
|
@ -29,6 +29,7 @@ local wibox = { mt = {} }
|
||||||
wibox.layout = require("wibox.layout")
|
wibox.layout = require("wibox.layout")
|
||||||
wibox.widget = require("wibox.widget")
|
wibox.widget = require("wibox.widget")
|
||||||
wibox.drawable = require("wibox.drawable")
|
wibox.drawable = require("wibox.drawable")
|
||||||
|
wibox.hierarchy = require("wibox.hierarchy")
|
||||||
|
|
||||||
--- Set the widget that the wibox displays
|
--- Set the widget that the wibox displays
|
||||||
function wibox:set_widget(widget)
|
function wibox:set_widget(widget)
|
||||||
|
|
|
@ -10,17 +10,17 @@ local table = table
|
||||||
local pairs = pairs
|
local pairs = pairs
|
||||||
local type = type
|
local type = type
|
||||||
local floor = math.floor
|
local floor = math.floor
|
||||||
local base = require("wibox.layout.base")
|
local base = require("wibox.widget.base")
|
||||||
local widget_base = require("wibox.widget.base")
|
|
||||||
|
|
||||||
local align = {}
|
local align = {}
|
||||||
|
|
||||||
--- Draw an align layout.
|
--- Calculate the layout of an align layout.
|
||||||
-- @param context The context in which we are drawn.
|
-- @param context The context in which we are drawn.
|
||||||
-- @param cr The cairo context to use.
|
|
||||||
-- @param width The available width.
|
-- @param width The available width.
|
||||||
-- @param height The available height.
|
-- @param height The available height.
|
||||||
function align:draw(context, cr, width, height)
|
function align:layout(context, width, height)
|
||||||
|
local result = {}
|
||||||
|
|
||||||
-- Draw will have to deal with all three align modes and should work in a
|
-- 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
|
-- 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
|
-- are all missing, it won't draw anything.) It should also handle the case
|
||||||
|
@ -45,8 +45,7 @@ function align:draw(context, cr, width, height)
|
||||||
-- if all the space is taken, skip the rest, and draw just the middle
|
-- if all the space is taken, skip the rest, and draw just the middle
|
||||||
-- widget
|
-- widget
|
||||||
if size_second >= size_remains then
|
if size_second >= size_remains then
|
||||||
base.draw_widget(context, cr, self.second, 0, 0, width, height)
|
return { base.place_widget_at(self.second, 0, 0, width, height) }
|
||||||
return
|
|
||||||
else
|
else
|
||||||
-- the middle widget is sized first, the outside widgets are given
|
-- the middle widget is sized first, the outside widgets are given
|
||||||
-- the remaining space if available we will draw later
|
-- the remaining space if available we will draw later
|
||||||
|
@ -84,7 +83,7 @@ function align:draw(context, cr, width, height)
|
||||||
w = size_remains
|
w = size_remains
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
base.draw_widget(context, cr, self.first, 0, 0, w, h)
|
table.insert(result, base.place_widget_at(self.first, 0, 0, w, h))
|
||||||
end
|
end
|
||||||
-- size_remains will be <= 0 if first used all the space
|
-- size_remains will be <= 0 if first used all the space
|
||||||
if self.third and size_remains > 0 then
|
if self.third and size_remains > 0 then
|
||||||
|
@ -110,7 +109,7 @@ function align:draw(context, cr, width, height)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local x, y = width - w, height - h
|
local x, y = width - w, height - h
|
||||||
base.draw_widget(context, cr, self.third, x, y, w, h)
|
table.insert(result, base.place_widget_at(self.third, x, y, w, h))
|
||||||
end
|
end
|
||||||
-- here we either draw the second widget in the space set aside for it
|
-- 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"
|
-- in the beginning, or in the remaining space, if it is "inside"
|
||||||
|
@ -133,37 +132,36 @@ function align:draw(context, cr, width, height)
|
||||||
x = floor( (width -w)/2 )
|
x = floor( (width -w)/2 )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
base.draw_widget(context, cr, self.second, x, y, w, h)
|
table.insert(result, base.place_widget_at(self.second, x, y, w, h))
|
||||||
end
|
end
|
||||||
end
|
return result
|
||||||
|
|
||||||
local function widget_changed(layout, old_w, new_w)
|
|
||||||
if old_w then
|
|
||||||
old_w:disconnect_signal("widget::updated", layout._emit_updated)
|
|
||||||
end
|
|
||||||
if new_w then
|
|
||||||
widget_base.check_widget(new_w)
|
|
||||||
new_w:weak_connect_signal("widget::updated", layout._emit_updated)
|
|
||||||
end
|
|
||||||
layout._emit_updated()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the layout's first widget. This is the widget that is at the left/top
|
--- Set the layout's first widget. This is the widget that is at the left/top
|
||||||
function align:set_first(widget)
|
function align:set_first(widget)
|
||||||
widget_changed(self, self.first, widget)
|
if self.first == widget then
|
||||||
|
return
|
||||||
|
end
|
||||||
self.first = widget
|
self.first = widget
|
||||||
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the layout's second widget. This is the centered one.
|
--- Set the layout's second widget. This is the centered one.
|
||||||
function align:set_second(widget)
|
function align:set_second(widget)
|
||||||
widget_changed(self, self.second, widget)
|
if self.second == widget then
|
||||||
|
return
|
||||||
|
end
|
||||||
self.second = widget
|
self.second = widget
|
||||||
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the layout's third widget. This is the widget that is at the right/bottom
|
--- Set the layout's third widget. This is the widget that is at the right/bottom
|
||||||
function align:set_third(widget)
|
function align:set_third(widget)
|
||||||
widget_changed(self, self.third, widget)
|
if self.third == widget then
|
||||||
|
return
|
||||||
|
end
|
||||||
self.third = widget
|
self.third = widget
|
||||||
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Fit the align layout into the given space. The align layout will
|
--- Fit the align layout into the given space. The align layout will
|
||||||
|
@ -192,6 +190,7 @@ function align:fit(context, orig_width, orig_height)
|
||||||
end
|
end
|
||||||
return used_in_dir, used_in_other
|
return used_in_dir, used_in_other
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the expand mode which determines how sub widgets expand to take up
|
--- Set the expand mode which determines how sub widgets expand to take up
|
||||||
-- unused space. Options are:
|
-- unused space. Options are:
|
||||||
-- "inside" - Default option. Size of outside widgets is determined using their
|
-- "inside" - Default option. Size of outside widgets is determined using their
|
||||||
|
@ -210,22 +209,19 @@ function align:set_expand(mode)
|
||||||
else
|
else
|
||||||
self._expand = "inside"
|
self._expand = "inside"
|
||||||
end
|
end
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
function align:reset()
|
function align:reset()
|
||||||
for k, v in pairs({ "first", "second", "third" }) do
|
for k, v in pairs({ "first", "second", "third" }) do
|
||||||
self[v] = nil
|
self[v] = nil
|
||||||
end
|
end
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_layout(dir)
|
local function get_layout(dir)
|
||||||
local ret = widget_base.make_widget()
|
local ret = base.make_widget()
|
||||||
ret.dir = dir
|
ret.dir = dir
|
||||||
ret._emit_updated = function()
|
|
||||||
ret:emit_signal("widget::updated")
|
|
||||||
end
|
|
||||||
|
|
||||||
for k, v in pairs(align) do
|
for k, v in pairs(align) do
|
||||||
if type(v) == "function" then
|
if type(v) == "function" then
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
---------------------------------------------------------------------------
|
|
||||||
-- @author Uli Schlachter
|
|
||||||
-- @copyright 2010 Uli Schlachter
|
|
||||||
-- @release @AWESOME_VERSION@
|
|
||||||
-- @classmod wibox.layout.base
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
local xpcall = xpcall
|
|
||||||
local print = print
|
|
||||||
local cairo = require("lgi").cairo
|
|
||||||
local wbase = require("wibox.widget.base")
|
|
||||||
|
|
||||||
local base = {}
|
|
||||||
|
|
||||||
--- Fit a widget for the given available width and height
|
|
||||||
-- @param context The context in which we are fit.
|
|
||||||
-- @param widget The widget to fit (this uses widget:fit(width, height)).
|
|
||||||
-- @param width The available width for the widget
|
|
||||||
-- @param height The available height for the widget
|
|
||||||
-- @return The width and height that the widget wants to use
|
|
||||||
function base.fit_widget(context, widget, width, height)
|
|
||||||
if not widget.visible then
|
|
||||||
return 0, 0
|
|
||||||
end
|
|
||||||
-- Sanitize the input. This also filters out e.g. NaN.
|
|
||||||
local width = math.max(0, width)
|
|
||||||
local height = math.max(0, height)
|
|
||||||
|
|
||||||
local w, h = widget._fit_geometry_cache:get(context, width, height)
|
|
||||||
|
|
||||||
-- Also sanitize the output.
|
|
||||||
w = math.max(0, math.min(w, width))
|
|
||||||
h = math.max(0, math.min(h, height))
|
|
||||||
return w, h
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Draw a widget via a cairo context
|
|
||||||
-- @param context The context in which we are drawn.
|
|
||||||
-- @param cr The cairo context used
|
|
||||||
-- @param widget The widget to draw (this uses widget:draw(cr, width, height)).
|
|
||||||
-- @param x The position that the widget should get
|
|
||||||
-- @param y The position that the widget should get
|
|
||||||
-- @param width The widget's width
|
|
||||||
-- @param height The widget's height
|
|
||||||
function base.draw_widget(context, cr, widget, x, y, width, height)
|
|
||||||
if not widget.visible then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Use save() / restore() so that our modifications aren't permanent
|
|
||||||
cr:save()
|
|
||||||
|
|
||||||
-- Move (0, 0) to the place where the widget should show up
|
|
||||||
cr:translate(x, y)
|
|
||||||
|
|
||||||
-- Make sure the widget cannot draw outside of the allowed area
|
|
||||||
cr:rectangle(0, 0, width, height)
|
|
||||||
cr:clip()
|
|
||||||
|
|
||||||
if widget.opacity ~= 1 then
|
|
||||||
cr:push_group()
|
|
||||||
end
|
|
||||||
-- Let the widget draw itself
|
|
||||||
xpcall(function()
|
|
||||||
widget:draw(context, cr, width, height)
|
|
||||||
end, function(err)
|
|
||||||
print(debug.traceback("Error while drawing widget: "..tostring(err), 2))
|
|
||||||
end)
|
|
||||||
if widget.opacity ~= 1 then
|
|
||||||
cr:pop_group_to_source()
|
|
||||||
cr.operator = cairo.Operator.OVER
|
|
||||||
cr:paint_with_alpha(widget.opacity)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Register the widget for input handling
|
|
||||||
context:widget_at(widget, wbase.rect_to_device_geometry(cr, 0, 0, width, height))
|
|
||||||
|
|
||||||
cr:restore()
|
|
||||||
end
|
|
||||||
|
|
||||||
return base
|
|
||||||
|
|
||||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
|
|
@ -8,19 +8,16 @@
|
||||||
local pairs = pairs
|
local pairs = pairs
|
||||||
local type = type
|
local type = type
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
local base = require("wibox.layout.base")
|
local base = require("wibox.widget.base")
|
||||||
local widget_base = require("wibox.widget.base")
|
|
||||||
local math = math
|
local math = math
|
||||||
|
|
||||||
local constraint = { mt = {} }
|
local constraint = { mt = {} }
|
||||||
|
|
||||||
--- Draw a constraint layout
|
--- Layout a constraint layout
|
||||||
function constraint:draw(context, cr, width, height)
|
function constraint:layout(context, width, height)
|
||||||
if not self.widget then
|
if self.widget then
|
||||||
return
|
return { base.place_widget_at(self.widget, 0, 0, width, height) }
|
||||||
end
|
end
|
||||||
|
|
||||||
base.draw_widget(context, cr, self.widget, 0, 0, width, height)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Fit a constraint layout into the given space
|
--- Fit a constraint layout into the given space
|
||||||
|
@ -43,15 +40,8 @@ end
|
||||||
|
|
||||||
--- Set the widget that this layout adds a constraint on.
|
--- Set the widget that this layout adds a constraint on.
|
||||||
function constraint:set_widget(widget)
|
function constraint:set_widget(widget)
|
||||||
if self.widget then
|
|
||||||
self.widget:disconnect_signal("widget::updated", self._emit_updated)
|
|
||||||
end
|
|
||||||
if widget then
|
|
||||||
widget_base.check_widget(widget)
|
|
||||||
widget:weak_connect_signal("widget::updated", self._emit_updated)
|
|
||||||
end
|
|
||||||
self.widget = widget
|
self.widget = widget
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the strategy to use for the constraining. Valid values are 'max',
|
--- Set the strategy to use for the constraining. Valid values are 'max',
|
||||||
|
@ -74,19 +64,19 @@ function constraint:set_strategy(val)
|
||||||
end
|
end
|
||||||
|
|
||||||
self._strategy = func[val]
|
self._strategy = func[val]
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the maximum width to val. nil for no width limit.
|
--- Set the maximum width to val. nil for no width limit.
|
||||||
function constraint:set_width(val)
|
function constraint:set_width(val)
|
||||||
self._width = val
|
self._width = val
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the maximum height to val. nil for no height limit.
|
--- Set the maximum height to val. nil for no height limit.
|
||||||
function constraint:set_height(val)
|
function constraint:set_height(val)
|
||||||
self._height = val
|
self._height = val
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Reset this layout. The widget will be unreferenced, strategy set to "max"
|
--- Reset this layout. The widget will be unreferenced, strategy set to "max"
|
||||||
|
@ -117,10 +107,6 @@ local function new(widget, strategy, width, height)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
ret._emit_updated = function()
|
|
||||||
ret:emit_signal("widget::updated")
|
|
||||||
end
|
|
||||||
|
|
||||||
ret:set_strategy(strategy or "max")
|
ret:set_strategy(strategy or "max")
|
||||||
ret:set_width(width)
|
ret:set_width(width)
|
||||||
ret:set_height(height)
|
ret:set_height(height)
|
||||||
|
|
|
@ -5,21 +5,19 @@
|
||||||
-- @classmod wibox.layout.fixed
|
-- @classmod wibox.layout.fixed
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
local base = require("wibox.layout.base")
|
local base = require("wibox.widget.base")
|
||||||
local widget_base = require("wibox.widget.base")
|
|
||||||
local table = table
|
local table = table
|
||||||
local pairs = pairs
|
local pairs = pairs
|
||||||
|
|
||||||
local fixed = {}
|
local fixed = {}
|
||||||
|
|
||||||
--- Draw a fixed layout. Each widget gets just the space it asks for.
|
--- Layout a fixed layout. Each widget gets just the space it asks for.
|
||||||
-- @param context The context in which we are drawn.
|
-- @param context The context in which we are drawn.
|
||||||
-- @param cr The cairo context to use.
|
|
||||||
-- @param width The available width.
|
-- @param width The available width.
|
||||||
-- @param height The available height.
|
-- @param height The available height.
|
||||||
-- @return The total space needed by the layout.
|
function fixed:layout(context, width, height)
|
||||||
function fixed:draw(context, cr, width, height)
|
local result = {}
|
||||||
local pos,spacing = 0,self._spacing or 0
|
local pos,spacing = 0, self._spacing
|
||||||
|
|
||||||
for k, v in pairs(self.widgets) do
|
for k, v in pairs(self.widgets) do
|
||||||
local x, y, w, h, _
|
local x, y, w, h, _
|
||||||
|
@ -46,16 +44,16 @@ function fixed:draw(context, cr, width, height)
|
||||||
(self.dir ~= "y" and pos-spacing > width) then
|
(self.dir ~= "y" and pos-spacing > width) then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
base.draw_widget(context, cr, v, x, y, w, h)
|
table.insert(result, base.place_widget_at(v, x, y, w, h))
|
||||||
end
|
end
|
||||||
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add a widget to the given fixed layout
|
--- Add a widget to the given fixed layout
|
||||||
function fixed:add(widget)
|
function fixed:add(widget)
|
||||||
widget_base.check_widget(widget)
|
base.check_widget(widget)
|
||||||
table.insert(self.widgets, widget)
|
table.insert(self.widgets, widget)
|
||||||
widget:weak_connect_signal("widget::updated", self._emit_updated)
|
self:emit_signal("widget::layout_changed")
|
||||||
self._emit_updated()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Fit the fixed layout into the given space
|
--- Fit the fixed layout into the given space
|
||||||
|
@ -91,7 +89,7 @@ function fixed:fit(context, orig_width, orig_height)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local spacing = ((self._spacing or 0)*(#self.widgets-1))
|
local spacing = self._spacing * (#self.widgets-1)
|
||||||
|
|
||||||
if self.dir == "y" then
|
if self.dir == "y" then
|
||||||
return used_max, used_in_dir + spacing
|
return used_max, used_in_dir + spacing
|
||||||
|
@ -101,23 +99,22 @@ end
|
||||||
|
|
||||||
--- Reset a fixed layout. This removes all widgets from the layout.
|
--- Reset a fixed layout. This removes all widgets from the layout.
|
||||||
function fixed:reset()
|
function fixed:reset()
|
||||||
for k, v in pairs(self.widgets) do
|
|
||||||
v:disconnect_signal("widget::updated", self._emit_updated)
|
|
||||||
end
|
|
||||||
self.widgets = {}
|
self.widgets = {}
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the layout's fill_space property. If this property is true, the last
|
--- 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
|
-- 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.
|
-- won't be handled specially and there can be space left unused.
|
||||||
function fixed:fill_space(val)
|
function fixed:fill_space(val)
|
||||||
self._fill_space = val
|
if self._fill_space ~= val then
|
||||||
self:emit_signal("widget::updated")
|
self._fill_space = not not val
|
||||||
|
self:emit_signal("widget::layout_changed")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_layout(dir)
|
local function get_layout(dir)
|
||||||
local ret = widget_base.make_widget()
|
local ret = base.make_widget()
|
||||||
|
|
||||||
for k, v in pairs(fixed) do
|
for k, v in pairs(fixed) do
|
||||||
if type(v) == "function" then
|
if type(v) == "function" then
|
||||||
|
@ -127,9 +124,8 @@ local function get_layout(dir)
|
||||||
|
|
||||||
ret.dir = dir
|
ret.dir = dir
|
||||||
ret.widgets = {}
|
ret.widgets = {}
|
||||||
ret._emit_updated = function()
|
ret:set_spacing(0)
|
||||||
ret:emit_signal("widget::updated")
|
ret:fill_space(false)
|
||||||
end
|
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
@ -151,8 +147,10 @@ end
|
||||||
--- Add spacing between each layout widgets
|
--- Add spacing between each layout widgets
|
||||||
-- @param spacing Spacing between widgets.
|
-- @param spacing Spacing between widgets.
|
||||||
function fixed:set_spacing(spacing)
|
function fixed:set_spacing(spacing)
|
||||||
self._spacing = spacing
|
if self._spacing ~= spacing then
|
||||||
self:emit_signal("widget::updated")
|
self._spacing = spacing
|
||||||
|
self:emit_signal("widget::layout_changed")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return fixed
|
return fixed
|
||||||
|
|
|
@ -5,8 +5,7 @@
|
||||||
-- @classmod wibox.layout.flex
|
-- @classmod wibox.layout.flex
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
local base = require("wibox.layout.base")
|
local base = require("wibox.widget.base")
|
||||||
local widget_base = require("wibox.widget.base")
|
|
||||||
local table = table
|
local table = table
|
||||||
local pairs = pairs
|
local pairs = pairs
|
||||||
local floor = math.floor
|
local floor = math.floor
|
||||||
|
@ -14,14 +13,17 @@ local round = require("awful.util").round
|
||||||
|
|
||||||
local flex = {}
|
local flex = {}
|
||||||
|
|
||||||
--- Draw a flex layout. Each widget gets an equal share of the available space.
|
local function round(x)
|
||||||
|
return floor(x + 0.5)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Layout a flex layout. Each widget gets an equal share of the available space.
|
||||||
-- @param context The context in which we are drawn.
|
-- @param context The context in which we are drawn.
|
||||||
-- @param cr The cairo context to use.
|
|
||||||
-- @param width The available width.
|
-- @param width The available width.
|
||||||
-- @param height The available height.
|
-- @param height The available height.
|
||||||
-- @return The total space needed by the layout.
|
function flex:layout(context, width, height)
|
||||||
function flex:draw(context, cr, width, height)
|
local result = {}
|
||||||
local pos,spacing = 0,self._spacing or 0
|
local pos,spacing = 0, self._spacing
|
||||||
local num = #self.widgets
|
local num = #self.widgets
|
||||||
local total_spacing = (spacing*(num-1))
|
local total_spacing = (spacing*(num-1))
|
||||||
|
|
||||||
|
@ -45,7 +47,7 @@ function flex:draw(context, cr, width, height)
|
||||||
x, y = round(pos), 0
|
x, y = round(pos), 0
|
||||||
w, h = floor(space_per_item), height
|
w, h = floor(space_per_item), height
|
||||||
end
|
end
|
||||||
base.draw_widget(context, cr, v, x, y, w, h)
|
table.insert(result, base.place_widget_at(v, x, y, w, h))
|
||||||
|
|
||||||
pos = pos + space_per_item + spacing
|
pos = pos + space_per_item + spacing
|
||||||
|
|
||||||
|
@ -54,21 +56,8 @@ function flex:draw(context, cr, width, height)
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
function flex:add(widget)
|
return result
|
||||||
widget_base.check_widget(widget)
|
|
||||||
table.insert(self.widgets, widget)
|
|
||||||
widget:weak_connect_signal("widget::updated", self._emit_updated)
|
|
||||||
self._emit_updated()
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Set the maximum size the widgets in this layout will take (that is,
|
|
||||||
-- maximum width for horizontal and maximum height for vertical).
|
|
||||||
-- @param val The maximum size of the widget.
|
|
||||||
function flex:set_max_widget_size(val)
|
|
||||||
self._max_widget_size = val
|
|
||||||
self:emit_signal("widget::updated")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Fit the flex layout into the given space.
|
--- Fit the flex layout into the given space.
|
||||||
|
@ -99,7 +88,7 @@ function flex:fit(context, orig_width, orig_height)
|
||||||
#self.widgets * self._max_widget_size)
|
#self.widgets * self._max_widget_size)
|
||||||
end
|
end
|
||||||
|
|
||||||
local spacing = ((self._spacing or 0)*(#self.widgets-1))
|
local spacing = self._spacing * (#self.widgets-1)
|
||||||
|
|
||||||
if self.dir == "y" then
|
if self.dir == "y" then
|
||||||
return used_in_other, used_in_dir + spacing
|
return used_in_other, used_in_dir + spacing
|
||||||
|
@ -107,17 +96,39 @@ function flex:fit(context, orig_width, orig_height)
|
||||||
return used_in_dir + spacing, used_in_other
|
return used_in_dir + spacing, used_in_other
|
||||||
end
|
end
|
||||||
|
|
||||||
function flex:reset()
|
function flex:add(widget)
|
||||||
for k, v in pairs(self.widgets) do
|
base.check_widget(widget)
|
||||||
v:disconnect_signal("widget::updated", self._emit_updated)
|
table.insert(self.widgets, widget)
|
||||||
|
self:emit_signal("widget::layout_changed")
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the maximum size the widgets in this layout will take (that is,
|
||||||
|
-- maximum width for horizontal and maximum height for vertical).
|
||||||
|
-- @param val The maximum size of the widget.
|
||||||
|
function flex:set_max_widget_size(val)
|
||||||
|
if self._max_widget_size ~= val then
|
||||||
|
self._max_widget_size = val
|
||||||
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add spacing between each layout widgets
|
||||||
|
-- @param spacing Spacing between widgets.
|
||||||
|
function flex:set_spacing(spacing)
|
||||||
|
if self._spacing ~= spacing then
|
||||||
|
self._spacing = spacing
|
||||||
|
self:emit_signal("widget::layout_changed")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function flex:reset()
|
||||||
self.widgets = {}
|
self.widgets = {}
|
||||||
self._max_widget_size = nil
|
self._max_widget_size = nil
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_layout(dir)
|
local function get_layout(dir)
|
||||||
local ret = widget_base.make_widget()
|
local ret = base.make_widget()
|
||||||
|
|
||||||
for k, v in pairs(flex) do
|
for k, v in pairs(flex) do
|
||||||
if type(v) == "function" then
|
if type(v) == "function" then
|
||||||
|
@ -127,9 +138,7 @@ local function get_layout(dir)
|
||||||
|
|
||||||
ret.dir = dir
|
ret.dir = dir
|
||||||
ret.widgets = {}
|
ret.widgets = {}
|
||||||
ret._emit_updated = function()
|
ret:set_spacing(0)
|
||||||
ret:emit_signal("widget::updated")
|
|
||||||
end
|
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
@ -146,13 +155,6 @@ function flex.vertical()
|
||||||
return get_layout("y")
|
return get_layout("y")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add spacing between each layout widgets
|
|
||||||
-- @param spacing Spacing between widgets.
|
|
||||||
function flex:set_spacing(spacing)
|
|
||||||
self._spacing = spacing
|
|
||||||
self:emit_signal("widget::updated")
|
|
||||||
end
|
|
||||||
|
|
||||||
return flex
|
return flex
|
||||||
|
|
||||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
return
|
return
|
||||||
{
|
{
|
||||||
base = require("wibox.layout.base");
|
|
||||||
fixed = require("wibox.layout.fixed");
|
fixed = require("wibox.layout.fixed");
|
||||||
align = require("wibox.layout.align");
|
align = require("wibox.layout.align");
|
||||||
flex = require("wibox.layout.flex");
|
flex = require("wibox.layout.flex");
|
||||||
|
|
|
@ -8,8 +8,7 @@
|
||||||
local pairs = pairs
|
local pairs = pairs
|
||||||
local type = type
|
local type = type
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
local base = require("wibox.layout.base")
|
local base = require("wibox.widget.base")
|
||||||
local widget_base = require("wibox.widget.base")
|
|
||||||
local gcolor = require("gears.color")
|
local gcolor = require("gears.color")
|
||||||
local cairo = require("lgi").cairo
|
local cairo = require("lgi").cairo
|
||||||
|
|
||||||
|
@ -28,16 +27,24 @@ function margin:draw(context, cr, width, height)
|
||||||
end
|
end
|
||||||
|
|
||||||
if color then
|
if color then
|
||||||
cr:save()
|
|
||||||
cr:set_source(color)
|
cr:set_source(color)
|
||||||
cr:rectangle(0, 0, width, height)
|
cr:rectangle(0, 0, width, height)
|
||||||
cr:rectangle(x, y, width - x - w, height - y - h)
|
cr:rectangle(x, y, width - x - w, height - y - h)
|
||||||
cr:set_fill_rule(cairo.FillRule.EVEN_ODD)
|
cr:set_fill_rule(cairo.FillRule.EVEN_ODD)
|
||||||
cr:fill()
|
cr:fill()
|
||||||
cr:restore()
|
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
base.draw_widget(context, cr, self.widget, x, y, width - x - w, height - y - h)
|
--- Layout a margin layout
|
||||||
|
function margin:layout(context, width, height)
|
||||||
|
if self.widget then
|
||||||
|
local x = self.left
|
||||||
|
local y = self.top
|
||||||
|
local w = self.right
|
||||||
|
local h = self.bottom
|
||||||
|
|
||||||
|
return { base.place_widget_at(self.widget, x, y, width - x - w, height - y - h) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Fit a margin layout into the given space
|
--- Fit a margin layout into the given space
|
||||||
|
@ -53,15 +60,11 @@ end
|
||||||
|
|
||||||
--- Set the widget that this layout adds a margin on.
|
--- Set the widget that this layout adds a margin on.
|
||||||
function margin:set_widget(widget)
|
function margin:set_widget(widget)
|
||||||
if self.widget then
|
|
||||||
self.widget:disconnect_signal("widget::updated", self._emit_updated)
|
|
||||||
end
|
|
||||||
if widget then
|
if widget then
|
||||||
widget_base.check_widget(widget)
|
base.check_widget(widget)
|
||||||
widget:weak_connect_signal("widget::updated", self._emit_updated)
|
|
||||||
end
|
end
|
||||||
self.widget = widget
|
self.widget = widget
|
||||||
self._emit_updated()
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set all the margins to val.
|
--- Set all the margins to val.
|
||||||
|
@ -70,13 +73,13 @@ function margin:set_margins(val)
|
||||||
self.right = val
|
self.right = val
|
||||||
self.top = val
|
self.top = val
|
||||||
self.bottom = val
|
self.bottom = val
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the margins color to color
|
--- Set the margins color to color
|
||||||
function margin:set_color(color)
|
function margin:set_color(color)
|
||||||
self.color = color and gcolor(color)
|
self.color = color and gcolor(color)
|
||||||
self._emit_updated()
|
self:emit_signal("widget::redraw_needed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Reset this layout. The widget will be unreferenced, the margins set to 0
|
--- Reset this layout. The widget will be unreferenced, the margins set to 0
|
||||||
|
@ -115,7 +118,7 @@ end
|
||||||
for k, v in pairs({ "left", "right", "top", "bottom" }) do
|
for k, v in pairs({ "left", "right", "top", "bottom" }) do
|
||||||
margin["set_" .. v] = function(layout, val)
|
margin["set_" .. v] = function(layout, val)
|
||||||
layout[v] = val
|
layout[v] = val
|
||||||
layout:emit_signal("widget::updated")
|
layout:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -127,7 +130,7 @@ end
|
||||||
-- @param[opt] bottom A margin to use on the bottom side of the widget.
|
-- @param[opt] bottom A margin to use on the bottom side of the widget.
|
||||||
-- @param[opt] color A color for the margins.
|
-- @param[opt] color A color for the margins.
|
||||||
local function new(widget, left, right, top, bottom, color)
|
local function new(widget, left, right, top, bottom, color)
|
||||||
local ret = widget_base.make_widget()
|
local ret = base.make_widget()
|
||||||
|
|
||||||
for k, v in pairs(margin) do
|
for k, v in pairs(margin) do
|
||||||
if type(v) == "function" then
|
if type(v) == "function" then
|
||||||
|
@ -135,10 +138,6 @@ local function new(widget, left, right, top, bottom, color)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
ret._emit_updated = function()
|
|
||||||
ret:emit_signal("widget::updated")
|
|
||||||
end
|
|
||||||
|
|
||||||
ret:set_left(left or 0)
|
ret:set_left(left or 0)
|
||||||
ret:set_right(right or 0)
|
ret:set_right(right or 0)
|
||||||
ret:set_top(top or 0)
|
ret:set_top(top or 0)
|
||||||
|
|
|
@ -10,21 +10,20 @@ local error = error
|
||||||
local pairs = pairs
|
local pairs = pairs
|
||||||
local ipairs = ipairs
|
local ipairs = ipairs
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
local base = require("wibox.layout.base")
|
local base = require("wibox.widget.base")
|
||||||
local widget_base = require("wibox.widget.base")
|
local Matrix = require("lgi").cairo.Matrix
|
||||||
|
|
||||||
local mirror = { mt = {} }
|
local mirror = { mt = {} }
|
||||||
|
|
||||||
--- Draw this layout
|
--- Layout this layout
|
||||||
function mirror:draw(context, cr, width, height)
|
function mirror:layout(context, cr, width, height)
|
||||||
if not self.widget then return end
|
if not self.widget then return end
|
||||||
if not self.horizontal and not self.vertical then
|
if not self.horizontal and not self.vertical then
|
||||||
base.draw_widget(wibox, cr, self.widget, 0, 0, width, height)
|
base.draw_widget(wibox, cr, self.widget, 0, 0, width, height)
|
||||||
return -- nothing changed
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
cr:save()
|
local m = Matrix.create_identity()
|
||||||
|
|
||||||
local t = { x = 0, y = 0 } -- translation
|
local t = { x = 0, y = 0 } -- translation
|
||||||
local s = { x = 1, y = 1 } -- scale
|
local s = { x = 1, y = 1 } -- scale
|
||||||
if self.horizontal then
|
if self.horizontal then
|
||||||
|
@ -35,13 +34,10 @@ function mirror:draw(context, cr, width, height)
|
||||||
t.x = width
|
t.x = width
|
||||||
s.x = -1
|
s.x = -1
|
||||||
end
|
end
|
||||||
cr:translate(t.x, t.y)
|
m:translate(t.x, t.y)
|
||||||
cr:scale(s.x, s.y)
|
m:scale(s.x, s.y)
|
||||||
|
|
||||||
self.widget:draw(context, cr, width, height)
|
return base.place_widget_via_matrix(widget, m, width, height)
|
||||||
|
|
||||||
-- Undo the scale and translation from above.
|
|
||||||
cr:restore()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Fit this layout into the given area
|
--- Fit this layout into the given area
|
||||||
|
@ -55,15 +51,11 @@ end
|
||||||
--- Set the widget that this layout mirrors.
|
--- Set the widget that this layout mirrors.
|
||||||
-- @param widget The widget to mirror
|
-- @param widget The widget to mirror
|
||||||
function mirror:set_widget(widget)
|
function mirror:set_widget(widget)
|
||||||
if self.widget then
|
|
||||||
self.widget:disconnect_signal("widget::updated", self._emit_updated)
|
|
||||||
end
|
|
||||||
if widget then
|
if widget then
|
||||||
widget_base.check_widget(widget)
|
base.check_widget(widget)
|
||||||
widget:weak_connect_signal("widget::updated", self._emit_updated)
|
|
||||||
end
|
end
|
||||||
self.widget = widget
|
self.widget = widget
|
||||||
self._emit_updated()
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Reset this layout. The widget will be removed and the axes reset.
|
--- Reset this layout. The widget will be removed and the axes reset.
|
||||||
|
@ -85,7 +77,7 @@ function mirror:set_reflection(reflection)
|
||||||
self[ref] = reflection[ref]
|
self[ref] = reflection[ref]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self._emit_updated()
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the reflection of this mirror layout.
|
--- Get the reflection of this mirror layout.
|
||||||
|
@ -101,7 +93,7 @@ end
|
||||||
-- @param[opt] widget The widget to display.
|
-- @param[opt] widget The widget to display.
|
||||||
-- @param[opt] reflection A table describing the reflection to apply.
|
-- @param[opt] reflection A table describing the reflection to apply.
|
||||||
local function new(widget, reflection)
|
local function new(widget, reflection)
|
||||||
local ret = widget_base.make_widget()
|
local ret = base.make_widget()
|
||||||
ret.horizontal = false
|
ret.horizontal = false
|
||||||
ret.vertical = false
|
ret.vertical = false
|
||||||
|
|
||||||
|
@ -111,10 +103,6 @@ local function new(widget, reflection)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
ret._emit_updated = function()
|
|
||||||
ret:emit_signal("widget::updated")
|
|
||||||
end
|
|
||||||
|
|
||||||
ret:set_widget(widget)
|
ret:set_widget(widget)
|
||||||
ret:set_reflection(reflection or {})
|
ret:set_reflection(reflection or {})
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@ local pi = math.pi
|
||||||
local type = type
|
local type = type
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
local tostring = tostring
|
local tostring = tostring
|
||||||
local base = require("wibox.layout.base")
|
local base = require("wibox.widget.base")
|
||||||
local widget_base = require("wibox.widget.base")
|
local Matrix = require("lgi").cairo.Matrix
|
||||||
|
|
||||||
local rotate = { mt = {} }
|
local rotate = { mt = {} }
|
||||||
|
|
||||||
|
@ -24,28 +24,29 @@ local function transform(layout, width, height)
|
||||||
return width, height
|
return width, height
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Draw this layout
|
--- Layout this layout
|
||||||
function rotate:draw(context, cr, width, height)
|
function rotate:layout(context, width, height)
|
||||||
if not self.widget or not self.widget.visible then
|
if not self.widget or not self.widget.visible then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local dir = self:get_direction()
|
local dir = self:get_direction()
|
||||||
|
|
||||||
|
local m = Matrix.create_identity()
|
||||||
if dir == "west" then
|
if dir == "west" then
|
||||||
cr:rotate(pi / 2)
|
m:rotate(pi / 2)
|
||||||
cr:translate(0, -width)
|
m:translate(0, -width)
|
||||||
elseif dir == "south" then
|
elseif dir == "south" then
|
||||||
cr:rotate(pi)
|
m:rotate(pi)
|
||||||
cr:translate(-width, -height)
|
m:translate(-width, -height)
|
||||||
elseif dir == "east" then
|
elseif dir == "east" then
|
||||||
cr:rotate(3 * pi / 2)
|
m:rotate(3 * pi / 2)
|
||||||
cr:translate(-height, 0)
|
m:translate(-height, 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Since we rotated, we might have to swap width and height.
|
-- Since we rotated, we might have to swap width and height.
|
||||||
-- transform() does that for us.
|
-- transform() does that for us.
|
||||||
base.draw_widget(context, cr, self.widget, 0, 0, transform(self, width, height))
|
return { base.place_widget_via_matrix(self.widget, m, transform(self, width, height)) }
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Fit this layout into the given area
|
--- Fit this layout into the given area
|
||||||
|
@ -58,15 +59,11 @@ end
|
||||||
|
|
||||||
--- Set the widget that this layout rotates.
|
--- Set the widget that this layout rotates.
|
||||||
function rotate:set_widget(widget)
|
function rotate:set_widget(widget)
|
||||||
if self.widget then
|
|
||||||
self.widget:disconnect_signal("widget::updated", self._emit_updated)
|
|
||||||
end
|
|
||||||
if widget then
|
if widget then
|
||||||
widget_base.check_widget(widget)
|
base.check_widget(widget)
|
||||||
widget:weak_connect_signal("widget::updated", self._emit_updated)
|
|
||||||
end
|
end
|
||||||
self.widget = widget
|
self.widget = widget
|
||||||
self._emit_updated()
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Reset this layout. The widget will be removed and the rotation reset.
|
--- Reset this layout. The widget will be removed and the rotation reset.
|
||||||
|
@ -90,7 +87,7 @@ function rotate:set_direction(dir)
|
||||||
end
|
end
|
||||||
|
|
||||||
self.direction = dir
|
self.direction = dir
|
||||||
self._emit_updated()
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the direction of this rotating layout
|
--- Get the direction of this rotating layout
|
||||||
|
@ -104,7 +101,7 @@ end
|
||||||
-- @param[opt] widget The widget to display.
|
-- @param[opt] widget The widget to display.
|
||||||
-- @param[opt] dir The direction to rotate to.
|
-- @param[opt] dir The direction to rotate to.
|
||||||
local function new(widget, dir)
|
local function new(widget, dir)
|
||||||
local ret = widget_base.make_widget()
|
local ret = base.make_widget()
|
||||||
|
|
||||||
for k, v in pairs(rotate) do
|
for k, v in pairs(rotate) do
|
||||||
if type(v) == "function" then
|
if type(v) == "function" then
|
||||||
|
@ -112,10 +109,6 @@ local function new(widget, dir)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
ret._emit_updated = function()
|
|
||||||
ret:emit_signal("widget::updated")
|
|
||||||
end
|
|
||||||
|
|
||||||
ret:set_widget(widget)
|
ret:set_widget(widget)
|
||||||
ret:set_direction(dir or "north")
|
ret:set_direction(dir or "north")
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
local base = require("wibox.widget.base")
|
local base = require("wibox.widget.base")
|
||||||
local color = require("gears.color")
|
local color = require("gears.color")
|
||||||
local layout_base = require("wibox.layout.base")
|
|
||||||
local surface = require("gears.surface")
|
local surface = require("gears.surface")
|
||||||
local cairo = require("lgi").cairo
|
local cairo = require("lgi").cairo
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
@ -22,8 +21,6 @@ function background:draw(context, cr, width, height)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
cr:save()
|
|
||||||
|
|
||||||
if self.background then
|
if self.background then
|
||||||
cr:set_source(self.background)
|
cr:set_source(self.background)
|
||||||
cr:paint()
|
cr:paint()
|
||||||
|
@ -33,16 +30,19 @@ function background:draw(context, cr, width, height)
|
||||||
cr:set_source(pattern)
|
cr:set_source(pattern)
|
||||||
cr:paint()
|
cr:paint()
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
cr:restore()
|
--- Prepare drawing the children of this widget
|
||||||
|
function background:before_draw_children(wibox, cr, width, height)
|
||||||
if self.foreground then
|
if self.foreground then
|
||||||
cr:save()
|
|
||||||
cr:set_source(self.foreground)
|
cr:set_source(self.foreground)
|
||||||
end
|
end
|
||||||
layout_base.draw_widget(context, cr, self.widget, 0, 0, width, height)
|
end
|
||||||
if self.foreground then
|
|
||||||
cr:restore()
|
--- Layout this widget
|
||||||
|
function background:layout(context, width, height)
|
||||||
|
if self.widget then
|
||||||
|
return { base.place_widget_at(self.widget, 0, 0, width, height) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -52,20 +52,16 @@ function background:fit(context, width, height)
|
||||||
return 0, 0
|
return 0, 0
|
||||||
end
|
end
|
||||||
|
|
||||||
return layout_base.fit_widget(context, self.widget, width, height)
|
return base.fit_widget(context, self.widget, width, height)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the widget that is drawn on top of the background
|
--- Set the widget that is drawn on top of the background
|
||||||
function background:set_widget(widget)
|
function background:set_widget(widget)
|
||||||
if self.widget then
|
|
||||||
self.widget:disconnect_signal("widget::updated", self._emit_updated)
|
|
||||||
end
|
|
||||||
if widget then
|
if widget then
|
||||||
base.check_widget(widget)
|
base.check_widget(widget)
|
||||||
widget:weak_connect_signal("widget::updated", self._emit_updated)
|
|
||||||
end
|
end
|
||||||
self.widget = widget
|
self.widget = widget
|
||||||
self._emit_updated()
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the background to use
|
--- Set the background to use
|
||||||
|
@ -75,7 +71,7 @@ function background:set_bg(bg)
|
||||||
else
|
else
|
||||||
self.background = nil
|
self.background = nil
|
||||||
end
|
end
|
||||||
self._emit_updated()
|
self:emit_signal("widget::redraw_needed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the foreground to use
|
--- Set the foreground to use
|
||||||
|
@ -85,13 +81,13 @@ function background:set_fg(fg)
|
||||||
else
|
else
|
||||||
self.foreground = nil
|
self.foreground = nil
|
||||||
end
|
end
|
||||||
self._emit_updated()
|
self:emit_signal("widget::redraw_needed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the background image to use
|
--- Set the background image to use
|
||||||
function background:set_bgimage(image)
|
function background:set_bgimage(image)
|
||||||
self.bgimage = surface.load(image)
|
self.bgimage = surface.load(image)
|
||||||
self._emit_updated()
|
self:emit_signal("widget::redraw_needed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a new background layout. A background layout applies a background
|
--- Returns a new background layout. A background layout applies a background
|
||||||
|
@ -107,10 +103,6 @@ local function new(widget, bg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
ret._emit_updated = function()
|
|
||||||
ret:emit_signal("widget::updated")
|
|
||||||
end
|
|
||||||
|
|
||||||
ret:set_widget(widget)
|
ret:set_widget(widget)
|
||||||
ret:set_bg(bg)
|
ret:set_bg(bg)
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,14 @@
|
||||||
-- @author Uli Schlachter
|
-- @author Uli Schlachter
|
||||||
-- @copyright 2010 Uli Schlachter
|
-- @copyright 2010 Uli Schlachter
|
||||||
-- @release @AWESOME_VERSION@
|
-- @release @AWESOME_VERSION@
|
||||||
-- @classmod wibox.widget.base
|
-- @module wibox.widget.base
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
local debug = require("gears.debug")
|
local debug = require("gears.debug")
|
||||||
local object = require("gears.object")
|
local object = require("gears.object")
|
||||||
local cache = require("gears.cache")
|
local cache = require("gears.cache")
|
||||||
local matrix = require("gears.matrix")
|
local matrix = require("gears.matrix")
|
||||||
|
local Matrix = require("lgi").cairo.Matrix
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
local pairs = pairs
|
local pairs = pairs
|
||||||
local type = type
|
local type = type
|
||||||
|
@ -16,13 +17,144 @@ local table = table
|
||||||
|
|
||||||
local base = {}
|
local base = {}
|
||||||
|
|
||||||
|
-- {{{ Caches
|
||||||
|
|
||||||
|
local call_stack = {}
|
||||||
|
-- Indexes are widgets, allow them to be garbage-collected
|
||||||
|
local widget_dependencies = setmetatable({}, { __mode = "k" })
|
||||||
|
|
||||||
|
-- Don't do this in unit tests
|
||||||
|
if awesome and awesome.connect_signal then
|
||||||
|
-- Reset the call stack at each refresh. This fixes things up in case there was
|
||||||
|
-- an error in some callback and thus put_cache() wasn't called (if this
|
||||||
|
-- happens, we possibly recorded too many deps, but so what?)
|
||||||
|
awesome.connect_signal("refresh", function()
|
||||||
|
call_stack = {}
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- When you call get_cache_and_record_deps(), the widget is recorded in a stack
|
||||||
|
-- until the following put_cache(). All other calls to
|
||||||
|
-- get_cache_and_record_deps() that happen during this will cause a dependency
|
||||||
|
-- between the widgets that are involved to be recorded. This information is
|
||||||
|
-- used by clear_caches() to also clear all caches of dependent widgets.
|
||||||
|
|
||||||
|
-- Get the caches for a widget and record its dependencies. All following
|
||||||
|
-- cache-uses will record this widgets as a dependency. This returns a function
|
||||||
|
-- that calls the callback of kind `kind` on the widget.
|
||||||
|
local function get_cache_and_record_deps(widget, kind)
|
||||||
|
-- Record dependencies (each entry in the call stack depends on `widget`)
|
||||||
|
local deps = widget_dependencies[widget] or {}
|
||||||
|
for _, w in pairs(call_stack) do
|
||||||
|
deps[w] = true
|
||||||
|
end
|
||||||
|
widget_dependencies[widget] = deps
|
||||||
|
|
||||||
|
-- Add widget to call stack
|
||||||
|
table.insert(call_stack, widget)
|
||||||
|
|
||||||
|
-- Create cache if needed
|
||||||
|
if not widget._widget_caches[kind] then
|
||||||
|
widget._widget_caches[kind] = cache.new(function(...)
|
||||||
|
return widget[kind](widget, ...)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
return widget._widget_caches[kind]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Each call to the above function should be followed by a call to this
|
||||||
|
-- function. Everything in-between is recorded as a dependency (it's
|
||||||
|
-- complicated...).
|
||||||
|
local function put_cache(widget)
|
||||||
|
assert(#call_stack ~= 0)
|
||||||
|
if table.remove(call_stack) ~= widget then
|
||||||
|
put_cache(widget)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Clear the caches for `widget` and all widgets that depend on it.
|
||||||
|
local function clear_caches(widget)
|
||||||
|
for w in pairs(widget_dependencies[widget] or {}) do
|
||||||
|
widget_dependencies[w] = {}
|
||||||
|
w._widget_caches = {}
|
||||||
|
end
|
||||||
|
widget_dependencies[widget] = {}
|
||||||
|
widget._widget_caches = {}
|
||||||
|
end
|
||||||
|
-- }}}
|
||||||
|
|
||||||
--- Figure out the geometry in device coordinate space. This gives only tight
|
--- Figure out the geometry in device coordinate space. This gives only tight
|
||||||
-- bounds if no rotations by non-multiples of 90° are used.
|
-- bounds if no rotations by non-multiples of 90° are used.
|
||||||
function base.rect_to_device_geometry(cr, x, y, width, height)
|
function base.rect_to_device_geometry(cr, x, y, width, height)
|
||||||
return matrix.transform_rectangle(cr.matrix, x, y, width, height)
|
return matrix.transform_rectangle(cr.matrix, x, y, width, height)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set/get a widget's buttons
|
--- Fit a widget for the given available width and height. This calls the
|
||||||
|
-- widget's `:fit` callback and caches the result for later use. Never call
|
||||||
|
-- `:fit` directly, but always through this function!
|
||||||
|
-- @param context The context in which we are fit.
|
||||||
|
-- @param widget The widget to fit (this uses widget:fit(width, height)).
|
||||||
|
-- @param width The available width for the widget
|
||||||
|
-- @param height The available height for the widget
|
||||||
|
-- @return The width and height that the widget wants to use
|
||||||
|
function base.fit_widget(context, widget, width, height)
|
||||||
|
if not widget.visible then
|
||||||
|
return 0, 0
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sanitize the input. This also filters out e.g. NaN.
|
||||||
|
local width = math.max(0, width)
|
||||||
|
local height = math.max(0, height)
|
||||||
|
|
||||||
|
local w, h = 0, 0
|
||||||
|
if widget.fit then
|
||||||
|
local cache = get_cache_and_record_deps(widget, "fit")
|
||||||
|
w, h = cache:get(context, width, height)
|
||||||
|
put_cache(widget)
|
||||||
|
else
|
||||||
|
-- If it has no fit method, calculate based on the size of children
|
||||||
|
local children = base.layout_widget(context, widget, width, height)
|
||||||
|
for _, info in ipairs(children or {}) do
|
||||||
|
local x, y, w2, h2 = matrix.transform_rectangle(info._matrix,
|
||||||
|
0, 0, info._width, info._height)
|
||||||
|
w, h = math.max(w, x + w2), math.max(h, y + h2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Also sanitize the output.
|
||||||
|
w = math.max(0, math.min(w, width))
|
||||||
|
h = math.max(0, math.min(h, height))
|
||||||
|
return w, h
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Lay out a widget for the given available width and height. This calls the
|
||||||
|
-- widget's `:layout` callback and caches the result for later use. Never call
|
||||||
|
-- `:layout` directly, but always through this function! However, normally there
|
||||||
|
-- shouldn't be any reason why you need to use this function.
|
||||||
|
-- @param context The context in which we are laid out.
|
||||||
|
-- @param widget The widget to layout (this uses widget:layout(context, width, height)).
|
||||||
|
-- @param width The available width for the widget
|
||||||
|
-- @param height The available height for the widget
|
||||||
|
-- @return The result from the widget's `:layout` callback.
|
||||||
|
function base.layout_widget(context, widget, width, height)
|
||||||
|
if not widget.visible then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sanitize the input. This also filters out e.g. NaN.
|
||||||
|
local width = math.max(0, width)
|
||||||
|
local height = math.max(0, height)
|
||||||
|
|
||||||
|
if widget.layout then
|
||||||
|
local cache = get_cache_and_record_deps(widget, "layout")
|
||||||
|
local result = cache:get(context, width, height)
|
||||||
|
put_cache(widget)
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set/get a widget's buttons.
|
||||||
|
-- This function is available on widgets created by @{make_widget}.
|
||||||
function base:buttons(_buttons)
|
function base:buttons(_buttons)
|
||||||
if _buttons then
|
if _buttons then
|
||||||
self.widget_buttons = _buttons
|
self.widget_buttons = _buttons
|
||||||
|
@ -31,7 +163,8 @@ function base:buttons(_buttons)
|
||||||
return self.widget_buttons
|
return self.widget_buttons
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Handle a button event on a widget. This is used internally.
|
-- Handle a button event on a widget. This is used internally and should not be
|
||||||
|
-- called directly.
|
||||||
function base.handle_button(event, widget, x, y, button, modifiers, geometry)
|
function base.handle_button(event, widget, x, y, button, modifiers, geometry)
|
||||||
local function is_any(mod)
|
local function is_any(mod)
|
||||||
return #mod == 1 and mod[1] == "Any"
|
return #mod == 1 and mod[1] == "Any"
|
||||||
|
@ -68,23 +201,174 @@ function base.handle_button(event, widget, x, y, button, modifiers, geometry)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Create a new widget. All widgets have to be generated via this function so
|
--- Create widget placement information. This should be used for a widget's
|
||||||
-- that the needed signals are added and mouse input handling is set up.
|
-- `:layout()` callback.
|
||||||
-- @param proxy If this is set, the returned widget will be a proxy for this
|
-- @param widget The widget that should be placed.
|
||||||
-- widget. It will be equivalent to this widget.
|
-- @param mat A cairo matrix transforming from the parent widget's coordinate
|
||||||
-- @tparam[opt] string widget_name Name of the widget. If not set, it will be
|
-- system. For example, use cairo.Matrix.create_translate(1, 2) to draw a
|
||||||
-- set automatically via `gears.object.modulename`.
|
-- widget at position (1, 2) relative to the parent widget.
|
||||||
|
-- @param width The width of the widget in its own coordinate system. That is,
|
||||||
|
-- after applying the transformation matrix.
|
||||||
|
-- @param height The height of the widget in its own coordinate system. That is,
|
||||||
|
-- after applying the transformation matrix.
|
||||||
|
-- @return An opaque object that can be returned from :layout()
|
||||||
|
function base.place_widget_via_matrix(widget, mat, width, height)
|
||||||
|
return {
|
||||||
|
_widget = widget,
|
||||||
|
_width = width,
|
||||||
|
_height = height,
|
||||||
|
_matrix = matrix.copy(mat)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Create widget placement information. This should be used for a widget's
|
||||||
|
-- `:layout()` callback.
|
||||||
|
-- @param widget The widget that should be placed.
|
||||||
|
-- @param x The x coordinate for the widget.
|
||||||
|
-- @param y The y coordinate for the widget.
|
||||||
|
-- @param width The width of the widget in its own coordinate system. That is,
|
||||||
|
-- after applying the transformation matrix.
|
||||||
|
-- @param height The height of the widget in its own coordinate system. That is,
|
||||||
|
-- after applying the transformation matrix.
|
||||||
|
-- @return An opaque object that can be returned from :layout()
|
||||||
|
function base.place_widget_at(widget, x, y, width, height)
|
||||||
|
return base.place_widget_via_matrix(widget, Matrix.create_translate(x, y), width, height)
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[--
|
||||||
|
Create a new widget. All widgets have to be generated via this function so that
|
||||||
|
the needed signals are added and mouse input handling is set up.
|
||||||
|
|
||||||
|
The returned widget will have a :buttons member function that can be used to
|
||||||
|
register a set of mouse button events with the widget.
|
||||||
|
|
||||||
|
To implement your own widget, you can implement some member functions on a
|
||||||
|
freshly-created widget. Note that all of these functions should be deterministic
|
||||||
|
in the sense that they will show the same behavior if they are repeatedly called
|
||||||
|
with the same arguments (same width and height). If your widget is updated and
|
||||||
|
needs to change, suitable signals have to be emitted. This will be explained
|
||||||
|
later.
|
||||||
|
|
||||||
|
The first callback is :fit. This function is called to select the size of your
|
||||||
|
widget. The arguments to this function is the available space and it should
|
||||||
|
return its desired size. Note that this function only provides a hint which is
|
||||||
|
not necessarily followed. The widget must also be able to draw itself at
|
||||||
|
different sizes than the one requested.
|
||||||
|
<pre><code>function widget:fit(context, width, height)
|
||||||
|
-- Find the maximum square available
|
||||||
|
local m = math.min(width, height)
|
||||||
|
return m, m
|
||||||
|
end</code></pre>
|
||||||
|
|
||||||
|
The next callback is :draw. As the name suggests, this function is called to
|
||||||
|
draw the widget. The arguments to this widget are the context that the widget is
|
||||||
|
drawn in, the cairo context on which it should be drawn and the widget's size.
|
||||||
|
The cairo context is set up in such a way that the widget as its top-left corner
|
||||||
|
at (0, 0) and its bottom-right corner at (width, height). In other words, no
|
||||||
|
special transformation needs to be done. Note that during this callback a
|
||||||
|
suitable clip will already be applied to the cairo context so that this callback
|
||||||
|
will not be able to draw outside of the area that was registered for the widget
|
||||||
|
by the layout that placed this widget. You should not call
|
||||||
|
<code>cr:reset_clip()</code>, as redraws will not be handled correctly in this
|
||||||
|
case.
|
||||||
|
<pre><code>function widget:draw(wibox, cr, width, height)
|
||||||
|
cr:move_to(0, 0)
|
||||||
|
cr:line_to(width, height)
|
||||||
|
cr:move_to(0, height)
|
||||||
|
cr:line_to(width, 0)
|
||||||
|
cr:stroke()
|
||||||
|
end</code></pre>
|
||||||
|
|
||||||
|
There are two signals configured for a widget. When the result that :fit would
|
||||||
|
return changes, the <code>widget::layout_changed</code> signal has to be
|
||||||
|
emitted. If this actually causes layout changes, the affected areas will be
|
||||||
|
redrawn. The other signal is <code>widget::redraw_needed</code>. This signal
|
||||||
|
signals that :draw has to be called to redraw the widget, but it is safe to
|
||||||
|
assume that :fit does still return the same values as before. If in doubt, you
|
||||||
|
can emit both signals to be safe.
|
||||||
|
|
||||||
|
If your widget only needs to draw something to the screen, the above is all that
|
||||||
|
is needed. The following callbacks can be used when implementing layouts which
|
||||||
|
place other widgets on the screen.
|
||||||
|
|
||||||
|
The :layout callback is used to figure out which other widgets should be drawn
|
||||||
|
relative to this widget. Note that it is allowed to place widgets outside of the
|
||||||
|
extents of your own widget, for example at a negative position or at twice the
|
||||||
|
size of this widget. Use this mechanism if your widget needs to draw outside of
|
||||||
|
its own extents. If the result of this callback changes,
|
||||||
|
<code>widget::layout_changed</code> has to be emitted. You can use @{fit_widget}
|
||||||
|
to call the `:fit` callback of other widgets. Never call `:fit` directly! For
|
||||||
|
example, if you want to place another widget <code>child</code> inside of your
|
||||||
|
widget, you can do it like this:
|
||||||
|
<pre><code>-- For readability
|
||||||
|
local base = wibox.widget.base
|
||||||
|
function widget:layout(width, height)
|
||||||
|
local result = {}
|
||||||
|
table.insert(result, base.place_widget_at(child, width/2, 0, width/2, height)
|
||||||
|
return result
|
||||||
|
end</code></pre>
|
||||||
|
|
||||||
|
Finally, if you want to influence how children are drawn, there are four
|
||||||
|
callbacks available that all get similar arguments:
|
||||||
|
<pre><code>function widget:before_draw_children(context, cr, width, height)
|
||||||
|
function widget:after_draw_children(context, cr, width, height)
|
||||||
|
function widget:before_draw_child(context, index, child, cr, width, height)
|
||||||
|
function widget:after_draw_child(context, index, child, cr, width, height)</code></pre>
|
||||||
|
|
||||||
|
All of these are called with the same arguments as the :draw() method. Please
|
||||||
|
note that a larger clip will be active during these callbacks that also contains
|
||||||
|
the area of all children. These callbacks can be used to influence the way in
|
||||||
|
which children are drawn, but they should not cause the drawing to cover a
|
||||||
|
different area. As an example, these functions can be used to draw children
|
||||||
|
translucently:
|
||||||
|
<pre><code>function widget:before_draw_children(wibox, cr, width, height)
|
||||||
|
cr:push_group()
|
||||||
|
end
|
||||||
|
function widget:after_draw_children(wibox, cr, width, height)
|
||||||
|
cr:pop_group_to_source()
|
||||||
|
cr:paint_with_alpha(0.5)
|
||||||
|
end</code></pre>
|
||||||
|
|
||||||
|
In pseudo-code, the call sequence for the drawing callbacks during a redraw
|
||||||
|
looks like this:
|
||||||
|
<pre><code>widget:draw(wibox, cr, width, height)
|
||||||
|
widget:before_draw_children(wibox, cr, width, height)
|
||||||
|
for child do
|
||||||
|
widget:before_draw_child(wibox, cr, child_index, child, width, height)
|
||||||
|
cr:save()
|
||||||
|
-- Draw child and all of its children recursively, taking into account the
|
||||||
|
-- position and size given to base.place_widget_at() in :layout().
|
||||||
|
cr:restore()
|
||||||
|
widget:after_draw_child(wibox, cr, child_index, child, width, height)
|
||||||
|
end
|
||||||
|
widget:after_draw_children(wibox, cr, width, height)</code></pre>
|
||||||
|
@param proxy If this is set, the returned widget will be a proxy for this
|
||||||
|
widget. It will be equivalent to this widget. This means it
|
||||||
|
looks the same on the screen.
|
||||||
|
@tparam[opt] string widget_name Name of the widget. If not set, it will be
|
||||||
|
set automatically via `gears.object.modulename`.
|
||||||
|
@see fit_widget
|
||||||
|
--]]--
|
||||||
function base.make_widget(proxy, widget_name)
|
function base.make_widget(proxy, widget_name)
|
||||||
local ret = object()
|
local ret = object()
|
||||||
|
|
||||||
-- This signal is used by layouts to find out when they have to update.
|
-- This signal is used by layouts to find out when they have to update.
|
||||||
ret:add_signal("widget::updated")
|
ret:add_signal("widget::layout_changed")
|
||||||
|
ret:add_signal("widget::redraw_needed")
|
||||||
-- Mouse input, oh noes!
|
-- Mouse input, oh noes!
|
||||||
ret:add_signal("button::press")
|
ret:add_signal("button::press")
|
||||||
ret:add_signal("button::release")
|
ret:add_signal("button::release")
|
||||||
ret:add_signal("mouse::enter")
|
ret:add_signal("mouse::enter")
|
||||||
ret:add_signal("mouse::leave")
|
ret:add_signal("mouse::leave")
|
||||||
|
|
||||||
|
-- Backwards compatibility
|
||||||
|
-- TODO: Remove this
|
||||||
|
ret:add_signal("widget::updated")
|
||||||
|
ret:connect_signal("widget::updated", function()
|
||||||
|
ret:emit_signal("widget::layout_changed")
|
||||||
|
ret:emit_signal("widget::redraw_needed")
|
||||||
|
end)
|
||||||
|
|
||||||
-- No buttons yet
|
-- No buttons yet
|
||||||
ret.widget_buttons = {}
|
ret.widget_buttons = {}
|
||||||
ret.buttons = base.buttons
|
ret.buttons = base.buttons
|
||||||
|
@ -98,20 +382,24 @@ function base.make_widget(proxy, widget_name)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
if proxy then
|
if proxy then
|
||||||
ret.draw = function(_, ...) return proxy:draw(...) end
|
ret.fit = function(_, context, width, height)
|
||||||
ret.fit = function(_, ...) return proxy:fit(...) end
|
return base.fit_widget(context, proxy, width, height)
|
||||||
proxy:connect_signal("widget::updated", function()
|
end
|
||||||
ret:emit_signal("widget::updated")
|
ret.layout = function(_, context, width, height)
|
||||||
|
return { base.place_widget_at(proxy, 0, 0, width, height) }
|
||||||
|
end
|
||||||
|
proxy:connect_signal("widget::layout_changed", function()
|
||||||
|
ret:emit_signal("widget::layout_changed")
|
||||||
|
end)
|
||||||
|
proxy:connect_signal("widget::redraw_needed", function()
|
||||||
|
ret:emit_signal("widget::redraw_needed")
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Add a geometry for base.fit_widget() that is cleared when necessary
|
-- Set up caches
|
||||||
local function cb(...)
|
clear_caches(ret)
|
||||||
return ret:fit(...)
|
ret:connect_signal("widget::layout_changed", function()
|
||||||
end
|
clear_caches(ret)
|
||||||
ret._fit_geometry_cache = cache.new(cb)
|
|
||||||
ret:connect_signal("widget::updated", function()
|
|
||||||
ret._fit_geometry_cache = cache.new(cb)
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- Add visible property and setter.
|
-- Add visible property and setter.
|
||||||
|
@ -119,7 +407,9 @@ function base.make_widget(proxy, widget_name)
|
||||||
function ret:set_visible(b)
|
function ret:set_visible(b)
|
||||||
if b ~= self.visible then
|
if b ~= self.visible then
|
||||||
self.visible = b
|
self.visible = b
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::layout_changed")
|
||||||
|
-- In case something ignored fit and drew the widget anyway
|
||||||
|
self:emit_signal("widget::redraw_needed")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -128,7 +418,7 @@ function base.make_widget(proxy, widget_name)
|
||||||
function ret:set_opacity(b)
|
function ret:set_opacity(b)
|
||||||
if b ~= self.opacity then
|
if b ~= self.opacity then
|
||||||
self.opacity = b
|
self.opacity = b
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::redraw")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -144,23 +434,16 @@ end
|
||||||
|
|
||||||
--- Generate an empty widget which takes no space and displays nothing
|
--- Generate an empty widget which takes no space and displays nothing
|
||||||
function base.empty_widget()
|
function base.empty_widget()
|
||||||
local widget = base.make_widget()
|
return base.make_widget()
|
||||||
widget.draw = function() end
|
|
||||||
widget.fit = function() return 0, 0 end
|
|
||||||
return widget
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Do some sanity checking on widget. This function raises a lua error if
|
--- Do some sanity checking on widget. This function raises a lua error if
|
||||||
-- widget is not a valid widget.
|
-- widget is not a valid widget.
|
||||||
function base.check_widget(widget)
|
function base.check_widget(widget)
|
||||||
debug.assert(type(widget) == "table")
|
debug.assert(type(widget) == "table")
|
||||||
for k, func in pairs({ "draw", "fit", "add_signal", "connect_signal", "disconnect_signal" }) do
|
for k, func in pairs({ "add_signal", "connect_signal", "disconnect_signal" }) do
|
||||||
debug.assert(type(widget[func]) == "function", func .. " is not a function")
|
debug.assert(type(widget[func]) == "function", func .. " is not a function")
|
||||||
end
|
end
|
||||||
|
|
||||||
local width, height = widget:fit({}, 0, 0)
|
|
||||||
debug.assert(type(width) == "number")
|
|
||||||
debug.assert(type(height) == "number")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return base
|
return base
|
||||||
|
|
|
@ -20,8 +20,6 @@ function imagebox:draw(context, cr, width, height)
|
||||||
if not self._image then return end
|
if not self._image then return end
|
||||||
if width == 0 or height == 0 then return end
|
if width == 0 or height == 0 then return end
|
||||||
|
|
||||||
cr:save()
|
|
||||||
|
|
||||||
if not self.resize_forbidden then
|
if not self.resize_forbidden then
|
||||||
-- Let's scale the image so that it fits into (width, height)
|
-- Let's scale the image so that it fits into (width, height)
|
||||||
local w = self._image:get_width()
|
local w = self._image:get_width()
|
||||||
|
@ -34,8 +32,6 @@ function imagebox:draw(context, cr, width, height)
|
||||||
end
|
end
|
||||||
cr:set_source_surface(self._image, 0, 0)
|
cr:set_source_surface(self._image, 0, 0)
|
||||||
cr:paint()
|
cr:paint()
|
||||||
|
|
||||||
cr:restore()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Fit the imagebox into the given geometry
|
--- Fit the imagebox into the given geometry
|
||||||
|
@ -99,9 +95,14 @@ function imagebox:set_image(image)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if self._image == image then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
self._image = image
|
self._image = image
|
||||||
|
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::redraw_needed")
|
||||||
|
self:emit_signal("widget::layout_changed")
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -110,7 +111,8 @@ end
|
||||||
-- to fit into the available space.
|
-- to fit into the available space.
|
||||||
function imagebox:set_resize(allowed)
|
function imagebox:set_resize(allowed)
|
||||||
self.resize_forbidden = not allowed
|
self.resize_forbidden = not allowed
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::redraw_needed")
|
||||||
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a new imagebox
|
--- Returns a new imagebox
|
||||||
|
|
|
@ -79,7 +79,7 @@ local function new(revers)
|
||||||
end
|
end
|
||||||
|
|
||||||
capi.awesome.connect_signal("systray::update", function()
|
capi.awesome.connect_signal("systray::update", function()
|
||||||
ret:emit_signal("widget::updated")
|
ret:emit_signal("widget::layout_changed")
|
||||||
end)
|
end)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
|
@ -70,7 +70,8 @@ function textbox:set_markup(text)
|
||||||
self._markup = text
|
self._markup = text
|
||||||
self._layout.text = parsed
|
self._layout.text = parsed
|
||||||
self._layout.attributes = attr
|
self._layout.attributes = attr
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::redraw_needed")
|
||||||
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set a textbox' text.
|
--- Set a textbox' text.
|
||||||
|
@ -82,7 +83,8 @@ function textbox:set_text(text)
|
||||||
self._markup = nil
|
self._markup = nil
|
||||||
self._layout.text = text
|
self._layout.text = text
|
||||||
self._layout.attributes = nil
|
self._layout.attributes = nil
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::redraw_needed")
|
||||||
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set a textbox' ellipsize mode.
|
--- Set a textbox' ellipsize mode.
|
||||||
|
@ -94,7 +96,8 @@ function textbox:set_ellipsize(mode)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
self._layout:set_ellipsize(allowed[mode])
|
self._layout:set_ellipsize(allowed[mode])
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::redraw_needed")
|
||||||
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -107,7 +110,8 @@ function textbox:set_wrap(mode)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
self._layout:set_wrap(allowed[mode])
|
self._layout:set_wrap(allowed[mode])
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::redraw_needed")
|
||||||
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -120,7 +124,8 @@ function textbox:set_valign(mode)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
self._valign = mode
|
self._valign = mode
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::redraw_needed")
|
||||||
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -133,7 +138,8 @@ function textbox:set_align(mode)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
self._layout:set_alignment(allowed[mode])
|
self._layout:set_alignment(allowed[mode])
|
||||||
self:emit_signal("widget::updated")
|
self:emit_signal("widget::redraw_needed")
|
||||||
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -141,6 +147,8 @@ end
|
||||||
-- @param font The font description as string
|
-- @param font The font description as string
|
||||||
function textbox:set_font(font)
|
function textbox:set_font(font)
|
||||||
self._layout:set_font_description(beautiful.get_font(font))
|
self._layout:set_font_description(beautiful.get_font(font))
|
||||||
|
self:emit_signal("widget::redraw_needed")
|
||||||
|
self:emit_signal("widget::layout_changed")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Returns a new textbox
|
-- Returns a new textbox
|
||||||
|
|
|
@ -0,0 +1,234 @@
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
-- @author Uli Schlachter
|
||||||
|
-- @copyright 2015 Uli Schlachter
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
local hierarchy = require("wibox.hierarchy")
|
||||||
|
|
||||||
|
local cairo = require("lgi").cairo
|
||||||
|
local matrix = require("gears.matrix")
|
||||||
|
local object = require("gears.object")
|
||||||
|
local utils = require("wibox.test_utils")
|
||||||
|
|
||||||
|
local function make_widget(children)
|
||||||
|
local result = utils.widget_stub()
|
||||||
|
result.layout = function()
|
||||||
|
return children
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
local function make_child(widget, width, height, matrix)
|
||||||
|
return { _widget = widget, _width = width, _height = height, _matrix = matrix }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe("wibox.hierarchy", function()
|
||||||
|
describe("Accessor functions", function()
|
||||||
|
local widget, instance
|
||||||
|
before_each(function()
|
||||||
|
local function nop() end
|
||||||
|
local context = {}
|
||||||
|
widget = make_widget(nil)
|
||||||
|
instance = hierarchy.new(context, widget, 10, 20, nop, nop)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("get_widget", function()
|
||||||
|
assert.is.equal(instance:get_widget(), widget)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("get_matrix_to_parent", function()
|
||||||
|
assert.is_true(matrix.equals(cairo.Matrix.create_identity(),
|
||||||
|
instance:get_matrix_to_parent()))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("get_matrix_to_device", function()
|
||||||
|
assert.is_true(matrix.equals(cairo.Matrix.create_identity(),
|
||||||
|
instance:get_matrix_to_device()))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("get_matrix_from_parent", function()
|
||||||
|
assert.is_true(matrix.equals(cairo.Matrix.create_identity(),
|
||||||
|
instance:get_matrix_from_parent()))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("get_matrix_from_device", function()
|
||||||
|
assert.is_true(matrix.equals(cairo.Matrix.create_identity(),
|
||||||
|
instance:get_matrix_from_device()))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("get_draw_extents", function()
|
||||||
|
assert.is.same({ instance:get_draw_extents() }, { 0, 0, 10, 20 })
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("get_size", function()
|
||||||
|
assert.is.same({ instance:get_size() }, { 10, 20 })
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("get_children", function()
|
||||||
|
assert.is.same(instance:get_children(), {})
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("disconnect works", function()
|
||||||
|
local child = make_widget(nil)
|
||||||
|
local parent = make_widget({
|
||||||
|
make_child(child, 2, 5, cairo.Matrix.create_translate(10, 0))
|
||||||
|
})
|
||||||
|
|
||||||
|
local extra_arg = {}
|
||||||
|
local child_redraws, child_layouts = 0, 0
|
||||||
|
local parent_redraws, parent_layouts = 0, 0
|
||||||
|
local function redraw(arg, extra)
|
||||||
|
assert.is.equal(extra_arg, extra)
|
||||||
|
if arg:get_widget() == child then
|
||||||
|
child_redraws = child_redraws + 1
|
||||||
|
elseif arg:get_widget() == parent then
|
||||||
|
parent_redraws = parent_redraws + 1
|
||||||
|
else
|
||||||
|
error("Unknown widget")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function layout(arg, extra)
|
||||||
|
assert.is.equal(extra_arg, extra)
|
||||||
|
if arg:get_widget() == child then
|
||||||
|
child_layouts = child_layouts + 1
|
||||||
|
elseif arg:get_widget() == parent then
|
||||||
|
parent_layouts = parent_layouts + 1
|
||||||
|
else
|
||||||
|
error("Unknown widget")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local context = {}
|
||||||
|
local instance = hierarchy.new(context, parent, 15, 20, redraw, layout, extra_arg)
|
||||||
|
|
||||||
|
-- There should be a connection
|
||||||
|
parent:emit_signal("widget::redraw_needed")
|
||||||
|
assert.is.same({ 0, 0, 1, 0 }, { child_redraws, child_layouts, parent_redraws, parent_layouts })
|
||||||
|
child:emit_signal("widget::redraw_needed")
|
||||||
|
assert.is.same({ 1, 0, 1, 0 }, { child_redraws, child_layouts, parent_redraws, parent_layouts })
|
||||||
|
child:emit_signal("widget::layout_changed")
|
||||||
|
assert.is.same({ 1, 1, 1, 0 }, { child_redraws, child_layouts, parent_redraws, parent_layouts })
|
||||||
|
parent:emit_signal("widget::layout_changed")
|
||||||
|
assert.is.same({ 1, 1, 1, 1 }, { child_redraws, child_layouts, parent_redraws, parent_layouts })
|
||||||
|
|
||||||
|
-- Garbage-collect the hierarchy
|
||||||
|
instance = nil
|
||||||
|
collectgarbage("collect")
|
||||||
|
|
||||||
|
-- No connections should be left
|
||||||
|
parent:emit_signal("widget::redraw_needed")
|
||||||
|
child:emit_signal("widget::redraw_needed")
|
||||||
|
child:emit_signal("widget::layout_changed")
|
||||||
|
parent:emit_signal("widget::layout_changed")
|
||||||
|
assert.is.same({ 1, 1, 1, 1 }, { child_redraws, child_layouts, parent_redraws, parent_layouts })
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("children", function()
|
||||||
|
local child, intermediate, parent
|
||||||
|
local hierarchy_child, hierarchy_intermediate, hierarchy_parent
|
||||||
|
before_each(function()
|
||||||
|
child = make_widget(nil)
|
||||||
|
intermediate = make_widget({
|
||||||
|
make_child(child, 10, 20, cairo.Matrix.create_translate(0, 5))
|
||||||
|
})
|
||||||
|
parent = make_widget({
|
||||||
|
make_child(intermediate, 5, 2, cairo.Matrix.create_translate(4, 0))
|
||||||
|
})
|
||||||
|
|
||||||
|
local function nop() end
|
||||||
|
local context = {}
|
||||||
|
hierarchy_parent = hierarchy.new(context, parent, 15, 16, nop, nop)
|
||||||
|
|
||||||
|
-- This also tests get_children
|
||||||
|
local children = hierarchy_parent:get_children()
|
||||||
|
assert.is.equal(#children, 1)
|
||||||
|
hierarchy_intermediate = children[1]
|
||||||
|
|
||||||
|
local children = hierarchy_intermediate:get_children()
|
||||||
|
assert.is.equal(#children, 1)
|
||||||
|
hierarchy_child = children[1]
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("get_widget", function()
|
||||||
|
assert.is.equal(hierarchy_child:get_widget(), child)
|
||||||
|
assert.is.equal(hierarchy_intermediate:get_widget(), intermediate)
|
||||||
|
assert.is.equal(hierarchy_parent:get_widget(), parent)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("get_matrix_to_parent", function()
|
||||||
|
assert.is_true(matrix.equals(hierarchy_child:get_matrix_to_parent(), cairo.Matrix.create_translate(0, 5)))
|
||||||
|
assert.is_true(matrix.equals(hierarchy_intermediate:get_matrix_to_parent(), cairo.Matrix.create_translate(4, 0)))
|
||||||
|
assert.is_true(matrix.equals(hierarchy_parent:get_matrix_to_parent(), cairo.Matrix.create_identity()))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("get_matrix_to_device", function()
|
||||||
|
assert.is_true(matrix.equals(hierarchy_child:get_matrix_to_device(), cairo.Matrix.create_translate(4, 5)))
|
||||||
|
assert.is_true(matrix.equals(hierarchy_intermediate:get_matrix_to_device(), cairo.Matrix.create_translate(4, 0)))
|
||||||
|
assert.is_true(matrix.equals(hierarchy_parent:get_matrix_to_device(), cairo.Matrix.create_identity()))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("get_matrix_from_parent", function()
|
||||||
|
assert.is_true(matrix.equals(hierarchy_child:get_matrix_from_parent(), cairo.Matrix.create_translate(0, -5)))
|
||||||
|
assert.is_true(matrix.equals(hierarchy_intermediate:get_matrix_from_parent(), cairo.Matrix.create_translate(-4, 0)))
|
||||||
|
assert.is_true(matrix.equals(hierarchy_parent:get_matrix_from_parent(), cairo.Matrix.create_identity()))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("get_matrix_from_device", function()
|
||||||
|
assert.is_true(matrix.equals(hierarchy_child:get_matrix_from_device(), cairo.Matrix.create_translate(-4, -5)))
|
||||||
|
assert.is_true(matrix.equals(hierarchy_intermediate:get_matrix_from_device(), cairo.Matrix.create_translate(-4, 0)))
|
||||||
|
assert.is_true(matrix.equals(hierarchy_parent:get_matrix_from_device(), cairo.Matrix.create_identity()))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("get_draw_extents", function()
|
||||||
|
assert.is.same({ hierarchy_child:get_draw_extents() }, { 0, 0, 10, 20 })
|
||||||
|
assert.is.same({ hierarchy_intermediate:get_draw_extents() }, { 0, 0, 10, 25 })
|
||||||
|
assert.is.same({ hierarchy_parent:get_draw_extents() }, { 0, 0, 15, 25 })
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("get_size", function()
|
||||||
|
assert.is.same({ hierarchy_child:get_size() }, { 10, 20 })
|
||||||
|
assert.is.same({ hierarchy_intermediate:get_size() }, { 5, 2 })
|
||||||
|
assert.is.same({ hierarchy_parent:get_size() }, { 15, 16 })
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("find_differences", function()
|
||||||
|
local child, intermediate, parent
|
||||||
|
local instance
|
||||||
|
local function nop() end
|
||||||
|
before_each(function()
|
||||||
|
child = make_widget(nil)
|
||||||
|
intermediate = make_widget({
|
||||||
|
make_child(child, 10, 20, cairo.Matrix.create_translate(0, 5))
|
||||||
|
})
|
||||||
|
parent = make_widget({
|
||||||
|
make_child(intermediate, 5, 2, cairo.Matrix.create_translate(4, 0))
|
||||||
|
})
|
||||||
|
|
||||||
|
local context = {}
|
||||||
|
instance = hierarchy.new(context, parent, 15, 16, nop, nop)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("No difference", function()
|
||||||
|
local context = {}
|
||||||
|
local instance2 = hierarchy.new(context, parent, 15, 16, nop, nop)
|
||||||
|
local region = instance:find_differences(instance2)
|
||||||
|
assert.is.equal(region:num_rectangles(), 0)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("child moved", function()
|
||||||
|
intermediate.layout = function()
|
||||||
|
return { make_child(child, 10, 20, cairo.Matrix.create_translate(0, 4)) }
|
||||||
|
end
|
||||||
|
local context = {}
|
||||||
|
local instance2 = hierarchy.new(context, parent, 15, 16, nop, nop)
|
||||||
|
local region = instance:find_differences(instance2)
|
||||||
|
assert.is.equal(region:num_rectangles(), 1)
|
||||||
|
local rect = region:get_rectangle(0)
|
||||||
|
-- The widget drew to 4, 5, 10, 20 before and 4, 4, 10, 20 after
|
||||||
|
assert.is.same({ rect.x, rect.y, rect.width, rect.height }, { 4, 4, 10, 21 })
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
|
@ -5,11 +5,9 @@
|
||||||
|
|
||||||
local align = require("wibox.layout.align")
|
local align = require("wibox.layout.align")
|
||||||
local utils = require("wibox.test_utils")
|
local utils = require("wibox.test_utils")
|
||||||
|
local p = require("wibox.widget.base").place_widget_at
|
||||||
|
|
||||||
describe("wibox.layout.flex", function()
|
describe("wibox.layout.align", function()
|
||||||
before_each(utils.stub_draw_widget)
|
|
||||||
after_each(utils.revert_draw_widget)
|
|
||||||
|
|
||||||
describe("expand=none", function()
|
describe("expand=none", function()
|
||||||
local layout
|
local layout
|
||||||
before_each(function()
|
before_each(function()
|
||||||
|
@ -21,9 +19,8 @@ describe("wibox.layout.flex", function()
|
||||||
assert.widget_fit(layout, { 10, 10 }, { 0, 0 })
|
assert.widget_fit(layout, { 10, 10 }, { 0, 0 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("empty layout draw", function()
|
it("empty layout layout", function()
|
||||||
layout:draw(nil, nil, 0, 0)
|
assert.is.same({}, layout:layout(0, 0))
|
||||||
utils.check_widgets_drawn({})
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe("with widgets", function()
|
describe("with widgets", function()
|
||||||
|
@ -44,12 +41,11 @@ describe("wibox.layout.flex", function()
|
||||||
assert.widget_fit(layout, { 100, 100 }, { 15, 35 })
|
assert.widget_fit(layout, { 100, 100 }, { 15, 35 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("draw", function()
|
it("layout", function()
|
||||||
layout:draw("wibox", "cr", 100, 100)
|
assert.widget_layout(layout, { 100, 100 }, {
|
||||||
utils.check_widgets_drawn({
|
p(first, 0, 0, 100, 10),
|
||||||
{ first, 0, 0, 100, 10 },
|
p(third, 0, 90, 100, 10),
|
||||||
{ third, 0, 90, 100, 10 },
|
p(second, 0, 42, 100, 15),
|
||||||
{ second, 0, 42, 100, 15 },
|
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
@ -59,12 +55,11 @@ describe("wibox.layout.flex", function()
|
||||||
assert.widget_fit(layout, { 5, 100 }, { 5, 35 })
|
assert.widget_fit(layout, { 5, 100 }, { 5, 35 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("draw", function()
|
it("layout", function()
|
||||||
layout:draw("wibox", "cr", 5, 100)
|
assert.widget_layout(layout, { 5, 100 }, {
|
||||||
utils.check_widgets_drawn({
|
p(first, 0, 0, 5, 10),
|
||||||
{ first, 0, 0, 5, 10 },
|
p(third, 0, 90, 5, 10),
|
||||||
{ third, 0, 90, 5, 10 },
|
p(second, 0, 42, 5, 15),
|
||||||
{ second, 0, 42, 5, 15 },
|
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
@ -74,12 +69,11 @@ describe("wibox.layout.flex", function()
|
||||||
assert.widget_fit(layout, { 100, 20 }, { 15, 20 })
|
assert.widget_fit(layout, { 100, 20 }, { 15, 20 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("draw", function()
|
it("layout", function()
|
||||||
layout:draw("wibox", "cr", 100, 20)
|
assert.widget_layout(layout, { 100, 20 }, {
|
||||||
utils.check_widgets_drawn({
|
p(first, 0, 0, 100, 2),
|
||||||
{ first, 0, 0, 100, 2 },
|
p(third, 0, 18, 100, 2),
|
||||||
{ third, 0, 18, 100, 2 },
|
p(second, 0, 2, 100, 15),
|
||||||
{ second, 0, 2, 100, 15 },
|
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
@ -97,9 +91,8 @@ describe("wibox.layout.flex", function()
|
||||||
assert.widget_fit(layout, { 10, 10 }, { 0, 0 })
|
assert.widget_fit(layout, { 10, 10 }, { 0, 0 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("empty layout draw", function()
|
it("empty layout layout", function()
|
||||||
layout:draw(nil, nil, 0, 0)
|
assert.widget_layout(layout, { 0, 0 }, {})
|
||||||
utils.check_widgets_drawn({})
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe("with widgets", function()
|
describe("with widgets", function()
|
||||||
|
@ -120,12 +113,11 @@ describe("wibox.layout.flex", function()
|
||||||
assert.widget_fit(layout, { 100, 100 }, { 15, 35 })
|
assert.widget_fit(layout, { 100, 100 }, { 15, 35 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("draw", function()
|
it("layout", function()
|
||||||
layout:draw("wibox", "cr", 100, 100)
|
assert.widget_layout(layout, { 100, 100 }, {
|
||||||
utils.check_widgets_drawn({
|
p(first, 0, 0, 100, 42),
|
||||||
{ first, 0, 0, 100, 42 },
|
p(third, 0, 58, 100, 42),
|
||||||
{ third, 0, 58, 100, 42 },
|
p(second, 0, 42, 100, 15),
|
||||||
{ second, 0, 42, 100, 15 },
|
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
@ -135,12 +127,11 @@ describe("wibox.layout.flex", function()
|
||||||
assert.widget_fit(layout, { 5, 100 }, { 5, 35 })
|
assert.widget_fit(layout, { 5, 100 }, { 5, 35 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("draw", function()
|
it("layout", function()
|
||||||
layout:draw("wibox", "cr", 5, 100)
|
assert.widget_layout(layout, { 5, 100 }, {
|
||||||
utils.check_widgets_drawn({
|
p(first, 0, 0, 5, 42),
|
||||||
{ first, 0, 0, 5, 42 },
|
p(third, 0, 58, 5, 42),
|
||||||
{ third, 0, 58, 5, 42 },
|
p(second, 0, 42, 5, 15),
|
||||||
{ second, 0, 42, 5, 15 },
|
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
@ -150,12 +141,11 @@ describe("wibox.layout.flex", function()
|
||||||
assert.widget_fit(layout, { 100, 20 }, { 15, 20 })
|
assert.widget_fit(layout, { 100, 20 }, { 15, 20 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("draw", function()
|
it("layout", function()
|
||||||
layout:draw("wibox", "cr", 100, 20)
|
assert.widget_layout(layout, { 100, 20 }, {
|
||||||
utils.check_widgets_drawn({
|
p(first, 0, 0, 100, 2),
|
||||||
{ first, 0, 0, 100, 2 },
|
p(third, 0, 18, 100, 2),
|
||||||
{ third, 0, 18, 100, 2 },
|
p(second, 0, 2, 100, 15),
|
||||||
{ second, 0, 2, 100, 15 },
|
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
@ -173,9 +163,8 @@ describe("wibox.layout.flex", function()
|
||||||
assert.widget_fit(layout, { 10, 10 }, { 0, 0 })
|
assert.widget_fit(layout, { 10, 10 }, { 0, 0 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("empty layout draw", function()
|
it("empty layout layout", function()
|
||||||
layout:draw(nil, nil, 0, 0)
|
assert.widget_layout(layout, { 0, 0 }, {})
|
||||||
utils.check_widgets_drawn({})
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe("with widgets", function()
|
describe("with widgets", function()
|
||||||
|
@ -196,12 +185,11 @@ describe("wibox.layout.flex", function()
|
||||||
assert.widget_fit(layout, { 100, 100 }, { 15, 35 })
|
assert.widget_fit(layout, { 100, 100 }, { 15, 35 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("draw", function()
|
it("layout", function()
|
||||||
layout:draw("wibox", "cr", 100, 100)
|
assert.widget_layout(layout, { 100, 100 }, {
|
||||||
utils.check_widgets_drawn({
|
p(first, 0, 0, 100, 10),
|
||||||
{ first, 0, 0, 100, 10 },
|
p(third, 0, 90, 100, 10),
|
||||||
{ third, 0, 90, 100, 10 },
|
p(second, 0, 10, 100, 80),
|
||||||
{ second, 0, 10, 100, 80 },
|
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
@ -211,12 +199,11 @@ describe("wibox.layout.flex", function()
|
||||||
assert.widget_fit(layout, { 5, 100 }, { 5, 35 })
|
assert.widget_fit(layout, { 5, 100 }, { 5, 35 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("draw", function()
|
it("layout", function()
|
||||||
layout:draw("wibox", "cr", 5, 100)
|
assert.widget_layout(layout, { 5, 100 }, {
|
||||||
utils.check_widgets_drawn({
|
p(first, 0, 0, 5, 10),
|
||||||
{ first, 0, 0, 5, 10 },
|
p(third, 0, 90, 5, 10),
|
||||||
{ third, 0, 90, 5, 10 },
|
p(second, 0, 10, 5, 80),
|
||||||
{ second, 0, 10, 5, 80 },
|
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
@ -226,17 +213,59 @@ describe("wibox.layout.flex", function()
|
||||||
assert.widget_fit(layout, { 100, 20 }, { 15, 20 })
|
assert.widget_fit(layout, { 100, 20 }, { 15, 20 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("draw", function()
|
it("layout", function()
|
||||||
layout:draw("wibox", "cr", 100, 20)
|
assert.widget_layout(layout, { 100, 20 }, {
|
||||||
--- XXX: Shouldn't this also draw part of the second widget?
|
p(first, 0, 0, 100, 10),
|
||||||
utils.check_widgets_drawn({
|
p(third, 0, 10, 100, 10),
|
||||||
{ first, 0, 0, 100, 10 },
|
|
||||||
{ third, 0, 10, 100, 10 },
|
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
describe("emitting signals", function()
|
||||||
|
local layout, layout_changed
|
||||||
|
before_each(function()
|
||||||
|
layout = align.vertical()
|
||||||
|
layout:connect_signal("widget::layout_changed", function()
|
||||||
|
layout_changed = layout_changed + 1
|
||||||
|
end)
|
||||||
|
layout_changed = 0
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("set first", function()
|
||||||
|
local w1, w2 = {}, {}
|
||||||
|
assert.is.equal(layout_changed, 0)
|
||||||
|
layout:set_first(w1)
|
||||||
|
assert.is.equal(layout_changed, 1)
|
||||||
|
layout:set_first(w2)
|
||||||
|
assert.is.equal(layout_changed, 2)
|
||||||
|
layout:set_first(w2)
|
||||||
|
assert.is.equal(layout_changed, 2)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("set second", function()
|
||||||
|
local w1, w2 = {}, {}
|
||||||
|
assert.is.equal(layout_changed, 0)
|
||||||
|
layout:set_second(w1)
|
||||||
|
assert.is.equal(layout_changed, 1)
|
||||||
|
layout:set_second(w2)
|
||||||
|
assert.is.equal(layout_changed, 2)
|
||||||
|
layout:set_second(w2)
|
||||||
|
assert.is.equal(layout_changed, 2)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("set third", function()
|
||||||
|
local w1, w2 = {}, {}
|
||||||
|
assert.is.equal(layout_changed, 0)
|
||||||
|
layout:set_third(w1)
|
||||||
|
assert.is.equal(layout_changed, 1)
|
||||||
|
layout:set_third(w2)
|
||||||
|
assert.is.equal(layout_changed, 2)
|
||||||
|
layout:set_third(w2)
|
||||||
|
assert.is.equal(layout_changed, 2)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
local fixed = require("wibox.layout.fixed")
|
local fixed = require("wibox.layout.fixed")
|
||||||
|
local base = require("wibox.widget.base")
|
||||||
local utils = require("wibox.test_utils")
|
local utils = require("wibox.test_utils")
|
||||||
|
local p = require("wibox.widget.base").place_widget_at
|
||||||
|
|
||||||
describe("wibox.layout.fixed", function()
|
describe("wibox.layout.fixed", function()
|
||||||
local layout
|
local layout
|
||||||
|
@ -12,16 +14,12 @@ describe("wibox.layout.fixed", function()
|
||||||
layout = fixed.vertical()
|
layout = fixed.vertical()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
before_each(utils.stub_draw_widget)
|
|
||||||
after_each(utils.revert_draw_widget)
|
|
||||||
|
|
||||||
it("empty layout fit", function()
|
it("empty layout fit", function()
|
||||||
assert.widget_fit(layout, { 10, 10 }, { 0, 0 })
|
assert.widget_fit(layout, { 10, 10 }, { 0, 0 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("empty layout draw", function()
|
it("empty layout layout", function()
|
||||||
layout:draw(nil, nil, 0, 0)
|
assert.widget_layout(layout, { 0, 0 }, {})
|
||||||
utils.check_widgets_drawn({})
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe("with widgets", function()
|
describe("with widgets", function()
|
||||||
|
@ -42,12 +40,11 @@ describe("wibox.layout.fixed", function()
|
||||||
assert.widget_fit(layout, { 100, 100 }, { 15, 35 })
|
assert.widget_fit(layout, { 100, 100 }, { 15, 35 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("draw", function()
|
it("layout", function()
|
||||||
layout:draw("wibox", "cr", 100, 100)
|
assert.widget_layout(layout, { 100, 100 }, {
|
||||||
utils.check_widgets_drawn({
|
p(first, 0, 0, 100, 10),
|
||||||
{ first, 0, 0, 100, 10 },
|
p(second, 0, 10, 100, 15),
|
||||||
{ second, 0, 10, 100, 15 },
|
p(third, 0, 25, 100, 10),
|
||||||
{ third, 0, 25, 100, 10 },
|
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
@ -57,32 +54,82 @@ describe("wibox.layout.fixed", function()
|
||||||
assert.widget_fit(layout, { 5, 100 }, { 5, 35 })
|
assert.widget_fit(layout, { 5, 100 }, { 5, 35 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("draw", function()
|
it("layout", function()
|
||||||
layout:draw("wibox", "cr", 5, 100)
|
assert.widget_layout(layout, { 5, 100 }, {
|
||||||
utils.check_widgets_drawn({
|
p(first, 0, 0, 5, 10),
|
||||||
{ first, 0, 0, 5, 10 },
|
p(second, 0, 10, 5, 15),
|
||||||
{ second, 0, 10, 5, 15 },
|
p(third, 0, 25, 5, 10),
|
||||||
{ third, 0, 25, 5, 10 },
|
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe("without enough width", function()
|
describe("without enough width", function()
|
||||||
it("fit", function()
|
it("fit", function()
|
||||||
-- XXX: Is this really what should happen?
|
|
||||||
assert.widget_fit(layout, { 100, 20 }, { 15, 20 })
|
assert.widget_fit(layout, { 100, 20 }, { 15, 20 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("draw", function()
|
it("layout", function()
|
||||||
layout:draw("wibox", "cr", 100, 20)
|
assert.widget_layout(layout, { 100, 20 }, {
|
||||||
utils.check_widgets_drawn({
|
p(first, 0, 0, 100, 10),
|
||||||
{ first, 0, 0, 100, 10 },
|
p(second, 0, 10, 100, 10),
|
||||||
{ second, 0, 10, 100, 10 },
|
p(third, 0, 20, 100, 0),
|
||||||
{ third, 0, 20, 100, 0 },
|
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
describe("emitting signals", function()
|
||||||
|
local layout_changed
|
||||||
|
before_each(function()
|
||||||
|
layout:connect_signal("widget::layout_changed", function()
|
||||||
|
layout_changed = layout_changed + 1
|
||||||
|
end)
|
||||||
|
layout_changed = 0
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("add", function()
|
||||||
|
local w1, w2 = base.empty_widget(), base.empty_widget()
|
||||||
|
assert.is.equal(layout_changed, 0)
|
||||||
|
layout:add(w1)
|
||||||
|
assert.is.equal(layout_changed, 1)
|
||||||
|
layout:add(w2)
|
||||||
|
assert.is.equal(layout_changed, 2)
|
||||||
|
layout:add(w2)
|
||||||
|
assert.is.equal(layout_changed, 3)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("set_spacing", function()
|
||||||
|
assert.is.equal(layout_changed, 0)
|
||||||
|
layout:set_spacing(0)
|
||||||
|
assert.is.equal(layout_changed, 0)
|
||||||
|
layout:set_spacing(5)
|
||||||
|
assert.is.equal(layout_changed, 1)
|
||||||
|
layout:set_spacing(2)
|
||||||
|
assert.is.equal(layout_changed, 2)
|
||||||
|
layout:set_spacing(2)
|
||||||
|
assert.is.equal(layout_changed, 2)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("reset", function()
|
||||||
|
assert.is.equal(layout_changed, 0)
|
||||||
|
layout:add(base.make_widget())
|
||||||
|
assert.is.equal(layout_changed, 1)
|
||||||
|
layout:reset()
|
||||||
|
assert.is.equal(layout_changed, 2)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("fill_space", function()
|
||||||
|
assert.is.equal(layout_changed, 0)
|
||||||
|
layout:fill_space(false)
|
||||||
|
assert.is.equal(layout_changed, 0)
|
||||||
|
layout:fill_space(true)
|
||||||
|
assert.is.equal(layout_changed, 1)
|
||||||
|
layout:fill_space(true)
|
||||||
|
assert.is.equal(layout_changed, 1)
|
||||||
|
layout:fill_space(false)
|
||||||
|
assert.is.equal(layout_changed, 2)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
local flex = require("wibox.layout.flex")
|
local flex = require("wibox.layout.flex")
|
||||||
|
local base = require("wibox.widget.base")
|
||||||
local utils = require("wibox.test_utils")
|
local utils = require("wibox.test_utils")
|
||||||
|
local p = require("wibox.widget.base").place_widget_at
|
||||||
|
|
||||||
describe("wibox.layout.flex", function()
|
describe("wibox.layout.flex", function()
|
||||||
local layout
|
local layout
|
||||||
|
@ -12,16 +14,12 @@ describe("wibox.layout.flex", function()
|
||||||
layout = flex.vertical()
|
layout = flex.vertical()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
before_each(utils.stub_draw_widget)
|
|
||||||
after_each(utils.revert_draw_widget)
|
|
||||||
|
|
||||||
it("empty layout fit", function()
|
it("empty layout fit", function()
|
||||||
assert.widget_fit(layout, { 10, 10 }, { 0, 0 })
|
assert.widget_fit(layout, { 10, 10 }, { 0, 0 })
|
||||||
utils.check_widgets_drawn({})
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("empty layout draw", function()
|
it("empty layout layout", function()
|
||||||
layout:draw(nil, nil, 0, 0)
|
assert.widget_layout(layout, { 0, 0 }, {})
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe("with widgets", function()
|
describe("with widgets", function()
|
||||||
|
@ -42,12 +40,11 @@ describe("wibox.layout.flex", function()
|
||||||
assert.widget_fit(layout, { 100, 100 }, { 15, 35 })
|
assert.widget_fit(layout, { 100, 100 }, { 15, 35 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("draw", function()
|
it("layout", function()
|
||||||
layout:draw("wibox", "cr", 100, 100)
|
assert.widget_layout(layout, { 100, 100 }, {
|
||||||
utils.check_widgets_drawn({
|
p(first, 0, 0, 100, 33),
|
||||||
{ first, 0, 0, 100, 33 },
|
p(second, 0, 33, 100, 33),
|
||||||
{ second, 0, 33, 100, 33 },
|
p(third, 0, 67, 100, 33),
|
||||||
{ third, 0, 67, 100, 33 },
|
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
@ -57,12 +54,11 @@ describe("wibox.layout.flex", function()
|
||||||
assert.widget_fit(layout, { 5, 100 }, { 5, 35 })
|
assert.widget_fit(layout, { 5, 100 }, { 5, 35 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("draw", function()
|
it("layout", function()
|
||||||
layout:draw("wibox", "cr", 5, 100)
|
assert.widget_layout(layout, { 5, 100 }, {
|
||||||
utils.check_widgets_drawn({
|
p(first, 0, 0, 5, 33),
|
||||||
{ first, 0, 0, 5, 33 },
|
p(second, 0, 33, 5, 33),
|
||||||
{ second, 0, 33, 5, 33 },
|
p(third, 0, 67, 5, 33),
|
||||||
{ third, 0, 67, 5, 33 },
|
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
@ -72,16 +68,68 @@ describe("wibox.layout.flex", function()
|
||||||
assert.widget_fit(layout, { 100, 20 }, { 15, 20 })
|
assert.widget_fit(layout, { 100, 20 }, { 15, 20 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("draw", function()
|
it("layout", function()
|
||||||
layout:draw("wibox", "cr", 100, 20)
|
assert.widget_layout(layout, { 100, 20 }, {
|
||||||
utils.check_widgets_drawn({
|
p(first, 0, 0, 100, 6),
|
||||||
{ first, 0, 0, 100, 6 },
|
p(second, 0, 7, 100, 6),
|
||||||
{ second, 0, 7, 100, 6 },
|
p(third, 0, 13, 100, 6),
|
||||||
{ third, 0, 13, 100, 6 },
|
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
describe("emitting signals", function()
|
||||||
|
local layout_changed
|
||||||
|
before_each(function()
|
||||||
|
layout:connect_signal("widget::layout_changed", function()
|
||||||
|
layout_changed = layout_changed + 1
|
||||||
|
end)
|
||||||
|
layout_changed = 0
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("add", function()
|
||||||
|
local w1, w2 = base.empty_widget(), base.empty_widget()
|
||||||
|
assert.is.equal(layout_changed, 0)
|
||||||
|
layout:add(w1)
|
||||||
|
assert.is.equal(layout_changed, 1)
|
||||||
|
layout:add(w2)
|
||||||
|
assert.is.equal(layout_changed, 2)
|
||||||
|
layout:add(w2)
|
||||||
|
assert.is.equal(layout_changed, 3)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("reset", function()
|
||||||
|
assert.is.equal(layout_changed, 0)
|
||||||
|
layout:add(base.make_widget())
|
||||||
|
assert.is.equal(layout_changed, 1)
|
||||||
|
layout:reset()
|
||||||
|
assert.is.equal(layout_changed, 2)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("set_spacing", function()
|
||||||
|
assert.is.equal(layout_changed, 0)
|
||||||
|
layout:set_spacing(0)
|
||||||
|
assert.is.equal(layout_changed, 0)
|
||||||
|
layout:set_spacing(5)
|
||||||
|
assert.is.equal(layout_changed, 1)
|
||||||
|
layout:set_spacing(2)
|
||||||
|
assert.is.equal(layout_changed, 2)
|
||||||
|
layout:set_spacing(2)
|
||||||
|
assert.is.equal(layout_changed, 2)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("set_max_widget_size", function()
|
||||||
|
assert.is.equal(layout_changed, 0)
|
||||||
|
layout:set_max_widget_size(nil)
|
||||||
|
assert.is.equal(layout_changed, 0)
|
||||||
|
layout:set_max_widget_size(20)
|
||||||
|
assert.is.equal(layout_changed, 1)
|
||||||
|
layout:set_max_widget_size(20)
|
||||||
|
assert.is.equal(layout_changed, 1)
|
||||||
|
layout:set_max_widget_size(nil)
|
||||||
|
assert.is.equal(layout_changed, 2)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||||
|
|
|
@ -5,37 +5,21 @@
|
||||||
|
|
||||||
local object = require("gears.object")
|
local object = require("gears.object")
|
||||||
local cache = require("gears.cache")
|
local cache = require("gears.cache")
|
||||||
local wbase = require("wibox.widget.base")
|
local matrix_equals = require("gears.matrix").equals
|
||||||
local lbase = require("wibox.layout.base")
|
local base = require("wibox.widget.base")
|
||||||
local say = require("say")
|
local say = require("say")
|
||||||
local assert = require("luassert")
|
local assert = require("luassert")
|
||||||
local spy = require("luassert.spy")
|
|
||||||
local stub = require("luassert.stub")
|
|
||||||
|
|
||||||
local real_draw_widget = lbase.draw_widget
|
|
||||||
local widgets_drawn = nil
|
|
||||||
|
|
||||||
-- This function would reject stubbed widgets
|
|
||||||
local real_check_widget = wbase.check_widget
|
|
||||||
wbase.check_widget = function()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function stub_draw_widget(wibox, cr, widget, x, y, width, height)
|
|
||||||
assert.is.equal("wibox", wibox)
|
|
||||||
assert.is.equal("cr", cr)
|
|
||||||
table.insert(widgets_drawn, { widget, x, y, width, height })
|
|
||||||
end
|
|
||||||
|
|
||||||
-- {{{ Own widget-based assertions
|
-- {{{ Own widget-based assertions
|
||||||
local function widget_fit(state, arguments)
|
local function widget_fit(state, arguments)
|
||||||
if #arguments ~= 3 then
|
if #arguments ~= 3 then
|
||||||
return false
|
error("Have " .. #arguments .. " arguments, but need 3")
|
||||||
end
|
end
|
||||||
|
|
||||||
local widget = arguments[1]
|
local widget = arguments[1]
|
||||||
local given = arguments[2]
|
local given = arguments[2]
|
||||||
local expected = arguments[3]
|
local expected = arguments[3]
|
||||||
local w, h = lbase.fit_widget({ "fake context" }, widget, given[1], given[2])
|
local w, h = base.fit_widget({ "fake context" }, widget, given[1], given[2])
|
||||||
|
|
||||||
local fits = expected[1] == w and expected[2] == h
|
local fits = expected[1] == w and expected[2] == h
|
||||||
if state.mod == fits then
|
if state.mod == fits then
|
||||||
|
@ -52,51 +36,65 @@ local function widget_fit(state, arguments)
|
||||||
end
|
end
|
||||||
say:set("assertion.widget_fit.positive", "Offering (%s, %s) to widget and expected (%s, %s), but got (%s, %s)")
|
say:set("assertion.widget_fit.positive", "Offering (%s, %s) to widget and expected (%s, %s), but got (%s, %s)")
|
||||||
assert:register("assertion", "widget_fit", widget_fit, "assertion.widget_fit.positive", "assertion.widget_fit.positive")
|
assert:register("assertion", "widget_fit", widget_fit, "assertion.widget_fit.positive", "assertion.widget_fit.positive")
|
||||||
|
|
||||||
|
local function widget_layout(state, arguments)
|
||||||
|
if #arguments ~= 3 then
|
||||||
|
error("Have " .. #arguments .. " arguments, but need 3")
|
||||||
|
end
|
||||||
|
|
||||||
|
local widget = arguments[1]
|
||||||
|
local given = arguments[2]
|
||||||
|
local expected = arguments[3]
|
||||||
|
local children = widget.layout and widget:layout({ "fake context" }, given[1], given[2]) or {}
|
||||||
|
|
||||||
|
local fits = true
|
||||||
|
if #children ~= #expected then
|
||||||
|
fits = false
|
||||||
|
else
|
||||||
|
for i = 1, #children do
|
||||||
|
local child, expected = children[i], expected[i]
|
||||||
|
if child._widget ~= expected._widget or
|
||||||
|
child._width ~= expected._width or
|
||||||
|
child._height ~= expected._height or
|
||||||
|
not matrix_equals(child._matrix, expected._matrix) then
|
||||||
|
fits = false
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if state.mod == fits then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- For proper error message, mess with the arguments
|
||||||
|
arguments[1] = expected
|
||||||
|
arguments[2] = children
|
||||||
|
arguments[3] = given[1]
|
||||||
|
arguments[4] = given[2]
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
say:set("assertion.widget_layout.positive", "Expected:\n%s\nbut got:\n%s\nwhen offering (%s, %s) to widget")
|
||||||
|
assert:register("assertion", "widget_layout", widget_layout, "assertion.widget_layout.positive", "assertion.widget_layout.positive")
|
||||||
-- }}}
|
-- }}}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
real_check_widget = real_check_widget,
|
|
||||||
|
|
||||||
widget_stub = function(width, height)
|
widget_stub = function(width, height)
|
||||||
local w = object()
|
local w = object()
|
||||||
|
w:add_signal("widget::redraw_needed")
|
||||||
|
w:add_signal("widget::layout_changed")
|
||||||
w.visible = true
|
w.visible = true
|
||||||
w:add_signal("widget::updated")
|
w.opacity = 1
|
||||||
|
if width or height then
|
||||||
w.fit = function()
|
w.fit = function()
|
||||||
return width or 10, height or 10
|
return width or 10, height or 10
|
||||||
|
end
|
||||||
end
|
end
|
||||||
w.draw = function() end
|
w._widget_caches = {}
|
||||||
w._fit_geometry_cache = cache.new(w.fit)
|
|
||||||
|
|
||||||
spy.on(w, "fit")
|
|
||||||
stub(w, "draw")
|
|
||||||
|
|
||||||
return w
|
return w
|
||||||
end,
|
end,
|
||||||
|
|
||||||
stub_draw_widget = function()
|
|
||||||
lbase.draw_widget = stub_draw_widget
|
|
||||||
widgets_drawn = {}
|
|
||||||
end,
|
|
||||||
|
|
||||||
revert_draw_widget = function()
|
|
||||||
lbase.draw_widget = real_draw_widget
|
|
||||||
widgets_drawn = nil
|
|
||||||
end,
|
|
||||||
|
|
||||||
check_widgets_drawn = function(expected)
|
|
||||||
assert.is.equals(#expected, #widgets_drawn)
|
|
||||||
for k, v in pairs(expected) do
|
|
||||||
-- widget, x, y, width, height
|
|
||||||
-- Compared like this so we get slightly less bad error messages
|
|
||||||
assert.is.equals(expected[k][1], widgets_drawn[k][1])
|
|
||||||
assert.is.equals(expected[k][2], widgets_drawn[k][2])
|
|
||||||
assert.is.equals(expected[k][3], widgets_drawn[k][3])
|
|
||||||
assert.is.equals(expected[k][4], widgets_drawn[k][4])
|
|
||||||
assert.is.equals(expected[k][5], widgets_drawn[k][5])
|
|
||||||
end
|
|
||||||
widgets_drawn = {}
|
|
||||||
end
|
|
||||||
}
|
}
|
||||||
|
|
||||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
-- @author Uli Schlachter
|
||||||
|
-- @copyright 2015 Uli Schlachter
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Grml...
|
||||||
|
_G.awesome = {
|
||||||
|
xrdb_get_value = function(a, b)
|
||||||
|
if a ~= "" then error() end
|
||||||
|
if b ~= "Xft.dpi" then error() end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
local textbox = require("wibox.widget.textbox")
|
||||||
|
|
||||||
|
describe("wibox.widget.textbox", function()
|
||||||
|
local widget
|
||||||
|
before_each(function()
|
||||||
|
widget = textbox()
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("emitting signals", function()
|
||||||
|
local redraw_needed, layout_changed
|
||||||
|
before_each(function()
|
||||||
|
widget:connect_signal("widget::redraw_needed", function()
|
||||||
|
redraw_needed = redraw_needed + 1
|
||||||
|
end)
|
||||||
|
widget:connect_signal("widget::layout_changed", function()
|
||||||
|
layout_changed = layout_changed + 1
|
||||||
|
end)
|
||||||
|
redraw_needed, layout_changed = 0, 0
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("text and markup", function()
|
||||||
|
assert.is.equal(0, redraw_needed)
|
||||||
|
assert.is.equal(0, layout_changed)
|
||||||
|
|
||||||
|
widget:set_text("text")
|
||||||
|
assert.is.equal(1, redraw_needed)
|
||||||
|
assert.is.equal(1, layout_changed)
|
||||||
|
|
||||||
|
widget:set_text("text")
|
||||||
|
assert.is.equal(1, redraw_needed)
|
||||||
|
assert.is.equal(1, layout_changed)
|
||||||
|
|
||||||
|
widget:set_text("<b>text</b>")
|
||||||
|
assert.is.equal(2, redraw_needed)
|
||||||
|
assert.is.equal(2, layout_changed)
|
||||||
|
|
||||||
|
widget:set_markup("<b>text</b>")
|
||||||
|
assert.is.equal(3, redraw_needed)
|
||||||
|
assert.is.equal(3, layout_changed)
|
||||||
|
|
||||||
|
widget:set_markup("<b>text</b>")
|
||||||
|
assert.is.equal(3, redraw_needed)
|
||||||
|
assert.is.equal(3, layout_changed)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("set_ellipsize", function()
|
||||||
|
assert.is.equal(0, redraw_needed)
|
||||||
|
assert.is.equal(0, layout_changed)
|
||||||
|
|
||||||
|
widget:set_ellipsize("end")
|
||||||
|
assert.is.equal(0, redraw_needed)
|
||||||
|
assert.is.equal(0, layout_changed)
|
||||||
|
|
||||||
|
widget:set_ellipsize("none")
|
||||||
|
assert.is.equal(1, redraw_needed)
|
||||||
|
assert.is.equal(1, layout_changed)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("set_wrap", function()
|
||||||
|
assert.is.equal(0, redraw_needed)
|
||||||
|
assert.is.equal(0, layout_changed)
|
||||||
|
|
||||||
|
widget:set_wrap("word_char")
|
||||||
|
assert.is.equal(0, redraw_needed)
|
||||||
|
assert.is.equal(0, layout_changed)
|
||||||
|
|
||||||
|
widget:set_wrap("char")
|
||||||
|
assert.is.equal(1, redraw_needed)
|
||||||
|
assert.is.equal(1, layout_changed)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("set_valign", function()
|
||||||
|
assert.is.equal(0, redraw_needed)
|
||||||
|
assert.is.equal(0, layout_changed)
|
||||||
|
|
||||||
|
widget:set_valign("center")
|
||||||
|
assert.is.equal(0, redraw_needed)
|
||||||
|
assert.is.equal(0, layout_changed)
|
||||||
|
|
||||||
|
widget:set_valign("top")
|
||||||
|
assert.is.equal(1, redraw_needed)
|
||||||
|
assert.is.equal(1, layout_changed)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("set_align", function()
|
||||||
|
assert.is.equal(0, redraw_needed)
|
||||||
|
assert.is.equal(0, layout_changed)
|
||||||
|
|
||||||
|
widget:set_align("left")
|
||||||
|
assert.is.equal(0, redraw_needed)
|
||||||
|
assert.is.equal(0, layout_changed)
|
||||||
|
|
||||||
|
widget:set_align("right")
|
||||||
|
assert.is.equal(1, redraw_needed)
|
||||||
|
assert.is.equal(1, layout_changed)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("set_font", function()
|
||||||
|
assert.is.equal(0, redraw_needed)
|
||||||
|
assert.is.equal(0, layout_changed)
|
||||||
|
|
||||||
|
widget:set_font("foo")
|
||||||
|
assert.is.equal(1, redraw_needed)
|
||||||
|
assert.is.equal(1, layout_changed)
|
||||||
|
|
||||||
|
widget:set_font("bar")
|
||||||
|
assert.is.equal(2, redraw_needed)
|
||||||
|
assert.is.equal(2, layout_changed)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
Loading…
Reference in New Issue