Reno is the second iteration of the AWMTK-powered AwesomeWM config.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

414 lines
15 KiB

-- 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/>.
-- RenoTK (formerly AWMTK2) - Template/Granular styling library for Reno
local wibox = require("wibox")
local awful = require("awful")
local gears = require("gears")
local beautiful = require("beautiful")
local awmtk = {}
-- {{{ Utils
awmtk.create_delta = function(name,instance_delta,class_delta,parent_delta)
-- To save memory, we create proxies for lower layers called "deltas"
-- This function creates that proxy layer using metatables
-- Fun story - i used instance_delta instead of {} at first.
-- The results were horrifying and confusing.
return setmetatable({},{
__index = function(self,k)
-- Per-instance overrides are top priority
if rawget(instance_delta,k) then
return rawget(instance_delta,k)
-- 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]
end
end
})
end
awmtk.create_style = function(name,parent,overrides)
-- A style is essentially a layer of deltas upon the previous (parent) style
local new_style = {}
local odelta = (overrides and overrides[name]) or {}
local cdelta = (beautiful.widgets and beautiful.widgets[name]) or {}
for name,parent_class in pairs(parent) do
new_style[name] = awmtk.create_delta(
name,
odelta,
cdelta,
parent_class
)
end
return new_style
end
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 = {}
for name,template in pairs(awmtk.proto_templates) do
new_templates[name] = templates[name](style)
end
return new_templates
end
awmtk.merge = gears.table.join
-- }}}
-- {{{ Default style
-- Prototype style
-- Notice that it's not awmtk.default style - it's used as a base for default.
awmtk.proto_style = {
base = setmetatable({
-- { Backgrounds
-- custom background color for highlighting elements
bg_highlight = beautiful.bg_highlight or beautiful.bg_focus,
-- allow more complex themes to define background images
bgimage_focus = beautiful.bgimage_focus,
bgimage_normal = beautiful.bgimage_normal,
-- }
-- { Borders
-- Borders for popups
shape_border_width = beautiful.shape_border_width or 0,
shape_border_color = beautiful.shape_border_color or beautiful.bg_normal,
-- }
-- { 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,
-- }
-- { Shapes
margins = 5,
spacing = 5,
shape = function(cr, width, height)
return require("gears").shape.rounded_rect(cr,width,height,5)
end,
-- }
},{__index = beautiful})
}
-- Subclasses
awmtk.proto_style.container = awmtk.create_delta("container",{
},awmtk.proto_style,awmtk.proto_style.base)
awmtk.proto_style.button = awmtk.create_delta("button",{
margins = 3
},awmtk.proto_style,awmtk.proto_style.base)
awmtk.proto_style.icon = awmtk.create_delta("icon",{
margins = 1
},awmtk.proto_style,awmtk.proto_style.base)
awmtk.proto_style.textbox = awmtk.create_delta("textbox",{
font = beautiful.font or "sans 8"
}, awmtk.proto_style,awmtk.proto_style.base)
awmtk.proto_style.separator = awmtk.create_delta("separator",{
thickness = 1,
color = beautiful.bg_focus,
border_width = 0
}, awmtk.proto_style,awmtk.proto_style.base)
awmtk.proto_style.article = awmtk.create_delta("article", {
icon_size = 16,
small_font = beautiful.small_font or beautiful.font,
font_align = "left",
small_font_align = "left"
}, awmtk.proto_style,awmtk.proto_style.base)
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)
awmtk.proto_style.wibar = awmtk.create_delta("wibar", {
margins = 1
}, awmtk.proto_style,awmtk.proto_style.base)
awmtk.proto_style.menu = awmtk.create_delta("menu", {
margins = 1
}, awmtk.proto_style,awmtk.proto_style.base)
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)
-- }}}
-- {{{ Generic templates
awmtk.proto_templates = {
-- Templates are built first using the given style, then applied to contents
-- through returned function
container = function(style)
-- 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.
return function(layout,options)
return awmtk.merge({
{
layout,
margins = style.container.margins,
layout = wibox.container.margin
},
bgimage = style.container.bgimage,
bg = style.container.bg_normal,
shape = style.container.shape,
widget = wibox.container.background
},options or {})
end
end,
button = function(style)
-- 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
return function(layout,options)
return awmtk.merge({
{
layout,
margins = style.button.margins,
layout = wibox.container.margin
},
bgimage = style.button.bgimage,
bg = style.button.bg_normal,
shape = style.button.shape,
widget = wibox.container.background
},options or {})
end
end,
textbox = function(style)
-- Nothing fancy here, but you can set per-widget fonts using beautiful.
return function(options)
return awmtk.merge({
font = style.textbox.font,
widget = wibox.widget.textbox
},options or {})
end
end,
hseparator = function(style)
-- Wow, i guess?
return function(options)
return awmtk.merge({
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)
-- I'm running out of comments
return function(options)
return awmtk.merge({
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)
-- Article is a template that combines 3 common pieces of a full item:
-- Icon, name and description. Designed to be placed within a container
-- or a button.
return function(options)
return awmtk.merge({
(options.icon and {
{
{
image = options.icon,
id = options.icon_id,
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 "",
id = options.title_id,
widget = wibox.widget.textbox,
font = style.article.font,
align = options.font_align or
style.article.font_align,
valign = style.article.title_valign or "center",
align = style.article.title_align or "left"
},
(options.description and {
markup = options.description or "",
id = options.desc_id,
widget = wibox.widget.textbox,
font = style.article.small_font,
align = options.small_font_align or
style.article.small_font_align,
valign = style.article.desc_valign or "center",
align = style.article.desc_align or "left"
}),
spacing = style.article.spacing,
layout = wibox.layout.flex.vertical
},
spacing = style.article.spacing,
layout = wibox.layout.fixed.horizontal,
}, options or {})
end
end,
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,
popup = function(style)
-- Popup is a distinct template designed to accomodate the "root" of
-- a popup, allowing one to add titlebars to popups, for example.
return function(widget,options)
return awmtk.merge({
widget = {
widget,
margins = style.popup.margins,
layout = wibox.container.margin
},
bgimage = style.popup.bgimage,
shape = style.popup.shape,
visible = false,
ontop = true
},options or {})
end
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)
-- 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
return awmtk.merge({
layout,
margins = margins,
layout = wibox.container.margin,
left = style.titlebar.left,
right = style.titlebar.right,
bottom = style.titlebar.bottom,
top = style.titlebar.top
},options or {})
end
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
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
end
}
-- 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
awmtk.default = awmtk.create_style("default",awmtk.proto_style,{})
awmtk.templates = awmtk.create_template_lib("templates",awmtk.proto_templates,{})
-- }}}
return awmtk