rename and simplification
This commit is contained in:
12
FlexLove.lua
12
FlexLove.lua
@@ -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
|
||||||
|
|||||||
15
README.md
15
README.md
@@ -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",
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user