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)
|
||||
end
|
||||
|
||||
_graph:emit_signal("widget::updated")
|
||||
_graph:emit_signal("widget::redraw_needed")
|
||||
return _graph
|
||||
end
|
||||
|
||||
|
@ -205,7 +205,7 @@ end
|
|||
function graph:set_height(height)
|
||||
if height >= 5 then
|
||||
data[self].height = height
|
||||
self:emit_signal("widget::updated")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
@ -215,7 +215,7 @@ end
|
|||
function graph:set_width(width)
|
||||
if width >= 5 then
|
||||
data[self].width = width
|
||||
self:emit_signal("widget::updated")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
@ -226,7 +226,7 @@ for _, prop in ipairs(properties) do
|
|||
graph["set_" .. prop] = function(_graph, value)
|
||||
if data[_graph][prop] ~= value then
|
||||
data[_graph][prop] = value
|
||||
_graph:emit_signal("widget::updated")
|
||||
_graph:emit_signal("widget::redraw_needed")
|
||||
end
|
||||
return _graph
|
||||
end
|
||||
|
|
|
@ -164,7 +164,7 @@ function progressbar:set_value(value)
|
|||
local value = value or 0
|
||||
local max_value = data[self].max_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
|
||||
end
|
||||
|
||||
|
@ -172,7 +172,7 @@ end
|
|||
-- @param height The height to set.
|
||||
function progressbar:set_height(height)
|
||||
data[self].height = height
|
||||
self:emit_signal("widget::updated")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
return self
|
||||
end
|
||||
|
||||
|
@ -180,7 +180,7 @@ end
|
|||
-- @param width The width to set.
|
||||
function progressbar:set_width(width)
|
||||
data[self].width = width
|
||||
self:emit_signal("widget::updated")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
return self
|
||||
end
|
||||
|
||||
|
@ -189,7 +189,7 @@ for _, prop in ipairs(properties) do
|
|||
if not progressbar["set_" .. prop] then
|
||||
progressbar["set_" .. prop] = function(pbar, value)
|
||||
data[pbar][prop] = value
|
||||
pbar:emit_signal("widget::updated")
|
||||
pbar:emit_signal("widget::redraw_needed")
|
||||
return pbar
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,6 +20,9 @@ local object = require("gears.object")
|
|||
local sort = require("gears.sort")
|
||||
local surface = require("gears.surface")
|
||||
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 wallpaper = nil
|
||||
|
@ -69,6 +72,36 @@ local function do_redraw(self)
|
|||
local geom = self.drawable:geometry();
|
||||
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
|
||||
cr:save()
|
||||
|
||||
|
@ -93,21 +126,9 @@ local function do_redraw(self)
|
|||
cr:restore()
|
||||
|
||||
-- Draw the widget
|
||||
self._widget_geometries = {}
|
||||
if self.widget and self.widget.visible then
|
||||
if self._widget_hierarchy then
|
||||
cr:set_source(self.foreground_color)
|
||||
|
||||
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)
|
||||
self._widget_hierarchy:draw(get_widget_context(self), cr)
|
||||
end
|
||||
|
||||
self.drawable:refresh()
|
||||
|
@ -115,16 +136,33 @@ local function do_redraw(self)
|
|||
debug.assert(cr.status == "SUCCESS", "Cairo context entered error state: " .. cr.status)
|
||||
end
|
||||
|
||||
--- Register a widget's position.
|
||||
-- This is internal, don't call it yourself! Only wibox.layout.base.draw_widget
|
||||
-- is allowed to call this.
|
||||
function drawable:widget_at(widget, x, y, width, height)
|
||||
local t = {
|
||||
widget = widget,
|
||||
x = x, y = y,drawable = self,
|
||||
width = width, height = height
|
||||
}
|
||||
table.insert(self._widget_geometries, t)
|
||||
local function find_widgets(drawable, result, hierarchy, x, y)
|
||||
local m = hierarchy:get_matrix_from_device()
|
||||
|
||||
-- Is (x,y) inside of this hierarchy or any child (aka the draw extents)
|
||||
local x1, y1 = m:transform_point(x, y)
|
||||
local x2, y2, width, height = hierarchy:get_draw_extents()
|
||||
if x1 < x2 or x1 >= x2 + width then
|
||||
return
|
||||
end
|
||||
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
|
||||
|
||||
--- Find a widget by a point.
|
||||
|
@ -134,43 +172,20 @@ end
|
|||
-- @return A sorted table with all widgets that contain the given point. The
|
||||
-- widgets are sorted by relevance.
|
||||
function drawable:find_widgets(x, y)
|
||||
local matches = {}
|
||||
-- Find all widgets that contain the point
|
||||
for k, v in pairs(self._widget_geometries) do
|
||||
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
|
||||
local result = {}
|
||||
if self._widget_hierarchy then
|
||||
find_widgets(self, result, self._widget_hierarchy, x, y)
|
||||
end
|
||||
|
||||
-- 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
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
--- Set the widget that the drawable displays
|
||||
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
|
||||
if widget then
|
||||
widget:weak_connect_signal("widget::updated", self.draw)
|
||||
end
|
||||
|
||||
-- Make sure the widget gets drawn
|
||||
self._need_relayout = true
|
||||
self.draw()
|
||||
end
|
||||
|
||||
|
@ -192,16 +207,16 @@ function drawable:set_bg(c)
|
|||
if self._redraw_on_move ~= redraw_on_move then
|
||||
self._redraw_on_move = redraw_on_move
|
||||
if redraw_on_move then
|
||||
self.drawable:connect_signal("property::x", self.draw)
|
||||
self.drawable:connect_signal("property::y", self.draw)
|
||||
self.drawable:connect_signal("property::x", self._do_complete_repaint)
|
||||
self.drawable:connect_signal("property::y", self._do_complete_repaint)
|
||||
else
|
||||
self.drawable:disconnect_signal("property::x", self.draw)
|
||||
self.drawable:disconnect_signal("property::y", self.draw)
|
||||
self.drawable:disconnect_signal("property::x", self._do_complete_repaint)
|
||||
self.drawable:disconnect_signal("property::y", self._do_complete_repaint)
|
||||
end
|
||||
end
|
||||
|
||||
self.background_color = c
|
||||
self.draw()
|
||||
self._do_complete_repaint()
|
||||
end
|
||||
|
||||
--- Set the foreground of the drawable
|
||||
|
@ -213,7 +228,7 @@ function drawable:set_fg(c)
|
|||
c = color(c)
|
||||
end
|
||||
self.foreground_color = c
|
||||
self.draw()
|
||||
self._do_complete_repaint()
|
||||
end
|
||||
|
||||
local function emit_difference(name, list, skip)
|
||||
|
@ -280,6 +295,9 @@ function drawable.new(d, widget_context_skeleton, drawable_name)
|
|||
local ret = object()
|
||||
ret.drawable = d
|
||||
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)
|
||||
|
||||
for k, v in pairs(drawable) do
|
||||
|
@ -302,8 +320,12 @@ function drawable.new(d, widget_context_skeleton, drawable_name)
|
|||
ret._redraw_pending = true
|
||||
end
|
||||
end
|
||||
drawables[ret.draw] = true
|
||||
d:connect_signal("property::surface", ret.draw)
|
||||
ret._do_complete_repaint = function()
|
||||
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).
|
||||
-- :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)
|
||||
|
||||
-- Initialize internals
|
||||
ret._widget_geometries = {}
|
||||
ret._widgets_under_mouse = {}
|
||||
|
||||
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::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.
|
||||
ret.drawable_name = drawable_name or object.modulename(3)
|
||||
local mt = {}
|
||||
|
@ -344,7 +387,7 @@ function drawable.new(d, widget_context_skeleton, drawable_name)
|
|||
ret = setmetatable(ret, mt)
|
||||
|
||||
-- Make sure the drawable is drawn at least once
|
||||
ret.draw()
|
||||
ret._do_complete_repaint()
|
||||
|
||||
return ret
|
||||
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.widget = require("wibox.widget")
|
||||
wibox.drawable = require("wibox.drawable")
|
||||
wibox.hierarchy = require("wibox.hierarchy")
|
||||
|
||||
--- Set the widget that the wibox displays
|
||||
function wibox:set_widget(widget)
|
||||
|
|
|
@ -10,17 +10,17 @@ local table = table
|
|||
local pairs = pairs
|
||||
local type = type
|
||||
local floor = math.floor
|
||||
local base = require("wibox.layout.base")
|
||||
local widget_base = require("wibox.widget.base")
|
||||
local base = require("wibox.widget.base")
|
||||
|
||||
local align = {}
|
||||
|
||||
--- Draw an align layout.
|
||||
--- Calculate the layout of an align layout.
|
||||
-- @param context The context in which we are drawn.
|
||||
-- @param cr The cairo context to use.
|
||||
-- @param width The available width.
|
||||
-- @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
|
||||
-- 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
|
||||
|
@ -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
|
||||
-- widget
|
||||
if size_second >= size_remains then
|
||||
base.draw_widget(context, cr, self.second, 0, 0, width, height)
|
||||
return
|
||||
return { base.place_widget_at(self.second, 0, 0, width, height) }
|
||||
else
|
||||
-- the middle widget is sized first, the outside widgets are given
|
||||
-- the remaining space if available we will draw later
|
||||
|
@ -84,7 +83,7 @@ function align:draw(context, cr, width, height)
|
|||
w = size_remains
|
||||
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
|
||||
-- size_remains will be <= 0 if first used all the space
|
||||
if self.third and size_remains > 0 then
|
||||
|
@ -110,7 +109,7 @@ function align:draw(context, cr, width, height)
|
|||
end
|
||||
end
|
||||
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
|
||||
-- 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"
|
||||
|
@ -133,37 +132,36 @@ function align:draw(context, cr, width, height)
|
|||
x = floor( (width -w)/2 )
|
||||
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
|
||||
|
||||
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()
|
||||
return result
|
||||
end
|
||||
|
||||
--- Set the layout's first widget. This is the widget that is at the left/top
|
||||
function align:set_first(widget)
|
||||
widget_changed(self, self.first, widget)
|
||||
if self.first == widget then
|
||||
return
|
||||
end
|
||||
self.first = widget
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
--- Set the layout's second widget. This is the centered one.
|
||||
function align:set_second(widget)
|
||||
widget_changed(self, self.second, widget)
|
||||
if self.second == widget then
|
||||
return
|
||||
end
|
||||
self.second = widget
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
--- Set the layout's third widget. This is the widget that is at the right/bottom
|
||||
function align:set_third(widget)
|
||||
widget_changed(self, self.third, widget)
|
||||
if self.third == widget then
|
||||
return
|
||||
end
|
||||
self.third = widget
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
--- 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
|
||||
return used_in_dir, used_in_other
|
||||
end
|
||||
|
||||
--- Set the expand mode which determines how sub widgets expand to take up
|
||||
-- unused space. Options are:
|
||||
-- "inside" - Default option. Size of outside widgets is determined using their
|
||||
|
@ -210,22 +209,19 @@ function align:set_expand(mode)
|
|||
else
|
||||
self._expand = "inside"
|
||||
end
|
||||
self:emit_signal("widget::updated")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
function align:reset()
|
||||
for k, v in pairs({ "first", "second", "third" }) do
|
||||
self[v] = nil
|
||||
end
|
||||
self:emit_signal("widget::updated")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
local function get_layout(dir)
|
||||
local ret = widget_base.make_widget()
|
||||
local ret = base.make_widget()
|
||||
ret.dir = dir
|
||||
ret._emit_updated = function()
|
||||
ret:emit_signal("widget::updated")
|
||||
end
|
||||
|
||||
for k, v in pairs(align) do
|
||||
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 type = type
|
||||
local setmetatable = setmetatable
|
||||
local base = require("wibox.layout.base")
|
||||
local widget_base = require("wibox.widget.base")
|
||||
local base = require("wibox.widget.base")
|
||||
local math = math
|
||||
|
||||
local constraint = { mt = {} }
|
||||
|
||||
--- Draw a constraint layout
|
||||
function constraint:draw(context, cr, width, height)
|
||||
if not self.widget then
|
||||
return
|
||||
--- Layout a constraint layout
|
||||
function constraint:layout(context, width, height)
|
||||
if self.widget then
|
||||
return { base.place_widget_at(self.widget, 0, 0, width, height) }
|
||||
end
|
||||
|
||||
base.draw_widget(context, cr, self.widget, 0, 0, width, height)
|
||||
end
|
||||
|
||||
--- Fit a constraint layout into the given space
|
||||
|
@ -43,15 +40,8 @@ end
|
|||
|
||||
--- Set the widget that this layout adds a constraint on.
|
||||
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:emit_signal("widget::updated")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
--- Set the strategy to use for the constraining. Valid values are 'max',
|
||||
|
@ -74,19 +64,19 @@ function constraint:set_strategy(val)
|
|||
end
|
||||
|
||||
self._strategy = func[val]
|
||||
self:emit_signal("widget::updated")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
--- Set the maximum width to val. nil for no width limit.
|
||||
function constraint:set_width(val)
|
||||
self._width = val
|
||||
self:emit_signal("widget::updated")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
--- Set the maximum height to val. nil for no height limit.
|
||||
function constraint:set_height(val)
|
||||
self._height = val
|
||||
self:emit_signal("widget::updated")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
--- 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
|
||||
|
||||
ret._emit_updated = function()
|
||||
ret:emit_signal("widget::updated")
|
||||
end
|
||||
|
||||
ret:set_strategy(strategy or "max")
|
||||
ret:set_width(width)
|
||||
ret:set_height(height)
|
||||
|
|
|
@ -5,21 +5,19 @@
|
|||
-- @classmod wibox.layout.fixed
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local base = require("wibox.layout.base")
|
||||
local widget_base = require("wibox.widget.base")
|
||||
local base = require("wibox.widget.base")
|
||||
local table = table
|
||||
local pairs = pairs
|
||||
|
||||
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 cr The cairo context to use.
|
||||
-- @param width The available width.
|
||||
-- @param height The available height.
|
||||
-- @return The total space needed by the layout.
|
||||
function fixed:draw(context, cr, width, height)
|
||||
local pos,spacing = 0,self._spacing or 0
|
||||
function fixed:layout(context, width, height)
|
||||
local result = {}
|
||||
local pos,spacing = 0, self._spacing
|
||||
|
||||
for k, v in pairs(self.widgets) do
|
||||
local x, y, w, h, _
|
||||
|
@ -46,16 +44,16 @@ function fixed:draw(context, cr, width, height)
|
|||
(self.dir ~= "y" and pos-spacing > width) then
|
||||
break
|
||||
end
|
||||
base.draw_widget(context, cr, v, x, y, w, h)
|
||||
table.insert(result, base.place_widget_at(v, x, y, w, h))
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
--- Add a widget to the given fixed layout
|
||||
function fixed:add(widget)
|
||||
widget_base.check_widget(widget)
|
||||
base.check_widget(widget)
|
||||
table.insert(self.widgets, widget)
|
||||
widget:weak_connect_signal("widget::updated", self._emit_updated)
|
||||
self._emit_updated()
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
--- Fit the fixed layout into the given space
|
||||
|
@ -91,7 +89,7 @@ function fixed:fit(context, orig_width, orig_height)
|
|||
end
|
||||
end
|
||||
|
||||
local spacing = ((self._spacing or 0)*(#self.widgets-1))
|
||||
local spacing = self._spacing * (#self.widgets-1)
|
||||
|
||||
if self.dir == "y" then
|
||||
return used_max, used_in_dir + spacing
|
||||
|
@ -101,23 +99,22 @@ end
|
|||
|
||||
--- Reset a fixed layout. This removes all widgets from the layout.
|
||||
function fixed:reset()
|
||||
for k, v in pairs(self.widgets) do
|
||||
v:disconnect_signal("widget::updated", self._emit_updated)
|
||||
end
|
||||
self.widgets = {}
|
||||
self:emit_signal("widget::updated")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
--- Set the layout's fill_space property. If this property is true, the last
|
||||
-- widget will get all the space that is left. If this is false, the last widget
|
||||
-- won't be handled specially and there can be space left unused.
|
||||
function fixed:fill_space(val)
|
||||
self._fill_space = val
|
||||
self:emit_signal("widget::updated")
|
||||
if self._fill_space ~= val then
|
||||
self._fill_space = not not val
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
end
|
||||
|
||||
local function get_layout(dir)
|
||||
local ret = widget_base.make_widget()
|
||||
local ret = base.make_widget()
|
||||
|
||||
for k, v in pairs(fixed) do
|
||||
if type(v) == "function" then
|
||||
|
@ -127,9 +124,8 @@ local function get_layout(dir)
|
|||
|
||||
ret.dir = dir
|
||||
ret.widgets = {}
|
||||
ret._emit_updated = function()
|
||||
ret:emit_signal("widget::updated")
|
||||
end
|
||||
ret:set_spacing(0)
|
||||
ret:fill_space(false)
|
||||
|
||||
return ret
|
||||
end
|
||||
|
@ -151,8 +147,10 @@ end
|
|||
--- Add spacing between each layout widgets
|
||||
-- @param spacing Spacing between widgets.
|
||||
function fixed:set_spacing(spacing)
|
||||
self._spacing = spacing
|
||||
self:emit_signal("widget::updated")
|
||||
if self._spacing ~= spacing then
|
||||
self._spacing = spacing
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
end
|
||||
|
||||
return fixed
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
-- @classmod wibox.layout.flex
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local base = require("wibox.layout.base")
|
||||
local widget_base = require("wibox.widget.base")
|
||||
local base = require("wibox.widget.base")
|
||||
local table = table
|
||||
local pairs = pairs
|
||||
local floor = math.floor
|
||||
|
@ -14,14 +13,17 @@ local round = require("awful.util").round
|
|||
|
||||
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 cr The cairo context to use.
|
||||
-- @param width The available width.
|
||||
-- @param height The available height.
|
||||
-- @return The total space needed by the layout.
|
||||
function flex:draw(context, cr, width, height)
|
||||
local pos,spacing = 0,self._spacing or 0
|
||||
function flex:layout(context, width, height)
|
||||
local result = {}
|
||||
local pos,spacing = 0, self._spacing
|
||||
local num = #self.widgets
|
||||
local total_spacing = (spacing*(num-1))
|
||||
|
||||
|
@ -45,7 +47,7 @@ function flex:draw(context, cr, width, height)
|
|||
x, y = round(pos), 0
|
||||
w, h = floor(space_per_item), height
|
||||
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
|
||||
|
||||
|
@ -54,21 +56,8 @@ function flex:draw(context, cr, width, height)
|
|||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function flex:add(widget)
|
||||
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")
|
||||
return result
|
||||
end
|
||||
|
||||
--- 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)
|
||||
end
|
||||
|
||||
local spacing = ((self._spacing or 0)*(#self.widgets-1))
|
||||
local spacing = self._spacing * (#self.widgets-1)
|
||||
|
||||
if self.dir == "y" then
|
||||
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
|
||||
end
|
||||
|
||||
function flex:reset()
|
||||
for k, v in pairs(self.widgets) do
|
||||
v:disconnect_signal("widget::updated", self._emit_updated)
|
||||
function flex:add(widget)
|
||||
base.check_widget(widget)
|
||||
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
|
||||
|
||||
--- 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._max_widget_size = nil
|
||||
self:emit_signal("widget::updated")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
local function get_layout(dir)
|
||||
local ret = widget_base.make_widget()
|
||||
local ret = base.make_widget()
|
||||
|
||||
for k, v in pairs(flex) do
|
||||
if type(v) == "function" then
|
||||
|
@ -127,9 +138,7 @@ local function get_layout(dir)
|
|||
|
||||
ret.dir = dir
|
||||
ret.widgets = {}
|
||||
ret._emit_updated = function()
|
||||
ret:emit_signal("widget::updated")
|
||||
end
|
||||
ret:set_spacing(0)
|
||||
|
||||
return ret
|
||||
end
|
||||
|
@ -146,13 +155,6 @@ function flex.vertical()
|
|||
return get_layout("y")
|
||||
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
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
return
|
||||
{
|
||||
base = require("wibox.layout.base");
|
||||
fixed = require("wibox.layout.fixed");
|
||||
align = require("wibox.layout.align");
|
||||
flex = require("wibox.layout.flex");
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
local pairs = pairs
|
||||
local type = type
|
||||
local setmetatable = setmetatable
|
||||
local base = require("wibox.layout.base")
|
||||
local widget_base = require("wibox.widget.base")
|
||||
local base = require("wibox.widget.base")
|
||||
local gcolor = require("gears.color")
|
||||
local cairo = require("lgi").cairo
|
||||
|
||||
|
@ -28,16 +27,24 @@ function margin:draw(context, cr, width, height)
|
|||
end
|
||||
|
||||
if color then
|
||||
cr:save()
|
||||
cr:set_source(color)
|
||||
cr:rectangle(0, 0, width, height)
|
||||
cr:rectangle(x, y, width - x - w, height - y - h)
|
||||
cr:set_fill_rule(cairo.FillRule.EVEN_ODD)
|
||||
cr:fill()
|
||||
cr:restore()
|
||||
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
|
||||
|
||||
--- Fit a margin layout into the given space
|
||||
|
@ -53,15 +60,11 @@ end
|
|||
|
||||
--- Set the widget that this layout adds a margin on.
|
||||
function margin: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)
|
||||
base.check_widget(widget)
|
||||
end
|
||||
self.widget = widget
|
||||
self._emit_updated()
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
--- Set all the margins to val.
|
||||
|
@ -70,13 +73,13 @@ function margin:set_margins(val)
|
|||
self.right = val
|
||||
self.top = val
|
||||
self.bottom = val
|
||||
self:emit_signal("widget::updated")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
--- Set the margins color to color
|
||||
function margin:set_color(color)
|
||||
self.color = color and gcolor(color)
|
||||
self._emit_updated()
|
||||
self:emit_signal("widget::redraw_needed")
|
||||
end
|
||||
|
||||
--- 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
|
||||
margin["set_" .. v] = function(layout, val)
|
||||
layout[v] = val
|
||||
layout:emit_signal("widget::updated")
|
||||
layout:emit_signal("widget::layout_changed")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -127,7 +130,7 @@ end
|
|||
-- @param[opt] bottom A margin to use on the bottom side of the widget.
|
||||
-- @param[opt] color A color for the margins.
|
||||
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
|
||||
if type(v) == "function" then
|
||||
|
@ -135,10 +138,6 @@ local function new(widget, left, right, top, bottom, color)
|
|||
end
|
||||
end
|
||||
|
||||
ret._emit_updated = function()
|
||||
ret:emit_signal("widget::updated")
|
||||
end
|
||||
|
||||
ret:set_left(left or 0)
|
||||
ret:set_right(right or 0)
|
||||
ret:set_top(top or 0)
|
||||
|
|
|
@ -10,21 +10,20 @@ local error = error
|
|||
local pairs = pairs
|
||||
local ipairs = ipairs
|
||||
local setmetatable = setmetatable
|
||||
local base = require("wibox.layout.base")
|
||||
local widget_base = require("wibox.widget.base")
|
||||
local base = require("wibox.widget.base")
|
||||
local Matrix = require("lgi").cairo.Matrix
|
||||
|
||||
local mirror = { mt = {} }
|
||||
|
||||
--- Draw this layout
|
||||
function mirror:draw(context, cr, width, height)
|
||||
--- Layout this layout
|
||||
function mirror:layout(context, cr, width, height)
|
||||
if not self.widget then return end
|
||||
if not self.horizontal and not self.vertical then
|
||||
base.draw_widget(wibox, cr, self.widget, 0, 0, width, height)
|
||||
return -- nothing changed
|
||||
return
|
||||
end
|
||||
|
||||
cr:save()
|
||||
|
||||
local m = Matrix.create_identity()
|
||||
local t = { x = 0, y = 0 } -- translation
|
||||
local s = { x = 1, y = 1 } -- scale
|
||||
if self.horizontal then
|
||||
|
@ -35,13 +34,10 @@ function mirror:draw(context, cr, width, height)
|
|||
t.x = width
|
||||
s.x = -1
|
||||
end
|
||||
cr:translate(t.x, t.y)
|
||||
cr:scale(s.x, s.y)
|
||||
m:translate(t.x, t.y)
|
||||
m:scale(s.x, s.y)
|
||||
|
||||
self.widget:draw(context, cr, width, height)
|
||||
|
||||
-- Undo the scale and translation from above.
|
||||
cr:restore()
|
||||
return base.place_widget_via_matrix(widget, m, width, height)
|
||||
end
|
||||
|
||||
--- Fit this layout into the given area
|
||||
|
@ -55,15 +51,11 @@ end
|
|||
--- Set the widget that this layout mirrors.
|
||||
-- @param widget The widget to mirror
|
||||
function mirror: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)
|
||||
base.check_widget(widget)
|
||||
end
|
||||
self.widget = widget
|
||||
self._emit_updated()
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
--- 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]
|
||||
end
|
||||
end
|
||||
self._emit_updated()
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
--- Get the reflection of this mirror layout.
|
||||
|
@ -101,7 +93,7 @@ end
|
|||
-- @param[opt] widget The widget to display.
|
||||
-- @param[opt] reflection A table describing the reflection to apply.
|
||||
local function new(widget, reflection)
|
||||
local ret = widget_base.make_widget()
|
||||
local ret = base.make_widget()
|
||||
ret.horizontal = false
|
||||
ret.vertical = false
|
||||
|
||||
|
@ -111,10 +103,6 @@ local function new(widget, reflection)
|
|||
end
|
||||
end
|
||||
|
||||
ret._emit_updated = function()
|
||||
ret:emit_signal("widget::updated")
|
||||
end
|
||||
|
||||
ret:set_widget(widget)
|
||||
ret:set_reflection(reflection or {})
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@ local pi = math.pi
|
|||
local type = type
|
||||
local setmetatable = setmetatable
|
||||
local tostring = tostring
|
||||
local base = require("wibox.layout.base")
|
||||
local widget_base = require("wibox.widget.base")
|
||||
local base = require("wibox.widget.base")
|
||||
local Matrix = require("lgi").cairo.Matrix
|
||||
|
||||
local rotate = { mt = {} }
|
||||
|
||||
|
@ -24,28 +24,29 @@ local function transform(layout, width, height)
|
|||
return width, height
|
||||
end
|
||||
|
||||
--- Draw this layout
|
||||
function rotate:draw(context, cr, width, height)
|
||||
--- Layout this layout
|
||||
function rotate:layout(context, width, height)
|
||||
if not self.widget or not self.widget.visible then
|
||||
return
|
||||
end
|
||||
|
||||
local dir = self:get_direction()
|
||||
|
||||
local m = Matrix.create_identity()
|
||||
if dir == "west" then
|
||||
cr:rotate(pi / 2)
|
||||
cr:translate(0, -width)
|
||||
m:rotate(pi / 2)
|
||||
m:translate(0, -width)
|
||||
elseif dir == "south" then
|
||||
cr:rotate(pi)
|
||||
cr:translate(-width, -height)
|
||||
m:rotate(pi)
|
||||
m:translate(-width, -height)
|
||||
elseif dir == "east" then
|
||||
cr:rotate(3 * pi / 2)
|
||||
cr:translate(-height, 0)
|
||||
m:rotate(3 * pi / 2)
|
||||
m:translate(-height, 0)
|
||||
end
|
||||
|
||||
-- Since we rotated, we might have to swap width and height.
|
||||
-- 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
|
||||
|
||||
--- Fit this layout into the given area
|
||||
|
@ -58,15 +59,11 @@ end
|
|||
|
||||
--- Set the widget that this layout rotates.
|
||||
function rotate: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)
|
||||
base.check_widget(widget)
|
||||
end
|
||||
self.widget = widget
|
||||
self._emit_updated()
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
--- Reset this layout. The widget will be removed and the rotation reset.
|
||||
|
@ -90,7 +87,7 @@ function rotate:set_direction(dir)
|
|||
end
|
||||
|
||||
self.direction = dir
|
||||
self._emit_updated()
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
--- Get the direction of this rotating layout
|
||||
|
@ -104,7 +101,7 @@ end
|
|||
-- @param[opt] widget The widget to display.
|
||||
-- @param[opt] dir The direction to rotate to.
|
||||
local function new(widget, dir)
|
||||
local ret = widget_base.make_widget()
|
||||
local ret = base.make_widget()
|
||||
|
||||
for k, v in pairs(rotate) do
|
||||
if type(v) == "function" then
|
||||
|
@ -112,10 +109,6 @@ local function new(widget, dir)
|
|||
end
|
||||
end
|
||||
|
||||
ret._emit_updated = function()
|
||||
ret:emit_signal("widget::updated")
|
||||
end
|
||||
|
||||
ret:set_widget(widget)
|
||||
ret:set_direction(dir or "north")
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
local base = require("wibox.widget.base")
|
||||
local color = require("gears.color")
|
||||
local layout_base = require("wibox.layout.base")
|
||||
local surface = require("gears.surface")
|
||||
local cairo = require("lgi").cairo
|
||||
local setmetatable = setmetatable
|
||||
|
@ -22,8 +21,6 @@ function background:draw(context, cr, width, height)
|
|||
return
|
||||
end
|
||||
|
||||
cr:save()
|
||||
|
||||
if self.background then
|
||||
cr:set_source(self.background)
|
||||
cr:paint()
|
||||
|
@ -33,16 +30,19 @@ function background:draw(context, cr, width, height)
|
|||
cr:set_source(pattern)
|
||||
cr:paint()
|
||||
end
|
||||
end
|
||||
|
||||
cr:restore()
|
||||
|
||||
--- Prepare drawing the children of this widget
|
||||
function background:before_draw_children(wibox, cr, width, height)
|
||||
if self.foreground then
|
||||
cr:save()
|
||||
cr:set_source(self.foreground)
|
||||
end
|
||||
layout_base.draw_widget(context, cr, self.widget, 0, 0, width, height)
|
||||
if self.foreground then
|
||||
cr:restore()
|
||||
end
|
||||
|
||||
--- 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
|
||||
|
||||
|
@ -52,20 +52,16 @@ function background:fit(context, width, height)
|
|||
return 0, 0
|
||||
end
|
||||
|
||||
return layout_base.fit_widget(context, self.widget, width, height)
|
||||
return base.fit_widget(context, self.widget, width, height)
|
||||
end
|
||||
|
||||
--- Set the widget that is drawn on top of the background
|
||||
function background:set_widget(widget)
|
||||
if self.widget then
|
||||
self.widget:disconnect_signal("widget::updated", self._emit_updated)
|
||||
end
|
||||
if widget then
|
||||
base.check_widget(widget)
|
||||
widget:weak_connect_signal("widget::updated", self._emit_updated)
|
||||
end
|
||||
self.widget = widget
|
||||
self._emit_updated()
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
--- Set the background to use
|
||||
|
@ -75,7 +71,7 @@ function background:set_bg(bg)
|
|||
else
|
||||
self.background = nil
|
||||
end
|
||||
self._emit_updated()
|
||||
self:emit_signal("widget::redraw_needed")
|
||||
end
|
||||
|
||||
--- Set the foreground to use
|
||||
|
@ -85,13 +81,13 @@ function background:set_fg(fg)
|
|||
else
|
||||
self.foreground = nil
|
||||
end
|
||||
self._emit_updated()
|
||||
self:emit_signal("widget::redraw_needed")
|
||||
end
|
||||
|
||||
--- Set the background image to use
|
||||
function background:set_bgimage(image)
|
||||
self.bgimage = surface.load(image)
|
||||
self._emit_updated()
|
||||
self:emit_signal("widget::redraw_needed")
|
||||
end
|
||||
|
||||
--- Returns a new background layout. A background layout applies a background
|
||||
|
@ -107,10 +103,6 @@ local function new(widget, bg)
|
|||
end
|
||||
end
|
||||
|
||||
ret._emit_updated = function()
|
||||
ret:emit_signal("widget::updated")
|
||||
end
|
||||
|
||||
ret:set_widget(widget)
|
||||
ret:set_bg(bg)
|
||||
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
-- @author Uli Schlachter
|
||||
-- @copyright 2010 Uli Schlachter
|
||||
-- @release @AWESOME_VERSION@
|
||||
-- @classmod wibox.widget.base
|
||||
-- @module wibox.widget.base
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local debug = require("gears.debug")
|
||||
local object = require("gears.object")
|
||||
local cache = require("gears.cache")
|
||||
local matrix = require("gears.matrix")
|
||||
local Matrix = require("lgi").cairo.Matrix
|
||||
local setmetatable = setmetatable
|
||||
local pairs = pairs
|
||||
local type = type
|
||||
|
@ -16,13 +17,144 @@ local table = table
|
|||
|
||||
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
|
||||
-- bounds if no rotations by non-multiples of 90° are used.
|
||||
function base.rect_to_device_geometry(cr, x, y, width, height)
|
||||
return matrix.transform_rectangle(cr.matrix, x, y, width, height)
|
||||
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)
|
||||
if _buttons then
|
||||
self.widget_buttons = _buttons
|
||||
|
@ -31,7 +163,8 @@ function base:buttons(_buttons)
|
|||
return self.widget_buttons
|
||||
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)
|
||||
local function is_any(mod)
|
||||
return #mod == 1 and mod[1] == "Any"
|
||||
|
@ -68,23 +201,174 @@ function base.handle_button(event, widget, x, y, button, modifiers, geometry)
|
|||
end
|
||||
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.
|
||||
-- @param proxy If this is set, the returned widget will be a proxy for this
|
||||
-- widget. It will be equivalent to this widget.
|
||||
-- @tparam[opt] string widget_name Name of the widget. If not set, it will be
|
||||
-- set automatically via `gears.object.modulename`.
|
||||
--- Create widget placement information. This should be used for a widget's
|
||||
-- `:layout()` callback.
|
||||
-- @param widget The widget that should be placed.
|
||||
-- @param mat A cairo matrix transforming from the parent widget's coordinate
|
||||
-- system. For example, use cairo.Matrix.create_translate(1, 2) to draw a
|
||||
-- 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)
|
||||
local ret = object()
|
||||
|
||||
-- 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!
|
||||
ret:add_signal("button::press")
|
||||
ret:add_signal("button::release")
|
||||
ret:add_signal("mouse::enter")
|
||||
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
|
||||
ret.widget_buttons = {}
|
||||
ret.buttons = base.buttons
|
||||
|
@ -98,20 +382,24 @@ function base.make_widget(proxy, widget_name)
|
|||
end)
|
||||
|
||||
if proxy then
|
||||
ret.draw = function(_, ...) return proxy:draw(...) end
|
||||
ret.fit = function(_, ...) return proxy:fit(...) end
|
||||
proxy:connect_signal("widget::updated", function()
|
||||
ret:emit_signal("widget::updated")
|
||||
ret.fit = function(_, context, width, height)
|
||||
return base.fit_widget(context, proxy, width, height)
|
||||
end
|
||||
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
|
||||
|
||||
-- Add a geometry for base.fit_widget() that is cleared when necessary
|
||||
local function cb(...)
|
||||
return ret:fit(...)
|
||||
end
|
||||
ret._fit_geometry_cache = cache.new(cb)
|
||||
ret:connect_signal("widget::updated", function()
|
||||
ret._fit_geometry_cache = cache.new(cb)
|
||||
-- Set up caches
|
||||
clear_caches(ret)
|
||||
ret:connect_signal("widget::layout_changed", function()
|
||||
clear_caches(ret)
|
||||
end)
|
||||
|
||||
-- Add visible property and setter.
|
||||
|
@ -119,7 +407,9 @@ function base.make_widget(proxy, widget_name)
|
|||
function ret:set_visible(b)
|
||||
if b ~= self.visible then
|
||||
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
|
||||
|
||||
|
@ -128,7 +418,7 @@ function base.make_widget(proxy, widget_name)
|
|||
function ret:set_opacity(b)
|
||||
if b ~= self.opacity then
|
||||
self.opacity = b
|
||||
self:emit_signal("widget::updated")
|
||||
self:emit_signal("widget::redraw")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -144,23 +434,16 @@ end
|
|||
|
||||
--- Generate an empty widget which takes no space and displays nothing
|
||||
function base.empty_widget()
|
||||
local widget = base.make_widget()
|
||||
widget.draw = function() end
|
||||
widget.fit = function() return 0, 0 end
|
||||
return widget
|
||||
return base.make_widget()
|
||||
end
|
||||
|
||||
--- Do some sanity checking on widget. This function raises a lua error if
|
||||
-- widget is not a valid widget.
|
||||
function base.check_widget(widget)
|
||||
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")
|
||||
end
|
||||
|
||||
local width, height = widget:fit({}, 0, 0)
|
||||
debug.assert(type(width) == "number")
|
||||
debug.assert(type(height) == "number")
|
||||
end
|
||||
|
||||
return base
|
||||
|
|
|
@ -20,8 +20,6 @@ function imagebox:draw(context, cr, width, height)
|
|||
if not self._image then return end
|
||||
if width == 0 or height == 0 then return end
|
||||
|
||||
cr:save()
|
||||
|
||||
if not self.resize_forbidden then
|
||||
-- Let's scale the image so that it fits into (width, height)
|
||||
local w = self._image:get_width()
|
||||
|
@ -34,8 +32,6 @@ function imagebox:draw(context, cr, width, height)
|
|||
end
|
||||
cr:set_source_surface(self._image, 0, 0)
|
||||
cr:paint()
|
||||
|
||||
cr:restore()
|
||||
end
|
||||
|
||||
--- Fit the imagebox into the given geometry
|
||||
|
@ -99,9 +95,14 @@ function imagebox:set_image(image)
|
|||
end
|
||||
end
|
||||
|
||||
if self._image == image then
|
||||
return
|
||||
end
|
||||
|
||||
self._image = image
|
||||
|
||||
self:emit_signal("widget::updated")
|
||||
self:emit_signal("widget::redraw_needed")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
return true
|
||||
end
|
||||
|
||||
|
@ -110,7 +111,8 @@ end
|
|||
-- to fit into the available space.
|
||||
function imagebox:set_resize(allowed)
|
||||
self.resize_forbidden = not allowed
|
||||
self:emit_signal("widget::updated")
|
||||
self:emit_signal("widget::redraw_needed")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
--- Returns a new imagebox
|
||||
|
|
|
@ -79,7 +79,7 @@ local function new(revers)
|
|||
end
|
||||
|
||||
capi.awesome.connect_signal("systray::update", function()
|
||||
ret:emit_signal("widget::updated")
|
||||
ret:emit_signal("widget::layout_changed")
|
||||
end)
|
||||
|
||||
return ret
|
||||
|
|
|
@ -70,7 +70,8 @@ function textbox:set_markup(text)
|
|||
self._markup = text
|
||||
self._layout.text = parsed
|
||||
self._layout.attributes = attr
|
||||
self:emit_signal("widget::updated")
|
||||
self:emit_signal("widget::redraw_needed")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
--- Set a textbox' text.
|
||||
|
@ -82,7 +83,8 @@ function textbox:set_text(text)
|
|||
self._markup = nil
|
||||
self._layout.text = text
|
||||
self._layout.attributes = nil
|
||||
self:emit_signal("widget::updated")
|
||||
self:emit_signal("widget::redraw_needed")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
--- Set a textbox' ellipsize mode.
|
||||
|
@ -94,7 +96,8 @@ function textbox:set_ellipsize(mode)
|
|||
return
|
||||
end
|
||||
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
|
||||
|
||||
|
@ -107,7 +110,8 @@ function textbox:set_wrap(mode)
|
|||
return
|
||||
end
|
||||
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
|
||||
|
||||
|
@ -120,7 +124,8 @@ function textbox:set_valign(mode)
|
|||
return
|
||||
end
|
||||
self._valign = mode
|
||||
self:emit_signal("widget::updated")
|
||||
self:emit_signal("widget::redraw_needed")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -133,7 +138,8 @@ function textbox:set_align(mode)
|
|||
return
|
||||
end
|
||||
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
|
||||
|
||||
|
@ -141,6 +147,8 @@ end
|
|||
-- @param font The font description as string
|
||||
function textbox:set_font(font)
|
||||
self._layout:set_font_description(beautiful.get_font(font))
|
||||
self:emit_signal("widget::redraw_needed")
|
||||
self:emit_signal("widget::layout_changed")
|
||||
end
|
||||
|
||||
-- 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 utils = require("wibox.test_utils")
|
||||
local p = require("wibox.widget.base").place_widget_at
|
||||
|
||||
describe("wibox.layout.flex", function()
|
||||
before_each(utils.stub_draw_widget)
|
||||
after_each(utils.revert_draw_widget)
|
||||
|
||||
describe("wibox.layout.align", function()
|
||||
describe("expand=none", function()
|
||||
local layout
|
||||
before_each(function()
|
||||
|
@ -21,9 +19,8 @@ describe("wibox.layout.flex", function()
|
|||
assert.widget_fit(layout, { 10, 10 }, { 0, 0 })
|
||||
end)
|
||||
|
||||
it("empty layout draw", function()
|
||||
layout:draw(nil, nil, 0, 0)
|
||||
utils.check_widgets_drawn({})
|
||||
it("empty layout layout", function()
|
||||
assert.is.same({}, layout:layout(0, 0))
|
||||
end)
|
||||
|
||||
describe("with widgets", function()
|
||||
|
@ -44,12 +41,11 @@ describe("wibox.layout.flex", function()
|
|||
assert.widget_fit(layout, { 100, 100 }, { 15, 35 })
|
||||
end)
|
||||
|
||||
it("draw", function()
|
||||
layout:draw("wibox", "cr", 100, 100)
|
||||
utils.check_widgets_drawn({
|
||||
{ first, 0, 0, 100, 10 },
|
||||
{ third, 0, 90, 100, 10 },
|
||||
{ second, 0, 42, 100, 15 },
|
||||
it("layout", function()
|
||||
assert.widget_layout(layout, { 100, 100 }, {
|
||||
p(first, 0, 0, 100, 10),
|
||||
p(third, 0, 90, 100, 10),
|
||||
p(second, 0, 42, 100, 15),
|
||||
})
|
||||
end)
|
||||
end)
|
||||
|
@ -59,12 +55,11 @@ describe("wibox.layout.flex", function()
|
|||
assert.widget_fit(layout, { 5, 100 }, { 5, 35 })
|
||||
end)
|
||||
|
||||
it("draw", function()
|
||||
layout:draw("wibox", "cr", 5, 100)
|
||||
utils.check_widgets_drawn({
|
||||
{ first, 0, 0, 5, 10 },
|
||||
{ third, 0, 90, 5, 10 },
|
||||
{ second, 0, 42, 5, 15 },
|
||||
it("layout", function()
|
||||
assert.widget_layout(layout, { 5, 100 }, {
|
||||
p(first, 0, 0, 5, 10),
|
||||
p(third, 0, 90, 5, 10),
|
||||
p(second, 0, 42, 5, 15),
|
||||
})
|
||||
end)
|
||||
end)
|
||||
|
@ -74,12 +69,11 @@ describe("wibox.layout.flex", function()
|
|||
assert.widget_fit(layout, { 100, 20 }, { 15, 20 })
|
||||
end)
|
||||
|
||||
it("draw", function()
|
||||
layout:draw("wibox", "cr", 100, 20)
|
||||
utils.check_widgets_drawn({
|
||||
{ first, 0, 0, 100, 2 },
|
||||
{ third, 0, 18, 100, 2 },
|
||||
{ second, 0, 2, 100, 15 },
|
||||
it("layout", function()
|
||||
assert.widget_layout(layout, { 100, 20 }, {
|
||||
p(first, 0, 0, 100, 2),
|
||||
p(third, 0, 18, 100, 2),
|
||||
p(second, 0, 2, 100, 15),
|
||||
})
|
||||
end)
|
||||
end)
|
||||
|
@ -97,9 +91,8 @@ describe("wibox.layout.flex", function()
|
|||
assert.widget_fit(layout, { 10, 10 }, { 0, 0 })
|
||||
end)
|
||||
|
||||
it("empty layout draw", function()
|
||||
layout:draw(nil, nil, 0, 0)
|
||||
utils.check_widgets_drawn({})
|
||||
it("empty layout layout", function()
|
||||
assert.widget_layout(layout, { 0, 0 }, {})
|
||||
end)
|
||||
|
||||
describe("with widgets", function()
|
||||
|
@ -120,12 +113,11 @@ describe("wibox.layout.flex", function()
|
|||
assert.widget_fit(layout, { 100, 100 }, { 15, 35 })
|
||||
end)
|
||||
|
||||
it("draw", function()
|
||||
layout:draw("wibox", "cr", 100, 100)
|
||||
utils.check_widgets_drawn({
|
||||
{ first, 0, 0, 100, 42 },
|
||||
{ third, 0, 58, 100, 42 },
|
||||
{ second, 0, 42, 100, 15 },
|
||||
it("layout", function()
|
||||
assert.widget_layout(layout, { 100, 100 }, {
|
||||
p(first, 0, 0, 100, 42),
|
||||
p(third, 0, 58, 100, 42),
|
||||
p(second, 0, 42, 100, 15),
|
||||
})
|
||||
end)
|
||||
end)
|
||||
|
@ -135,12 +127,11 @@ describe("wibox.layout.flex", function()
|
|||
assert.widget_fit(layout, { 5, 100 }, { 5, 35 })
|
||||
end)
|
||||
|
||||
it("draw", function()
|
||||
layout:draw("wibox", "cr", 5, 100)
|
||||
utils.check_widgets_drawn({
|
||||
{ first, 0, 0, 5, 42 },
|
||||
{ third, 0, 58, 5, 42 },
|
||||
{ second, 0, 42, 5, 15 },
|
||||
it("layout", function()
|
||||
assert.widget_layout(layout, { 5, 100 }, {
|
||||
p(first, 0, 0, 5, 42),
|
||||
p(third, 0, 58, 5, 42),
|
||||
p(second, 0, 42, 5, 15),
|
||||
})
|
||||
end)
|
||||
end)
|
||||
|
@ -150,12 +141,11 @@ describe("wibox.layout.flex", function()
|
|||
assert.widget_fit(layout, { 100, 20 }, { 15, 20 })
|
||||
end)
|
||||
|
||||
it("draw", function()
|
||||
layout:draw("wibox", "cr", 100, 20)
|
||||
utils.check_widgets_drawn({
|
||||
{ first, 0, 0, 100, 2 },
|
||||
{ third, 0, 18, 100, 2 },
|
||||
{ second, 0, 2, 100, 15 },
|
||||
it("layout", function()
|
||||
assert.widget_layout(layout, { 100, 20 }, {
|
||||
p(first, 0, 0, 100, 2),
|
||||
p(third, 0, 18, 100, 2),
|
||||
p(second, 0, 2, 100, 15),
|
||||
})
|
||||
end)
|
||||
end)
|
||||
|
@ -173,9 +163,8 @@ describe("wibox.layout.flex", function()
|
|||
assert.widget_fit(layout, { 10, 10 }, { 0, 0 })
|
||||
end)
|
||||
|
||||
it("empty layout draw", function()
|
||||
layout:draw(nil, nil, 0, 0)
|
||||
utils.check_widgets_drawn({})
|
||||
it("empty layout layout", function()
|
||||
assert.widget_layout(layout, { 0, 0 }, {})
|
||||
end)
|
||||
|
||||
describe("with widgets", function()
|
||||
|
@ -196,12 +185,11 @@ describe("wibox.layout.flex", function()
|
|||
assert.widget_fit(layout, { 100, 100 }, { 15, 35 })
|
||||
end)
|
||||
|
||||
it("draw", function()
|
||||
layout:draw("wibox", "cr", 100, 100)
|
||||
utils.check_widgets_drawn({
|
||||
{ first, 0, 0, 100, 10 },
|
||||
{ third, 0, 90, 100, 10 },
|
||||
{ second, 0, 10, 100, 80 },
|
||||
it("layout", function()
|
||||
assert.widget_layout(layout, { 100, 100 }, {
|
||||
p(first, 0, 0, 100, 10),
|
||||
p(third, 0, 90, 100, 10),
|
||||
p(second, 0, 10, 100, 80),
|
||||
})
|
||||
end)
|
||||
end)
|
||||
|
@ -211,12 +199,11 @@ describe("wibox.layout.flex", function()
|
|||
assert.widget_fit(layout, { 5, 100 }, { 5, 35 })
|
||||
end)
|
||||
|
||||
it("draw", function()
|
||||
layout:draw("wibox", "cr", 5, 100)
|
||||
utils.check_widgets_drawn({
|
||||
{ first, 0, 0, 5, 10 },
|
||||
{ third, 0, 90, 5, 10 },
|
||||
{ second, 0, 10, 5, 80 },
|
||||
it("layout", function()
|
||||
assert.widget_layout(layout, { 5, 100 }, {
|
||||
p(first, 0, 0, 5, 10),
|
||||
p(third, 0, 90, 5, 10),
|
||||
p(second, 0, 10, 5, 80),
|
||||
})
|
||||
end)
|
||||
end)
|
||||
|
@ -226,17 +213,59 @@ describe("wibox.layout.flex", function()
|
|||
assert.widget_fit(layout, { 100, 20 }, { 15, 20 })
|
||||
end)
|
||||
|
||||
it("draw", function()
|
||||
layout:draw("wibox", "cr", 100, 20)
|
||||
--- XXX: Shouldn't this also draw part of the second widget?
|
||||
utils.check_widgets_drawn({
|
||||
{ first, 0, 0, 100, 10 },
|
||||
{ third, 0, 10, 100, 10 },
|
||||
it("layout", function()
|
||||
assert.widget_layout(layout, { 100, 20 }, {
|
||||
p(first, 0, 0, 100, 10),
|
||||
p(third, 0, 10, 100, 10),
|
||||
})
|
||||
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)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
---------------------------------------------------------------------------
|
||||
|
||||
local fixed = require("wibox.layout.fixed")
|
||||
local base = require("wibox.widget.base")
|
||||
local utils = require("wibox.test_utils")
|
||||
local p = require("wibox.widget.base").place_widget_at
|
||||
|
||||
describe("wibox.layout.fixed", function()
|
||||
local layout
|
||||
|
@ -12,16 +14,12 @@ describe("wibox.layout.fixed", function()
|
|||
layout = fixed.vertical()
|
||||
end)
|
||||
|
||||
before_each(utils.stub_draw_widget)
|
||||
after_each(utils.revert_draw_widget)
|
||||
|
||||
it("empty layout fit", function()
|
||||
assert.widget_fit(layout, { 10, 10 }, { 0, 0 })
|
||||
end)
|
||||
|
||||
it("empty layout draw", function()
|
||||
layout:draw(nil, nil, 0, 0)
|
||||
utils.check_widgets_drawn({})
|
||||
it("empty layout layout", function()
|
||||
assert.widget_layout(layout, { 0, 0 }, {})
|
||||
end)
|
||||
|
||||
describe("with widgets", function()
|
||||
|
@ -42,12 +40,11 @@ describe("wibox.layout.fixed", function()
|
|||
assert.widget_fit(layout, { 100, 100 }, { 15, 35 })
|
||||
end)
|
||||
|
||||
it("draw", function()
|
||||
layout:draw("wibox", "cr", 100, 100)
|
||||
utils.check_widgets_drawn({
|
||||
{ first, 0, 0, 100, 10 },
|
||||
{ second, 0, 10, 100, 15 },
|
||||
{ third, 0, 25, 100, 10 },
|
||||
it("layout", function()
|
||||
assert.widget_layout(layout, { 100, 100 }, {
|
||||
p(first, 0, 0, 100, 10),
|
||||
p(second, 0, 10, 100, 15),
|
||||
p(third, 0, 25, 100, 10),
|
||||
})
|
||||
end)
|
||||
end)
|
||||
|
@ -57,32 +54,82 @@ describe("wibox.layout.fixed", function()
|
|||
assert.widget_fit(layout, { 5, 100 }, { 5, 35 })
|
||||
end)
|
||||
|
||||
it("draw", function()
|
||||
layout:draw("wibox", "cr", 5, 100)
|
||||
utils.check_widgets_drawn({
|
||||
{ first, 0, 0, 5, 10 },
|
||||
{ second, 0, 10, 5, 15 },
|
||||
{ third, 0, 25, 5, 10 },
|
||||
it("layout", function()
|
||||
assert.widget_layout(layout, { 5, 100 }, {
|
||||
p(first, 0, 0, 5, 10),
|
||||
p(second, 0, 10, 5, 15),
|
||||
p(third, 0, 25, 5, 10),
|
||||
})
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("without enough width", function()
|
||||
it("fit", function()
|
||||
-- XXX: Is this really what should happen?
|
||||
assert.widget_fit(layout, { 100, 20 }, { 15, 20 })
|
||||
end)
|
||||
|
||||
it("draw", function()
|
||||
layout:draw("wibox", "cr", 100, 20)
|
||||
utils.check_widgets_drawn({
|
||||
{ first, 0, 0, 100, 10 },
|
||||
{ second, 0, 10, 100, 10 },
|
||||
{ third, 0, 20, 100, 0 },
|
||||
it("layout", function()
|
||||
assert.widget_layout(layout, { 100, 20 }, {
|
||||
p(first, 0, 0, 100, 10),
|
||||
p(second, 0, 10, 100, 10),
|
||||
p(third, 0, 20, 100, 0),
|
||||
})
|
||||
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)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
---------------------------------------------------------------------------
|
||||
|
||||
local flex = require("wibox.layout.flex")
|
||||
local base = require("wibox.widget.base")
|
||||
local utils = require("wibox.test_utils")
|
||||
local p = require("wibox.widget.base").place_widget_at
|
||||
|
||||
describe("wibox.layout.flex", function()
|
||||
local layout
|
||||
|
@ -12,16 +14,12 @@ describe("wibox.layout.flex", function()
|
|||
layout = flex.vertical()
|
||||
end)
|
||||
|
||||
before_each(utils.stub_draw_widget)
|
||||
after_each(utils.revert_draw_widget)
|
||||
|
||||
it("empty layout fit", function()
|
||||
assert.widget_fit(layout, { 10, 10 }, { 0, 0 })
|
||||
utils.check_widgets_drawn({})
|
||||
end)
|
||||
|
||||
it("empty layout draw", function()
|
||||
layout:draw(nil, nil, 0, 0)
|
||||
it("empty layout layout", function()
|
||||
assert.widget_layout(layout, { 0, 0 }, {})
|
||||
end)
|
||||
|
||||
describe("with widgets", function()
|
||||
|
@ -42,12 +40,11 @@ describe("wibox.layout.flex", function()
|
|||
assert.widget_fit(layout, { 100, 100 }, { 15, 35 })
|
||||
end)
|
||||
|
||||
it("draw", function()
|
||||
layout:draw("wibox", "cr", 100, 100)
|
||||
utils.check_widgets_drawn({
|
||||
{ first, 0, 0, 100, 33 },
|
||||
{ second, 0, 33, 100, 33 },
|
||||
{ third, 0, 67, 100, 33 },
|
||||
it("layout", function()
|
||||
assert.widget_layout(layout, { 100, 100 }, {
|
||||
p(first, 0, 0, 100, 33),
|
||||
p(second, 0, 33, 100, 33),
|
||||
p(third, 0, 67, 100, 33),
|
||||
})
|
||||
end)
|
||||
end)
|
||||
|
@ -57,12 +54,11 @@ describe("wibox.layout.flex", function()
|
|||
assert.widget_fit(layout, { 5, 100 }, { 5, 35 })
|
||||
end)
|
||||
|
||||
it("draw", function()
|
||||
layout:draw("wibox", "cr", 5, 100)
|
||||
utils.check_widgets_drawn({
|
||||
{ first, 0, 0, 5, 33 },
|
||||
{ second, 0, 33, 5, 33 },
|
||||
{ third, 0, 67, 5, 33 },
|
||||
it("layout", function()
|
||||
assert.widget_layout(layout, { 5, 100 }, {
|
||||
p(first, 0, 0, 5, 33),
|
||||
p(second, 0, 33, 5, 33),
|
||||
p(third, 0, 67, 5, 33),
|
||||
})
|
||||
end)
|
||||
end)
|
||||
|
@ -72,16 +68,68 @@ describe("wibox.layout.flex", function()
|
|||
assert.widget_fit(layout, { 100, 20 }, { 15, 20 })
|
||||
end)
|
||||
|
||||
it("draw", function()
|
||||
layout:draw("wibox", "cr", 100, 20)
|
||||
utils.check_widgets_drawn({
|
||||
{ first, 0, 0, 100, 6 },
|
||||
{ second, 0, 7, 100, 6 },
|
||||
{ third, 0, 13, 100, 6 },
|
||||
it("layout", function()
|
||||
assert.widget_layout(layout, { 100, 20 }, {
|
||||
p(first, 0, 0, 100, 6),
|
||||
p(second, 0, 7, 100, 6),
|
||||
p(third, 0, 13, 100, 6),
|
||||
})
|
||||
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)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||
|
|
|
@ -5,37 +5,21 @@
|
|||
|
||||
local object = require("gears.object")
|
||||
local cache = require("gears.cache")
|
||||
local wbase = require("wibox.widget.base")
|
||||
local lbase = require("wibox.layout.base")
|
||||
local matrix_equals = require("gears.matrix").equals
|
||||
local base = require("wibox.widget.base")
|
||||
local say = require("say")
|
||||
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
|
||||
local function widget_fit(state, arguments)
|
||||
if #arguments ~= 3 then
|
||||
return false
|
||||
error("Have " .. #arguments .. " arguments, but need 3")
|
||||
end
|
||||
|
||||
local widget = arguments[1]
|
||||
local given = arguments[2]
|
||||
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
|
||||
if state.mod == fits then
|
||||
|
@ -52,51 +36,65 @@ local function widget_fit(state, arguments)
|
|||
end
|
||||
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")
|
||||
|
||||
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 {
|
||||
real_check_widget = real_check_widget,
|
||||
|
||||
widget_stub = function(width, height)
|
||||
local w = object()
|
||||
w:add_signal("widget::redraw_needed")
|
||||
w:add_signal("widget::layout_changed")
|
||||
w.visible = true
|
||||
w:add_signal("widget::updated")
|
||||
|
||||
w.fit = function()
|
||||
return width or 10, height or 10
|
||||
w.opacity = 1
|
||||
if width or height then
|
||||
w.fit = function()
|
||||
return width or 10, height or 10
|
||||
end
|
||||
end
|
||||
w.draw = function() end
|
||||
w._fit_geometry_cache = cache.new(w.fit)
|
||||
|
||||
spy.on(w, "fit")
|
||||
stub(w, "draw")
|
||||
w._widget_caches = {}
|
||||
|
||||
return w
|
||||
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
|
||||
|
|
|
@ -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