Merge pull request #462 from psychon/gears.matrix2
Implement full matrix operations in gears.matrix Closes https://github.com/awesomeWM/awesome/pull/462.
This commit is contained in:
commit
21dbe262fb
|
@ -1,50 +1,166 @@
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
|
-- An implementation of matrices for describing and working with affine
|
||||||
|
-- transformations.
|
||||||
-- @author Uli Schlachter
|
-- @author Uli Schlachter
|
||||||
-- @copyright 2015 Uli Schlachter
|
-- @copyright 2015 Uli Schlachter
|
||||||
-- @release @AWESOME_VERSION@
|
-- @release @AWESOME_VERSION@
|
||||||
-- @module gears.matrix
|
-- @classmod gears.matrix
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
local cairo = require("lgi").cairo
|
local cairo = require("lgi").cairo
|
||||||
local debug = require("gears.debug")
|
local debug = require("gears.debug")
|
||||||
local matrix = {}
|
local matrix = {}
|
||||||
|
|
||||||
--- Copy a cairo matrix
|
-- Metatable for matrix instances. This is set up near the end of the file.
|
||||||
-- @param matrix The matrix to copy.
|
local matrix_mt = {}
|
||||||
-- @return A copy of the given cairo matrix.
|
|
||||||
function matrix.copy(matrix)
|
--- Create a new matrix instance
|
||||||
debug.assert(cairo.Matrix:is_type_of(matrix), "Argument should be a cairo matrix")
|
-- @tparam number xx The xx transformation part.
|
||||||
local ret = cairo.Matrix()
|
-- @tparam number yx The yx transformation part.
|
||||||
ret:init(matrix.xx, matrix.yx, matrix.xy, matrix.yy, matrix.x0, matrix.y0)
|
-- @tparam number xy The xy transformation part.
|
||||||
return ret
|
-- @tparam number yy The yy transformation part.
|
||||||
|
-- @tparam number x0 The x0 transformation part.
|
||||||
|
-- @tparam number y0 The y0 transformation part.
|
||||||
|
-- @return A new matrix describing the given transformation.
|
||||||
|
function matrix.create(xx, yx, xy, yy, x0, y0)
|
||||||
|
return setmetatable({
|
||||||
|
xx = xx, xy = xy, x0 = x0,
|
||||||
|
yx = yx, yy = yy, y0 = y0
|
||||||
|
}, matrix_mt)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Check if two cairo matrices are equal
|
--- Create a new translation matrix
|
||||||
-- @param m1 The first matrix to compare with.
|
-- @tparam number x The translation in x direction.
|
||||||
-- @param m2 The second matrix to compare with.
|
-- @tparam number y The translation in y direction.
|
||||||
-- @return True if they are equal.
|
-- @return A new matrix describing the given transformation.
|
||||||
function matrix.equals(m1, m2)
|
function matrix.create_translate(x, y)
|
||||||
|
return matrix.create(1, 0, 0, 1, x, y)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Create a new scaling matrix
|
||||||
|
-- @tparam number sx The scaling in x direction.
|
||||||
|
-- @tparam number sy The scaling in y direction.
|
||||||
|
-- @return A new matrix describing the given transformation.
|
||||||
|
function matrix.create_scale(sx, sy)
|
||||||
|
return matrix.create(sx, 0, 0, sy, 0, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Create a new rotation matrix
|
||||||
|
-- @tparam number angle The angle of the rotation in radians.
|
||||||
|
-- @return A new matrix describing the given transformation.
|
||||||
|
function matrix.create_rotate(angle)
|
||||||
|
local c, s = math.cos(angle), math.sin(angle)
|
||||||
|
return matrix.create(c, s, -s, c, 0, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Translate this matrix
|
||||||
|
-- @tparam number x The translation in x direction.
|
||||||
|
-- @tparam number y The translation in y direction.
|
||||||
|
-- @return A new matrix describing the new transformation.
|
||||||
|
function matrix:translate(x, y)
|
||||||
|
return matrix.create_translate(x, y):multiply(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Scale this matrix
|
||||||
|
-- @tparam number sx The scaling in x direction.
|
||||||
|
-- @tparam number sy The scaling in y direction.
|
||||||
|
-- @return A new matrix describing the new transformation.
|
||||||
|
function matrix:scale(sx, sy)
|
||||||
|
return matrix.create_scale(sx, sy):multiply(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Rotate this matrix
|
||||||
|
-- @tparam number angle The angle of the rotation in radians.
|
||||||
|
-- @return A new matrix describing the new transformation.
|
||||||
|
function matrix:rotate(angle)
|
||||||
|
return matrix.create_rotate(angle):multiply(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Invert this matrix
|
||||||
|
-- @return A new matrix describing the inverse transformation.
|
||||||
|
function matrix:invert()
|
||||||
|
-- Beware of math! (I just copied the algorithm from cairo's source code)
|
||||||
|
local a, b, c, d, x0, y0 = self.xx, self.yx, self.xy, self.yy, self.x0, self.y0
|
||||||
|
local inv_det = 1/(a*d - b*c)
|
||||||
|
return matrix.create(inv_det * d, inv_det * -b,
|
||||||
|
inv_det * -c, inv_det * a,
|
||||||
|
inv_det * (c * y0 - d * x0), inv_det * (b * x0 - a * y0))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Multiply this matrix with another matrix.
|
||||||
|
-- The resulting matrix describes a transformation that is equivalent to first
|
||||||
|
-- applying this transformation and then the transformation from `other`.
|
||||||
|
-- Note that this function can also be called by directly multiplicating two
|
||||||
|
-- matrix instances: `a * b == a:multiply(b)`.
|
||||||
|
-- @tparam gears.matrix|cairo.Matrix other The other matrix to multiply with.
|
||||||
|
-- @return The multiplication result.
|
||||||
|
function matrix:multiply(other)
|
||||||
|
return matrix.create(self.xx * other.xx + self.yx * other.xy,
|
||||||
|
self.xx * other.yx + self.yx * other.yy,
|
||||||
|
self.xy * other.xx + self.yy * other.xy,
|
||||||
|
self.xy * other.yx + self.yy * other.yy,
|
||||||
|
self.x0 * other.xx + self.y0 * other.xy + other.x0,
|
||||||
|
self.x0 * other.yx + self.y0 * other.yy + other.y0)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if two matrices are equal.
|
||||||
|
-- Note that this function cal also be called by directly comparing two matrix
|
||||||
|
-- instances: `a == b`.
|
||||||
|
-- @tparam gears.matrix|cairo.Matrix other The matrix to compare with.
|
||||||
|
-- @return True if this and the other matrix are equal.
|
||||||
|
function matrix:equals(other)
|
||||||
for _, k in pairs{ "xx", "xy", "yx", "yy", "x0", "y0" } do
|
for _, k in pairs{ "xx", "xy", "yx", "yy", "x0", "y0" } do
|
||||||
if m1[k] ~= m2[k] then
|
if self[k] ~= other[k] then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get a string representation of this matrix
|
||||||
|
-- @return A string showing this matrix in column form.
|
||||||
|
function matrix:tostring()
|
||||||
|
return string.format("[[%g, %g], [%g, %g], [%g, %g]]",
|
||||||
|
self.xx, self.yx, self.xy,
|
||||||
|
self.yy, self.x0, self.y0)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Transform a distance by this matrix.
|
||||||
|
-- The difference to @{matrix:transform_point} is that the translation part of
|
||||||
|
-- this matrix is ignored.
|
||||||
|
-- @tparam number x The x coordinate of the point.
|
||||||
|
-- @tparam number y The y coordinate of the point.
|
||||||
|
-- @treturn number The x coordinate of the transformed point.
|
||||||
|
-- @treturn number The x coordinate of the transformed point.
|
||||||
|
function matrix:transform_distance(x, y)
|
||||||
|
return self.xx * x + self.xy * y, self.yx * x + self.yy * y
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Transform a point by this matrix.
|
||||||
|
-- @tparam number x The x coordinate of the point.
|
||||||
|
-- @tparam number y The y coordinate of the point.
|
||||||
|
-- @treturn number The x coordinate of the transformed point.
|
||||||
|
-- @treturn number The x coordinate of the transformed point.
|
||||||
|
function matrix:transform_point(x, y)
|
||||||
|
local x, y = self:transform_distance(x, y)
|
||||||
|
return self.x0 + x, self.y0 + y
|
||||||
|
end
|
||||||
|
|
||||||
--- Calculate a bounding rectangle for transforming a rectangle by a matrix.
|
--- Calculate a bounding rectangle for transforming a rectangle by a matrix.
|
||||||
-- @param matrix The cairo matrix that describes the transformation.
|
-- @tparam number x The x coordinate of the rectangle.
|
||||||
-- @param x The x coordinate of the rectangle.
|
-- @tparam number y The y coordinate of the rectangle.
|
||||||
-- @param y The y coordinate of the rectangle.
|
-- @tparam number width The width of the rectangle.
|
||||||
-- @param width The width of the rectangle.
|
-- @tparam number height The height of the rectangle.
|
||||||
-- @param height The height of the rectangle.
|
-- @treturn number X coordinate of the bounding rectangle.
|
||||||
-- @return The x, y, width and height of the bounding rectangle.
|
-- @treturn number Y coordinate of the bounding rectangle.
|
||||||
function matrix.transform_rectangle(matrix, x, y, width, height)
|
-- @treturn number Width of the bounding rectangle.
|
||||||
|
-- @treturn number Height of the bounding rectangle.
|
||||||
|
function matrix:transform_rectangle(x, y, width, height)
|
||||||
-- Transform all four corners of the rectangle
|
-- Transform all four corners of the rectangle
|
||||||
local x1, y1 = matrix:transform_point(x, y)
|
local x1, y1 = self:transform_point(x, y)
|
||||||
local x2, y2 = matrix:transform_point(x, y + height)
|
local x2, y2 = self:transform_point(x, y + height)
|
||||||
local x3, y3 = matrix:transform_point(x + width, y + height)
|
local x3, y3 = self:transform_point(x + width, y + height)
|
||||||
local x4, y4 = matrix:transform_point(x + width, y)
|
local x4, y4 = self:transform_point(x + width, y)
|
||||||
-- Find the extremal points of the result
|
-- Find the extremal points of the result
|
||||||
local x = math.min(x1, x2, x3, x4)
|
local x = math.min(x1, x2, x3, x4)
|
||||||
local y = math.min(y1, y2, y3, y4)
|
local y = math.min(y1, y2, y3, y4)
|
||||||
|
@ -54,6 +170,30 @@ function matrix.transform_rectangle(matrix, x, y, width, height)
|
||||||
return x, y, width, height
|
return x, y, width, height
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Convert to a cairo matrix
|
||||||
|
-- @treturn cairo.Matrix A cairo matrix describing the same transformation.
|
||||||
|
function matrix:to_cairo_matrix()
|
||||||
|
local ret = cairo.Matrix()
|
||||||
|
ret:init(self.xx, self.yx, self.xy, self.yy, self.x0, self.y0)
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Convert to a cairo matrix
|
||||||
|
-- @tparam cairo.Matrix mat A cairo matrix describing the sought transformation
|
||||||
|
-- @treturn gears.matrix A matrix instance describing the same transformation.
|
||||||
|
function matrix.from_cairo_matrix(mat)
|
||||||
|
return matrix.create(mat.xx, mat.yx, mat.xy, mat.yy, mat.x0, mat.y0)
|
||||||
|
end
|
||||||
|
|
||||||
|
matrix_mt.__index = matrix
|
||||||
|
matrix_mt.__newindex = error
|
||||||
|
matrix_mt.__eq = matrix.equals
|
||||||
|
matrix_mt.__mul = matrix.multiply
|
||||||
|
matrix_mt.__tostring = matrix.tostring
|
||||||
|
|
||||||
|
--- A constant for the identity matrix.
|
||||||
|
matrix.identity = matrix.create(1, 0, 0, 1, 0, 0)
|
||||||
|
|
||||||
return matrix
|
return matrix
|
||||||
|
|
||||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||||
|
|
|
@ -37,11 +37,8 @@ local function hierarchy_new(context, widget, width, height, redraw_callback, la
|
||||||
widget:weak_connect_signal("widget::layout_changed", result._layout)
|
widget:weak_connect_signal("widget::layout_changed", result._layout)
|
||||||
|
|
||||||
for _, w in ipairs(children or {}) do
|
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,
|
local r = hierarchy_new(context, w._widget, w._width, w._height, redraw_callback, layout_callback,
|
||||||
callback_arg, matrix.copy(w._matrix), to_dev)
|
callback_arg, w._matrix, matrix_to_device * w._matrix)
|
||||||
table.insert(result._children, r)
|
table.insert(result._children, r)
|
||||||
|
|
||||||
-- Update our drawing extents
|
-- Update our drawing extents
|
||||||
|
@ -82,7 +79,7 @@ end
|
||||||
-- @return A new widget hierarchy
|
-- @return A new widget hierarchy
|
||||||
function hierarchy.new(context, widget, width, height, redraw_callback, layout_callback, callback_arg)
|
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,
|
return hierarchy_new(context, widget, width, height, redraw_callback, layout_callback, callback_arg,
|
||||||
cairo.Matrix.create_identity(), cairo.Matrix.create_identity())
|
matrix.identity, matrix.identity)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the widget that this hierarchy manages.
|
--- Get the widget that this hierarchy manages.
|
||||||
|
@ -90,38 +87,36 @@ function hierarchy:get_widget()
|
||||||
return self._widget
|
return self._widget
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get a cairo matrix that transforms to the parent's coordinate space from
|
--- Get a matrix that transforms to the parent's coordinate space from this
|
||||||
-- this hierarchy's coordinate system.
|
-- hierarchy's coordinate system.
|
||||||
-- @return A cairo matrix describing the transformation.
|
-- @return A matrix describing the transformation.
|
||||||
function hierarchy:get_matrix_to_parent()
|
function hierarchy:get_matrix_to_parent()
|
||||||
return matrix.copy(self._matrix)
|
return self._matrix
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get a cairo matrix that transforms to the base of this hierarchy's
|
--- Get a matrix that transforms to the base of this hierarchy's coordinate
|
||||||
-- coordinate system (aka the coordinate system of the device that this
|
-- system (aka the coordinate system of the device that this
|
||||||
-- hierarchy is applied upon) from this hierarchy's coordinate system.
|
-- hierarchy is applied upon) from this hierarchy's coordinate system.
|
||||||
-- @return A cairo matrix describing the transformation.
|
-- @return A matrix describing the transformation.
|
||||||
function hierarchy:get_matrix_to_device()
|
function hierarchy:get_matrix_to_device()
|
||||||
return matrix.copy(self._matrix_to_device)
|
return self._matrix_to_device
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get a cairo matrix that transforms from the parent's coordinate space into
|
--- Get a matrix that transforms from the parent's coordinate space into this
|
||||||
-- this hierarchy's coordinate system.
|
-- hierarchy's coordinate system.
|
||||||
-- @return A cairo matrix describing the transformation.
|
-- @return A matrix describing the transformation.
|
||||||
function hierarchy:get_matrix_from_parent()
|
function hierarchy:get_matrix_from_parent()
|
||||||
local m = self:get_matrix_to_parent()
|
local m = self:get_matrix_to_parent()
|
||||||
m:invert()
|
return m:invert()
|
||||||
return m
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get a cairo matrix that transforms from the base of this hierarchy's
|
--- Get a matrix that transforms from the base of this hierarchy's coordinate
|
||||||
-- coordinate system (aka the coordinate system of the device that this
|
-- system (aka the coordinate system of the device that this
|
||||||
-- hierarchy is applied upon) into this hierarchy's coordinate system.
|
-- hierarchy is applied upon) into this hierarchy's coordinate system.
|
||||||
-- @return A cairo matrix describing the transformation.
|
-- @return A matrix describing the transformation.
|
||||||
function hierarchy:get_matrix_from_device()
|
function hierarchy:get_matrix_from_device()
|
||||||
local m = self:get_matrix_to_device()
|
local m = self:get_matrix_to_device()
|
||||||
m:invert()
|
return m:invert()
|
||||||
return m
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the extents that this hierarchy possibly draws to (in the current coordinate space).
|
--- Get the extents that this hierarchy possibly draws to (in the current coordinate space).
|
||||||
|
@ -198,7 +193,7 @@ function hierarchy:draw(context, cr)
|
||||||
end
|
end
|
||||||
|
|
||||||
cr:save()
|
cr:save()
|
||||||
cr:transform(self:get_matrix_to_parent())
|
cr:transform(self:get_matrix_to_parent():to_cairo_matrix())
|
||||||
|
|
||||||
-- Clip to the draw extents
|
-- Clip to the draw extents
|
||||||
cr:rectangle(self:get_draw_extents())
|
cr:rectangle(self:get_draw_extents())
|
||||||
|
|
|
@ -11,7 +11,7 @@ local pairs = pairs
|
||||||
local ipairs = ipairs
|
local ipairs = ipairs
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
local base = require("wibox.widget.base")
|
local base = require("wibox.widget.base")
|
||||||
local Matrix = require("lgi").cairo.Matrix
|
local matrix = require("gears.matrix")
|
||||||
|
|
||||||
local mirror = { mt = {} }
|
local mirror = { mt = {} }
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ function mirror:layout(context, cr, width, height)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local m = Matrix.create_identity()
|
local m = matrix.identity
|
||||||
local t = { x = 0, y = 0 } -- translation
|
local t = { x = 0, y = 0 } -- translation
|
||||||
local s = { x = 1, y = 1 } -- scale
|
local s = { x = 1, y = 1 } -- scale
|
||||||
if self.horizontal then
|
if self.horizontal then
|
||||||
|
@ -34,8 +34,8 @@ function mirror:layout(context, cr, width, height)
|
||||||
t.x = width
|
t.x = width
|
||||||
s.x = -1
|
s.x = -1
|
||||||
end
|
end
|
||||||
m:translate(t.x, t.y)
|
m = m:translate(t.x, t.y)
|
||||||
m:scale(s.x, s.y)
|
m = m:scale(s.x, s.y)
|
||||||
|
|
||||||
return base.place_widget_via_matrix(widget, m, width, height)
|
return base.place_widget_via_matrix(widget, m, width, height)
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,7 +12,7 @@ local type = type
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
local tostring = tostring
|
local tostring = tostring
|
||||||
local base = require("wibox.widget.base")
|
local base = require("wibox.widget.base")
|
||||||
local Matrix = require("lgi").cairo.Matrix
|
local matrix = require("gears.matrix")
|
||||||
|
|
||||||
local rotate = { mt = {} }
|
local rotate = { mt = {} }
|
||||||
|
|
||||||
|
@ -32,16 +32,16 @@ function rotate:layout(context, width, height)
|
||||||
|
|
||||||
local dir = self:get_direction()
|
local dir = self:get_direction()
|
||||||
|
|
||||||
local m = Matrix.create_identity()
|
local m = matrix.identity
|
||||||
if dir == "west" then
|
if dir == "west" then
|
||||||
m:rotate(pi / 2)
|
m = m:rotate(pi / 2)
|
||||||
m:translate(0, -width)
|
m = m:translate(0, -width)
|
||||||
elseif dir == "south" then
|
elseif dir == "south" then
|
||||||
m:rotate(pi)
|
m = m:rotate(pi)
|
||||||
m:translate(-width, -height)
|
m = m:translate(-width, -height)
|
||||||
elseif dir == "east" then
|
elseif dir == "east" then
|
||||||
m:rotate(3 * pi / 2)
|
m = m:rotate(3 * pi / 2)
|
||||||
m:translate(-height, 0)
|
m = m:translate(-height, 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Since we rotated, we might have to swap width and height.
|
-- Since we rotated, we might have to swap width and height.
|
||||||
|
|
|
@ -9,7 +9,6 @@ local debug = require("gears.debug")
|
||||||
local object = require("gears.object")
|
local object = require("gears.object")
|
||||||
local cache = require("gears.cache")
|
local cache = require("gears.cache")
|
||||||
local matrix = require("gears.matrix")
|
local matrix = require("gears.matrix")
|
||||||
local Matrix = require("lgi").cairo.Matrix
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
local pairs = pairs
|
local pairs = pairs
|
||||||
local type = type
|
local type = type
|
||||||
|
@ -204,8 +203,8 @@ end
|
||||||
--- Create widget placement information. This should be used for a widget's
|
--- Create widget placement information. This should be used for a widget's
|
||||||
-- `:layout()` callback.
|
-- `:layout()` callback.
|
||||||
-- @param widget The widget that should be placed.
|
-- @param widget The widget that should be placed.
|
||||||
-- @param mat A cairo matrix transforming from the parent widget's coordinate
|
-- @param mat A matrix transforming from the parent widget's coordinate
|
||||||
-- system. For example, use cairo.Matrix.create_translate(1, 2) to draw a
|
-- system. For example, use matrix.create_translate(1, 2) to draw a
|
||||||
-- widget at position (1, 2) relative to the parent widget.
|
-- widget at position (1, 2) relative to the parent widget.
|
||||||
-- @param width The width of the widget in its own coordinate system. That is,
|
-- @param width The width of the widget in its own coordinate system. That is,
|
||||||
-- after applying the transformation matrix.
|
-- after applying the transformation matrix.
|
||||||
|
@ -217,7 +216,7 @@ function base.place_widget_via_matrix(widget, mat, width, height)
|
||||||
_widget = widget,
|
_widget = widget,
|
||||||
_width = width,
|
_width = width,
|
||||||
_height = height,
|
_height = height,
|
||||||
_matrix = matrix.copy(mat)
|
_matrix = mat
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -232,7 +231,7 @@ end
|
||||||
-- after applying the transformation matrix.
|
-- after applying the transformation matrix.
|
||||||
-- @return An opaque object that can be returned from :layout()
|
-- @return An opaque object that can be returned from :layout()
|
||||||
function base.place_widget_at(widget, x, y, width, height)
|
function base.place_widget_at(widget, x, y, width, height)
|
||||||
return base.place_widget_via_matrix(widget, Matrix.create_translate(x, y), width, height)
|
return base.place_widget_via_matrix(widget, matrix.create_translate(x, y), width, height)
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[--
|
--[[--
|
||||||
|
|
|
@ -7,48 +7,98 @@ local matrix = require("gears.matrix")
|
||||||
local cairo = require("lgi").cairo
|
local cairo = require("lgi").cairo
|
||||||
|
|
||||||
describe("gears.matrix", function()
|
describe("gears.matrix", function()
|
||||||
describe("copy", function()
|
local function round(n)
|
||||||
it("Test copy", function()
|
return math.floor(n + 0.5)
|
||||||
local m1 = cairo.Matrix()
|
end
|
||||||
m1:init(1, 2, 3, 4, 5, 6)
|
|
||||||
local m2 = matrix.copy(m1)
|
|
||||||
assert.is.equal(m1.xx, m2.xx)
|
|
||||||
assert.is.equal(m1.xy, m2.xy)
|
|
||||||
assert.is.equal(m1.yx, m2.yx)
|
|
||||||
assert.is.equal(m1.yy, m2.yy)
|
|
||||||
assert.is.equal(m1.x0, m2.x0)
|
|
||||||
assert.is.equal(m1.y0, m2.y0)
|
|
||||||
|
|
||||||
m1.x0 = 42
|
describe("cannot modify", function()
|
||||||
assert.is_not.equal(m1.x0, m2.x0)
|
assert.has.errors(function()
|
||||||
|
matrix.identity.something = 42
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe("equals", function()
|
describe("equals", function()
|
||||||
it("Same matrix", function()
|
it("Same matrix", function()
|
||||||
local m = cairo.Matrix.create_rotate(1)
|
local m = matrix.create_rotate(1)
|
||||||
assert.is_true(matrix.equals(m, m))
|
assert.is_true(matrix.equals(m, m))
|
||||||
|
assert.is.equal(m, m)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("Different matrix equals", function()
|
it("Different matrix equals", function()
|
||||||
local m1 = cairo.Matrix.create_rotate(1)
|
local m1 = matrix.create_rotate(1)
|
||||||
local m2 = cairo.Matrix.create_rotate(1)
|
local m2 = matrix.create_rotate(1)
|
||||||
assert.is_true(matrix.equals(m1, m2))
|
assert.is_true(matrix.equals(m1, m2))
|
||||||
|
assert.is.equal(m1, m2)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("Different matrix unequal", function()
|
it("Different matrix unequal", function()
|
||||||
local m1 = cairo.Matrix()
|
local m1 = matrix.create(1, 2, 3, 4, 5, 6)
|
||||||
local m2 = cairo.Matrix()
|
local m2 = matrix.create(1, 2, 3, 4, 5, 0)
|
||||||
m1:init(1, 2, 3, 4, 5, 6)
|
|
||||||
m2:init(1, 2, 3, 4, 5, 0)
|
|
||||||
assert.is_false(matrix.equals(m1, m2))
|
assert.is_false(matrix.equals(m1, m2))
|
||||||
|
assert.is_not.equal(m1, m2)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("Identity matrix", function()
|
||||||
|
local m1 = matrix.identity
|
||||||
|
local m2 = matrix.create(1, 0, 0, 1, 0, 0)
|
||||||
|
assert.is_true(matrix.equals(m1, m2))
|
||||||
|
assert.is.equal(m1, m2)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("create", function()
|
||||||
|
it("translate", function()
|
||||||
|
assert.is.equal(matrix.create(1, 0, 0, 1, 2, 3), matrix.create_translate(2, 3))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("scale", function()
|
||||||
|
assert.is.equal(matrix.create(2, 0, 0, 3, 0, 0), matrix.create_scale(2, 3))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("rotate", function()
|
||||||
|
local m = matrix.create_rotate(math.pi / 2)
|
||||||
|
assert.is_true(math.abs(round(m.xx) - m.xx) < 0.00000001)
|
||||||
|
assert.is.equal(-1, m.xy)
|
||||||
|
assert.is.equal(1, m.yx)
|
||||||
|
assert.is_true(math.abs(round(m.yy) - m.yy) < 0.00000001)
|
||||||
|
assert.is.equal(0, m.x0)
|
||||||
|
assert.is.equal(0, m.y0)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("multiply", function()
|
||||||
|
-- Just some random matrices which I multiplied by hand
|
||||||
|
local a = matrix.create(1, 2, 3, 4, 5, 6)
|
||||||
|
local b = matrix.create(7, 8, 9, 1, 1, 1)
|
||||||
|
local m = matrix.create(25, 10, 57, 28, 90, 47)
|
||||||
|
assert.is.equal(m, a:multiply(b))
|
||||||
|
assert.is.equal(m, a * b)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("invert", function()
|
||||||
|
it("translate", function()
|
||||||
|
local m1, m2 = matrix.create_translate(2, 3), matrix.create_translate(-2, -3)
|
||||||
|
assert.is.equal(m2, m1:invert())
|
||||||
|
assert.is.equal(matrix.identity, m1 * m2)
|
||||||
|
assert.is.equal(matrix.identity, m2 * m1)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("scale", function()
|
||||||
|
local m1, m2 = matrix.create_scale(2, 3), matrix.create_scale(1/2, 1/3)
|
||||||
|
assert.is.equal(m2, m1:invert())
|
||||||
|
assert.is.equal(matrix.identity, m1 * m2)
|
||||||
|
assert.is.equal(matrix.identity, m2 * m1)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("rotate", function()
|
||||||
|
local m1, m2 = matrix.create_rotate(2), matrix.create_rotate(-2)
|
||||||
|
assert.is.equal(m2, m1:invert())
|
||||||
|
assert.is.equal(matrix.identity, m1 * m2)
|
||||||
|
assert.is.equal(matrix.identity, m2 * m1)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe("transform_rectangle", function()
|
describe("transform_rectangle", function()
|
||||||
local function round(n)
|
|
||||||
return math.floor(n + 0.5)
|
|
||||||
end
|
|
||||||
local function test(m, x, y, width, height,
|
local function test(m, x, y, width, height,
|
||||||
expected_x, expected_y, expected_width, expected_height)
|
expected_x, expected_y, expected_width, expected_height)
|
||||||
local actual_x, actual_y, actual_width, actual_height =
|
local actual_x, actual_y, actual_width, actual_height =
|
||||||
|
@ -64,19 +114,42 @@ describe("gears.matrix", function()
|
||||||
assert.is_true(math.abs(round(actual_height) - actual_height) < 0.00000001)
|
assert.is_true(math.abs(round(actual_height) - actual_height) < 0.00000001)
|
||||||
end
|
end
|
||||||
it("Identity matrix", function()
|
it("Identity matrix", function()
|
||||||
test(cairo.Matrix.create_identity(), 1, 2, 3, 4, 1, 2, 3, 4)
|
test(matrix.identity, 1, 2, 3, 4, 1, 2, 3, 4)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("Rotate 180", function()
|
it("Rotate 180", function()
|
||||||
test(cairo.Matrix.create_rotate(math.pi),
|
test(matrix.create_rotate(math.pi),
|
||||||
1, 2, 3, 4, -4, -6, 3, 4)
|
1, 2, 3, 4, -4, -6, 3, 4)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("Rotate 90", function()
|
it("Rotate 90", function()
|
||||||
test(cairo.Matrix.create_rotate(math.pi / 2),
|
test(matrix.create_rotate(math.pi / 2),
|
||||||
1, 2, 3, 4, -6, 1, 4, 3)
|
1, 2, 3, 4, -6, 1, 4, 3)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it("tostring", function()
|
||||||
|
local m = matrix.create(1, 2, 3, 4, 5, 6)
|
||||||
|
local expected = "[[1, 2], [3, 4], [5, 6]]"
|
||||||
|
assert.is.equal(expected, m:tostring())
|
||||||
|
assert.is.equal(expected, tostring(m))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("from_cairo_matrix", function()
|
||||||
|
local m1 = matrix.create_translate(2, 3)
|
||||||
|
local m2 = matrix.from_cairo_matrix(cairo.Matrix.create_translate(2, 3))
|
||||||
|
assert.is.equal(m1, m2)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("to_cairo_matrix", function()
|
||||||
|
local m = matrix.create_scale(3, 4):to_cairo_matrix()
|
||||||
|
assert.is.equal(3, m.xx)
|
||||||
|
assert.is.equal(0, m.xy)
|
||||||
|
assert.is.equal(0, m.yx)
|
||||||
|
assert.is.equal(4, m.yy)
|
||||||
|
assert.is.equal(0, m.x0)
|
||||||
|
assert.is.equal(0, m.y0)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
local hierarchy = require("wibox.hierarchy")
|
local hierarchy = require("wibox.hierarchy")
|
||||||
|
|
||||||
local cairo = require("lgi").cairo
|
local Region = require("lgi").cairo.Region
|
||||||
local matrix = require("gears.matrix")
|
local matrix = require("gears.matrix")
|
||||||
local object = require("gears.object")
|
local object = require("gears.object")
|
||||||
local utils = require("wibox.test_utils")
|
local utils = require("wibox.test_utils")
|
||||||
|
@ -37,23 +37,19 @@ describe("wibox.hierarchy", function()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("get_matrix_to_parent", function()
|
it("get_matrix_to_parent", function()
|
||||||
assert.is_true(matrix.equals(cairo.Matrix.create_identity(),
|
assert.is.equal(matrix.identity, instance:get_matrix_to_parent())
|
||||||
instance:get_matrix_to_parent()))
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("get_matrix_to_device", function()
|
it("get_matrix_to_device", function()
|
||||||
assert.is_true(matrix.equals(cairo.Matrix.create_identity(),
|
assert.is.equal(matrix.identity, instance:get_matrix_to_device())
|
||||||
instance:get_matrix_to_device()))
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("get_matrix_from_parent", function()
|
it("get_matrix_from_parent", function()
|
||||||
assert.is_true(matrix.equals(cairo.Matrix.create_identity(),
|
assert.is.equal(matrix.identity, instance:get_matrix_from_parent())
|
||||||
instance:get_matrix_from_parent()))
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("get_matrix_from_device", function()
|
it("get_matrix_from_device", function()
|
||||||
assert.is_true(matrix.equals(cairo.Matrix.create_identity(),
|
assert.is.equal(matrix.identity, instance:get_matrix_from_device())
|
||||||
instance:get_matrix_from_device()))
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("get_draw_extents", function()
|
it("get_draw_extents", function()
|
||||||
|
@ -72,7 +68,7 @@ describe("wibox.hierarchy", function()
|
||||||
it("disconnect works", function()
|
it("disconnect works", function()
|
||||||
local child = make_widget(nil)
|
local child = make_widget(nil)
|
||||||
local parent = make_widget({
|
local parent = make_widget({
|
||||||
make_child(child, 2, 5, cairo.Matrix.create_translate(10, 0))
|
make_child(child, 2, 5, matrix.create_translate(10, 0))
|
||||||
})
|
})
|
||||||
|
|
||||||
local extra_arg = {}
|
local extra_arg = {}
|
||||||
|
@ -129,10 +125,10 @@ describe("wibox.hierarchy", function()
|
||||||
before_each(function()
|
before_each(function()
|
||||||
child = make_widget(nil)
|
child = make_widget(nil)
|
||||||
intermediate = make_widget({
|
intermediate = make_widget({
|
||||||
make_child(child, 10, 20, cairo.Matrix.create_translate(0, 5))
|
make_child(child, 10, 20, matrix.create_translate(0, 5))
|
||||||
})
|
})
|
||||||
parent = make_widget({
|
parent = make_widget({
|
||||||
make_child(intermediate, 5, 2, cairo.Matrix.create_translate(4, 0))
|
make_child(intermediate, 5, 2, matrix.create_translate(4, 0))
|
||||||
})
|
})
|
||||||
|
|
||||||
local function nop() end
|
local function nop() end
|
||||||
|
@ -156,27 +152,27 @@ describe("wibox.hierarchy", function()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("get_matrix_to_parent", function()
|
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.equal(hierarchy_child:get_matrix_to_parent(), matrix.create_translate(0, 5))
|
||||||
assert.is_true(matrix.equals(hierarchy_intermediate:get_matrix_to_parent(), cairo.Matrix.create_translate(4, 0)))
|
assert.is.equal(hierarchy_intermediate:get_matrix_to_parent(), matrix.create_translate(4, 0))
|
||||||
assert.is_true(matrix.equals(hierarchy_parent:get_matrix_to_parent(), cairo.Matrix.create_identity()))
|
assert.is.equal(hierarchy_parent:get_matrix_to_parent(), matrix.identity)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("get_matrix_to_device", function()
|
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.equal(hierarchy_child:get_matrix_to_device(), matrix.create_translate(4, 5))
|
||||||
assert.is_true(matrix.equals(hierarchy_intermediate:get_matrix_to_device(), cairo.Matrix.create_translate(4, 0)))
|
assert.is.equal(hierarchy_intermediate:get_matrix_to_device(), matrix.create_translate(4, 0))
|
||||||
assert.is_true(matrix.equals(hierarchy_parent:get_matrix_to_device(), cairo.Matrix.create_identity()))
|
assert.is.equal(hierarchy_parent:get_matrix_to_device(), matrix.identity)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("get_matrix_from_parent", function()
|
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.equal(hierarchy_child:get_matrix_from_parent(), matrix.create_translate(0, -5))
|
||||||
assert.is_true(matrix.equals(hierarchy_intermediate:get_matrix_from_parent(), cairo.Matrix.create_translate(-4, 0)))
|
assert.is.equal(hierarchy_intermediate:get_matrix_from_parent(), matrix.create_translate(-4, 0))
|
||||||
assert.is_true(matrix.equals(hierarchy_parent:get_matrix_from_parent(), cairo.Matrix.create_identity()))
|
assert.is.equal(hierarchy_parent:get_matrix_from_parent(), matrix.identity)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("get_matrix_from_device", function()
|
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.equal(hierarchy_child:get_matrix_from_device(), matrix.create_translate(-4, -5))
|
||||||
assert.is_true(matrix.equals(hierarchy_intermediate:get_matrix_from_device(), cairo.Matrix.create_translate(-4, 0)))
|
assert.is.equal(hierarchy_intermediate:get_matrix_from_device(), matrix.create_translate(-4, 0))
|
||||||
assert.is_true(matrix.equals(hierarchy_parent:get_matrix_from_device(), cairo.Matrix.create_identity()))
|
assert.is.equal(hierarchy_parent:get_matrix_from_device(), matrix.identity)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("get_draw_extents", function()
|
it("get_draw_extents", function()
|
||||||
|
@ -199,10 +195,10 @@ describe("wibox.hierarchy", function()
|
||||||
before_each(function()
|
before_each(function()
|
||||||
child = make_widget(nil)
|
child = make_widget(nil)
|
||||||
intermediate = make_widget({
|
intermediate = make_widget({
|
||||||
make_child(child, 10, 20, cairo.Matrix.create_translate(0, 5))
|
make_child(child, 10, 20, matrix.create_translate(0, 5))
|
||||||
})
|
})
|
||||||
parent = make_widget({
|
parent = make_widget({
|
||||||
make_child(intermediate, 5, 2, cairo.Matrix.create_translate(4, 0))
|
make_child(intermediate, 5, 2, matrix.create_translate(4, 0))
|
||||||
})
|
})
|
||||||
|
|
||||||
local context = {}
|
local context = {}
|
||||||
|
@ -218,7 +214,7 @@ describe("wibox.hierarchy", function()
|
||||||
|
|
||||||
it("child moved", function()
|
it("child moved", function()
|
||||||
intermediate.layout = function()
|
intermediate.layout = function()
|
||||||
return { make_child(child, 10, 20, cairo.Matrix.create_translate(0, 4)) }
|
return { make_child(child, 10, 20, matrix.create_translate(0, 4)) }
|
||||||
end
|
end
|
||||||
local context = {}
|
local context = {}
|
||||||
local instance2 = hierarchy.new(context, parent, 15, 16, nop, nop)
|
local instance2 = hierarchy.new(context, parent, 15, 16, nop, nop)
|
||||||
|
|
Loading…
Reference in New Issue