From 730b0f5c5c39fabadc78ab1d1f9331d6256d1533 Mon Sep 17 00:00:00 2001 From: hung Date: Fri, 1 May 2020 15:17:14 +0700 Subject: [PATCH 1/2] gears.math: add the sign function --- lib/gears/math.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/gears/math.lua b/lib/gears/math.lua index 61c19d004..db295f673 100644 --- a/lib/gears/math.lua +++ b/lib/gears/math.lua @@ -76,5 +76,19 @@ function gmath.round(x) return math.floor(x + 0.5) end +--- Return the sign of the number x +-- return 1 if x is positive, -1 if negative and 0 if x is 0 +-- @tparam number x +-- @treturn integer +-- @staticfct gears.math.sign +function gmath.sign(x) + if x > 0 then + return 1 + elseif x < 0 then + return -1 + else + return 0 + end +end return gmath From fdee02cdcf63fb672efe9c168ecfc819f96cf28f Mon Sep 17 00:00:00 2001 From: hung Date: Fri, 1 May 2020 15:18:10 +0700 Subject: [PATCH 2/2] gears.shape: new shape (partial) squircle --- lib/gears/shape.lua | 123 ++++++++++++++++++ .../examples/gears/shape/partial_squircle.lua | 13 ++ tests/examples/gears/shape/squircle.lua | 13 ++ 3 files changed, 149 insertions(+) create mode 100644 tests/examples/gears/shape/partial_squircle.lua create mode 100644 tests/examples/gears/shape/squircle.lua diff --git a/lib/gears/shape.lua b/lib/gears/shape.lua index ac12f58b2..0b8db9260 100644 --- a/lib/gears/shape.lua +++ b/lib/gears/shape.lua @@ -41,14 +41,137 @@ -- @themelib gears.shape --------------------------------------------------------------------------- local g_matrix = require( "gears.matrix" ) +local g_math = require( "gears.math" ) local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1) local atan2 = math.atan2 or math.atan -- lua 5.3 compat local min = math.min +local max = math.max local cos = math.cos local sin = math.sin +local abs = math.abs +local pow = math.pow -- luacheck: globals math.pow +if not pow then + -- math.pow can be disabled in Lua 5.3 via LUA_COMPAT_MATHLIB + pow = function(x, y) + return x^y + end +end local module = {} +--- Add a squircle shape with only some of the corner are "circled" to the current path. +-- The squircle is not exactly as the definition. +-- It will expand to the shape's width and height, kinda like an ellipse +-- +-- @DOC_gears_shape_partial_squircle_EXAMPLE@ +-- +-- @param cr A cairo context +-- @tparam number width The shape width +-- @tparam number height The shape height +-- @tparam boolean tl If the top left corner is rounded +-- @tparam boolean tr If the top right corner is rounded +-- @tparam boolean br If the bottom right corner is rounded +-- @tparam boolean bl If the bottom left corner is rounded +-- @tparam number rate The "squareness" of the squircle, should be greater than 1 +-- @tparam number delta The "smoothness" of the shape, delta must be greater than 0.01 and will be reset to 0.01 if not +-- @staticfct gears.shape.partial_squircle +function module.partial_squircle(cr, width, height, tl, tr, br, bl, rate, delta) + -- rate ~ 2 can be used by icon + -- this shape doesn't really fit clients + -- but you can still use with rate ~ 32 + rate = rate or 2 + -- smaller the delta the smoother the shape + -- but probably more laggy + -- so we'll limit delta to the miminum of 0.01 + -- so people don't burn their computer + delta = delta or 1 / max(width, height) + delta = delta > 0.01 and delta or 0.01 + + -- just ellipse things + local a = width / 2 + local b = height / 2 + local phi = 0 + + -- move to origin + -- the shape goes counter clock wise + -- start from (w h / 2) + cr:save() + cr:translate(a, b) + cr:move_to(a, 0) + + -- draw the corner if that corner is rounded + local curved_corner = function() + local end_angle = phi + math.pi / 2 + while phi < end_angle do + local cosphi = cos(phi) + local sinphi = sin(phi) + local x = a * pow(abs(cosphi), 1 / rate) * g_math.sign(cosphi) + local y = b * pow(abs(sinphi), 1 / rate) * g_math.sign(sinphi) + -- so weird, y axis is inverted + cr:line_to(x, -y) + phi = phi + delta + end + end + + -- draw with polar cord + -- draw top right + if tr then + curved_corner() + else + cr:move_to(a, 0) + cr:line_to(a, -b) + cr:line_to(0, -b) + phi = math.pi * 0.5 + end + + -- draw top left + if tl then + curved_corner() + else + cr:line_to(-a, -b) + cr:line_to(-a, 0) + phi = math.pi + end + + if bl then + curved_corner() + else + cr:line_to(-a, b) + cr:line_to( 0, b) + phi = math.pi * 1.5 + end + + -- bottom right + if br then + curved_corner() + else + cr:line_to(a, b) + cr:line_to(a, 0) + phi = math.pi * 2 + end + + -- it's time to stop + cr:close_path() + + -- restore cairo context + cr:restore() +end + +--- Add a squircle shape to the current path. +-- This will behave the same as `partial_squircle` +-- +-- @DOC_gears_shape_squircle_EXAMPLE@ +-- +-- @param cr A cairo context +-- @tparam number width The shape width +-- @tparam number height The shape height +-- @tparam number rate The "squareness" of the squircle, should be greater than 1 +-- @tparam number delta The "smoothness" of the shape, delta must be greater than 0.01 and will be reset to 0.01 if not +-- @staticfct gears.shape.squircle +function module.squircle(cr, width, height, rate, delta) + module.partial_squircle(cr, width, height, true, true, true, true, rate, delta) +end + --- Add a star shape to the current path. -- The star size will be the minimum of the given width and weight -- diff --git a/tests/examples/gears/shape/partial_squircle.lua b/tests/examples/gears/shape/partial_squircle.lua new file mode 100644 index 000000000..bbf336c23 --- /dev/null +++ b/tests/examples/gears/shape/partial_squircle.lua @@ -0,0 +1,13 @@ +--DOC_GEN_IMAGE --DOC_HIDE +local shape,cr,show = ... --DOC_HIDE + +shape.partial_squircle(cr, 70, 70, false, true) +show(cr) --DOC_HIDE + +shape.partial_squircle(cr, 70, 70, true, false, true) +show(cr) --DOC_HIDE + +shape.partial_squircle(cr, 70, 70, true, false, true, true) +show(cr) --DOC_HIDE + +--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/tests/examples/gears/shape/squircle.lua b/tests/examples/gears/shape/squircle.lua new file mode 100644 index 000000000..7aa0692be --- /dev/null +++ b/tests/examples/gears/shape/squircle.lua @@ -0,0 +1,13 @@ +--DOC_GEN_IMAGE --DOC_HIDE +local shape,cr,show = ... --DOC_HIDE + +shape.squircle(cr, 70, 70, 2) +show(cr) --DOC_HIDE + +shape.squircle(cr, 70, 70, 8) +show(cr) --DOC_HIDE + +shape.squircle(cr, 70, 70, 1.5) +show(cr) --DOC_HIDE + +--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80