diff --git a/FlexLove.lua b/FlexLove.lua index 381e271..e1977ad 100644 --- a/FlexLove.lua +++ b/FlexLove.lua @@ -677,7 +677,7 @@ local Gui = { } --- Initialize FlexLove with configuration ----@param config {baseScale?: {width?:number, height?:number}} --Default: {width: 1920, height: 1080} +---@param config {baseScale?: {width?:number, height?:number}, theme?: string|ThemeDefinition} --Default: {width: 1920, height: 1080} function Gui.init(config) if config.baseScale then Gui.baseScale = { @@ -690,6 +690,19 @@ function Gui.init(config) Gui.scaleFactors.x = currentWidth / Gui.baseScale.width Gui.scaleFactors.y = currentHeight / Gui.baseScale.height end + + -- Load and set theme if specified + if config.theme then + if type(config.theme) == "string" then + -- Load theme by name + Theme.load(config.theme) + Theme.setActive(config.theme) + elseif type(config.theme) == "table" then + -- Load theme from definition + local theme = Theme.new(config.theme) + Theme.setActive(theme) + end + end end --- Get current scale factors @@ -1084,7 +1097,7 @@ function Element.new(props) -- Initialize theme self.theme = props.theme self._themeState = "normal" - + -- Initialize state properties self.disabled = props.disabled or false self.active = props.active or false diff --git a/examples/ThemeInitDemo.lua b/examples/ThemeInitDemo.lua new file mode 100644 index 0000000..c361892 --- /dev/null +++ b/examples/ThemeInitDemo.lua @@ -0,0 +1,97 @@ +-- Example: Setting theme in Gui.init() +local FlexLove = require("FlexLove") +local Gui = FlexLove.GUI +local Color = FlexLove.Color + +-- Initialize GUI with theme +Gui.init({ + baseScale = { width = 1920, height = 1080 }, + theme = "space" -- Load and activate the space theme +}) + +-- Now all elements can use the theme +local panel = Gui.new({ + x = 100, + y = 100, + width = 400, + height = 300, + theme = "panel", + padding = { top = 20, right = 20, bottom = 20, left = 20 }, +}) + +local button1 = Gui.new({ + parent = panel, + x = 20, + y = 20, + width = 150, + height = 50, + text = "Normal Button", + textAlign = "center", + textColor = Color.new(1, 1, 1, 1), + theme = "button", + callback = function(element, event) + if event.type == "click" then + print("Button clicked!") + end + end +}) + +local button2 = Gui.new({ + parent = panel, + x = 20, + y = 80, + width = 150, + height = 50, + text = "Disabled", + textAlign = "center", + textColor = Color.new(0.6, 0.6, 0.6, 1), + theme = "button", + disabled = true, -- Shows disabled state + callback = function(element, event) + print("This won't fire!") + end +}) + +local input1 = Gui.new({ + parent = panel, + x = 20, + y = 140, + width = 200, + height = 40, + text = "Type here...", + textColor = Color.new(1, 1, 1, 1), + theme = "input", +}) + +local input2 = Gui.new({ + parent = panel, + x = 20, + y = 190, + width = 200, + height = 40, + text = "Active input", + textColor = Color.new(1, 1, 1, 1), + theme = "input", + active = true, -- Shows active/focused state +}) + +local input3 = Gui.new({ + parent = panel, + x = 20, + y = 240, + width = 200, + height = 40, + text = "Disabled input", + textColor = Color.new(0.6, 0.6, 0.6, 1), + theme = "input", + disabled = true, -- Shows disabled state +}) + +return { + panel = panel, + button1 = button1, + button2 = button2, + input1 = input1, + input2 = input2, + input3 = input3, +} diff --git a/themes/space.lua b/themes/space.lua index 3745683..e629597 100644 --- a/themes/space.lua +++ b/themes/space.lua @@ -1,45 +1,176 @@ +-- Space Theme +-- All images are 256x256 with perfectly centered 9-slice regions + +local Color = require("FlexLove").Color + return { name = "Space Theme", + components = { + -- Panel component panel = { atlas = "themes/space/panel-compressed.png", - regions = {}, + regions = { + -- Equal-sized regions for 256x256 image (85-86-85 split) + -- Top row + topLeft = { x = 0, y = 0, w = 85, h = 85 }, + topCenter = { x = 85, y = 0, w = 86, h = 85 }, + topRight = { x = 171, y = 0, w = 85, h = 85 }, + -- Middle row (stretchable) + middleLeft = { x = 0, y = 85, w = 85, h = 86 }, + middleCenter = { x = 85, y = 85, w = 86, h = 86 }, + middleRight = { x = 171, y = 85, w = 85, h = 86 }, + -- Bottom row + bottomLeft = { x = 0, y = 171, w = 85, h = 85 }, + bottomCenter = { x = 85, y = 171, w = 86, h = 85 }, + bottomRight = { x = 171, y = 171, w = 85, h = 85 }, + }, + stretch = { + horizontal = { "topCenter", "middleCenter", "bottomCenter" }, + vertical = { "middleLeft", "middleCenter", "middleRight" }, + }, }, + + -- Button component with states button = { atlas = "themes/space/interactive-compressed.png", - regions = {}, + regions = { + topLeft = { x = 0, y = 0, w = 85, h = 85 }, + topCenter = { x = 85, y = 0, w = 86, h = 85 }, + topRight = { x = 171, y = 0, w = 85, h = 85 }, + middleLeft = { x = 0, y = 85, w = 85, h = 86 }, + middleCenter = { x = 85, y = 85, w = 86, h = 86 }, + middleRight = { x = 171, y = 85, w = 85, h = 86 }, + bottomLeft = { x = 0, y = 171, w = 85, h = 85 }, + bottomCenter = { x = 85, y = 171, w = 86, h = 85 }, + bottomRight = { x = 171, y = 171, w = 85, h = 85 }, + }, + stretch = { + horizontal = { "topCenter", "middleCenter", "bottomCenter" }, + vertical = { "middleLeft", "middleCenter", "middleRight" }, + }, states = { hover = { - atlas = "themes/interactive_hover-compressed.png", - regions = { ... }, + atlas = "themes/space/interactive-hovered-compressed.png", + regions = { + topLeft = { x = 0, y = 0, w = 85, h = 85 }, + topCenter = { x = 85, y = 0, w = 86, h = 85 }, + topRight = { x = 171, y = 0, w = 85, h = 85 }, + middleLeft = { x = 0, y = 85, w = 85, h = 86 }, + middleCenter = { x = 85, y = 85, w = 86, h = 86 }, + middleRight = { x = 171, y = 85, w = 85, h = 86 }, + bottomLeft = { x = 0, y = 171, w = 85, h = 85 }, + bottomCenter = { x = 85, y = 171, w = 86, h = 85 }, + bottomRight = { x = 171, y = 171, w = 85, h = 85 }, + }, + stretch = { + horizontal = { "topCenter", "middleCenter", "bottomCenter" }, + vertical = { "middleLeft", "middleCenter", "middleRight" }, + }, }, pressed = { - atlas = "themes/interactive_pressed-compressed.png", - regions = { ... }, + atlas = "themes/space/interactive-pressed-compressed.png", + regions = { + topLeft = { x = 0, y = 0, w = 85, h = 85 }, + topCenter = { x = 85, y = 0, w = 86, h = 85 }, + topRight = { x = 171, y = 0, w = 85, h = 85 }, + middleLeft = { x = 0, y = 85, w = 85, h = 86 }, + middleCenter = { x = 85, y = 85, w = 86, h = 86 }, + middleRight = { x = 171, y = 85, w = 85, h = 86 }, + bottomLeft = { x = 0, y = 171, w = 85, h = 85 }, + bottomCenter = { x = 85, y = 171, w = 86, h = 85 }, + bottomRight = { x = 171, y = 171, w = 85, h = 85 }, + }, + stretch = { + horizontal = { "topCenter", "middleCenter", "bottomCenter" }, + vertical = { "middleLeft", "middleCenter", "middleRight" }, + }, }, disabled = { - atlas = "themes/interactive_disabled-compressed.png", - regions = { ... }, + atlas = "themes/space/interactive-disabled-compressed.png", + regions = { + topLeft = { x = 0, y = 0, w = 85, h = 85 }, + topCenter = { x = 85, y = 0, w = 86, h = 85 }, + topRight = { x = 171, y = 0, w = 85, h = 85 }, + middleLeft = { x = 0, y = 85, w = 85, h = 86 }, + middleCenter = { x = 85, y = 85, w = 86, h = 86 }, + middleRight = { x = 171, y = 85, w = 85, h = 86 }, + bottomLeft = { x = 0, y = 171, w = 85, h = 85 }, + bottomCenter = { x = 85, y = 171, w = 86, h = 85 }, + bottomRight = { x = 171, y = 171, w = 85, h = 85 }, + }, + stretch = { + horizontal = { "topCenter", "middleCenter", "bottomCenter" }, + vertical = { "middleLeft", "middleCenter", "middleRight" }, + }, }, }, }, + + -- Input component with active and disabled states input = { atlas = "themes/space/interactive-compressed.png", - regions = {}, + regions = { + topLeft = { x = 0, y = 0, w = 85, h = 85 }, + topCenter = { x = 85, y = 0, w = 86, h = 85 }, + topRight = { x = 171, y = 0, w = 85, h = 85 }, + middleLeft = { x = 0, y = 85, w = 85, h = 86 }, + middleCenter = { x = 85, y = 85, w = 86, h = 86 }, + middleRight = { x = 171, y = 85, w = 85, h = 86 }, + bottomLeft = { x = 0, y = 171, w = 85, h = 85 }, + bottomCenter = { x = 85, y = 171, w = 86, h = 85 }, + bottomRight = { x = 171, y = 171, w = 85, h = 85 }, + }, + stretch = { + horizontal = { "topCenter", "middleCenter", "bottomCenter" }, + vertical = { "middleLeft", "middleCenter", "middleRight" }, + }, states = { - hover = { - atlas = "themes/interactive_hover-compressed.png", - regions = { ... }, - }, - pressed = { - atlas = "themes/interactive_pressed-compressed.png", - regions = { ... }, + active = { + atlas = "themes/space/interactive-hovered-compressed.png", + regions = { + topLeft = { x = 0, y = 0, w = 85, h = 85 }, + topCenter = { x = 85, y = 0, w = 86, h = 85 }, + topRight = { x = 171, y = 0, w = 85, h = 85 }, + middleLeft = { x = 0, y = 85, w = 85, h = 86 }, + middleCenter = { x = 85, y = 85, w = 86, h = 86 }, + middleRight = { x = 171, y = 85, w = 85, h = 86 }, + bottomLeft = { x = 0, y = 171, w = 85, h = 85 }, + bottomCenter = { x = 85, y = 171, w = 86, h = 85 }, + bottomRight = { x = 171, y = 171, w = 85, h = 85 }, + }, + stretch = { + horizontal = { "topCenter", "middleCenter", "bottomCenter" }, + vertical = { "middleLeft", "middleCenter", "middleRight" }, + }, }, disabled = { - atlas = "themes/interactive_disabled-compressed.png", - regions = { ... }, + atlas = "themes/space/interactive-disabled-compressed.png", + regions = { + topLeft = { x = 0, y = 0, w = 85, h = 85 }, + topCenter = { x = 85, y = 0, w = 86, h = 85 }, + topRight = { x = 171, y = 0, w = 85, h = 85 }, + middleLeft = { x = 0, y = 85, w = 85, h = 86 }, + middleCenter = { x = 85, y = 85, w = 86, h = 86 }, + middleRight = { x = 171, y = 85, w = 85, h = 86 }, + bottomLeft = { x = 0, y = 171, w = 85, h = 85 }, + bottomCenter = { x = 85, y = 171, w = 86, h = 85 }, + bottomRight = { x = 171, y = 171, w = 85, h = 85 }, + }, + stretch = { + horizontal = { "topCenter", "middleCenter", "bottomCenter" }, + vertical = { "middleLeft", "middleCenter", "middleRight" }, + }, }, }, }, }, + + -- Optional: Theme colors + colors = { + primary = Color.new(0.08, 0.75, 0.95), -- bright cyan-blue glow for accents and highlights + secondary = Color.new(0.15, 0.20, 0.25), -- deep steel-gray background for panels + text = Color.new(0.80, 0.90, 1.00), -- soft cool-white for general text + textDark = Color.new(0.35, 0.40, 0.45), -- dimmed gray-blue for secondary text + }, }