Files
Basalt2/src/plugins/theme.lua
Robert Jelic 8b6eaccd18 Docs Update
2025-02-18 09:46:32 +01:00

214 lines
5.7 KiB
Lua

local defaultTheme = {
default = {
background = colors.lightGray,
foreground = colors.black,
},
BaseFrame = {
background = colors.white,
foreground = colors.black,
Frame = {
background = colors.black,
names = {
basaltDebugLogClose = {
background = colors.blue,
foreground = colors.white
}
},
},
Button = {
background = "{self.clicked and colors.black or colors.cyan}",
foreground = "{self.clicked and colors.cyan or colors.black}",
},
names = {
basaltDebugLog = {
background = colors.red,
foreground = colors.white
},
test = {
background = "{self.clicked and colors.black or colors.green}",
foreground = "{self.clicked and colors.green or colors.black}"
}
},
}
}
local themes = {
default = defaultTheme
}
local currentTheme = "default"
--- This is the theme plugin. It provides a theming system that allows for consistent styling across elements
--- with support for inheritance, named styles, and dynamic theme switching.
---@class BaseElement
local BaseElement = {
hooks = {
postInit = {
pre = function(self)
self:applyTheme()
end
}
}
}
---@private
function BaseElement.____getElementPath(self, types)
if types then
table.insert(types, 1, self._values.type)
else
types = {self._values.type}
end
local parent = self.parent
if parent then
return parent.____getElementPath(parent, types)
else
return types
end
end
local function lookUpTemplate(theme, path)
local current = theme
for i = 1, #path do
local found = false
local types = path[i]
for _, elementType in ipairs(types) do
if current[elementType] then
current = current[elementType]
found = true
break
end
end
if not found then
return nil
end
end
return current
end
local function getDefaultProperties(theme, elementType)
local result = {}
if theme.default then
for k,v in pairs(theme.default) do
if type(v) ~= "table" then
result[k] = v
end
end
if theme.default[elementType] then
for k,v in pairs(theme.default[elementType]) do
if type(v) ~= "table" then
result[k] = v
end
end
end
end
return result
end
local function applyNamedStyles(result, theme, elementType, elementName, themeTable)
if theme.default and theme.default.names and theme.default.names[elementName] then
for k,v in pairs(theme.default.names[elementName]) do
if type(v) ~= "table" then result[k] = v end
end
end
if theme.default and theme.default[elementType] and theme.default[elementType].names
and theme.default[elementType].names[elementName] then
for k,v in pairs(theme.default[elementType].names[elementName]) do
if type(v) ~= "table" then result[k] = v end
end
end
if themeTable and themeTable.names and themeTable.names[elementName] then
for k,v in pairs(themeTable.names[elementName]) do
if type(v) ~= "table" then result[k] = v end
end
end
end
local function collectThemeProps(theme, path, elementType, elementName)
local result = {}
local themeTable = lookUpTemplate(theme, path)
if themeTable then
for k,v in pairs(themeTable) do
if type(v) ~= "table" then
result[k] = v
end
end
end
if next(result) == nil then
result = getDefaultProperties(theme, elementType)
end
applyNamedStyles(result, theme, elementType, elementName, themeTable)
return result
end
--- Applies the current theme to this element
--- @shortDescription Applies theme styles to the element
--- @param self BaseElement The element to apply theme to
--- @return BaseElement self The element instance
function BaseElement:applyTheme()
local styles = self:getTheme()
if(styles ~= nil) then
for prop, value in pairs(styles) do
self.set(prop, value)
end
end
end
--- Gets the theme properties for this element
--- @shortDescription Gets theme properties for the element
--- @param self BaseElement The element to get theme for
--- @return table styles The theme properties
function BaseElement:getTheme()
local path = self:____getElementPath()
local elementType = self.get("type")
local elementName = self.get("name")
return collectThemeProps(themes[currentTheme], path, elementType, elementName)
end
--- The Theme API provides methods for managing themes globally
---@class ThemeAPI
local themeAPI = {}
--- Sets the current theme
--- @shortDescription Sets a new theme
--- @param newTheme table The theme configuration to set
function themeAPI.setTheme(newTheme)
defaultTheme = newTheme
end
--- Gets the current theme configuration
--- @shortDescription Gets the current theme
--- @return table theme The current theme configuration
function themeAPI.getTheme()
return defaultTheme
end
--- Loads a theme from a JSON file
--- @shortDescription Loads theme from JSON file
--- @param path string Path to the theme JSON file
function themeAPI.loadTheme(path)
local file = fs.open(path, "r")
if file then
local content = file.readAll()
file.close()
defaultTheme = textutils.unserializeJSON(content)
end
end
return {
BaseElement = BaseElement,
API = themeAPI
}