- Updated theme plugin to support changing themes on runtime
- Added 4 themes - Added Cache System for States
This commit is contained in:
@@ -101,6 +101,7 @@ function BaseElement:init(props, basalt)
|
|||||||
self.basalt = basalt
|
self.basalt = basalt
|
||||||
self._registeredEvents = {}
|
self._registeredEvents = {}
|
||||||
self._registeredStates = {}
|
self._registeredStates = {}
|
||||||
|
self._cachedActiveStates = nil
|
||||||
|
|
||||||
local currentClass = getmetatable(self).__index
|
local currentClass = getmetatable(self).__index
|
||||||
|
|
||||||
@@ -142,6 +143,7 @@ function BaseElement:postInit()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
self._postInitialized = true
|
self._postInitialized = true
|
||||||
|
self._modifiedProperties = {}
|
||||||
if(self._props)then
|
if(self._props)then
|
||||||
for k,v in pairs(self._props)do
|
for k,v in pairs(self._props)do
|
||||||
self.set(k, v)
|
self.set(k, v)
|
||||||
@@ -234,6 +236,7 @@ function BaseElement:setState(stateName, priority)
|
|||||||
states[stateName] = priority or 0
|
states[stateName] = priority or 0
|
||||||
|
|
||||||
self.set("states", states)
|
self.set("states", states)
|
||||||
|
self._cachedActiveStates = nil
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -246,6 +249,7 @@ function BaseElement:unsetState(stateName)
|
|||||||
if states[stateName] ~= nil then
|
if states[stateName] ~= nil then
|
||||||
states[stateName] = nil
|
states[stateName] = nil
|
||||||
self.set("states", states)
|
self.set("states", states)
|
||||||
|
self._cachedActiveStates = nil
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -282,6 +286,11 @@ end
|
|||||||
--- @shortDescription Gets all active states
|
--- @shortDescription Gets all active states
|
||||||
--- @return table states Array of {name, priority} sorted by priority
|
--- @return table states Array of {name, priority} sorted by priority
|
||||||
function BaseElement:getActiveStates()
|
function BaseElement:getActiveStates()
|
||||||
|
-- Return cached version if available
|
||||||
|
if self._cachedActiveStates then
|
||||||
|
return self._cachedActiveStates
|
||||||
|
end
|
||||||
|
|
||||||
local states = self.get("states")
|
local states = self.get("states")
|
||||||
local result = {}
|
local result = {}
|
||||||
|
|
||||||
@@ -291,6 +300,7 @@ function BaseElement:getActiveStates()
|
|||||||
|
|
||||||
table.sort(result, function(a, b) return a.priority > b.priority end)
|
table.sort(result, function(a, b) return a.priority > b.priority end)
|
||||||
|
|
||||||
|
self._cachedActiveStates = result
|
||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ function Frame.new()
|
|||||||
self.class = Frame
|
self.class = Frame
|
||||||
self.set("width", 12)
|
self.set("width", 12)
|
||||||
self.set("height", 6)
|
self.set("height", 6)
|
||||||
self.set("background", colors.gray)
|
|
||||||
self.set("z", 10)
|
self.set("z", 10)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ function Label.new()
|
|||||||
local self = setmetatable({}, Label):__init()
|
local self = setmetatable({}, Label):__init()
|
||||||
self.class = Label
|
self.class = Label
|
||||||
self.set("z", 3)
|
self.set("z", 3)
|
||||||
self.set("foreground", colors.black)
|
|
||||||
self.set("backgroundEnabled", false)
|
self.set("backgroundEnabled", false)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -49,10 +48,6 @@ end
|
|||||||
--- @protected
|
--- @protected
|
||||||
function Label:init(props, basalt)
|
function Label:init(props, basalt)
|
||||||
VisualElement.init(self, props, basalt)
|
VisualElement.init(self, props, basalt)
|
||||||
if(self.parent)then
|
|
||||||
self.set("background", self.parent.get("background"))
|
|
||||||
self.set("foreground", self.parent.get("foreground"))
|
|
||||||
end
|
|
||||||
self.set("type", "Label")
|
self.set("type", "Label")
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ function List.new()
|
|||||||
self.set("width", 16)
|
self.set("width", 16)
|
||||||
self.set("height", 8)
|
self.set("height", 8)
|
||||||
self.set("z", 5)
|
self.set("z", 5)
|
||||||
self.set("background", colors.gray)
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -114,4 +114,4 @@ function LayoutManager.destroy(instance)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return LayoutManager
|
return LayoutManager
|
||||||
@@ -4,25 +4,49 @@ local errorManager = require("errorManager")
|
|||||||
|
|
||||||
local defaultTheme = {
|
local defaultTheme = {
|
||||||
default = {
|
default = {
|
||||||
background = colors.lightGray,
|
background = colors.cyan,
|
||||||
foreground = colors.black,
|
foreground = colors.black,
|
||||||
},
|
},
|
||||||
BaseFrame = {
|
BaseFrame = {
|
||||||
background = colors.white,
|
background = colors.white,
|
||||||
foreground = colors.black,
|
foreground = colors.black,
|
||||||
|
|
||||||
Frame = {
|
Container = {
|
||||||
|
default = {
|
||||||
|
background = colors.cyan,
|
||||||
|
foreground = colors.black,
|
||||||
|
},
|
||||||
background = colors.black,
|
background = colors.black,
|
||||||
names = {
|
Button = {
|
||||||
basaltDebugLogClose = {
|
background = colors.cyan,
|
||||||
background = colors.blue,
|
foreground = colors.black,
|
||||||
foreground = colors.white
|
states = {
|
||||||
|
clicked = {
|
||||||
|
background = colors.white,
|
||||||
|
foreground = colors.black,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Input = {
|
||||||
|
background = colors.cyan,
|
||||||
|
foreground = colors.black,
|
||||||
|
},
|
||||||
|
Label = {
|
||||||
|
foreground = colors.white,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Button = {
|
Button = {
|
||||||
background = colors.cyan,
|
background = colors.cyan,
|
||||||
foreground = colors.black,
|
foreground = colors.black,
|
||||||
|
states = {
|
||||||
|
clicked = {
|
||||||
|
background = colors.black,
|
||||||
|
foreground = colors.cyan,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Label = {
|
||||||
|
foreground = colors.black,
|
||||||
},
|
},
|
||||||
|
|
||||||
names = {
|
names = {
|
||||||
@@ -96,26 +120,6 @@ local function lookUpTemplate(theme, path)
|
|||||||
return current
|
return current
|
||||||
end
|
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)
|
local function applyNamedStyles(result, theme, elementType, elementName, themeTable)
|
||||||
if theme.default and theme.default.names and theme.default.names[elementName] then
|
if theme.default and theme.default.names and theme.default.names[elementName] then
|
||||||
for k,v in pairs(theme.default.names[elementName]) do
|
for k,v in pairs(theme.default.names[elementName]) do
|
||||||
@@ -139,17 +143,46 @@ end
|
|||||||
|
|
||||||
local function collectThemeProps(theme, path, elementType, elementName)
|
local function collectThemeProps(theme, path, elementType, elementName)
|
||||||
local result = {}
|
local result = {}
|
||||||
local themeTable = lookUpTemplate(theme, path)
|
if theme.default then
|
||||||
if themeTable then
|
for k,v in pairs(theme.default) do
|
||||||
for k,v in pairs(themeTable) do
|
|
||||||
if type(v) ~= "table" then
|
if type(v) ~= "table" then
|
||||||
result[k] = v
|
result[k] = v
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
local current = theme
|
||||||
|
for i = 1, #path do
|
||||||
|
local types = path[i]
|
||||||
|
local found = false
|
||||||
|
|
||||||
if next(result) == nil then
|
for _, elementType in ipairs(types) do
|
||||||
result = getDefaultProperties(theme, elementType)
|
if current[elementType] then
|
||||||
|
current = current[elementType]
|
||||||
|
found = true
|
||||||
|
if current.default then
|
||||||
|
for k,v in pairs(current.default) do
|
||||||
|
if type(v) ~= "table" then
|
||||||
|
result[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not found then
|
||||||
|
current = nil
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local themeTable = lookUpTemplate(theme, path)
|
||||||
|
if themeTable then
|
||||||
|
for k,v in pairs(themeTable) do
|
||||||
|
if type(v) ~= "table" or k == "states" then
|
||||||
|
result[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
applyNamedStyles(result, theme, elementType, elementName, themeTable)
|
applyNamedStyles(result, theme, elementType, elementName, themeTable)
|
||||||
@@ -163,22 +196,53 @@ end
|
|||||||
--- @param applyToChildren boolean? Whether to apply theme to child elements (default: true)
|
--- @param applyToChildren boolean? Whether to apply theme to child elements (default: true)
|
||||||
--- @return BaseElement self The element instance
|
--- @return BaseElement self The element instance
|
||||||
function BaseElement:applyTheme(applyToChildren)
|
function BaseElement:applyTheme(applyToChildren)
|
||||||
|
local backup = {}
|
||||||
|
if self._modifiedProperties then
|
||||||
|
for prop, _ in pairs(self._modifiedProperties) do
|
||||||
|
backup[prop] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local styles = self:getTheme()
|
local styles = self:getTheme()
|
||||||
if(styles ~= nil) then
|
if(styles ~= nil) then
|
||||||
for prop, value in pairs(styles) do
|
for prop, value in pairs(styles) do
|
||||||
local config = self._properties[prop]
|
if prop ~= "states" and not backup[prop] then
|
||||||
if(config)then
|
local config = self._properties[prop]
|
||||||
if((config.type)=="color")then
|
if(config)then
|
||||||
if(type(value)=="string")then
|
if((config.type)=="color")then
|
||||||
if(colors[value])then
|
if(type(value)=="string")then
|
||||||
value = colors[value]
|
if(colors[value])then
|
||||||
|
value = colors[value]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.set(prop, value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if styles.states then
|
||||||
|
for stateName, stateConfig in pairs(styles.states) do
|
||||||
|
for prop, value in pairs(stateConfig) do
|
||||||
|
if prop ~= "priority" then
|
||||||
|
local config = self._properties[prop]
|
||||||
|
local capitalizedName = prop:sub(1,1):upper() .. prop:sub(2)
|
||||||
|
if(config)then
|
||||||
|
if((config.type)=="color")then
|
||||||
|
if(type(value)=="string")then
|
||||||
|
if(colors[value])then
|
||||||
|
value = colors[value]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self["set" .. capitalizedName .. "State"](self, stateName, value)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self.set(prop, value)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
self._modifiedProperties = backup
|
||||||
|
|
||||||
if(applyToChildren~=false)then
|
if(applyToChildren~=false)then
|
||||||
if(self:isType("Container"))then
|
if(self:isType("Container"))then
|
||||||
local children = self.get("children")
|
local children = self.get("children")
|
||||||
|
|||||||
@@ -263,6 +263,7 @@ function PropertySystem:__init()
|
|||||||
self._values = {}
|
self._values = {}
|
||||||
self._observers = {}
|
self._observers = {}
|
||||||
self._states = {}
|
self._states = {}
|
||||||
|
self._modifiedProperties = {}
|
||||||
|
|
||||||
self.set = function(name, value, ...)
|
self.set = function(name, value, ...)
|
||||||
local oldValue = self._values[name]
|
local oldValue = self._values[name]
|
||||||
@@ -275,6 +276,7 @@ function PropertySystem:__init()
|
|||||||
self:updateRender()
|
self:updateRender()
|
||||||
end
|
end
|
||||||
self._values[name] = applyHooks(self, name, value, config)
|
self._values[name] = applyHooks(self, name, value, config)
|
||||||
|
self._modifiedProperties[name] = true
|
||||||
if oldValue ~= value and self._observers[name] then
|
if oldValue ~= value and self._observers[name] then
|
||||||
for _, callback in ipairs(self._observers[name]) do
|
for _, callback in ipairs(self._observers[name]) do
|
||||||
callback(self, value, oldValue)
|
callback(self, value, oldValue)
|
||||||
@@ -431,6 +433,7 @@ function PropertySystem:_updateProperty(name, value)
|
|||||||
oldValue = oldValue(self)
|
oldValue = oldValue(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self._modifiedProperties[name] = true
|
||||||
self._values[name] = value
|
self._values[name] = value
|
||||||
local newValue = type(value) == "function" and value(self) or value
|
local newValue = type(value) == "function" and value(self) or value
|
||||||
|
|
||||||
|
|||||||
47
themes/classic.json
Normal file
47
themes/classic.json
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"theme": "classic",
|
||||||
|
"default": {
|
||||||
|
"background": "black",
|
||||||
|
"foreground": "lightGray"
|
||||||
|
},
|
||||||
|
"BaseFrame": {
|
||||||
|
"background": "lightGray",
|
||||||
|
"Container": {
|
||||||
|
"background": "gray",
|
||||||
|
"foreground": "white",
|
||||||
|
"Button" : {
|
||||||
|
"background" : "black",
|
||||||
|
"foreground" : "lightGray",
|
||||||
|
"states": {
|
||||||
|
"clicked": {
|
||||||
|
"background": "white",
|
||||||
|
"foreground": "black"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Input": {
|
||||||
|
"background": "black",
|
||||||
|
"foreground": "lightGray"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Button": {
|
||||||
|
"background": "black",
|
||||||
|
"foreground": "lightGray",
|
||||||
|
"states": {
|
||||||
|
"clicked": {
|
||||||
|
"background": "white",
|
||||||
|
"foreground": "black"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Label": {
|
||||||
|
"foreground": "black"
|
||||||
|
},
|
||||||
|
"names": {
|
||||||
|
"basaltDebugLog": {
|
||||||
|
"background": "black",
|
||||||
|
"foreground": "white"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
44
themes/dark.json
Normal file
44
themes/dark.json
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"theme": "dark",
|
||||||
|
"default": {
|
||||||
|
"background": "white",
|
||||||
|
"foreground": "black"
|
||||||
|
},
|
||||||
|
"BaseFrame": {
|
||||||
|
"background": "black",
|
||||||
|
"Container": {
|
||||||
|
"background": "gray",
|
||||||
|
"foreground": "white",
|
||||||
|
"Button": {
|
||||||
|
"background": "lightGray",
|
||||||
|
"foreground": "black",
|
||||||
|
"states": {
|
||||||
|
"clicked": {
|
||||||
|
"background": "blue",
|
||||||
|
"foreground": "white"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Input": {
|
||||||
|
"background": "black",
|
||||||
|
"foreground": "lightGray"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Button": {
|
||||||
|
"background": "gray",
|
||||||
|
"foreground": "white",
|
||||||
|
"states": {
|
||||||
|
"clicked": {
|
||||||
|
"background": "blue",
|
||||||
|
"foreground": "white"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"names": {
|
||||||
|
"basaltDebugLog": {
|
||||||
|
"background": "red",
|
||||||
|
"foreground": "white"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
50
themes/light.json
Normal file
50
themes/light.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"theme": "light",
|
||||||
|
"default": {
|
||||||
|
"background": "black",
|
||||||
|
"foreground": "white"
|
||||||
|
},
|
||||||
|
"BaseFrame": {
|
||||||
|
"background": "lightGray",
|
||||||
|
"Container": {
|
||||||
|
"background": "white",
|
||||||
|
"foreground": "black",
|
||||||
|
"Button": {
|
||||||
|
"background": "black",
|
||||||
|
"foreground": "white",
|
||||||
|
"states": {
|
||||||
|
"clicked": {
|
||||||
|
"background": "lightGray",
|
||||||
|
"foreground": "black"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Input": {
|
||||||
|
"background": "black",
|
||||||
|
"foreground": "white"
|
||||||
|
},
|
||||||
|
"Label": {
|
||||||
|
"foreground": "black"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Button": {
|
||||||
|
"background": "black",
|
||||||
|
"foreground": "white",
|
||||||
|
"states": {
|
||||||
|
"clicked": {
|
||||||
|
"background": "white",
|
||||||
|
"foreground": "black"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Label": {
|
||||||
|
"foreground": "black"
|
||||||
|
},
|
||||||
|
"names": {
|
||||||
|
"basaltDebugLog": {
|
||||||
|
"background": "orange",
|
||||||
|
"foreground": "white"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
47
themes/orange.json
Normal file
47
themes/orange.json
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"theme": "orange",
|
||||||
|
"default": {
|
||||||
|
"background": "black",
|
||||||
|
"foreground": "orange"
|
||||||
|
},
|
||||||
|
"BaseFrame": {
|
||||||
|
"background": "white",
|
||||||
|
"Container": {
|
||||||
|
"default": {
|
||||||
|
"background": "black",
|
||||||
|
"foreground": "orange"
|
||||||
|
},
|
||||||
|
"background": "orange",
|
||||||
|
"foreground": "white",
|
||||||
|
"Button": {
|
||||||
|
"background": "black",
|
||||||
|
"foreground": "orange",
|
||||||
|
"states": {
|
||||||
|
"clicked": {
|
||||||
|
"background": "white",
|
||||||
|
"foreground": "orange"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Label": {
|
||||||
|
"foreground": "black"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Button": {
|
||||||
|
"background": "black",
|
||||||
|
"foreground": "orange",
|
||||||
|
"states": {
|
||||||
|
"clicked": {
|
||||||
|
"background": "orange",
|
||||||
|
"foreground": "white"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"names": {
|
||||||
|
"basaltDebugLog": {
|
||||||
|
"background": "red",
|
||||||
|
"foreground": "white"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user