mirror of
https://github.com/airstruck/luigi.git
synced 2025-11-18 12:25:06 +00:00
scissor me baby
This commit is contained in:
@@ -52,27 +52,27 @@ return { id = 'mainWindow', type = 'panel',
|
||||
{ type = 'panel', id = 'mainCanvas' },
|
||||
{ type = 'sash' },
|
||||
{ type = 'panel', id = 'rightSideBox', width = 200, minwidth = 64, scroll = true,
|
||||
{ id = 'flowTest',
|
||||
{ minheight = 64,
|
||||
{ id = 'flowTest', height = 'auto', minheight = 128,
|
||||
{
|
||||
{ type = 'label', text = 'Slider' },
|
||||
{ type = 'slider', id = 'slidey', value = 0 },
|
||||
{ type = 'slider', id = 'slidey', width = false },
|
||||
},
|
||||
{ minheight = 64,
|
||||
{
|
||||
{ type = 'label', text = 'Stepper' },
|
||||
{ type = 'stepper',
|
||||
{ type = 'stepper', id = 'stepper', width = false,
|
||||
{ value = 1, text = 'Thing One' },
|
||||
{ value = 2, text = 'Thing Two' },
|
||||
{ value = 3, text = 'Thing Three' },
|
||||
},
|
||||
},
|
||||
{ minheight = 64,
|
||||
{
|
||||
{ type = 'label', text = 'Progress' },
|
||||
{ type = 'progress', id = 'progressBar', },
|
||||
{ type = 'progress', id = 'progressBar', width = false },
|
||||
},
|
||||
},
|
||||
{
|
||||
{ type = 'label', text = 'Above layout' },
|
||||
{ type = 'check', text = 'Flow horizontal', id = 'flowToggle', },
|
||||
{ height = 'auto',
|
||||
{ type = 'label', text = 'Flow test' },
|
||||
{ type = 'check', text = 'Vertical controls', id = 'flowToggle', },
|
||||
{ type = 'label', text = 'Some radio widgets' },
|
||||
{ type = 'radio', text = 'One fish' },
|
||||
{ type = 'radio', text = 'Two fish' },
|
||||
|
||||
@@ -11,9 +11,10 @@ layout.slidey:onChange(function (event)
|
||||
end)
|
||||
|
||||
layout.flowToggle:onChange(function (event)
|
||||
layout.flowTest.flow = event.value and 'x' or 'y'
|
||||
layout.slidey.flow = event.value and 'y' or 'x'
|
||||
layout.progressBar.flow = event.value and 'y' or 'x'
|
||||
layout.stepper.flow = event.value and 'y' or 'x'
|
||||
layout.flowTest.flow = event.value and 'x' or 'y'
|
||||
end)
|
||||
|
||||
layout.newButton:onPress(function (event)
|
||||
|
||||
@@ -9,6 +9,7 @@ return {
|
||||
type = 'button',
|
||||
align = 'center middle',
|
||||
width = 48,
|
||||
height = 48,
|
||||
slices = function (self)
|
||||
if self.focused or self.hovered or self.pressed then
|
||||
return nil -- fall back to theme default
|
||||
|
||||
@@ -283,7 +283,9 @@ To get the calculated height, use `Widget:getHeight`.
|
||||
Attribute.height = {}
|
||||
|
||||
function Attribute.height.set (widget, value)
|
||||
value = value and math.max(value, widget.minheight or 0)
|
||||
if value ~= 'auto' then
|
||||
value = value and math.max(value, widget.minheight or 0)
|
||||
end
|
||||
widget.attributes.height = value
|
||||
widget.reshape(widget.parent or widget)
|
||||
end
|
||||
@@ -415,6 +417,8 @@ and horizontal alignment is defined by either 'left', 'center', or 'right'.
|
||||
|
||||
For example, `align = 'top left'`
|
||||
|
||||
- This attribute cascades.
|
||||
|
||||
@attrib align
|
||||
--]]--
|
||||
Attribute.align = {}
|
||||
@@ -424,6 +428,10 @@ function Attribute.align.set (widget, value)
|
||||
widget.textData = nil
|
||||
end
|
||||
|
||||
function Attribute.align.get (widget)
|
||||
return widget.attributes.align or widget.parent and widget.parent.align
|
||||
end
|
||||
|
||||
--[[--
|
||||
Wrap text onto multiple lines.
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ local Text = require((...) .. '.text')
|
||||
|
||||
local IntOut = ffi.typeof 'int[1]'
|
||||
|
||||
local stack = {}
|
||||
|
||||
-- create window and renderer
|
||||
sdl.setHint(sdl.HINT_VIDEO_ALLOW_SCREENSAVER, '1')
|
||||
|
||||
@@ -257,6 +259,12 @@ Backend.setScissor = function (x, y, w, h)
|
||||
sdl.renderSetClipRect(renderer, lastScissor)
|
||||
end
|
||||
|
||||
Backend.getScissor = function ()
|
||||
if lastScissor ~= nil then
|
||||
return lastScissor.x, lastScissor.y, lastScissor.w, lastScissor.h
|
||||
end
|
||||
end
|
||||
|
||||
function Backend.hide (layout)
|
||||
for _, item in ipairs(layout.hooks) do
|
||||
Hooker.unhook(item)
|
||||
@@ -269,15 +277,14 @@ local function hook (layout, key, method, hookLast)
|
||||
callback, key, method, hookLast)
|
||||
end
|
||||
|
||||
local stack = {}
|
||||
|
||||
Backend.pop = function ()
|
||||
local history = stack[#stack]
|
||||
local color = history.color or { 0, 0, 0, 255 }
|
||||
lastColor = history.color or { 0, 0, 0, 255 }
|
||||
lastScissor = history.scissor
|
||||
|
||||
sdl.setRenderDrawColor(renderer,
|
||||
color[1], color[2], color[3], color[4] or 255)
|
||||
sdl.renderSetClipRect(renderer, history.scissor) -- Backend.setScissor(history.scissor)
|
||||
lastColor[1], lastColor[2], lastColor[3], lastColor[4] or 255)
|
||||
sdl.renderSetClipRect(renderer, lastScissor) -- Backend.setScissor(history.scissor)
|
||||
stack[#stack] = nil
|
||||
end
|
||||
|
||||
|
||||
@@ -73,6 +73,8 @@ end
|
||||
|
||||
Backend.setScissor = love.graphics.setScissor
|
||||
|
||||
Backend.getScissor = love.graphics.getScissor
|
||||
|
||||
function Backend.hide (layout)
|
||||
for _, item in ipairs(layout.hooks) do
|
||||
Hooker.unhook(item)
|
||||
|
||||
@@ -11,6 +11,25 @@ local Renderer = Base:extend()
|
||||
local imageCache = {}
|
||||
local sliceCache = {}
|
||||
|
||||
|
||||
|
||||
local function intersectScissor (x, y, w, h)
|
||||
local sx, sy, sw, sh = Backend.getScissor()
|
||||
if not sx then
|
||||
return Backend.setScissor(x, y, w, h)
|
||||
end
|
||||
local x1 = math.max(sx, x)
|
||||
local y1 = math.max(sy, y)
|
||||
local x2 = math.min(sx + sw, x + w)
|
||||
local y2 = math.min(sy + sh, y + h)
|
||||
if x2 > x1 and y2 > y1 then
|
||||
Backend.setScissor(x1, y1, x2 - x1, y2 - y1)
|
||||
else
|
||||
-- HACK
|
||||
Backend.setScissor(-100, -100, 1, 1)
|
||||
end
|
||||
end
|
||||
|
||||
function Renderer:loadImage (path)
|
||||
if not imageCache[path] then
|
||||
imageCache[path] = Backend.Image(path)
|
||||
@@ -194,8 +213,6 @@ function Renderer:renderIconAndText (widget)
|
||||
return
|
||||
end
|
||||
|
||||
local parentY = widget.parent and widget.parent:getY() or 0
|
||||
|
||||
-- calculate position for icon and text based on alignment and padding
|
||||
local iconX, iconY, x1, y1, x2, y2 = self:positionIcon(
|
||||
widget, x, y, x + w, y + h)
|
||||
@@ -239,14 +256,12 @@ function Renderer:renderIconAndText (widget)
|
||||
end
|
||||
|
||||
Backend.push()
|
||||
Backend.setScissor(x, math.max(y, parentY), w, h)
|
||||
|
||||
intersectScissor(x, y, w, h)
|
||||
|
||||
-- draw the icon
|
||||
if icon then
|
||||
iconX, iconY = math.floor(iconX), math.floor(iconY)
|
||||
if widget.tint then
|
||||
Backend.setColor(widget.tint)
|
||||
end
|
||||
Backend.draw(icon, iconX, iconY)
|
||||
end
|
||||
|
||||
@@ -277,9 +292,9 @@ function Renderer:render (widget)
|
||||
|
||||
Backend.push()
|
||||
|
||||
if widget.parent then
|
||||
local parentY = widget.parent:getY()
|
||||
Backend.setScissor(x, math.max(y, parentY), w, h)
|
||||
local parent = widget.parent
|
||||
if parent then
|
||||
intersectScissor(x, y, w, h)
|
||||
else
|
||||
Backend.setScissor()
|
||||
end
|
||||
@@ -288,11 +303,10 @@ function Renderer:render (widget)
|
||||
self:renderOutline(widget)
|
||||
self:renderSlices(widget)
|
||||
self:renderIconAndText(widget)
|
||||
self:renderChildren(widget)
|
||||
|
||||
Backend.pop()
|
||||
|
||||
return self:renderChildren(widget)
|
||||
|
||||
end)
|
||||
Event.Display:emit(widget, { target = widget })
|
||||
end
|
||||
|
||||
@@ -55,11 +55,11 @@ return function (config)
|
||||
end
|
||||
|
||||
local function getSashHeight (self)
|
||||
return self.parent.flow ~= 'x' and 4
|
||||
return self.parent and self.parent.flow ~= 'x' and 4
|
||||
end
|
||||
|
||||
local function getSashWidth (self)
|
||||
return self.parent.flow == 'x' and 4
|
||||
return self.parent and self.parent.flow == 'x' and 4
|
||||
end
|
||||
|
||||
local function getTextSlices (self)
|
||||
@@ -75,10 +75,10 @@ return function (config)
|
||||
color = textColor,
|
||||
minheight = 28,
|
||||
minwidth = 28,
|
||||
align = 'center middle',
|
||||
},
|
||||
button = {
|
||||
type = 'control',
|
||||
align = 'center middle',
|
||||
padding = 6,
|
||||
slices = getButtonSlices,
|
||||
minwidth = 24,
|
||||
@@ -92,11 +92,13 @@ return function (config)
|
||||
color = textColor,
|
||||
icon = getCheckOrRadioIcon,
|
||||
padding = 4,
|
||||
align = 'left middle',
|
||||
},
|
||||
label = {
|
||||
type = 'control',
|
||||
background = backColor,
|
||||
padding = 4,
|
||||
align = 'left middle',
|
||||
},
|
||||
menu = {
|
||||
height = 24,
|
||||
@@ -131,6 +133,7 @@ return function (config)
|
||||
color = textColor,
|
||||
icon = getCheckOrRadioIcon,
|
||||
padding = 4,
|
||||
align = 'left middle',
|
||||
},
|
||||
sash = {
|
||||
background = getSashBackground,
|
||||
@@ -153,7 +156,6 @@ return function (config)
|
||||
slices = resources .. 'button_pressed.png',
|
||||
},
|
||||
['stepper.item'] = {
|
||||
type = 'control',
|
||||
align = 'center middle',
|
||||
color = textColor,
|
||||
},
|
||||
|
||||
@@ -291,15 +291,11 @@ function Widget:addChild (data)
|
||||
return child
|
||||
end
|
||||
|
||||
local function clamp (value, min, max)
|
||||
return value < min and min or value > max and max or value
|
||||
end
|
||||
|
||||
local function checkReshape (widget)
|
||||
if widget.needsReshape then
|
||||
widget.position = {}
|
||||
widget.dimensions = {}
|
||||
widget.needsReshape = false
|
||||
widget.needsReshape = nil
|
||||
end
|
||||
end
|
||||
|
||||
@@ -313,19 +309,21 @@ function Widget:calculateDimension (name)
|
||||
local min = (name == 'width') and (self.minwidth or 0)
|
||||
or (self.minheight or 0)
|
||||
|
||||
local windowWidth, windowHeight = Backend.getWindowSize()
|
||||
|
||||
local max = name == 'width' and windowWidth or windowHeight
|
||||
|
||||
if self[name] then
|
||||
self.dimensions[name] = clamp(self[name], min, max)
|
||||
if self[name] == 'auto' then
|
||||
self.dimensions[name] = self:calculateDimensionMinimum(name)
|
||||
return self.dimensions[name]
|
||||
end
|
||||
self.dimensions[name] = math.max(self[name], min)
|
||||
return self.dimensions[name]
|
||||
end
|
||||
|
||||
local parent = self.parent
|
||||
|
||||
if not parent then
|
||||
self.dimensions[name] = max
|
||||
local windowWidth, windowHeight = Backend.getWindowSize()
|
||||
local size = name == 'width' and windowWidth or windowHeight
|
||||
self.dimensions[name] = size
|
||||
return self.dimensions[name]
|
||||
end
|
||||
|
||||
@@ -333,21 +331,23 @@ function Widget:calculateDimension (name)
|
||||
parentDimension = parentDimension - (parent.margin or 0) * 2
|
||||
parentDimension = parentDimension - (parent.padding or 0) * 2
|
||||
local parentFlow = parent.flow or 'y'
|
||||
if (parentFlow == 'y' and name == 'width') or
|
||||
(parentFlow == 'x' and name == 'height')
|
||||
then
|
||||
self.dimensions[name] = clamp(parentDimension, min, max)
|
||||
if (parentFlow ~= 'x' and name == 'width')
|
||||
or (parentFlow == 'x' and name == 'height') then
|
||||
self.dimensions[name] = math.max(parentDimension, min)
|
||||
return self.dimensions[name]
|
||||
end
|
||||
local claimed = 0
|
||||
local unsized = 1
|
||||
for i, widget in ipairs(self.parent) do
|
||||
if widget ~= self then
|
||||
if widget[name] then
|
||||
claimed = claimed + widget:calculateDimension(name)
|
||||
if claimed > parentDimension then
|
||||
claimed = parentDimension
|
||||
local value = widget[name]
|
||||
if value == 'auto' then
|
||||
if not widget.dimensions[name] then
|
||||
widget.dimensions[name] = widget:calculateDimensionMinimum(name)
|
||||
end
|
||||
claimed = claimed + widget.dimensions[name]
|
||||
elseif value then
|
||||
claimed = claimed + value
|
||||
else
|
||||
unsized = unsized + 1
|
||||
end
|
||||
@@ -355,13 +355,13 @@ function Widget:calculateDimension (name)
|
||||
end
|
||||
local size = (parentDimension - claimed) / unsized
|
||||
|
||||
size = clamp(size, min, max)
|
||||
size = math.max(size, min)
|
||||
self.dimensions[name] = size
|
||||
return size
|
||||
end
|
||||
|
||||
local function calculateRootPosition (self, axis)
|
||||
local value = (axis == 'x' and self.left) or (axis == 'y' and self.top)
|
||||
local value = (axis == 'x' and self.left) or (axis ~= 'x' and self.top)
|
||||
|
||||
if value then
|
||||
self.position[axis] = value
|
||||
@@ -370,9 +370,9 @@ local function calculateRootPosition (self, axis)
|
||||
|
||||
local ww, wh = Backend.getWindowSize()
|
||||
|
||||
if axis == 'x' and self.width then
|
||||
if axis == 'x' and type(self.width) == 'number' then
|
||||
value = (ww - self.width) / 2
|
||||
elseif axis == 'y' and self.height then
|
||||
elseif axis ~= 'x' and type(self.height) == 'number' then
|
||||
value = (wh - self.height) / 2
|
||||
else
|
||||
value = 0
|
||||
@@ -394,7 +394,7 @@ function Widget:calculatePosition (axis)
|
||||
return calculateRootPosition(self, axis)
|
||||
else
|
||||
scroll = axis == 'x' and (parent.scrollX or 0)
|
||||
or axis == 'y' and (parent.scrollY or 0)
|
||||
or axis ~= 'x' and (parent.scrollY or 0)
|
||||
end
|
||||
local parentPos = parent:calculatePosition(axis)
|
||||
local p = parentPos - scroll
|
||||
@@ -415,6 +415,24 @@ function Widget:calculatePosition (axis)
|
||||
return 0
|
||||
end
|
||||
|
||||
function Widget:calculateDimensionMinimum (name)
|
||||
local space = (self.margin or 0) * 2 + (self.padding or 0) * 2
|
||||
local min = name == 'width' and 'minwidth' or 'minheight'
|
||||
local value = space
|
||||
|
||||
for _, child in ipairs(self) do
|
||||
if (name == 'width' and self.flow == 'x')
|
||||
or (name == 'height' and self.flow ~= 'x') then
|
||||
value = value + child:calculateDimensionMinimum(name)
|
||||
else
|
||||
value = math.max(value, child:calculateDimensionMinimum(name))
|
||||
end
|
||||
end
|
||||
local dim = self[name]
|
||||
dim = type(dim) == 'number' and dim
|
||||
return math.max(value, dim or 0, self[min] or 0)
|
||||
end
|
||||
|
||||
--[[--
|
||||
Get the widget's X coordinate.
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ between 0 and 1 (inclusive) to change the width of the bar.
|
||||
--]]--
|
||||
|
||||
return function (self)
|
||||
self.value = 0
|
||||
self.value = self.value or 0
|
||||
|
||||
local pad = self:addChild {
|
||||
width = 0,
|
||||
@@ -35,7 +35,7 @@ return function (self)
|
||||
y1 = y1 + min
|
||||
bar.width = false
|
||||
bar.height = false
|
||||
pad.height = h - (self.value * (y2 - y1) + min)
|
||||
pad.height = math.ceil(h - (self.value * (y2 - y1) + min))
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -44,8 +44,6 @@ local function setDimension (widget, name, size)
|
||||
or (widget.minheight or 0)
|
||||
|
||||
widget[name] = math.max(size, min)
|
||||
|
||||
return widget[name]
|
||||
end
|
||||
|
||||
|
||||
@@ -79,10 +77,9 @@ return function (self)
|
||||
end
|
||||
if nextSize then
|
||||
setDimension(nextSibling, dimension,
|
||||
nextSibling:calculatePosition(axis) +
|
||||
nextSibling:calculateDimension(dimension) - event[axis])
|
||||
nextSibling:calculatePosition(axis) + nextSize - event[axis])
|
||||
end
|
||||
|
||||
self.parent:reshape()
|
||||
end)
|
||||
|
||||
end
|
||||
|
||||
@@ -21,13 +21,22 @@ return function (self)
|
||||
self[index] = nil
|
||||
end
|
||||
|
||||
local decrement = self:addChild { type = 'stepper.left' }
|
||||
local before = self:addChild { type = 'stepper.left' }
|
||||
local view = self:addChild()
|
||||
local increment = self:addChild { type = 'stepper.right' }
|
||||
local after = self:addChild { type = 'stepper.right' }
|
||||
|
||||
self:onReshape(function (event)
|
||||
decrement.width = decrement:getHeight()
|
||||
increment.width = increment:getHeight()
|
||||
if self.flow == 'x' then
|
||||
before.height = false
|
||||
after.height = false
|
||||
before.width = 0
|
||||
after.width = 0
|
||||
else
|
||||
before.width = false
|
||||
after.width = false
|
||||
before.height = 0
|
||||
after.height = 0
|
||||
end
|
||||
end)
|
||||
|
||||
local function updateValue ()
|
||||
@@ -35,25 +44,33 @@ return function (self)
|
||||
self.value = item.value
|
||||
view[1] = nil
|
||||
view:addChild(item)
|
||||
item:reshape()
|
||||
view:reshape()
|
||||
end
|
||||
|
||||
decrement:onPress(function (event)
|
||||
local function decrement ()
|
||||
if not self.items then return end
|
||||
self.index = self.index - 1
|
||||
if self.index < 1 then
|
||||
self.index = #self.items
|
||||
end
|
||||
updateValue()
|
||||
end)
|
||||
end
|
||||
|
||||
increment:onPress(function (event)
|
||||
local function increment ()
|
||||
if not self.items then return end
|
||||
self.index = self.index + 1
|
||||
if self.index > #self.items then
|
||||
self.index = 1
|
||||
end
|
||||
updateValue()
|
||||
end
|
||||
|
||||
before:onPress(function (event)
|
||||
if self.flow == 'x' then decrement() else increment() end
|
||||
end)
|
||||
|
||||
after:onPress(function (event)
|
||||
if self.flow == 'x' then increment() else decrement() end
|
||||
end)
|
||||
|
||||
updateValue()
|
||||
|
||||
Reference in New Issue
Block a user