rename and simplification

This commit is contained in:
Michael Freno
2025-11-13 17:38:19 -05:00
parent c3b8e8ba08
commit 614536a3df
7 changed files with 75 additions and 65 deletions

View File

@@ -7,7 +7,7 @@ end
local Blur = req("Blur") local Blur = req("Blur")
local utils = req("utils") local utils = req("utils")
local Units = req("Units") local Units = req("Units")
local GuiState = req("GuiState") local Context = req("Context")
local StateManager = req("StateManager") local StateManager = req("StateManager")
---@type Element ---@type Element
local Element = req("Element") local Element = req("Element")
@@ -22,7 +22,7 @@ local Theme = req("Theme")
local enums = utils.enums local enums = utils.enums
---@class FlexLove ---@class FlexLove
local flexlove = GuiState local flexlove = Context
-- Add version and metadata -- Add version and metadata
flexlove._VERSION = "0.1.0" flexlove._VERSION = "0.1.0"
@@ -153,7 +153,7 @@ function flexlove.beginFrame()
flexlove._frameStarted = true flexlove._frameStarted = true
flexlove.topElements = {} flexlove.topElements = {}
GuiState.clearFrameElements() Context.clearFrameElements()
end end
function flexlove.endFrame() function flexlove.endFrame()
@@ -161,7 +161,7 @@ function flexlove.endFrame()
return return
end end
GuiState.sortElementsByZIndex() Context.sortElementsByZIndex()
-- Layout all top-level elements now that all children have been added -- Layout all top-level elements now that all children have been added
-- This ensures overflow detection happens with complete child lists -- This ensures overflow detection happens with complete child lists
@@ -510,8 +510,8 @@ function flexlove.wheelmoved(x, y)
if flexlove._immediateMode then if flexlove._immediateMode then
-- Find topmost scrollable element at mouse position using z-index ordering -- Find topmost scrollable element at mouse position using z-index ordering
for i = #GuiState._zIndexOrderedElements, 1, -1 do for i = #Context._zIndexOrderedElements, 1, -1 do
local element = GuiState._zIndexOrderedElements[i] local element = Context._zIndexOrderedElements[i]
local bx = element.x local bx = element.x
local by = element.y local by = element.y

View File

@@ -28,17 +28,12 @@ The following features are currently being actively developed:
- **Corner Radius**: Rounded corners with individual corner control - **Corner Radius**: Rounded corners with individual corner control
- **Advanced Positioning**: Absolute, relative, flex, and grid positioning modes - **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 ## 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 ```lua
local FlexLove = require("FlexLove") local FlexLove = require("FlexLove")
@@ -53,7 +48,7 @@ FlexLove.init({
local button = FlexLove.new({ local button = FlexLove.new({
width = "20vw", width = "20vw",
height = "10vh", 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", text = "Click Me",
textSize = "md", textSize = "md",
themeComponent = "button", themeComponent = "button",

View File

@@ -1,5 +1,5 @@
---@class GuiState ---@class Context
local GuiState = { local Context = {
-- Top-level elements -- Top-level elements
topElements = {}, topElements = {},
@@ -35,30 +35,30 @@ local GuiState = {
--- Get current scale factors --- Get current scale factors
---@return number, number -- scaleX, scaleY ---@return number, number -- scaleX, scaleY
function GuiState.getScaleFactors() function Context.getScaleFactors()
return GuiState.scaleFactors.x, GuiState.scaleFactors.y return Context.scaleFactors.x, Context.scaleFactors.y
end end
--- Register an element in the z-index ordered tree (for immediate mode) --- Register an element in the z-index ordered tree (for immediate mode)
---@param element Element The element to register ---@param element Element The element to register
function GuiState.registerElement(element) function Context.registerElement(element)
if not GuiState._immediateMode then if not Context._immediateMode then
return return
end end
table.insert(GuiState._zIndexOrderedElements, element) table.insert(Context._zIndexOrderedElements, element)
end end
--- Clear frame elements (called at start of each immediate mode frame) --- Clear frame elements (called at start of each immediate mode frame)
function GuiState.clearFrameElements() function Context.clearFrameElements()
GuiState._zIndexOrderedElements = {} Context._zIndexOrderedElements = {}
end end
--- Sort elements by z-index (called after all elements are registered) --- 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) -- Sort elements by z-index (lowest to highest)
-- We need to consider parent-child relationships and z-index -- 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 -- Calculate effective z-index considering parent hierarchy
local function getEffectiveZIndex(elem) local function getEffectiveZIndex(elem)
local z = elem.z or 0 local z = elem.z or 0
@@ -113,8 +113,8 @@ end
---@param x number Screen X coordinate ---@param x number Screen X coordinate
---@param y number Screen Y coordinate ---@param y number Screen Y coordinate
---@return Element|nil The topmost element at the position, or nil if none ---@return Element|nil The topmost element at the position, or nil if none
function GuiState.getTopElementAt(x, y) function Context.getTopElementAt(x, y)
if not GuiState._immediateMode then if not Context._immediateMode then
return nil return nil
end end
@@ -132,8 +132,8 @@ function GuiState.getTopElementAt(x, y)
end end
-- Traverse from highest to lowest z-index (reverse order) -- Traverse from highest to lowest z-index (reverse order)
for i = #GuiState._zIndexOrderedElements, 1, -1 do for i = #Context._zIndexOrderedElements, 1, -1 do
local element = GuiState._zIndexOrderedElements[i] local element = Context._zIndexOrderedElements[i]
if isPointInElement(element, x, y) then if isPointInElement(element, x, y) then
local interactive = findInteractiveAncestor(element) local interactive = findInteractiveAncestor(element)
@@ -148,4 +148,4 @@ function GuiState.getTopElementAt(x, y)
return nil return nil
end end
return GuiState return Context

View File

@@ -4,7 +4,7 @@ local function req(name)
end end
-- Module dependencies -- Module dependencies
local GuiState = req("GuiState") local Context = req("Context")
local Theme = req("Theme") local Theme = req("Theme")
local Color = req("Color") local Color = req("Color")
local Units = req("Units") local Units = req("Units")
@@ -41,8 +41,8 @@ local AlignSelf = enums.AlignSelf
local JustifySelf = enums.JustifySelf local JustifySelf = enums.JustifySelf
local FlexWrap = enums.FlexWrap local FlexWrap = enums.FlexWrap
-- Reference to Gui (via GuiState) -- Reference to Gui (via Context)
local Gui = GuiState local Gui = Context
-- UTF-8 support (available in LÖVE/Lua 5.3+) -- UTF-8 support (available in LÖVE/Lua 5.3+)
local utf8 = utf8 or require("utf8") local utf8 = utf8 or require("utf8")
@@ -284,7 +284,7 @@ function Element.new(props)
onEvent = self.onEvent, onEvent = self.onEvent,
}, { }, {
InputEvent = InputEvent, InputEvent = InputEvent,
GuiState = GuiState, Context = Context,
}) })
self._eventHandler:initialize(self) self._eventHandler:initialize(self)
@@ -397,7 +397,7 @@ function Element.new(props)
onTextChange = props.onTextChange, onTextChange = props.onTextChange,
onEnter = props.onEnter, onEnter = props.onEnter,
}, { }, {
GuiState = GuiState, Context = Context,
StateManager = StateManager, StateManager = StateManager,
Color = Color, Color = Color,
utils = utils, utils = utils,
@@ -1328,7 +1328,7 @@ function Element.new(props)
-- Register element in z-index tracking for immediate mode -- Register element in z-index tracking for immediate mode
if Gui._immediateMode then if Gui._immediateMode then
GuiState.registerElement(self) Context.registerElement(self)
end end
-- Initialize TextEditor after element is fully constructed -- Initialize TextEditor after element is fully constructed
@@ -2082,7 +2082,7 @@ function Element:update(dt)
local isActiveElement local isActiveElement
if Gui._immediateMode then if Gui._immediateMode then
-- In immediate mode, use z-index occlusion detection -- 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) isActiveElement = (topElement == self or topElement == nil)
else else
-- In retained mode, use the old _activeEventElement mechanism -- In retained mode, use the old _activeEventElement mechanism

View File

@@ -22,13 +22,13 @@ end
---@field _element Element? ---@field _element Element?
---@field _scrollbarPressHandled boolean ---@field _scrollbarPressHandled boolean
---@field _InputEvent table ---@field _InputEvent table
---@field _GuiState table ---@field _Context table
local EventHandler = {} local EventHandler = {}
EventHandler.__index = EventHandler EventHandler.__index = EventHandler
--- Create a new EventHandler instance --- Create a new EventHandler instance
---@param config table Configuration options ---@param config table Configuration options
---@param deps table Dependencies {InputEvent, GuiState} ---@param deps table Dependencies {InputEvent, Context}
---@return EventHandler ---@return EventHandler
function EventHandler.new(config, deps) function EventHandler.new(config, deps)
config = config or {} config = config or {}
@@ -36,7 +36,7 @@ function EventHandler.new(config, deps)
local self = setmetatable({}, EventHandler) local self = setmetatable({}, EventHandler)
self._InputEvent = deps.InputEvent self._InputEvent = deps.InputEvent
self._GuiState = deps.GuiState self._Context = deps.Context
self.onEvent = config.onEvent self.onEvent = config.onEvent

View File

@@ -38,7 +38,7 @@ local utf8 = utf8 or require("utf8")
---@field onTextChange fun(element:Element, text:string)? ---@field onTextChange fun(element:Element, text:string)?
---@field onEnter fun(element:Element)? ---@field onEnter fun(element:Element)?
---@field _element Element? ---@field _element Element?
---@field _GuiState table ---@field _Context table
---@field _StateManager table ---@field _StateManager table
---@field _Color table ---@field _Color table
---@field _FONT_CACHE table ---@field _FONT_CACHE table
@@ -66,13 +66,13 @@ TextEditor.__index = TextEditor
---Create a new TextEditor instance ---Create a new TextEditor instance
---@param config TextEditorConfig ---@param config TextEditorConfig
---@param deps table Dependencies {GuiState, StateManager, Color, utils} ---@param deps table Dependencies {Context, StateManager, Color, utils}
---@return table TextEditor instance ---@return table TextEditor instance
function TextEditor.new(config, deps) function TextEditor.new(config, deps)
local self = setmetatable({}, TextEditor) local self = setmetatable({}, TextEditor)
-- Store dependencies -- Store dependencies
self._GuiState = deps.GuiState self._Context = deps.Context
self._StateManager = deps.StateManager self._StateManager = deps.StateManager
self._Color = deps.Color self._Color = deps.Color
self._FONT_CACHE = deps.utils.FONT_CACHE self._FONT_CACHE = deps.utils.FONT_CACHE
@@ -140,12 +140,12 @@ function TextEditor:initialize(element)
self._element = element self._element = element
-- Restore state from StateManager if in immediate mode -- 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) local state = self._StateManager.getState(element._stateId)
if state then if state then
if state._focused then if state._focused then
self._focused = true self._focused = true
self._GuiState._focusedElement = element self._Context._focusedElement = element
end end
if state._textBuffer and state._textBuffer ~= "" then if state._textBuffer and state._textBuffer ~= "" then
self._textBuffer = state._textBuffer self._textBuffer = state._textBuffer
@@ -935,16 +935,16 @@ end
---Focus this element for keyboard input ---Focus this element for keyboard input
function TextEditor:focus() 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 -- Blur the previously focused element's text editor if it has one
if self._GuiState._focusedElement._textEditor then if self._Context._focusedElement._textEditor then
self._GuiState._focusedElement._textEditor:blur() self._Context._focusedElement._textEditor:blur()
end end
end end
self._focused = true self._focused = true
if self._element then if self._element then
self._GuiState._focusedElement = self._element self._Context._focusedElement = self._element
end end
self:_resetCursorBlink() self:_resetCursorBlink()
@@ -966,8 +966,8 @@ end
function TextEditor:blur() function TextEditor:blur()
self._focused = false self._focused = false
if self._element and self._GuiState._focusedElement == self._element then if self._element and self._Context._focusedElement == self._element then
self._GuiState._focusedElement = nil self._Context._focusedElement = nil
end end
if self.onBlur and self._element then if self.onBlur and self._element then
@@ -1560,7 +1560,7 @@ end
---Save state to StateManager (for immediate mode) ---Save state to StateManager (for immediate mode)
function TextEditor:_saveState() 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 return
end end

View File

@@ -170,15 +170,19 @@ Legend:
```lua ```lua
local FlexLove = require("FlexLove") local FlexLove = require("FlexLove")
local Theme = FlexLove.Theme local Theme = FlexLove.Theme
local Gui = FlexLove.Gui
local Color = FlexLove.Color local Color = FlexLove.Color
-- Load theme FlexLove.init({
Theme.load("my_theme") baseScale = { width = 1920, height = 1080 },
Theme.setActive("my_theme") 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 -- Create themed button
local button = Gui.new({ local button_my_theme = FlexLove.new({
width = 150, width = 150,
height = 40, height = 40,
text = "Click Me", text = "Click Me",
@@ -193,13 +197,24 @@ local button = Gui.new({
end end
}) })
-- Create themed panel -- set active to switch between
local panel = Gui.new({ Theme.setActive("my_theme2")
width = 300,
height = 200, local button_my_theme2 = FlexLove.new({
backgroundColor = Color.new(0.1, 0.1, 0.2, 0.5), -- Background tint width = 150,
themeComponent = "panel" 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 ## Rendering Layers