2022-08-31 12:20:58 +00:00
-- This file is part of Reno desktop.
--
-- Reno desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
--
-- Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see <https://www.gnu.org/licenses/>.
2022-08-21 12:28:28 +00:00
-- RenoTK (formerly AWMTK2) - Template/Granular styling library for Reno
2022-07-12 21:26:11 +00:00
local wibox = require ( " wibox " )
local awful = require ( " awful " )
local gears = require ( " gears " )
local beautiful = require ( " beautiful " )
2022-09-05 21:54:11 +00:00
beautiful.widgets = beautiful.widgets or { }
beautiful.templates = beautiful.templates or { }
2022-07-12 21:26:11 +00:00
local awmtk = { }
-- {{{ Utils
2022-08-11 19:34:25 +00:00
awmtk.create_delta = function ( name , instance_delta , class_delta , parent_delta )
2022-07-23 19:10:02 +00:00
-- To save memory, we create proxies for lower layers called "deltas"
-- This function creates that proxy layer using metatables
2022-08-11 19:34:25 +00:00
-- Fun story - i used instance_delta instead of {} at first.
-- The results were horrifying and confusing.
return setmetatable ( { } , {
2022-07-12 21:26:11 +00:00
__index = function ( self , k )
2022-07-23 19:10:02 +00:00
-- Per-instance overrides are top priority
2022-08-11 19:34:25 +00:00
if rawget ( instance_delta , k ) then
return rawget ( instance_delta , k )
2022-07-23 19:10:02 +00:00
-- Class-wide overrides are second in priority
elseif type ( class_delta [ name ] ) == " table "
and rawget ( class_delta [ name ] , k ) then
return rawget ( class_delta [ name ] , k )
-- Parent is fallback
elseif parent_delta [ k ] then
return parent_delta [ k ]
2022-07-12 21:26:11 +00:00
end
end
} )
end
2022-07-23 19:10:02 +00:00
awmtk.create_style = function ( name , parent , overrides )
-- A style is essentially a layer of deltas upon the previous (parent) style
2022-07-12 21:26:11 +00:00
local new_style = { }
2022-08-11 19:34:25 +00:00
local odelta = ( overrides and overrides [ name ] ) or { }
2022-09-05 21:54:11 +00:00
local cdelta = beautiful.widgets [ name ] or { }
2022-07-12 21:26:11 +00:00
for name , parent_class in pairs ( parent ) do
2022-07-23 19:10:02 +00:00
new_style [ name ] = awmtk.create_delta (
2022-07-12 21:26:11 +00:00
name ,
2022-08-11 19:34:25 +00:00
odelta ,
cdelta ,
2022-07-12 21:26:11 +00:00
parent_class
)
end
return new_style
end
2022-07-23 19:10:02 +00:00
awmtk.create_template_lib = function ( name , parent , overrides )
-- same thing but beautiful.templates
return awmtk.create_delta (
name ,
overrides or { } ,
beautiful.templates or { } ,
parent
)
end
awmtk.build_templates = function ( templates , style )
local new_templates = { }
2022-08-11 19:34:25 +00:00
for name , template in pairs ( awmtk.proto_templates ) do
2022-07-23 19:10:02 +00:00
new_templates [ name ] = templates [ name ] ( style )
end
return new_templates
end
2022-08-21 12:28:28 +00:00
awmtk.merge = gears.table . join
2022-07-12 21:26:11 +00:00
-- }}}
-- {{{ Default style
2022-08-21 12:28:28 +00:00
-- Prototype style
-- Notice that it's not awmtk.default style - it's used as a base for default.
2022-08-11 19:34:25 +00:00
awmtk.proto_style = {
2022-07-12 21:26:11 +00:00
base = setmetatable ( {
-- { Backgrounds
-- custom background color for highlighting elements
bg_highlight = beautiful.bg_highlight or beautiful.bg_focus ,
2022-08-11 19:34:25 +00:00
-- allow more complex themes to define background images
bgimage_focus = beautiful.bgimage_focus ,
bgimage_normal = beautiful.bgimage_normal ,
2022-07-12 21:26:11 +00:00
-- }
-- { Borders
-- Borders for popups
shape_border_width = beautiful.shape_border_width or 0 ,
shape_border_color = beautiful.shape_border_color or beautiful.bg_normal ,
2022-08-21 12:28:28 +00:00
-- }
2022-08-11 19:34:25 +00:00
-- { Callbacks
-- a tiny bit more complex thing to account for more extensibility
-- the stub functions do nothing - you should implement functionality inside theme
onpress = function ( ) end ,
onrelease = function ( ) end ,
-- }
2022-07-12 21:26:11 +00:00
-- { Shapes
2022-07-23 19:10:02 +00:00
margins = 5 ,
spacing = 5 ,
shape = function ( cr , width , height )
return require ( " gears " ) . shape.rounded_rect ( cr , width , height , 5 )
end ,
2022-07-12 21:26:11 +00:00
-- }
} , { __index = beautiful } )
}
2022-07-23 19:10:02 +00:00
-- Subclasses
2022-08-11 19:34:25 +00:00
awmtk.proto_style . container = awmtk.create_delta ( " container " , {
} , awmtk.proto_style , awmtk.proto_style . base )
2022-07-12 21:26:11 +00:00
2022-08-11 19:34:25 +00:00
awmtk.proto_style . button = awmtk.create_delta ( " button " , {
2022-07-23 19:10:02 +00:00
margins = 3
2022-08-11 19:34:25 +00:00
} , awmtk.proto_style , awmtk.proto_style . base )
2022-07-12 21:26:11 +00:00
2022-08-11 19:34:25 +00:00
awmtk.proto_style . icon = awmtk.create_delta ( " icon " , {
2022-07-23 19:10:02 +00:00
margins = 1
2022-08-11 19:34:25 +00:00
} , awmtk.proto_style , awmtk.proto_style . base )
2022-07-12 21:26:11 +00:00
2022-08-11 19:34:25 +00:00
awmtk.proto_style . textbox = awmtk.create_delta ( " textbox " , {
2022-07-23 19:10:02 +00:00
font = beautiful.font or " sans 8 "
2022-08-11 19:34:25 +00:00
} , awmtk.proto_style , awmtk.proto_style . base )
2022-07-23 19:10:02 +00:00
2022-08-11 19:34:25 +00:00
awmtk.proto_style . separator = awmtk.create_delta ( " separator " , {
2022-07-23 19:10:02 +00:00
thickness = 1 ,
color = beautiful.bg_focus ,
border_width = 0
2022-08-11 19:34:25 +00:00
} , awmtk.proto_style , awmtk.proto_style . base )
2022-07-23 19:10:02 +00:00
2022-08-11 19:34:25 +00:00
awmtk.proto_style . article = awmtk.create_delta ( " article " , {
2022-07-23 19:10:02 +00:00
icon_size = 16 ,
2022-08-11 19:34:25 +00:00
small_font = beautiful.small_font or beautiful.font ,
2022-07-23 19:10:02 +00:00
font_align = " left " ,
small_font_align = " left "
2022-08-11 19:34:25 +00:00
} , awmtk.proto_style , awmtk.proto_style . base )
2022-07-23 19:10:02 +00:00
2022-08-11 19:34:25 +00:00
awmtk.proto_style . popup = awmtk.create_delta ( " popup " , {
} , awmtk.proto_style , awmtk.proto_style . base )
awmtk.proto_style . titlebar = awmtk.create_delta ( " titlebar " , {
margins = 1
} , awmtk.proto_style , awmtk.proto_style . base )
2022-08-21 12:28:28 +00:00
awmtk.proto_style . wibar = awmtk.create_delta ( " wibar " , {
margins = 1
} , awmtk.proto_style , awmtk.proto_style . base )
2022-08-23 13:03:15 +00:00
awmtk.proto_style . menu = awmtk.create_delta ( " menu " , {
margins = 1
} , awmtk.proto_style , awmtk.proto_style . base )
2022-08-30 07:00:35 +00:00
awmtk.proto_style . center = awmtk.create_delta ( " center " , {
margins = 1
} , awmtk.proto_style , awmtk.proto_style . base )
awmtk.proto_style . slider = awmtk.create_delta ( " slider " , {
margins = 1
} , awmtk.proto_style , awmtk.proto_style . base )
2022-08-11 19:34:25 +00:00
-- }}}
2022-07-12 21:26:11 +00:00
2022-07-23 19:10:02 +00:00
-- {{{ Generic templates
2022-08-11 19:34:25 +00:00
awmtk.proto_templates = {
2022-07-23 19:10:02 +00:00
-- Templates are built first using the given style, then applied to contents
-- through returned function
container = function ( style )
2022-08-11 19:34:25 +00:00
-- Container is practically any "box" that contains buttons, textboxes,
-- and anything you want to put into the container. Do not confuse with
-- popup - containers are designed to separate contents within a popup.
2022-07-23 19:10:02 +00:00
return function ( layout , options )
return awmtk.merge ( {
{
layout ,
2022-08-21 12:28:28 +00:00
margins = style.container . margins ,
layout = wibox.container . margin
2022-07-23 19:10:02 +00:00
} ,
2022-08-11 19:34:25 +00:00
bgimage = style.container . bgimage ,
2022-07-23 19:10:02 +00:00
bg = style.container . bg_normal ,
shape = style.container . shape ,
widget = wibox.container . background
} , options or { } )
end
end ,
button = function ( style )
2022-08-11 19:34:25 +00:00
-- Self explanatory. Notice that this does not bear any function -
-- only the visual part of the button. By design, onpress and onrelease
-- callbacks should be connected to button events for animations
2022-07-23 19:10:02 +00:00
return function ( layout , options )
return awmtk.merge ( {
{
layout ,
2022-08-21 12:28:28 +00:00
margins = style.button . margins ,
layout = wibox.container . margin
2022-07-23 19:10:02 +00:00
} ,
2022-08-11 19:34:25 +00:00
bgimage = style.button . bgimage ,
2022-07-23 19:10:02 +00:00
bg = style.button . bg_normal ,
shape = style.button . shape ,
widget = wibox.container . background
} , options or { } )
end
end ,
textbox = function ( style )
2022-08-11 19:34:25 +00:00
-- Nothing fancy here, but you can set per-widget fonts using beautiful.
2022-07-23 19:10:02 +00:00
return function ( options )
return awmtk.merge ( {
font = style.textbox . font ,
widget = wibox.widget . textbox
} , options or { } )
end
end ,
hseparator = function ( style )
2022-08-11 19:34:25 +00:00
-- Wow, i guess?
2022-07-23 19:10:02 +00:00
return function ( options )
2022-08-11 19:34:25 +00:00
return awmtk.merge ( {
2022-07-23 19:10:02 +00:00
widget = wibox.widget . separator ,
orientation = " horizontal " ,
thickness = style.separator . thickness ,
color = style.separator . color ,
border_width = style.separator . border_width
} , options or { } )
end
end ,
vseparator = function ( style )
2022-08-11 19:34:25 +00:00
-- I'm running out of comments
2022-07-23 19:10:02 +00:00
return function ( options )
2022-08-11 19:34:25 +00:00
return awmtk.merge ( {
2022-07-23 19:10:02 +00:00
widget = wibox.widget . separator ,
orientation = " vertical " ,
thickness = style.separator . thickness ,
color = style.separator . color ,
border_width = style.separator . border_width
} , options or { } )
end
end ,
article = function ( style )
2022-08-11 19:34:25 +00:00
-- Article is a template that combines 3 common pieces of a full item:
-- Icon, name and description. Designed to be placed within a container
2022-08-23 13:03:15 +00:00
-- or a button.
2022-07-23 19:10:02 +00:00
return function ( options )
return awmtk.merge ( {
( options.icon and {
{
{
image = options.icon ,
2022-08-21 12:28:28 +00:00
id = options.icon_id ,
2022-07-23 19:10:02 +00:00
resize = options.resize ,
widget = wibox.widget . imagebox
} ,
strategy = " exact " ,
height = options.icon_size or
style.article . icon_size ,
width = options.icon_size or
style.article . icon_size ,
widget = wibox.container . constraint
} ,
widget = wibox.container . place ,
valign = " center " ,
halign = " center "
} ) ,
{
{
markup = options.title or " " ,
2022-08-21 12:28:28 +00:00
id = options.title_id ,
2022-07-23 19:10:02 +00:00
widget = wibox.widget . textbox ,
2022-08-21 12:28:28 +00:00
font = style.article . font ,
2022-07-23 19:10:02 +00:00
align = options.font_align or
style.article . font_align ,
2022-08-30 07:00:35 +00:00
valign = style.article . title_valign or " center " ,
align = style.article . title_align or " left "
2022-07-23 19:10:02 +00:00
} ,
( options.description and {
2022-08-21 12:28:28 +00:00
markup = options.description or " " ,
id = options.desc_id ,
2022-07-23 19:10:02 +00:00
widget = wibox.widget . textbox ,
2022-08-21 12:28:28 +00:00
font = style.article . small_font ,
2022-07-23 19:10:02 +00:00
align = options.small_font_align or
style.article . small_font_align ,
2022-08-30 07:00:35 +00:00
valign = style.article . desc_valign or " center " ,
align = style.article . desc_align or " left "
2022-07-23 19:10:02 +00:00
} ) ,
spacing = style.article . spacing ,
layout = wibox.layout . flex.vertical
} ,
spacing = style.article . spacing ,
layout = wibox.layout . fixed.horizontal ,
} , options or { } )
end
end ,
2022-08-30 07:00:35 +00:00
center = function ( style )
return function ( layout , options )
options = options or { }
return awmtk.merge ( {
{
layout ,
strategy = " exact " ,
height = options.height or
style.center . height ,
width = options.width or
style.center . width ,
widget = wibox.container . constraint
} ,
widget = wibox.container . place ,
valign = " center " ,
halign = " center "
} , options or { } )
end
end ,
2022-07-23 19:10:02 +00:00
popup = function ( style )
2022-08-11 19:34:25 +00:00
-- Popup is a distinct template designed to accomodate the "root" of
-- a popup, allowing one to add titlebars to popups, for example.
2022-07-23 19:10:02 +00:00
return function ( widget , options )
return awmtk.merge ( {
widget = {
2022-08-11 19:34:25 +00:00
widget ,
2022-08-21 12:28:28 +00:00
margins = style.popup . margins ,
layout = wibox.container . margin
2022-07-23 19:10:02 +00:00
} ,
2022-08-11 19:34:25 +00:00
bgimage = style.popup . bgimage ,
2022-07-23 19:10:02 +00:00
shape = style.popup . shape ,
visible = false ,
ontop = true
} , options or { } )
end
2022-08-11 19:34:25 +00:00
end ,
titlebar = function ( style )
-- Titlebar is a separate class specifically for window and popup
-- titlebars. The decision to make it a separate class was due to
-- the fact that much customization is done through default theme table
return function ( layout , options )
2022-08-21 12:28:28 +00:00
-- If there's one thing that fascinates me, it's how much weird
-- bugs i manage to uncover by some sort of miraculous accident.
-- This one fixes a race condition in margins+(left/right/bottom/top) configuration scenario
local margins = style.titlebar . margins
if ( style.titlebar . left or
style.titlebar . right or
style.titlebar . bottom or
style.titlebar . top ) then
margins = nil
end
2022-08-11 19:34:25 +00:00
return awmtk.merge ( {
layout ,
2022-08-21 12:28:28 +00:00
margins = margins ,
layout = wibox.container . margin ,
2022-08-11 19:34:25 +00:00
left = style.titlebar . left ,
right = style.titlebar . right ,
bottom = style.titlebar . bottom ,
top = style.titlebar . top
} , options or { } )
end
2022-08-21 12:28:28 +00:00
end ,
wibar = function ( style )
-- Just you regular old wibar, but as a style template.
return function ( layout , options )
local margins = style.wibar . margins
if ( style.wibar . left or
style.wibar . right or
style.wibar . bottom or
style.wibar . top ) then
margins = nil
end
return awmtk.merge ( {
layout ,
margins = margins ,
layout = wibox.container . margin ,
left = style.wibar . left ,
right = style.wibar . right ,
bottom = style.wibar . bottom ,
top = style.wibar . top
} , options or { } )
end
2022-08-30 07:00:35 +00:00
end ,
slider = function ( style )
-- Slider widget but wired to work with the AWMTK2 namespace system
return function ( args )
return awmtk.merge ( {
handle_shape = style.slider . handle_shape or style.slider . shape ,
handle_color = style.slider . bg_normal ,
handle_margins = style.slider . handle_margins ,
handle_width = style.slider . handle_width ,
handle_border_color = style.slider . handle_border_color ,
handle_border_width = style.slider . handle_border_width ,
bar_shape = style.slider . bar_shape or style.slider . shape ,
bar_height = style.slider . bar_height ,
bar_color = style.slider . bg_focus ,
bar_margins = style.slider . bar_margins ,
bar_border_width = style.slider . bar_border_width ,
bar_border_color = style.slider . bar_border_color ,
forced_width = style.slider . width ,
forced_height = style.slider . height ,
widget = wibox.widget . slider
} , args or { } )
end
2022-08-23 13:03:15 +00:00
end
2022-07-23 19:10:02 +00:00
}
2022-08-11 19:34:25 +00:00
2022-08-21 12:28:28 +00:00
-- Last but not least - we export a default template lib and default style.
-- This is done in order to allow overriding default style behaviour from theme
2022-08-11 19:34:25 +00:00
awmtk.default = awmtk.create_style ( " default " , awmtk.proto_style , { } )
awmtk.templates = awmtk.create_template_lib ( " templates " , awmtk.proto_templates , { } )
2022-09-05 21:54:11 +00:00
-- Generic styles for widgets that need them
awmtk.generic = { }
awmtk.generic . menu = awmtk.create_style ( " generic_menu " , awmtk.default , { } )
awmtk.generic . button_list = awmtk.create_style ( " generic_button_list " , awmtk.default , { } )
awmtk.generic . iconified_widget = awmtk.create_style ( " generic_iconified_widget " , awmtk.default , { } )
awmtk.generic . status_widget = awmtk.create_style ( " generic_status_widget " , awmtk.default , { } )
awmtk.generic . oneline_widget = awmtk.create_style ( " generic_oneline_widget " , awmtk.default , { } )
awmtk.generic . composite_widget = awmtk.create_style ( " generic_composite_widget " , awmtk.default , { } )
2022-09-06 22:40:51 +00:00
awmtk.generic . popup = awmtk.create_style ( " generic_popup " , awmtk.default , { } )
2022-07-23 19:10:02 +00:00
-- }}}
2022-07-12 21:26:11 +00:00
return awmtk