Merge pull request #655 from Elv13/upstream_shape_api_p3

Add various methods to improve the new shape API
This commit is contained in:
Emmanuel Lepage Vallée 2016-02-02 04:06:31 -05:00
commit 502c3631d2
4 changed files with 233 additions and 7 deletions

View File

@ -52,6 +52,22 @@ function matrix.create_rotate(angle)
return matrix.create(c, s, -s, c, 0, 0)
end
--- Create a matrix copy
-- @return A new matrix identical to `other`
function matrix:copy()
local m = matrix.create(
self.xx, self.yx, self.xy,
self.yy, self.x0, self.y0
)
-- Used internally
if rawget(self, "_call") then
rawset(m, "_call", self._call)
end
return m
end
--- Translate this matrix
-- @tparam number x The translation in x direction.
-- @tparam number y The translation in y direction.
@ -75,6 +91,17 @@ function matrix:rotate(angle)
return matrix.create_rotate(angle):multiply(self)
end
--- Rotate a shape from a custom point
-- @tparam number x The horizontal rotation point
-- @tparam number y The vertical rotation point
-- @tparam number angle The angle (in radiant: -2*math.pi to 2*math.pi)
-- @return A transformation object
function matrix:rotate_at(x, y, angle)
return self * matrix.create_translate( -x, -y )
* matrix.create_rotate ( angle )
* matrix.create_translate( x, y )
end
--- Invert this matrix
-- @return A new matrix describing the inverse transformation.
function matrix:invert()
@ -94,12 +121,19 @@ end
-- @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,
local ret = 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)
-- Used internally
if rawget(self, "_call") or rawget(other, "_call") then
rawset(ret, "_call", self._call or other._call)
end
return ret
end
--- Check if two matrices are equal.
@ -189,6 +223,7 @@ matrix_mt.__newindex = error
matrix_mt.__eq = matrix.equals
matrix_mt.__mul = matrix.multiply
matrix_mt.__tostring = matrix.tostring
matrix_mt.__call = function(self, ...) return self._call(self, ...) end
--- A constant for the identity matrix.
matrix.identity = matrix.create(1, 0, 0, 1, 0, 0)

View File

@ -21,6 +21,7 @@
-- @release @AWESOME_VERSION@
-- @module gears.shape
---------------------------------------------------------------------------
local g_matrix = require( "gears.matrix" )
local module = {}
@ -55,4 +56,142 @@ function module.rounded_bar(cr, width, height)
module.rounded_rect(cr, width, height, height / 2)
end
--- A rounded rectangle with a triangle at the top
-- @param cr A cairo context
-- @tparam number width The shape with
-- @tparam number height The shape height
-- @tparam[opt=5] number corner_radius The corner radius
-- @tparam[opt=10] number arrow_size The width and height of the arrow
-- @tparam[opt=width/2 - arrow_size/2] number arrow_position The position of the arrow
function module.infobubble(cr, width, height, corner_radius, arrow_size, arrow_position)
local corner_radius = corner_radius or 5
local arrow_size = arrow_size or 10
local arrow_position = arrow_position or width/2 - arrow_size/2
cr:move_to(0 ,corner_radius)
-- Top left corner
cr:arc(corner_radius, corner_radius+arrow_size, (corner_radius), math.pi, 3*(math.pi/2))
-- The arrow triangle (still at the top)
cr:line_to(arrow_position , arrow_size )
cr:line_to(arrow_position + arrow_size , 0 )
cr:line_to(arrow_position + 2*arrow_size , arrow_size )
-- Complete the rounded rounded rectangle
cr:arc(width-corner_radius, corner_radius+arrow_size , (corner_radius) , 3*(math.pi/2) , math.pi*2 )
cr:arc(width-corner_radius, height-(corner_radius) , (corner_radius) , math.pi*2 , math.pi/2 )
cr:arc(corner_radius , height-(corner_radius) , (corner_radius) , math.pi/2 , math.pi )
-- Close path
cr:close_path()
end
--- A rectangle terminated by an arrow
-- @param cr A cairo context
-- @tparam number width The shape with
-- @tparam number height The shape height
function module.rectangular_tag(cr, width, height)
cr:move_to(0 , height/2)
cr:line_to(height/2 , 0 )
cr:line_to(width , 0 )
cr:line_to(width , height )
cr:line_to(height/2 , height )
cr:close_path()
end
--- A simple arrow shape
-- @param cr A cairo context
-- @tparam number width The shape with
-- @tparam number height The shape height
-- @tparam[opt=head_width] number head_width The width of the head (/\) of the arrow
-- @tparam[opt=width /2] number shaft_width The width of the shaft of the arrow
-- @tparam[opt=height/2] number shaft_length The head_length of the shaft (the rest is the head)
function module.arrow(cr, width, height, head_width, shaft_width, shaft_length)
local shaft_length = shaft_length or height / 2
local shaft_width = shaft_width or width / 2
local head_width = head_width or width
local head_length = height - shaft_length
cr:move_to ( width/2 , 0 )
cr:rel_line_to( head_width/2 , head_length )
cr:rel_line_to( -(head_width-shaft_width)/2 , 0 )
cr:rel_line_to( 0 , shaft_length )
cr:rel_line_to( -shaft_width , 0 )
cr:rel_line_to( 0 , -shaft_length )
cr:rel_line_to( -(head_width-shaft_width)/2 , 0 )
cr:close_path()
end
--- A squeezed hexagon filling the rectangle
-- @param cr A cairo context
-- @tparam number width The shape with
-- @tparam number height The shape height
function module.hexagon(cr, width, height)
cr:move_to(height/2,0)
cr:line_to(width-height/2,0)
cr:line_to(width,height/2)
cr:line_to(width-height/2,height)
cr:line_to(height/2,height)
cr:line_to(0,height/2)
cr:line_to(height/2,0)
cr:close_path()
end
--- Double arrow popularized by the vim-powerline module
-- @param cr A cairo context
-- @tparam number width The shape with
-- @tparam number height The shape height
-- @tparam[opt=height/2] number arrow_depth The width of the arrow part of the shape
function module.powerline(cr, width, height, arrow_depth)
local arrow_depth = arrow_depth or height/2
cr:move_to(0 , 0 )
cr:line_to(width - arrow_depth , 0 )
cr:line_to(width , height/2 )
cr:line_to(width - arrow_depth , height )
cr:line_to(0 , height )
cr:line_to(arrow_depth , height/2 )
cr:close_path()
end
--- An isosceles triangle
-- @param cr A cairo context
-- @tparam number width The shape with
-- @tparam number height The shape height
function module.isosceles_triangle(cr, width, height)
cr:move_to( width/2, 0 )
cr:line_to( width , height )
cr:line_to( 0 , height )
cr:close_path()
end
--- Ajust the shape using a transformation object
--
-- Apply various transformations to the shape
--
-- @usage gears.shape.transform(gears.shape.rounded_bar)
-- : rotate(math.pi/2)
-- : translate(10, 10)
--
-- @param shape A shape function
-- @return A transformation handle, also act as a shape function
function module.transform(shape)
-- Apply the transformation matrix and apply the shape, then restore
local function apply(self, cr, width, height, ...)
cr:save()
cr:transform(self:to_cairo_matrix())
shape(cr, width, height, ...)
cr:restore()
end
local matrix = g_matrix.identity:copy()
rawset(matrix, "_call", apply)
return matrix
end
return module

View File

@ -9,6 +9,7 @@ local setmetatable = setmetatable
local type = type
local capi = { awesome = awesome }
local cairo = require("lgi").cairo
local color = nil
local gdebug = require("gears.debug")
-- Keep this in sync with build-utils/lgi-check.sh!
@ -152,6 +153,32 @@ function surface.duplicate_surface(s)
return result
end
--- Create a surface from a `gears.shape`
-- Any additional parameters will be passed to the shape function
-- @tparam number width The surface width
-- @tparam number height The surface height
-- @param shape A `gears.shape` compatible function
-- @param[opt=white] shape_color The shape color or pattern
-- @param[opt=transparent] bg_color The surface background color
-- @treturn cairo.surface the new surface
function surface.load_from_shape(width, height, shape, shape_color, bg_color, ...)
color = color or require("gears.color")
local img = cairo.ImageSurface(cairo.Format.ARGB32, width, height)
local cr = cairo.Context(img)
cr:set_source(color(bg_color or "#00000000"))
cr:paint()
cr:set_source(color(shape_color or "#000000"))
shape(cr, width, height, ...)
cr:fill()
return img
end
--- Apply a shape to a client or a wibox.
--
-- If the wibox or client size change, this function need to be called

View File

@ -12,6 +12,7 @@ local pairs = pairs
local type = type
local pcall = pcall
local print = print
local unpack = unpack or table.unpack
local imagebox = { mt = {} }
@ -30,6 +31,12 @@ function imagebox:draw(context, cr, width, height)
cr:scale(aspect, aspect)
end
-- Set the clip
if self._clip_shape then
cr:clip(self._clip_shape(cr, width, height, unpack(self._clip_args)))
end
cr:set_source_surface(self._image, 0, 0)
cr:paint()
end
@ -107,6 +114,19 @@ function imagebox:set_image(image)
return true
end
--- Set a clip shape for this imagebox
-- A clip shape define an area where the content is displayed and one where it
-- is trimmed.
--
-- Any other parameters will be passed to the clip shape function
--
-- @param clip_shape A `gears_shape` compatible shape function
function imagebox:set_clip_shape(clip_shape, ...)
self._clip_shape = clip_shape
self._clip_args = {...}
self:emit_signal("widget::redraw_needed")
end
--- Should the image be resized to fit into the available space?
-- @param allowed If false, the image will be clipped, else it will be resized
-- to fit into the available space.
@ -117,10 +137,12 @@ function imagebox:set_resize(allowed)
end
--- Returns a new imagebox
-- Any other arguments will be passed to the clip shape function
-- @param image the image to display, may be nil
-- @param resize_allowed If false, the image will be clipped, else it will be resized
-- to fit into the available space.
local function new(image, resize_allowed)
-- @param clip_shape A `gears.shape` compatible function
local function new(image, resize_allowed, clip_shape)
local ret = base.make_widget()
for k, v in pairs(imagebox) do
@ -136,6 +158,9 @@ local function new(image, resize_allowed)
ret:set_resize(resize_allowed)
end
ret._clip_shape = clip_shape
ret._clip_args = {}
return ret
end