imagebox: Support a CSS file.
Before, the CSS had to be inline. Now that the border container uses this code, it makes sense to make it more flexible.
This commit is contained in:
parent
5c9ffb8ef3
commit
ab121e9ac0
|
@ -31,12 +31,17 @@ local base = require("wibox.widget.base")
|
||||||
local surface = require("gears.surface")
|
local surface = require("gears.surface")
|
||||||
local gtable = require("gears.table")
|
local gtable = require("gears.table")
|
||||||
local gdebug = require("gears.debug")
|
local gdebug = require("gears.debug")
|
||||||
|
local gfs = require("gears.filesystem")
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
local type = type
|
local type = type
|
||||||
local math = math
|
local math = math
|
||||||
|
|
||||||
local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1)
|
local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1)
|
||||||
|
|
||||||
|
-- Placeholder table to represent an emty stylesheet.
|
||||||
|
-- It has to be defined here to avoid being GCed
|
||||||
|
local empty_stylesheet = {}
|
||||||
|
|
||||||
local policies_to_extents = {
|
local policies_to_extents = {
|
||||||
["pad"] = cairo.Extend.PAD,
|
["pad"] = cairo.Extend.PAD,
|
||||||
["repeat"] = cairo.Extend.REPEAT,
|
["repeat"] = cairo.Extend.REPEAT,
|
||||||
|
@ -55,18 +60,25 @@ end
|
||||||
local imagebox = { mt = {} }
|
local imagebox = { mt = {} }
|
||||||
|
|
||||||
local rsvg_handle_cache = setmetatable({}, { __mode = 'k' })
|
local rsvg_handle_cache = setmetatable({}, { __mode = 'k' })
|
||||||
|
local stylesheet_cache = {}
|
||||||
|
|
||||||
--Load rsvg handle form image file
|
--Load rsvg handle form image file
|
||||||
-- @tparam string file Path to svg file.
|
-- @tparam string file Path to svg file.
|
||||||
-- @return Rsvg handle
|
-- @return Rsvg handle
|
||||||
-- @treturn table A table where cached data can be stored.
|
-- @treturn table A table where cached data can be stored.
|
||||||
function imagebox._load_rsvg_handle(file)
|
function imagebox._load_rsvg_handle(file, style)
|
||||||
|
-- Make sure this is called in the right order.
|
||||||
|
assert((not style) or (style and stylesheet_cache[style]))
|
||||||
|
|
||||||
|
local style_ref = style and stylesheet_cache[style] or empty_stylesheet
|
||||||
|
|
||||||
if not Rsvg then return end
|
if not Rsvg then return end
|
||||||
|
|
||||||
local cache = (rsvg_handle_cache[file] or {})["handle"]
|
local bucket = rsvg_handle_cache[file] or {}
|
||||||
|
local cache = (bucket[style_ref] or {})["handle"]
|
||||||
|
|
||||||
if cache then
|
if cache then
|
||||||
return cache, rsvg_handle_cache[file]
|
return cache, bucket[style_ref]
|
||||||
end
|
end
|
||||||
|
|
||||||
local handle, err
|
local handle, err
|
||||||
|
@ -78,9 +90,10 @@ function imagebox._load_rsvg_handle(file)
|
||||||
end
|
end
|
||||||
|
|
||||||
if not err then
|
if not err then
|
||||||
rsvg_handle_cache[file] = rsvg_handle_cache[file] or {}
|
rsvg_handle_cache[file] = rsvg_handle_cache[file] or setmetatable({}, {__mode = "k"})
|
||||||
rsvg_handle_cache[file]["handle"] = handle
|
rsvg_handle_cache[file][style_ref] = rsvg_handle_cache[file][style_ref] or {}
|
||||||
return handle, rsvg_handle_cache[file]
|
rsvg_handle_cache[file][style_ref]["handle"] = handle
|
||||||
|
return handle, rsvg_handle_cache[file][style_ref]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -117,7 +130,7 @@ end
|
||||||
---@treturn boolean True if image was successfully applied
|
---@treturn boolean True if image was successfully applied
|
||||||
local function load_and_apply(ib, file, image_loader, image_setter)
|
local function load_and_apply(ib, file, image_loader, image_setter)
|
||||||
local image_applied
|
local image_applied
|
||||||
local object, cache = image_loader(file)
|
local object, cache = image_loader(file, ib._private.stylesheet_og)
|
||||||
|
|
||||||
if object then
|
if object then
|
||||||
image_applied = image_setter(ib, object, cache)
|
image_applied = image_setter(ib, object, cache)
|
||||||
|
@ -125,6 +138,38 @@ local function load_and_apply(ib, file, image_loader, image_setter)
|
||||||
return image_applied
|
return image_applied
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Support both CSS data and filepath for the stylsheet.
|
||||||
|
function imagebox._get_stylesheet(self, content_or_path)
|
||||||
|
if not content_or_path then return nil end
|
||||||
|
|
||||||
|
-- Always set the entry because the image cache uses it.
|
||||||
|
stylesheet_cache[content_or_path] = stylesheet_cache[content_or_path]
|
||||||
|
or setmetatable({}, {__mode = "v"})
|
||||||
|
|
||||||
|
if gfs.file_readable(content_or_path) then
|
||||||
|
local ret
|
||||||
|
|
||||||
|
local _, obj = next(stylesheet_cache[content_or_path])
|
||||||
|
|
||||||
|
if obj then
|
||||||
|
ret = obj._private.stylesheet
|
||||||
|
table.insert(stylesheet_cache[content_or_path], self)
|
||||||
|
else
|
||||||
|
local f = io.open(content_or_path, 'r')
|
||||||
|
|
||||||
|
if not f then return nil end
|
||||||
|
|
||||||
|
ret = f:read("*all")
|
||||||
|
f:close()
|
||||||
|
table.insert(stylesheet_cache[content_or_path], self)
|
||||||
|
end
|
||||||
|
|
||||||
|
return ret
|
||||||
|
else
|
||||||
|
return content_or_path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
---Update the cached size depending on the stylesheet and dpi.
|
---Update the cached size depending on the stylesheet and dpi.
|
||||||
--
|
--
|
||||||
-- It's necessary because a single RSVG handle can be used by
|
-- It's necessary because a single RSVG handle can be used by
|
||||||
|
@ -443,8 +488,7 @@ end
|
||||||
-- If the image is an SVG (vector graphics), this property allows to set
|
-- If the image is an SVG (vector graphics), this property allows to set
|
||||||
-- a CSS stylesheet. It can be used to set colors and much more.
|
-- a CSS stylesheet. It can be used to set colors and much more.
|
||||||
--
|
--
|
||||||
-- Note that this property is a string, not a path. If the stylesheet is
|
-- The value can be either CSS data or a file path.
|
||||||
-- stored on disk, read the content first.
|
|
||||||
--
|
--
|
||||||
--@DOC_wibox_widget_imagebox_stylesheet_EXAMPLE@
|
--@DOC_wibox_widget_imagebox_stylesheet_EXAMPLE@
|
||||||
--
|
--
|
||||||
|
@ -483,18 +527,47 @@ end
|
||||||
-- @propemits true false
|
-- @propemits true false
|
||||||
-- @see dpi
|
-- @see dpi
|
||||||
|
|
||||||
for _, prop in ipairs {"stylesheet", "dpi", "auto_dpi"} do
|
for _, prop in ipairs {"dpi", "auto_dpi"} do
|
||||||
imagebox["set_" .. prop] = function(self, value)
|
imagebox["set_" .. prop] = function(self, value)
|
||||||
|
local old = self._private[prop]
|
||||||
|
|
||||||
-- It will be set in :fit and :draw. The handle is shared
|
-- It will be set in :fit and :draw. The handle is shared
|
||||||
-- by multiple imagebox, so it cannot be set just once.
|
-- by multiple imagebox, so it cannot be set just once.
|
||||||
self._private[prop] = value
|
self._private[prop] = value
|
||||||
|
|
||||||
self:emit_signal("widget::redraw_needed")
|
self:emit_signal("widget::redraw_needed")
|
||||||
self:emit_signal("widget::layout_changed")
|
self:emit_signal("widget::layout_changed")
|
||||||
self:emit_signal("property::" .. prop)
|
self:emit_signal("property::" .. prop, value, old)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function imagebox:set_stylesheet(value)
|
||||||
|
if value == self._private.stylesheet_og then return end
|
||||||
|
|
||||||
|
local old = self._private.stylesheet_og
|
||||||
|
|
||||||
|
if old and stylesheet_cache[old] then
|
||||||
|
for k, v in ipairs(stylesheet_cache[old]) do
|
||||||
|
if self == v then
|
||||||
|
table.remove(stylesheet_cache[old], k)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local content = imagebox._get_stylesheet(self, value)
|
||||||
|
|
||||||
|
self._private.stylesheet = content
|
||||||
|
self._private.stylesheet_og = value
|
||||||
|
|
||||||
|
-- Refresh the pixmap.
|
||||||
|
self.image = self._private.original_image
|
||||||
|
|
||||||
|
self:emit_signal("widget::redraw_needed")
|
||||||
|
self:emit_signal("widget::layout_changed")
|
||||||
|
self:emit_signal("property::stylesheet", value)
|
||||||
|
end
|
||||||
|
|
||||||
function imagebox:set_resize(allowed)
|
function imagebox:set_resize(allowed)
|
||||||
self._private.resize = allowed
|
self._private.resize = allowed
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue