diff --git a/FlexLove.lua b/FlexLove.lua index 45cca25..f9725df 100644 --- a/FlexLove.lua +++ b/FlexLove.lua @@ -7,7 +7,7 @@ end local Blur = req("Blur") local utils = req("utils") local Units = req("Units") -local GuiState = req("GuiState") +local Context = req("Context") local StateManager = req("StateManager") ---@type Element local Element = req("Element") @@ -22,7 +22,7 @@ local Theme = req("Theme") local enums = utils.enums ---@class FlexLove -local flexlove = GuiState +local flexlove = Context -- Add version and metadata flexlove._VERSION = "0.1.0" @@ -153,7 +153,7 @@ function flexlove.beginFrame() flexlove._frameStarted = true flexlove.topElements = {} - GuiState.clearFrameElements() + Context.clearFrameElements() end function flexlove.endFrame() @@ -161,7 +161,7 @@ function flexlove.endFrame() return end - GuiState.sortElementsByZIndex() + Context.sortElementsByZIndex() -- Layout all top-level elements now that all children have been added -- This ensures overflow detection happens with complete child lists @@ -510,8 +510,8 @@ function flexlove.wheelmoved(x, y) if flexlove._immediateMode then -- Find topmost scrollable element at mouse position using z-index ordering - for i = #GuiState._zIndexOrderedElements, 1, -1 do - local element = GuiState._zIndexOrderedElements[i] + for i = #Context._zIndexOrderedElements, 1, -1 do + local element = Context._zIndexOrderedElements[i] local bx = element.x local by = element.y diff --git a/README.md b/README.md index 180c65a..7429502 100644 --- a/README.md +++ b/README.md @@ -28,17 +28,12 @@ The following features are currently being actively developed: - **Corner Radius**: Rounded corners with individual corner control - **Advanced Positioning**: Absolute, relative, flex, and grid positioning modes -## Installation - -Add the `modules` directory and `FlexLove.lua` into your project and require it: - -```lua -local FlexLove = require("FlexLove") -local Color = FlexLove.Color -``` - ## Quick Start +Add the `modules` directory and `FlexLove.lua` into your project. I recommend going to the +RELEASES page, but you can clone the repo if you want the latest features, but bugs are more +likely. + ```lua local FlexLove = require("FlexLove") @@ -53,7 +48,7 @@ FlexLove.init({ local button = FlexLove.new({ width = "20vw", height = "10vh", - backgroundColor = FlexLove.Color.new(0.2, 0.2, 0.8, 1), + backgroundColor = Color.new(0.2, 0.2, 0.8, 1), text = "Click Me", textSize = "md", themeComponent = "button", diff --git a/modules/GuiState.lua b/modules/Context.lua similarity index 86% rename from modules/GuiState.lua rename to modules/Context.lua index 41b9344..ef81ac1 100644 --- a/modules/GuiState.lua +++ b/modules/Context.lua @@ -1,5 +1,5 @@ ----@class GuiState -local GuiState = { +---@class Context +local Context = { -- Top-level elements topElements = {}, @@ -35,30 +35,30 @@ local GuiState = { --- Get current scale factors ---@return number, number -- scaleX, scaleY -function GuiState.getScaleFactors() - return GuiState.scaleFactors.x, GuiState.scaleFactors.y +function Context.getScaleFactors() + return Context.scaleFactors.x, Context.scaleFactors.y end --- Register an element in the z-index ordered tree (for immediate mode) ---@param element Element The element to register -function GuiState.registerElement(element) - if not GuiState._immediateMode then +function Context.registerElement(element) + if not Context._immediateMode then return end - table.insert(GuiState._zIndexOrderedElements, element) + table.insert(Context._zIndexOrderedElements, element) end --- Clear frame elements (called at start of each immediate mode frame) -function GuiState.clearFrameElements() - GuiState._zIndexOrderedElements = {} +function Context.clearFrameElements() + Context._zIndexOrderedElements = {} end --- Sort elements by z-index (called after all elements are registered) -function GuiState.sortElementsByZIndex() +function Context.sortElementsByZIndex() -- Sort elements by z-index (lowest to highest) -- We need to consider parent-child relationships and z-index - table.sort(GuiState._zIndexOrderedElements, function(a, b) + table.sort(Context._zIndexOrderedElements, function(a, b) -- Calculate effective z-index considering parent hierarchy local function getEffectiveZIndex(elem) local z = elem.z or 0 @@ -113,8 +113,8 @@ end ---@param x number Screen X coordinate ---@param y number Screen Y coordinate ---@return Element|nil The topmost element at the position, or nil if none -function GuiState.getTopElementAt(x, y) - if not GuiState._immediateMode then +function Context.getTopElementAt(x, y) + if not Context._immediateMode then return nil end @@ -132,8 +132,8 @@ function GuiState.getTopElementAt(x, y) end -- Traverse from highest to lowest z-index (reverse order) - for i = #GuiState._zIndexOrderedElements, 1, -1 do - local element = GuiState._zIndexOrderedElements[i] + for i = #Context._zIndexOrderedElements, 1, -1 do + local element = Context._zIndexOrderedElements[i] if isPointInElement(element, x, y) then local interactive = findInteractiveAncestor(element) @@ -148,4 +148,4 @@ function GuiState.getTopElementAt(x, y) return nil end -return GuiState +return Context diff --git a/modules/Element.lua b/modules/Element.lua index 6a5d012..be100f9 100644 --- a/modules/Element.lua +++ b/modules/Element.lua @@ -4,7 +4,7 @@ local function req(name) end -- Module dependencies -local GuiState = req("GuiState") +local Context = req("Context") local Theme = req("Theme") local Color = req("Color") local Units = req("Units") @@ -41,8 +41,8 @@ local AlignSelf = enums.AlignSelf local JustifySelf = enums.JustifySelf local FlexWrap = enums.FlexWrap --- Reference to Gui (via GuiState) -local Gui = GuiState +-- Reference to Gui (via Context) +local Gui = Context -- UTF-8 support (available in LÖVE/Lua 5.3+) local utf8 = utf8 or require("utf8") @@ -284,7 +284,7 @@ function Element.new(props) onEvent = self.onEvent, }, { InputEvent = InputEvent, - GuiState = GuiState, + Context = Context, }) self._eventHandler:initialize(self) @@ -397,7 +397,7 @@ function Element.new(props) onTextChange = props.onTextChange, onEnter = props.onEnter, }, { - GuiState = GuiState, + Context = Context, StateManager = StateManager, Color = Color, utils = utils, @@ -1328,7 +1328,7 @@ function Element.new(props) -- Register element in z-index tracking for immediate mode if Gui._immediateMode then - GuiState.registerElement(self) + Context.registerElement(self) end -- Initialize TextEditor after element is fully constructed @@ -2082,7 +2082,7 @@ function Element:update(dt) local isActiveElement if Gui._immediateMode then -- In immediate mode, use z-index occlusion detection - local topElement = GuiState.getTopElementAt(mx, my) + local topElement = Context.getTopElementAt(mx, my) isActiveElement = (topElement == self or topElement == nil) else -- In retained mode, use the old _activeEventElement mechanism diff --git a/modules/EventHandler.lua b/modules/EventHandler.lua index 65e8d72..51cbaee 100644 --- a/modules/EventHandler.lua +++ b/modules/EventHandler.lua @@ -22,13 +22,13 @@ end ---@field _element Element? ---@field _scrollbarPressHandled boolean ---@field _InputEvent table ----@field _GuiState table +---@field _Context table local EventHandler = {} EventHandler.__index = EventHandler --- Create a new EventHandler instance ---@param config table Configuration options ----@param deps table Dependencies {InputEvent, GuiState} +---@param deps table Dependencies {InputEvent, Context} ---@return EventHandler function EventHandler.new(config, deps) config = config or {} @@ -36,7 +36,7 @@ function EventHandler.new(config, deps) local self = setmetatable({}, EventHandler) self._InputEvent = deps.InputEvent - self._GuiState = deps.GuiState + self._Context = deps.Context self.onEvent = config.onEvent diff --git a/modules/TextEditor.lua b/modules/TextEditor.lua index e5febd0..50543c7 100644 --- a/modules/TextEditor.lua +++ b/modules/TextEditor.lua @@ -38,7 +38,7 @@ local utf8 = utf8 or require("utf8") ---@field onTextChange fun(element:Element, text:string)? ---@field onEnter fun(element:Element)? ---@field _element Element? ----@field _GuiState table +---@field _Context table ---@field _StateManager table ---@field _Color table ---@field _FONT_CACHE table @@ -66,13 +66,13 @@ TextEditor.__index = TextEditor ---Create a new TextEditor instance ---@param config TextEditorConfig ----@param deps table Dependencies {GuiState, StateManager, Color, utils} +---@param deps table Dependencies {Context, StateManager, Color, utils} ---@return table TextEditor instance function TextEditor.new(config, deps) local self = setmetatable({}, TextEditor) -- Store dependencies - self._GuiState = deps.GuiState + self._Context = deps.Context self._StateManager = deps.StateManager self._Color = deps.Color self._FONT_CACHE = deps.utils.FONT_CACHE @@ -140,12 +140,12 @@ function TextEditor:initialize(element) self._element = element -- Restore state from StateManager if in immediate mode - if element._stateId and self._GuiState._immediateMode then + if element._stateId and self._Context._immediateMode then local state = self._StateManager.getState(element._stateId) if state then if state._focused then self._focused = true - self._GuiState._focusedElement = element + self._Context._focusedElement = element end if state._textBuffer and state._textBuffer ~= "" then self._textBuffer = state._textBuffer @@ -935,16 +935,16 @@ end ---Focus this element for keyboard input function TextEditor:focus() - if self._GuiState._focusedElement and self._GuiState._focusedElement ~= self._element then + if self._Context._focusedElement and self._Context._focusedElement ~= self._element then -- Blur the previously focused element's text editor if it has one - if self._GuiState._focusedElement._textEditor then - self._GuiState._focusedElement._textEditor:blur() + if self._Context._focusedElement._textEditor then + self._Context._focusedElement._textEditor:blur() end end self._focused = true if self._element then - self._GuiState._focusedElement = self._element + self._Context._focusedElement = self._element end self:_resetCursorBlink() @@ -966,8 +966,8 @@ end function TextEditor:blur() self._focused = false - if self._element and self._GuiState._focusedElement == self._element then - self._GuiState._focusedElement = nil + if self._element and self._Context._focusedElement == self._element then + self._Context._focusedElement = nil end if self.onBlur and self._element then @@ -1560,7 +1560,7 @@ end ---Save state to StateManager (for immediate mode) function TextEditor:_saveState() - if not self._element or not self._element._stateId or not self._GuiState._immediateMode then + if not self._element or not self._element._stateId or not self._Context._immediateMode then return end diff --git a/themes/README.md b/themes/README.md index 53d23a7..6aa76c0 100644 --- a/themes/README.md +++ b/themes/README.md @@ -170,15 +170,19 @@ Legend: ```lua local FlexLove = require("FlexLove") local Theme = FlexLove.Theme -local Gui = FlexLove.Gui local Color = FlexLove.Color --- Load theme -Theme.load("my_theme") -Theme.setActive("my_theme") +FlexLove.init({ + baseScale = { width = 1920, height = 1080 }, + theme = "my_theme" -- only supports autoload of one theme + immediateMode = true -- Optional: enable immediate mode (default: false) +}) + +-- you can dynamically add more +Theme.load("my_theme2") -- Create themed button -local button = Gui.new({ +local button_my_theme = FlexLove.new({ width = 150, height = 40, text = "Click Me", @@ -193,13 +197,24 @@ local button = Gui.new({ end }) --- Create themed panel -local panel = Gui.new({ - width = 300, - height = 200, - backgroundColor = Color.new(0.1, 0.1, 0.2, 0.5), -- Background tint - themeComponent = "panel" +-- set active to switch between +Theme.setActive("my_theme2") + +local button_my_theme2 = FlexLove.new({ + width = 150, + height = 40, + text = "Click Me", + textAlign = "center", + textColor = Color.new(1, 1, 1, 1), + backgroundColor = Color.new(0.2, 0.4, 0.8, 0.3), -- Shows behind theme + themeComponent = "button", -- Uses button component from active theme + onEvent = function(element, event) + if event.type == "click" then + print("Clicked!") + end + end }) + ``` ## Rendering Layers