checking logic
This commit is contained in:
135
FlexLove.lua
135
FlexLove.lua
@@ -840,7 +840,7 @@ function ImageCache.load(imagePath, loadImageData)
|
|||||||
-- Cache the image
|
-- Cache the image
|
||||||
ImageCache._cache[normalizedPath] = {
|
ImageCache._cache[normalizedPath] = {
|
||||||
image = image,
|
image = image,
|
||||||
imageData = imgData
|
imageData = imgData,
|
||||||
}
|
}
|
||||||
|
|
||||||
return image, nil
|
return image, nil
|
||||||
@@ -927,7 +927,7 @@ function ImageCache.getStats()
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
count = count,
|
count = count,
|
||||||
memoryEstimate = memoryEstimate
|
memoryEstimate = memoryEstimate,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -966,7 +966,7 @@ function ImageRenderer.calculateFit(imageWidth, imageHeight, boundsWidth, bounds
|
|||||||
dw = boundsWidth, -- Destination width
|
dw = boundsWidth, -- Destination width
|
||||||
dh = boundsHeight, -- Destination height
|
dh = boundsHeight, -- Destination height
|
||||||
scaleX = 1, -- Scale factor X
|
scaleX = 1, -- Scale factor X
|
||||||
scaleY = 1 -- Scale factor Y
|
scaleY = 1, -- Scale factor Y
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Calculate based on fit mode
|
-- Calculate based on fit mode
|
||||||
@@ -976,7 +976,6 @@ function ImageRenderer.calculateFit(imageWidth, imageHeight, boundsWidth, bounds
|
|||||||
result.scaleY = boundsHeight / imageHeight
|
result.scaleY = boundsHeight / imageHeight
|
||||||
result.dw = boundsWidth
|
result.dw = boundsWidth
|
||||||
result.dh = boundsHeight
|
result.dh = boundsHeight
|
||||||
|
|
||||||
elseif fitMode == "contain" then
|
elseif fitMode == "contain" then
|
||||||
-- Scale to fit within bounds (preserves aspect ratio)
|
-- Scale to fit within bounds (preserves aspect ratio)
|
||||||
local scale = math.min(boundsWidth / imageWidth, boundsHeight / imageHeight)
|
local scale = math.min(boundsWidth / imageWidth, boundsHeight / imageHeight)
|
||||||
@@ -989,7 +988,6 @@ function ImageRenderer.calculateFit(imageWidth, imageHeight, boundsWidth, bounds
|
|||||||
local posX, posY = ImageRenderer._parsePosition(objectPosition)
|
local posX, posY = ImageRenderer._parsePosition(objectPosition)
|
||||||
result.dx = (boundsWidth - result.dw) * posX
|
result.dx = (boundsWidth - result.dw) * posX
|
||||||
result.dy = (boundsHeight - result.dh) * posY
|
result.dy = (boundsHeight - result.dh) * posY
|
||||||
|
|
||||||
elseif fitMode == "cover" then
|
elseif fitMode == "cover" then
|
||||||
-- Scale to cover bounds (preserves aspect ratio, may crop)
|
-- Scale to cover bounds (preserves aspect ratio, may crop)
|
||||||
local scale = math.max(boundsWidth / imageWidth, boundsHeight / imageHeight)
|
local scale = math.max(boundsWidth / imageWidth, boundsHeight / imageHeight)
|
||||||
@@ -1016,7 +1014,6 @@ function ImageRenderer.calculateFit(imageWidth, imageHeight, boundsWidth, bounds
|
|||||||
result.dy = 0
|
result.dy = 0
|
||||||
result.dw = boundsWidth
|
result.dw = boundsWidth
|
||||||
result.dh = boundsHeight
|
result.dh = boundsHeight
|
||||||
|
|
||||||
elseif fitMode == "none" then
|
elseif fitMode == "none" then
|
||||||
-- Use natural size (no scaling)
|
-- Use natural size (no scaling)
|
||||||
result.scaleX = 1
|
result.scaleX = 1
|
||||||
@@ -1028,7 +1025,6 @@ function ImageRenderer.calculateFit(imageWidth, imageHeight, boundsWidth, bounds
|
|||||||
local posX, posY = ImageRenderer._parsePosition(objectPosition)
|
local posX, posY = ImageRenderer._parsePosition(objectPosition)
|
||||||
result.dx = (boundsWidth - imageWidth) * posX
|
result.dx = (boundsWidth - imageWidth) * posX
|
||||||
result.dy = (boundsHeight - imageHeight) * posY
|
result.dy = (boundsHeight - imageHeight) * posY
|
||||||
|
|
||||||
elseif fitMode == "scale-down" then
|
elseif fitMode == "scale-down" then
|
||||||
-- Use none or contain, whichever is smaller
|
-- Use none or contain, whichever is smaller
|
||||||
if imageWidth <= boundsWidth and imageHeight <= boundsHeight then
|
if imageWidth <= boundsWidth and imageHeight <= boundsHeight then
|
||||||
@@ -1038,7 +1034,6 @@ function ImageRenderer.calculateFit(imageWidth, imageHeight, boundsWidth, bounds
|
|||||||
-- Image too large, use "contain"
|
-- Image too large, use "contain"
|
||||||
return ImageRenderer.calculateFit(imageWidth, imageHeight, boundsWidth, boundsHeight, "contain", objectPosition)
|
return ImageRenderer.calculateFit(imageWidth, imageHeight, boundsWidth, boundsHeight, "contain", objectPosition)
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
error(formatError("ImageRenderer", string.format("Invalid fit mode: '%s'. Must be one of: fill, contain, cover, scale-down, none", tostring(fitMode))))
|
error(formatError("ImageRenderer", string.format("Invalid fit mode: '%s'. Must be one of: fill, contain, cover, scale-down, none", tostring(fitMode))))
|
||||||
end
|
end
|
||||||
@@ -1065,11 +1060,11 @@ function ImageRenderer._parsePosition(position)
|
|||||||
if #parts == 1 then
|
if #parts == 1 then
|
||||||
local val = parts[1]
|
local val = parts[1]
|
||||||
if val == "left" or val == "right" then
|
if val == "left" or val == "right" then
|
||||||
parts = {val, "center"}
|
parts = { val, "center" }
|
||||||
elseif val == "top" or val == "bottom" then
|
elseif val == "top" or val == "bottom" then
|
||||||
parts = {"center", val}
|
parts = { "center", val }
|
||||||
else
|
else
|
||||||
parts = {val, val}
|
parts = { val, val }
|
||||||
end
|
end
|
||||||
elseif #parts == 0 then
|
elseif #parts == 0 then
|
||||||
return 0.5, 0.5 -- Default to center
|
return 0.5, 0.5 -- Default to center
|
||||||
@@ -1077,9 +1072,12 @@ function ImageRenderer._parsePosition(position)
|
|||||||
|
|
||||||
local function parseValue(val)
|
local function parseValue(val)
|
||||||
-- Handle keywords
|
-- Handle keywords
|
||||||
if val == "center" then return 0.5
|
if val == "center" then
|
||||||
elseif val == "left" or val == "top" then return 0
|
return 0.5
|
||||||
elseif val == "right" or val == "bottom" then return 1
|
elseif val == "left" or val == "top" then
|
||||||
|
return 0
|
||||||
|
elseif val == "right" or val == "bottom" then
|
||||||
|
return 1
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Handle percentages
|
-- Handle percentages
|
||||||
@@ -2340,6 +2338,29 @@ function Gui.init(config)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Check for Z-index coverage (occlusion)
|
||||||
|
---@param elem Element
|
||||||
|
---@param clickX number
|
||||||
|
---@param clickY number
|
||||||
|
---@return boolean
|
||||||
|
function Gui.isOccluded(elem, clickX, clickY)
|
||||||
|
for _, element in ipairs(Gui.topElements) do
|
||||||
|
if element.z > elem.z and element:contains(clickX, clickY) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
--TODO: check if walking the children tree is necessary here - might only need to check for absolute positioned
|
||||||
|
--children
|
||||||
|
for _, child in ipairs(element.children) do
|
||||||
|
if child.positioning == "absolute" then
|
||||||
|
if child.z > elem.z and child:contains(clickX, clickY) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
--- Get current scale factors
|
--- Get current scale factors
|
||||||
---@return number, number -- scaleX, scaleY
|
---@return number, number -- scaleX, scaleY
|
||||||
function Gui.getScaleFactors()
|
function Gui.getScaleFactors()
|
||||||
@@ -2591,14 +2612,15 @@ function Gui.wheelmoved(x, y)
|
|||||||
-- Check children first (depth-first)
|
-- Check children first (depth-first)
|
||||||
if #element.children > 0 then
|
if #element.children > 0 then
|
||||||
local childResult = findScrollableAtPosition(element.children, mx, my)
|
local childResult = findScrollableAtPosition(element.children, mx, my)
|
||||||
if childResult then return childResult end
|
if childResult then
|
||||||
|
return childResult
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check if this element is scrollable
|
-- Check if this element is scrollable
|
||||||
local overflowX = element.overflowX or element.overflow
|
local overflowX = element.overflowX or element.overflow
|
||||||
local overflowY = element.overflowY or element.overflow
|
local overflowY = element.overflowY or element.overflow
|
||||||
if (overflowX == "scroll" or overflowX == "auto" or overflowY == "scroll" or overflowY == "auto") and
|
if (overflowX == "scroll" or overflowX == "auto" or overflowY == "scroll" or overflowY == "auto") and (element._overflowX or element._overflowY) then
|
||||||
(element._overflowX or element._overflowY) then
|
|
||||||
return element
|
return element
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -4154,6 +4176,15 @@ function Element:getBounds()
|
|||||||
return { x = self.x, y = self.y, width = self:getBorderBoxWidth(), height = self:getBorderBoxHeight() }
|
return { x = self.x, y = self.y, width = self:getBorderBoxWidth(), height = self:getBorderBoxHeight() }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Check if point is inside element bounds
|
||||||
|
--- @param x number
|
||||||
|
--- @param y number
|
||||||
|
--- @return boolean
|
||||||
|
function Element:contains(x, y)
|
||||||
|
local bounds = self:getBounds()
|
||||||
|
return bounds.x <= x and bounds.y <= y and bounds.x + bounds.width >= x and bounds.y + bounds.height >= y
|
||||||
|
end
|
||||||
|
|
||||||
--- Get border-box width (including padding)
|
--- Get border-box width (including padding)
|
||||||
---@return number
|
---@return number
|
||||||
function Element:getBorderBoxWidth()
|
function Element:getBorderBoxWidth()
|
||||||
@@ -4246,7 +4277,7 @@ end
|
|||||||
function Element:_calculateScrollbarDimensions()
|
function Element:_calculateScrollbarDimensions()
|
||||||
local result = {
|
local result = {
|
||||||
vertical = { visible = false, trackHeight = 0, thumbHeight = 0, thumbY = 0 },
|
vertical = { visible = false, trackHeight = 0, thumbHeight = 0, thumbY = 0 },
|
||||||
horizontal = { visible = false, trackWidth = 0, thumbWidth = 0, thumbX = 0 }
|
horizontal = { visible = false, trackWidth = 0, thumbWidth = 0, thumbX = 0 },
|
||||||
}
|
}
|
||||||
|
|
||||||
local overflowX = self.overflowX or self.overflow
|
local overflowX = self.overflowX or self.overflow
|
||||||
@@ -4307,20 +4338,10 @@ function Element:_drawScrollbars(dims)
|
|||||||
local thumbColor = self.scrollbarColor
|
local thumbColor = self.scrollbarColor
|
||||||
if self._scrollbarDragging then
|
if self._scrollbarDragging then
|
||||||
-- Active state: brighter
|
-- Active state: brighter
|
||||||
thumbColor = Color.new(
|
thumbColor = Color.new(math.min(1, thumbColor.r * 1.4), math.min(1, thumbColor.g * 1.4), math.min(1, thumbColor.b * 1.4), thumbColor.a)
|
||||||
math.min(1, thumbColor.r * 1.4),
|
|
||||||
math.min(1, thumbColor.g * 1.4),
|
|
||||||
math.min(1, thumbColor.b * 1.4),
|
|
||||||
thumbColor.a
|
|
||||||
)
|
|
||||||
elseif self._scrollbarHovered then
|
elseif self._scrollbarHovered then
|
||||||
-- Hover state: slightly brighter
|
-- Hover state: slightly brighter
|
||||||
thumbColor = Color.new(
|
thumbColor = Color.new(math.min(1, thumbColor.r * 1.2), math.min(1, thumbColor.g * 1.2), math.min(1, thumbColor.b * 1.2), thumbColor.a)
|
||||||
math.min(1, thumbColor.r * 1.2),
|
|
||||||
math.min(1, thumbColor.g * 1.2),
|
|
||||||
math.min(1, thumbColor.b * 1.2),
|
|
||||||
thumbColor.a
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Vertical scrollbar
|
-- Vertical scrollbar
|
||||||
@@ -4330,13 +4351,11 @@ function Element:_drawScrollbars(dims)
|
|||||||
|
|
||||||
-- Draw track
|
-- Draw track
|
||||||
love.graphics.setColor(self.scrollbarTrackColor:toRGBA())
|
love.graphics.setColor(self.scrollbarTrackColor:toRGBA())
|
||||||
love.graphics.rectangle("fill", trackX, trackY,
|
love.graphics.rectangle("fill", trackX, trackY, self.scrollbarWidth, dims.vertical.trackHeight, self.scrollbarRadius)
|
||||||
self.scrollbarWidth, dims.vertical.trackHeight, self.scrollbarRadius)
|
|
||||||
|
|
||||||
-- Draw thumb with state-based color
|
-- Draw thumb with state-based color
|
||||||
love.graphics.setColor(thumbColor:toRGBA())
|
love.graphics.setColor(thumbColor:toRGBA())
|
||||||
love.graphics.rectangle("fill", trackX, trackY + dims.vertical.thumbY,
|
love.graphics.rectangle("fill", trackX, trackY + dims.vertical.thumbY, self.scrollbarWidth, dims.vertical.thumbHeight, self.scrollbarRadius)
|
||||||
self.scrollbarWidth, dims.vertical.thumbHeight, self.scrollbarRadius)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Horizontal scrollbar
|
-- Horizontal scrollbar
|
||||||
@@ -4346,13 +4365,11 @@ function Element:_drawScrollbars(dims)
|
|||||||
|
|
||||||
-- Draw track
|
-- Draw track
|
||||||
love.graphics.setColor(self.scrollbarTrackColor:toRGBA())
|
love.graphics.setColor(self.scrollbarTrackColor:toRGBA())
|
||||||
love.graphics.rectangle("fill", trackX, trackY,
|
love.graphics.rectangle("fill", trackX, trackY, dims.horizontal.trackWidth, self.scrollbarWidth, self.scrollbarRadius)
|
||||||
dims.horizontal.trackWidth, self.scrollbarWidth, self.scrollbarRadius)
|
|
||||||
|
|
||||||
-- Draw thumb with state-based color
|
-- Draw thumb with state-based color
|
||||||
love.graphics.setColor(thumbColor:toRGBA())
|
love.graphics.setColor(thumbColor:toRGBA())
|
||||||
love.graphics.rectangle("fill", trackX + dims.horizontal.thumbX, trackY,
|
love.graphics.rectangle("fill", trackX + dims.horizontal.thumbX, trackY, dims.horizontal.thumbWidth, self.scrollbarWidth, self.scrollbarRadius)
|
||||||
dims.horizontal.thumbWidth, self.scrollbarWidth, self.scrollbarRadius)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Reset color
|
-- Reset color
|
||||||
@@ -4382,8 +4399,7 @@ function Element:_getScrollbarAtPosition(mouseX, mouseY)
|
|||||||
local trackW = self.scrollbarWidth
|
local trackW = self.scrollbarWidth
|
||||||
local trackH = dims.vertical.trackHeight
|
local trackH = dims.vertical.trackHeight
|
||||||
|
|
||||||
if mouseX >= trackX and mouseX <= trackX + trackW and
|
if mouseX >= trackX and mouseX <= trackX + trackW and mouseY >= trackY and mouseY <= trackY + trackH then
|
||||||
mouseY >= trackY and mouseY <= trackY + trackH then
|
|
||||||
-- Check if over thumb
|
-- Check if over thumb
|
||||||
local thumbY = trackY + dims.vertical.thumbY
|
local thumbY = trackY + dims.vertical.thumbY
|
||||||
local thumbH = dims.vertical.thumbHeight
|
local thumbH = dims.vertical.thumbHeight
|
||||||
@@ -4402,8 +4418,7 @@ function Element:_getScrollbarAtPosition(mouseX, mouseY)
|
|||||||
local trackW = dims.horizontal.trackWidth
|
local trackW = dims.horizontal.trackWidth
|
||||||
local trackH = self.scrollbarWidth
|
local trackH = self.scrollbarWidth
|
||||||
|
|
||||||
if mouseX >= trackX and mouseX <= trackX + trackW and
|
if mouseX >= trackX and mouseX <= trackX + trackW and mouseY >= trackY and mouseY <= trackY + trackH then
|
||||||
mouseY >= trackY and mouseY <= trackY + trackH then
|
|
||||||
-- Check if over thumb
|
-- Check if over thumb
|
||||||
local thumbX = trackX + dims.horizontal.thumbX
|
local thumbX = trackX + dims.horizontal.thumbX
|
||||||
local thumbW = dims.horizontal.thumbWidth
|
local thumbW = dims.horizontal.thumbWidth
|
||||||
@@ -4424,10 +4439,14 @@ end
|
|||||||
---@param button number
|
---@param button number
|
||||||
---@return boolean -- True if event was consumed
|
---@return boolean -- True if event was consumed
|
||||||
function Element:_handleScrollbarPress(mouseX, mouseY, button)
|
function Element:_handleScrollbarPress(mouseX, mouseY, button)
|
||||||
if button ~= 1 then return false end -- Only left click
|
if button ~= 1 then
|
||||||
|
return false
|
||||||
|
end -- Only left click
|
||||||
|
|
||||||
local scrollbar = self:_getScrollbarAtPosition(mouseX, mouseY)
|
local scrollbar = self:_getScrollbarAtPosition(mouseX, mouseY)
|
||||||
if not scrollbar then return false end
|
if not scrollbar then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
if scrollbar.region == "thumb" then
|
if scrollbar.region == "thumb" then
|
||||||
-- Start dragging thumb
|
-- Start dragging thumb
|
||||||
@@ -4446,7 +4465,6 @@ function Element:_handleScrollbarPress(mouseX, mouseY, button)
|
|||||||
end
|
end
|
||||||
|
|
||||||
return true -- Event consumed
|
return true -- Event consumed
|
||||||
|
|
||||||
elseif scrollbar.region == "track" then
|
elseif scrollbar.region == "track" then
|
||||||
-- Click on track - jump to position
|
-- Click on track - jump to position
|
||||||
self:_scrollToTrackPosition(mouseX, mouseY, scrollbar.component)
|
self:_scrollToTrackPosition(mouseX, mouseY, scrollbar.component)
|
||||||
@@ -4461,7 +4479,9 @@ end
|
|||||||
---@param mouseY number
|
---@param mouseY number
|
||||||
---@return boolean -- True if event was consumed
|
---@return boolean -- True if event was consumed
|
||||||
function Element:_handleScrollbarDrag(mouseX, mouseY)
|
function Element:_handleScrollbarDrag(mouseX, mouseY)
|
||||||
if not self._scrollbarDragging then return false end
|
if not self._scrollbarDragging then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
local dims = self:_calculateScrollbarDimensions()
|
local dims = self:_calculateScrollbarDimensions()
|
||||||
|
|
||||||
@@ -4480,7 +4500,6 @@ function Element:_handleScrollbarDrag(mouseX, mouseY)
|
|||||||
|
|
||||||
self:setScrollPosition(nil, newScrollY)
|
self:setScrollPosition(nil, newScrollY)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
elseif self._hoveredScrollbar == "horizontal" then
|
elseif self._hoveredScrollbar == "horizontal" then
|
||||||
local trackX = self.x + self.scrollbarPadding + self.padding.left
|
local trackX = self.x + self.scrollbarPadding + self.padding.left
|
||||||
local trackW = dims.horizontal.trackWidth
|
local trackW = dims.horizontal.trackWidth
|
||||||
@@ -4505,7 +4524,9 @@ end
|
|||||||
---@param button number
|
---@param button number
|
||||||
---@return boolean -- True if event was consumed
|
---@return boolean -- True if event was consumed
|
||||||
function Element:_handleScrollbarRelease(button)
|
function Element:_handleScrollbarRelease(button)
|
||||||
if button ~= 1 then return false end
|
if button ~= 1 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
if self._scrollbarDragging then
|
if self._scrollbarDragging then
|
||||||
self._scrollbarDragging = false
|
self._scrollbarDragging = false
|
||||||
@@ -4536,7 +4557,6 @@ function Element:_scrollToTrackPosition(mouseX, mouseY, component)
|
|||||||
local newScrollY = scrollRatio * self._maxScrollY
|
local newScrollY = scrollRatio * self._maxScrollY
|
||||||
|
|
||||||
self:setScrollPosition(nil, newScrollY)
|
self:setScrollPosition(nil, newScrollY)
|
||||||
|
|
||||||
elseif component == "horizontal" then
|
elseif component == "horizontal" then
|
||||||
local trackX = self.x + self.scrollbarPadding + self.padding.left
|
local trackX = self.x + self.scrollbarPadding + self.padding.left
|
||||||
local trackW = dims.horizontal.trackWidth
|
local trackW = dims.horizontal.trackWidth
|
||||||
@@ -5344,8 +5364,10 @@ function Element:draw(backdropCanvas)
|
|||||||
local finalOpacity = self.opacity * self.imageOpacity
|
local finalOpacity = self.opacity * self.imageOpacity
|
||||||
|
|
||||||
-- Apply cornerRadius clipping if set
|
-- Apply cornerRadius clipping if set
|
||||||
local hasCornerRadius = self.cornerRadius.topLeft > 0 or self.cornerRadius.topRight > 0
|
local hasCornerRadius = self.cornerRadius.topLeft > 0
|
||||||
or self.cornerRadius.bottomLeft > 0 or self.cornerRadius.bottomRight > 0
|
or self.cornerRadius.topRight > 0
|
||||||
|
or self.cornerRadius.bottomLeft > 0
|
||||||
|
or self.cornerRadius.bottomRight > 0
|
||||||
|
|
||||||
if hasCornerRadius then
|
if hasCornerRadius then
|
||||||
-- Use stencil to clip image to rounded corners
|
-- Use stencil to clip image to rounded corners
|
||||||
@@ -5356,16 +5378,7 @@ function Element:draw(backdropCanvas)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Draw the image
|
-- Draw the image
|
||||||
ImageRenderer.draw(
|
ImageRenderer.draw(self._loadedImage, imageX, imageY, imageWidth, imageHeight, self.objectFit, self.objectPosition, finalOpacity)
|
||||||
self._loadedImage,
|
|
||||||
imageX,
|
|
||||||
imageY,
|
|
||||||
imageWidth,
|
|
||||||
imageHeight,
|
|
||||||
self.objectFit,
|
|
||||||
self.objectPosition,
|
|
||||||
finalOpacity
|
|
||||||
)
|
|
||||||
|
|
||||||
-- Clear stencil if it was used
|
-- Clear stencil if it was used
|
||||||
if hasCornerRadius then
|
if hasCornerRadius then
|
||||||
|
|||||||
Reference in New Issue
Block a user