Woring on features #1

Open
rayaman wants to merge 2 commits from v0.1.0 into master
9 changed files with 762 additions and 176 deletions
Showing only changes of commit d1f1d79c76 - Show all commits

0
addons/init.lua Normal file
View File

View File

@ -1,4 +1,5 @@
local gui = require("gui") local gui = require("gui")
local theme = require("gui.core.theme")
local default_theme = theme:new("64342e", "b2989e", "909b9a") local default_theme = theme:new("64342e", "b2989e", "909b9a")
function gui:newWindow(x, y, w, h, text, draggable) function gui:newWindow(x, y, w, h, text, draggable)

26
core/canvas.lua Normal file
View File

@ -0,0 +1,26 @@
local gui = require("gui")
function newCanvas(domain)
local c
if domain == "visual" then
c = gui:newVisualFrame()
else
c = gui:newVirtualFrame()
end
c:fullFrame()
function c:swap(c1, c2)
local temp = c1.children
c1.children = c2.children
c2.children = temp
for i,v in pairs(c1.children) do
v.parent = c1
end
for i,v in pairs(c2.children) do
v.parent = c2
end
end
return c
end
return newCanvas

View File

@ -47,7 +47,7 @@ function color.hsl(h, s, l)
elseif h < 4 then r,b,g = 0,x,c elseif h < 4 then r,b,g = 0,x,c
elseif h < 5 then r,b,g = x,0,c elseif h < 5 then r,b,g = x,0,c
else r,b,g = c,0,x else r,b,g = c,0,x
end return (r+m)*255, (g+m)*255, (b+m)*255 end return (r+m)*255, (g+m)*255, (b+m)*255, 255
end end
min = math.min min = math.min
@ -60,7 +60,7 @@ function color.hsv(h, s, v)
local r = min (max (3*abs (((h )/180)%2-1)-1, 0), 1) local r = min (max (3*abs (((h )/180)%2-1)-1, 0), 1)
local g = min (max (3*abs (((h -120)/180)%2-1)-1, 0), 1) local g = min (max (3*abs (((h -120)/180)%2-1)-1, 0), 1)
local b = min (max (3*abs (((h +120)/180)%2-1)-1, 0), 1) local b = min (max (3*abs (((h +120)/180)%2-1)-1, 0), 1)
return k1 + k2 * r, k1 + k2 * g, k1 + k2 * b return k1 + k2 * r, k1 + k2 * g, k1 + k2 * b, 1
end end
function color.isLight(r, g, b) function color.isLight(r, g, b)
@ -102,9 +102,10 @@ function color.new(r, g, b, fmt)
end end
local temp local temp
if fmt then if fmt then
temp = {r,b,g} temp = {r, b, g, 1}
else else
temp = {love.math.colorFromBytes(r, g, b)} temp = {love.math.colorFromBytes(r, g, b)}
temp[4] = 1
end end
setmetatable(temp, mt) setmetatable(temp, mt)
return temp return temp

90
core/simulate.lua Normal file
View File

@ -0,0 +1,90 @@
local gui = require("gui")
local multi, thread = require("multi"):init()
local transition = require("gui.elements.transitions")
-- Triggers press then release
local function getPosition(obj, x, y)
if not x or y then
local cx, cy, w, h = obj:getAbsolutes()
return cx + w/2, cy + h/2
else
return x, y
end
end
proc = gui:getProcessor()
local simulate = {}
function simulate:Press(button, x, y, istouch)
if self then
x, y = getPosition(self, x, y)
elseif x == nil or y == nil then
x, y = love.mouse.getPosition()
end
love.mouse.setPosition(x, y)
gui.Events.OnMousePressed:Fire(x, y, button or gui.MOUSE_PRIMARY, istouch or false)
end
function simulate:Release(button, x, y, istouch)
if self then
x, y = getPosition(self, x, y)
elseif x == nil or y == nil then
x, y = love.mouse.getPosition()
end
love.mouse.setPosition(x, y)
gui.Events.OnMouseReleased:Fire(x, y, button or gui.MOUSE_PRIMARY, istouch or false)
end
simulate.Click = proc:newFunction(function(self, button, x, y, istouch)
if self then
x, y = getPosition(self, x, y)
elseif x == nil or y == nil then
x, y = love.mouse.getPosition()
end
love.mouse.setPosition(x, y)
gui.Events.OnMousePressed:Fire(x, y, button or gui.MOUSE_PRIMARY, istouch or false)
thread.skip(1)
gui.Events.OnMouseReleased:Fire(x, y, button or gui.MOUSE_PRIMARY, istouch or false)
end, true)
simulate.Move = proc:newFunction(function(self, dx, dy, x, y, istouch)
local dx, dy = dx or 0, dy or 0
if self then
x, y = getPosition(self, x, y)
elseif x == nil or y == nil then
x, y = love.mouse.getPosition()
end
if dx == 0 and dy == 0 then
_x, _y = love.mouse.getPosition()
if x == _x and y == _y then
return
end
local dx, dy = 0, 0
dx = x - _x
dy = y - _y
return simulate.Move(nil, dx, dy)
end
gui.Events.OnMouseMoved:Fire(x, y, 0, 0, istouch or false)
thread.skip(1)
local gx = transition.glide(0, dx, .25)
local gy = transition.glide(0, dy, .25)
local xx = gx()
xx.OnStep(function(p)
_x, _y = love.mouse.getPosition()
love.mouse.setPosition(x + p, _y)
end)
local yy = gy()
yy.OnStep(function(p)
_x, _y = love.mouse.getPosition()
love.mouse.setPosition(_x, y + p)
end)
if not(dx==0 and dy == 0) then
thread.hold(xx.OnStop * yy.OnStop)
end
gui.Events.OnMouseMoved:Fire(x + dx, y + dy, 0, 0, istouch or false)
end, true)
return simulate

View File

@ -47,7 +47,6 @@ function theme:random(seed, lightness, rand)
end end
end end
t.seed = seed t.seed = seed
return t return t
end end

104
elements/init.lua Normal file
View File

@ -0,0 +1,104 @@
local gui = require("gui")
local color = require("gui.core.color")
local theme = require("gui.core.theme")
local transition = require("gui.elements.transitions")
local processor = gui:newProcessor("menu")
function gui:newMenu(title, sx, position, trans, callback, t,t2)
if not title then multi.error("Argument 1 string('title') is required") end
if not sx then multi.error("Argument 2 number('sx') is required") end
if callback then if not type(callback) == "function" then multi.error("Argument 5 function('callback(menu(self),align[left,center,right],transition_position)') must be a function") end end
local t = t or .35
local t2 = t2 or .25
local position = position or gui.ALIGN_LEFT
local trans = trans or transition.glide
local menu, to, tc, open
if callback then
menu = self:newFrame(0, 0, 0, 0, .5 -sx/2, 1, sx, 1)
to = trans(1, 0, t)
tc = trans(0, 1, t)
else
if position == gui.ALIGN_LEFT then
menu = self:newFrame(0, 0, 0, 0, -sx, 0, sx, 1)
to = trans(-sx, 0, t2)
tc = trans(0, -sx, t2)
elseif position == gui.ALIGN_CENTER then
menu = self:newFrame(0, 0, 0, 0, .5 -sx/2, 1, sx, 1)
to = trans(1, 0, t)
tc = trans(0, 1, t)
elseif position == gui.ALIGN_RIGHT then
menu = self:newFrame(0, 0, 0, 0, 1, 0, sx, 1)
to = trans(1, 1 - sx, t2)
tc = trans(1 - sx, 1, t2)
end
end
function menu:isOpen()
return open
end
function menu:Open(show)
if show then
if not menu.lock then
menu.visible = true
menu.lock = true
local t = to()
t.OnStop(function()
open = true
menu.lock = false
end)
t.OnStep(function(p)
if callback then
callback(menu,position,p,"open")
for i,v in pairs(menu:getAllChildren()) do
callback(v,position,p,"open")
end
else
if position == gui.ALIGN_CENTER then
menu:setDualDim(nil, nil, nil, nil, nil, p)
else
menu:setDualDim(nil, nil, nil, nil, p)
end
end
end)
end
else
if not menu.lock then
menu.lock = true
local t = tc()
t.OnStop(function()
open = false
menu.lock = false
menu.visible = false
end)
t.OnStep(function(p)
if callback then
callback(menu,position,p,"open")
for i,v in pairs(menu:getAllChildren()) do
callback(v,position,p,"open")
end
else
if position == gui.ALIGN_CENTER then
menu:setDualDim(nil, nil, nil, nil, nil, p)
else
menu:setDualDim(nil, nil, nil, nil, p)
end
end
end)
end
end
end
menu.OnCreate = processor:newConnection()
local items = {}
function menu:addItem(text)
local item = menu:newTextButton(text,0,100*#items,0,100,0,0,1)
items[#items+1] = item
item:fitFont()
item.align = gui.ALIGN_CENTER
self.OnCreate:Fire(self,item,items)
end
return menu
end

65
elements/transitions.lua Normal file
View File

@ -0,0 +1,65 @@
local gui = require("gui")
local multi, thread = require("multi"):init()
local processor = gui:newProcessor("Transistion Processor")
local transition = {}
local width, height, flags = love.window.getMode()
local fps = 60
if flags.refreshrate > 0 then
fps = flags.refreshrate
end
transition.__index = transition
transition.__call = function(t, start, stop, time, ...)
local args = {...}
return function()
if not start or not stop then return multi.error("start and stop must be supplied") end
if start == stop then
local temp = {
OnStep = function() end,
OnStop = multi:newConnection()
}
proc:newTask(function()
temp.OnStop:Fire()
end)
return temp
end
local handle = t.func(t, start, stop, time or 1, unpack(args))
return {
OnStep = handle.OnStatus,
OnStop = handle.OnReturn + handle.OnError
}
end
end
function transition:newTransition(func)
local c = {}
setmetatable(c, self)
c.fps = fps
c.func = processor:newFunction(func)
c.OnStop = multi:newConnection()
function c:SetFPS(fps)
self.fps = fps
end
function c:GetFPS(fps)
return self.fps
end
return c
end
transition.glide = transition:newTransition(function(t, start, stop, time, ...)
local steps = t.fps*time
local piece = time/steps
local split = stop-start
for i = 0, steps do
thread.sleep(piece)
thread.pushStatus(start + i*(split/steps))
end
end)
return transition

542
init.lua
View File

@ -4,7 +4,9 @@ local GLOBAL, THREAD = require("multi.integration.loveManager"):init()
local color = require("gui.core.color") local color = require("gui.core.color")
local gui = {} local gui = {}
local updater = multi:newProcessor("UpdateManager", true) local updater = multi:newProcessor("UpdateManager", true)
local drawer = multi:newProcessor("DrawManager", true) local drawer = multi:newProcessor("DrawManager", true)
local bit = require("bit") local bit = require("bit")
local band, bor = bit.band, bit.bor local band, bor = bit.band, bit.bor
local cursor_hand = love.mouse.getSystemCursor("hand") local cursor_hand = love.mouse.getSystemCursor("hand")
@ -16,6 +18,8 @@ local global_drag
local object_focus = gui local object_focus = gui
local first_loop = false local first_loop = false
gui.Version = "0.1.0"
-- Types -- Types
gui.TYPE_FRAME = frame gui.TYPE_FRAME = frame
gui.TYPE_IMAGE = image gui.TYPE_IMAGE = image
@ -25,7 +29,7 @@ gui.TYPE_VIDEO = video
gui.TYPE_BUTTON = button gui.TYPE_BUTTON = button
gui.TYPE_ANIM = anim gui.TYPE_ANIM = anim
-- -- Variables
gui.__index = gui gui.__index = gui
gui.MOUSE_PRIMARY = 1 gui.MOUSE_PRIMARY = 1
@ -58,6 +62,16 @@ gui.Events.OnTouchMoved = multi:newConnection()
gui.Events.OnTouchPressed = multi:newConnection() gui.Events.OnTouchPressed = multi:newConnection()
gui.Events.OnTouchReleased = multi:newConnection() gui.Events.OnTouchReleased = multi:newConnection()
-- Joysticks and gamepads
gui.Events.OnGamepadPressed = multi:newConnection()
gui.Events.OnGamepadReleased = multi:newConnection()
gui.Events.OnGamepadAxis = multi:newConnection()
gui.Events.OnJoystickAdded = multi:newConnection()
gui.Events.OnJoystickHat = multi:newConnection()
gui.Events.OnJoystickPressed = multi:newConnection()
gui.Events.OnJoystickReleased = multi:newConnection()
gui.Events.OnJoystickRemoved = multi:newConnection()
-- Non Love Events -- Non Love Events
gui.Events.OnThemeChanged = multi:newConnection() gui.Events.OnThemeChanged = multi:newConnection()
@ -82,27 +96,44 @@ local function Hook(funcname, func)
end end
end end
-- This will run the hooks after everything has loaded -- Incase you define one of these methods, we need to process this after that
updater:newTask(function() updater:newTask(function()
-- System
Hook("quit", gui.Events.OnQuit.Fire) Hook("quit", gui.Events.OnQuit.Fire)
Hook("directorydropped", gui.Events.OnDirectoryDropped.Fire) Hook("directorydropped", gui.Events.OnDirectoryDropped.Fire)
Hook("displayrotated", gui.Events.OnDisplayRotated.Fire) Hook("displayrotated", gui.Events.OnDisplayRotated.Fire)
Hook("filedropped", gui.Events.OnFilesDropped.Fire) Hook("filedropped", gui.Events.OnFilesDropped.Fire)
Hook("focus", gui.Events.OnFocus.Fire) Hook("focus", gui.Events.OnFocus.Fire)
Hook("mousefocus", gui.Events.OnMouseFocus.Fire)
Hook("resize", gui.Events.OnResized.Fire) Hook("resize", gui.Events.OnResized.Fire)
Hook("visible", gui.Events.OnVisible.Fire) Hook("visible", gui.Events.OnVisible.Fire)
-- Mouse
Hook("mousefocus", gui.Events.OnMouseFocus.Fire)
Hook("keypressed", gui.Events.OnKeyPressed.Fire) Hook("keypressed", gui.Events.OnKeyPressed.Fire)
Hook("keyreleased", gui.Events.OnKeyReleased.Fire) Hook("keyreleased", gui.Events.OnKeyReleased.Fire)
Hook("textedited", gui.Events.OnTextEdited.Fire)
Hook("textinput", gui.Events.OnTextInputed.Fire)
Hook("mousemoved", gui.Events.OnMouseMoved.Fire) Hook("mousemoved", gui.Events.OnMouseMoved.Fire)
Hook("mousepressed", gui.Events.OnMousePressed.Fire) Hook("mousepressed", gui.Events.OnMousePressed.Fire)
Hook("mousereleased", gui.Events.OnMouseReleased.Fire) Hook("mousereleased", gui.Events.OnMouseReleased.Fire)
Hook("wheelmoved", gui.Events.OnWheelMoved.Fire) Hook("wheelmoved", gui.Events.OnWheelMoved.Fire)
-- Keyboard
Hook("textedited", gui.Events.OnTextEdited.Fire)
Hook("textinput", gui.Events.OnTextInputed.Fire)
-- Touchscreen
Hook("touchmoved", gui.Events.OnTouchMoved.Fire) Hook("touchmoved", gui.Events.OnTouchMoved.Fire)
Hook("touchpressed", gui.Events.OnTouchPressed.Fire) Hook("touchpressed", gui.Events.OnTouchPressed.Fire)
Hook("touchreleased", gui.Events.OnTouchReleased.Fire) Hook("touchreleased", gui.Events.OnTouchReleased.Fire)
-- Joystick/Gamepad
Hook("gamepadpressed", gui.Events.OnGamepadPressed.Fire)
Hook("gamepadaxis", gui.Events.OnGamepadAxis.Fire)
Hook("gamepadreleased", gui.Events.OnGamepadReleased.Fire)
Hook("joystickpressed", gui.Events.OnJoystickPressed.Fire)
Hook("joystickreleased", gui.Events.OnJoystickReleased.Fire)
Hook("joystickhat", gui.Events.OnJoystickHat.Fire)
Hook("joystickremoved", gui.Events.OnJoystickRemoved.Fire)
Hook("joystickadded", gui.Events.OnJoystickAdded.Fire)
end) end)
-- Hotkeys -- Hotkeys
@ -179,6 +210,10 @@ gui.HotKeys.OnRedo = gui:setHotKey({"lctrl", "y"}) +
-- Utils -- Utils
gui.newFunction = updater.newFunction
function gui:getProcessor() return updater end
function gui:getObjectFocus() return object_focus end function gui:getObjectFocus() return object_focus end
function gui:hasType(t) return band(self.type, t) == t end function gui:hasType(t) return band(self.type, t) == t end
@ -186,6 +221,7 @@ function gui:hasType(t) return band(self.type, t) == t end
function gui:move(x, y) function gui:move(x, y)
self.dualDim.offset.pos.x = self.dualDim.offset.pos.x + x self.dualDim.offset.pos.x = self.dualDim.offset.pos.x + x
self.dualDim.offset.pos.y = self.dualDim.offset.pos.y + y self.dualDim.offset.pos.y = self.dualDim.offset.pos.y + y
self.OnPositionChanged:Fire(self, x, y)
end end
function gui:moveInBounds(dx, dy) function gui:moveInBounds(dx, dy)
@ -237,7 +273,29 @@ end
function gui:getChildren() return self.children end function gui:getChildren() return self.children end
function gui:getAbsolutes() -- returns x, y, w, h function gui:offsetToScale()
local children = self:getAllChildren()
for i = 1, #children do
local child = children[i]
local x, y = child:getAbsolutes()
local _, __, w, h = child.parent:getAbsolutes()
print(x / w, y / h)
local _, __, w, h = child:getAbsolutes()
local _, __, pw, ph = child.parent:getAbsolutes()
print(w / pw, h / ph)
end
end
function gui:getAbsolutes(transform) -- returns x, y, w, h
if transform then
return transform((self.parent.w * self.dualDim.scale.pos.x) +
self.dualDim.offset.pos.x + self.parent.x),
transform((self.parent.h * self.dualDim.scale.pos.y) +
self.dualDim.offset.pos.y + self.parent.y), transform((self.parent.w *
self.dualDim.scale.size.x) + self.dualDim.offset.size.x),
transform((self.parent.h * self.dualDim.scale.size.y) +
self.dualDim.offset.size.y)
else
return (self.parent.w * self.dualDim.scale.pos.x) + return (self.parent.w * self.dualDim.scale.pos.x) +
self.dualDim.offset.pos.x + self.parent.x, self.dualDim.offset.pos.x + self.parent.x,
(self.parent.h * self.dualDim.scale.pos.y) + (self.parent.h * self.dualDim.scale.pos.y) +
@ -245,6 +303,7 @@ function gui:getAbsolutes() -- returns x, y, w, h
self.dualDim.scale.size.x) + self.dualDim.offset.size.x, self.dualDim.scale.size.x) + self.dualDim.offset.size.x,
(self.parent.h * self.dualDim.scale.size.y) + (self.parent.h * self.dualDim.scale.size.y) +
self.dualDim.offset.size.y self.dualDim.offset.size.y
end
end end
function gui:getAllChildren(vis) function gui:getAllChildren(vis)
@ -263,31 +322,38 @@ function gui:getAllChildren(vis)
end end
function gui:newThread(func) function gui:newThread(func)
return updater:newThread("ThreadHandler<" .. self.type .. ">", func, self, return updater:newThread("ThreadHandler<" .. self.type .. ">", func, self, thread)
thread)
end end
function gui:setDualDim(x, y, w, h, sx, sy, sw, sh) function gui:setDualDim(x, y, w, h, sx, sy, sw, sh)
self.dualDim.offset = { --[[
pos = { dd.offset.pos = {x = x or 0, y = y or 0}
x = x or self.dualDim.offset.pos.x, self.dualDim.offset.size = {x = w or 0, y = h or 0}
y = y or self.dualDim.offset.pos.y self.dualDim.scale.pos = {x = sx or 0, y = sy or 0}
}, self.dualDim.scale.size = {x = sw or 0, y = sh or 0}
size = { ]]
x = w or self.dualDim.offset.size.x, self.dualDim = self:newDualDim(
y = h or self.dualDim.offset.size.y x or self.dualDim.offset.pos.x,
} y or self.dualDim.offset.pos.y,
} w or self.dualDim.offset.size.x,
self.dualDim.scale = { h or self.dualDim.offset.size.y,
pos = { sx or self.dualDim.scale.pos.x,
x = sx or self.dualDim.scale.pos.x, sy or self.dualDim.scale.pos.y,
y = sy or self.dualDim.scale.pos.y sw or self.dualDim.scale.size.x,
}, sh or self.dualDim.scale.size.y)
size = { self.OnSizeChanged:Fire(self, x, y, w, h, sx, sy, sw, sh)
x = sw or self.dualDim.scale.size.x, end
y = sh or self.dualDim.scale.size.y
} function gui:rawSetDualDim(x, y, w, h, sx, sy, sw, sh)
} self.dualDim = self:newDualDim(
x or self.dualDim.offset.pos.x,
y or self.dualDim.offset.pos.y,
w or self.dualDim.offset.size.x,
h or self.dualDim.offset.size.y,
sx or self.dualDim.scale.pos.x,
sy or self.dualDim.scale.pos.y,
sw or self.dualDim.scale.size.x,
sh or self.dualDim.scale.size.y)
end end
local image_cache = {} local image_cache = {}
@ -332,6 +398,11 @@ end
local mainupdater = updater:newLoop().OnLoop local mainupdater = updater:newLoop().OnLoop
function gui:OnUpdate(func) -- Not crazy about this approach, will probably rework this
if type(self) == "function" then func = self end
mainupdater(function() func(self) end)
end
function gui:canPress(mx, my) -- Get the intersection of the clip area and the self then test with the clip, otherwise test as normal function gui:canPress(mx, my) -- Get the intersection of the clip area and the self then test with the clip, otherwise test as normal
local x, y, w, h local x, y, w, h
if self.__variables.clip[1] then if self.__variables.clip[1] then
@ -385,8 +456,7 @@ function gui:clone(opt)
connections: Do we copy connections? (true/false) connections: Do we copy connections? (true/false)
} }
]] ]]
-- DO = {[[setImage]], c.image or IMAGE}
-- Connections are used greatly throughout do we copy those
local temp local temp
local u = self:getUniques() local u = self:getUniques()
if self.type == frame then if self.type == frame then
@ -398,9 +468,9 @@ function gui:clone(opt)
elseif self.type == text then elseif self.type == text then
temp = gui:newTextLabel(self.text, self:getDualDim()) temp = gui:newTextLabel(self.text, self:getDualDim())
elseif self.type == image + button then elseif self.type == image + button then
temp = gui:newImageButton(u.DO[2], self:getDualDim()) temp = gui:newImageButton(u.Do[2], self:getDualDim())
elseif self.type == image then elseif self.type == image then
temp = gui:newImageLabel(u.DO[2], self:getDualDim()) temp = gui:newImageLabel(u.Do[2], self:getDualDim())
else -- We are dealing with a complex object else -- We are dealing with a complex object
temp = processDo(u) temp = processDo(u)
end end
@ -413,7 +483,7 @@ function gui:clone(opt)
if opt.connections then if opt.connections then
conn = true conn = true
for i, v in pairs(self) do for i, v in pairs(self) do
if v.Type == "connector" then if type(v) == "table" and v.Type == "connector" then
-- We want to copy the connection functions from the original object and bind them to the new one -- We want to copy the connection functions from the original object and bind them to the new one
if not temp[i] then if not temp[i] then
-- Incase we are dealing with a custom object, create a connection if the custom objects unique declearation didn't -- Incase we are dealing with a custom object, create a connection if the custom objects unique declearation didn't
@ -437,6 +507,11 @@ function gui:isActive()
return self.active and not (self:isDescendantOf(gui.virtual)) return self.active and not (self:isDescendantOf(gui.virtual))
end end
function gui:isOnScreen()
return
end
-- Base get uniques -- Base get uniques
function gui:getUniques(tab) function gui:getUniques(tab)
local base = { local base = {
@ -445,6 +520,7 @@ function gui:getUniques(tab)
visibility = self.visibility, visibility = self.visibility,
color = self.color, color = self.color,
borderColor = self.borderColor, borderColor = self.borderColor,
drawBorder = self.drawborder,
rotation = self.rotation rotation = self.rotation
} }
@ -452,9 +528,32 @@ function gui:getUniques(tab)
return base return base
end end
function gui:setTag(tag)
self.tags[tag] = true
end
function gui:hasTag(tag)
return self.tags[tag]
end
function gui:parentHasTag(tag)
local parent = self.parent
while parent do
if parent.tags and parent.tags[tag] then return true end
parent = parent.parent
if parent == gui.virtual or parent == gui then return false end
end
return false
end
local function testVisual(c, x, y, button, istouch, presses)
return not(c:hasTag("visual") or c:parentHasTag("visual"))
end
-- Base Library -- Base Library
function gui:newBase(typ, x, y, w, h, sx, sy, sw, sh, virtual) function gui:newBase(typ, x, y, w, h, sx, sy, sw, sh, virtual)
local c = {} local c = {}
c.tags = {}
local buildBackBetter local buildBackBetter
local centerX = false local centerX = false
local centerY = false local centerY = false
@ -470,8 +569,19 @@ function gui:newBase(typ, x, y, w, h, sx, sy, sw, sh, virtual)
return true return true
end end
setmetatable(c, gui) local function defaultCheck(...)
if not c:isActive() then return false end
local x, y = love.mouse.getPosition()
if c:canPress(x, y) then
return c, ...
end
return false
end
setmetatable(c, self)
c.__index = self.__index
c.__variables = {clip = {false, 0, 0, 0, 0}} c.__variables = {clip = {false, 0, 0, 0, 0}}
c.focus = false
c.active = true c.active = true
c.type = typ c.type = typ
c.dualDim = self:newDualDim(x, y, w, h, sx, sy, sw, sh) c.dualDim = self:newDualDim(x, y, w, h, sx, sy, sw, sh)
@ -480,22 +590,38 @@ function gui:newBase(typ, x, y, w, h, sx, sy, sw, sh, virtual)
c.visibility = 1 c.visibility = 1
c.color = {.6, .6, .6} c.color = {.6, .6, .6}
c.borderColor = color.black c.borderColor = color.black
c.drawBorder = true
c.rotation = 0 c.rotation = 0
c.OnPressed = testHierarchy .. multi:newConnection() c.OnLoad = multi:newConnection()
c.OnPressedOuter = multi:newConnection()
c.OnReleased = testHierarchy .. multi:newConnection()
c.OnReleasedOuter = multi:newConnection()
c.OnReleasedOther = multi:newConnection()
c.OnDragStart = multi:newConnection() c.OnPressed = testVisual .. (testHierarchy .. multi:newConnection())
c.OnDragging = multi:newConnection() c.OnPressedOuter = testVisual .. multi:newConnection()
c.OnDragEnd = multi:newConnection() c.OnReleased = testVisual .. (testHierarchy .. multi:newConnection())
c.OnReleasedOuter = testVisual .. multi:newConnection()
c.OnReleasedOther = testVisual .. multi:newConnection()
c.OnEnter = testHierarchy .. multi:newConnection() c.OnDragStart = testVisual .. multi:newConnection()
c.OnExit = multi:newConnection() c.OnDragging = testVisual .. multi:newConnection()
c.OnDragEnd = testVisual .. multi:newConnection()
c.OnMoved = testHierarchy .. multi:newConnection() c.OnEnter = (testHierarchy .. multi:newConnection())
c.OnExit = testVisual .. multi:newConnection()
c.OnMoved = testVisual .. (testHierarchy .. multi:newConnection())
c.OnWheelMoved = testVisual .. (defaultCheck / gui.Events.OnWheelMoved)
c.OnSizeChanged = testVisual .. multi:newConnection()
c.OnPositionChanged = testVisual .. multi:newConnection()
c.OnLeftStickUp = testVisual .. multi:newConnection()
c.OnLeftStickDown = testVisual .. multi:newConnection()
c.OnLeftStickLeft = testVisual .. multi:newConnection()
c.OnLeftStickRight = testVisual .. multi:newConnection()
c.OnRightStickUp = testVisual .. multi:newConnection()
c.OnRightStickDown = testVisual .. multi:newConnection()
c.OnRightStickLeft = testVisual .. multi:newConnection()
c.OnRightStickRight = testVisual .. multi:newConnection()
local dragging = false local dragging = false
local entered = false local entered = false
@ -522,7 +648,7 @@ function gui:newBase(typ, x, y, w, h, sx, sy, sw, sh, virtual)
gui.Events.OnMouseReleased(function(x, y, button, istouch, presses) gui.Events.OnMouseReleased(function(x, y, button, istouch, presses)
if not c:isActive() then return end if not c:isActive() then return end
if c:canPress(x, y) then if c:canPress(x, y) then
c.OnReleased:Fire(c, x, y, dx, dy, istouch, presses) c.OnReleased:Fire(c, x, y, button, istouch, presses)
elseif pressed then elseif pressed then
c.OnReleasedOuter:Fire(c, x, y, button, istouch, presses) c.OnReleasedOuter:Fire(c, x, y, button, istouch, presses)
else else
@ -559,6 +685,11 @@ function gui:newBase(typ, x, y, w, h, sx, sy, sw, sh, virtual)
end end
end) end)
function c:isOffScreen()
local x, y, w, h = self:getAbsolutes()
return y + h < 0 or y > gui.h or x + w < 0 or x > gui.w
end
function c:setRoundness(rx, ry, seg, side) function c:setRoundness(rx, ry, seg, side)
self.roundness = side or true self.roundness = side or true
self.__rx, self.__ry, self.__segments = rx or 5, ry or 5, seg or 30 self.__rx, self.__ry, self.__segments = rx or 5, ry or 5, seg or 30
@ -571,27 +702,16 @@ function gui:newBase(typ, x, y, w, h, sx, sy, sw, sh, virtual)
function c:respectHierarchy(bool) hierarchy = bool end function c:respectHierarchy(bool) hierarchy = bool end
function c:OnUpdate(func) -- Not crazy about this approach, will probably rework this
if type(self) == "function" then func = self end
mainupdater(function() func(c) end)
end
local function centerthread() local function centerthread()
local centerfunc = function() if centerX or centerY then
return centerX or centerY -- If the condition is true it acts like a yield
end
c:newThread(function()
while true do
thread.hold(centerfunc)
local x, y, w, h = c:getAbsolutes() local x, y, w, h = c:getAbsolutes()
if centerX then if centerX then
c:setDualDim(-w / 2, nil, nil, nil, .5) c:rawSetDualDim(-w / 2, nil, nil, nil, .5)
end end
if centerY then if centerY then
c:setDualDim(nil, -h / 2, nil, nil, nil, .5) c:rawSetDualDim(nil, -h / 2, nil, nil, nil, .5)
end end
end end
end)
end end
function c:enableDragging(but) function c:enableDragging(but)
@ -607,14 +727,22 @@ function gui:newBase(typ, x, y, w, h, sx, sy, sw, sh, virtual)
centerX = bool centerX = bool
if centering then return end if centering then return end
centering = true centering = true
centerthread() self.OnSizeChanged(centerthread)
self.OnPositionChanged(centerthread)
updater:newLoop(centerthread)
end end
function c:centerY(bool) function c:centerY(bool)
centerY = bool centerY = bool
if centering then return end if centering then return end
centering = true centering = true
centerthread() self.OnSizeChanged(centerthread)
self.OnPositionChanged(centerthread)
updater:newLoop(centerthread)
end
function c:fullFrame()
self:setDualDim(0,0,0,0,0,0,1,1)
end end
-- Add to the parents children table -- Add to the parents children table
@ -625,6 +753,7 @@ function gui:newBase(typ, x, y, w, h, sx, sy, sw, sh, virtual)
c.parent = self c.parent = self
table.insert(self.children, c) table.insert(self.children, c)
end end
local a = 0
return c return c
end end
@ -653,6 +782,13 @@ end
function gui:newVirtualFrame(x, y, w, h, sx, sy, sw, sh) function gui:newVirtualFrame(x, y, w, h, sx, sy, sw, sh)
return self:newBase(frame, x, y, w, h, sx, sy, sw, sh, true) return self:newBase(frame, x, y, w, h, sx, sy, sw, sh, true)
end end
function gui:newVisualFrame(x, y, w, h, sx, sy, sw, sh)
local visual = self:newBase(frame, x, y, w, h, sx, sy, sw, sh)
visual:setTag("visual")
return visual
end
local testIMG local testIMG
-- Texts -- Texts
function gui:newTextBase(typ, txt, x, y, w, h, sx, sy, sw, sh) function gui:newTextBase(typ, txt, x, y, w, h, sx, sy, sw, sh)
@ -669,7 +805,7 @@ function gui:newTextBase(typ, txt, x, y, w, h, sx, sy, sw, sh)
c.textVisibility = 1 c.textVisibility = 1
c.font = love.graphics.newFont(12) c.font = love.graphics.newFont(12)
c.textColor = color.black c.textColor = color.black
c.OnFontUpdated = multi:newConnection() c.OnFontUpdated = testVisual .. multi:newConnection()
function c:calculateFontOffset(font, adjust) function c:calculateFontOffset(font, adjust)
local adjust = adjust or 20 local adjust = adjust or 20
@ -716,7 +852,9 @@ function gui:newTextBase(typ, txt, x, y, w, h, sx, sy, sw, sh)
end end
function c:setFont(font, size) function c:setFont(font, size)
if type(font) == "string" then if type(font) == "number" then
self.font = love.graphics.newFont(font)
elseif type(font) == "string" then
self.fontFile = font self.fontFile = font
self.font = love.graphics.newFont(font, size) self.font = love.graphics.newFont(font, size)
else else
@ -725,10 +863,8 @@ function gui:newTextBase(typ, txt, x, y, w, h, sx, sy, sw, sh)
self.OnFontUpdated:Fire(self) self.OnFontUpdated:Fire(self)
end end
function c:fitFont(n, max) function c:fitFont(min_size, max_size)
local max = max or math.huge
local font local font
local isdefault = false
if self.fontFile then if self.fontFile then
if self.fontFile:match("ttf") then if self.fontFile:match("ttf") then
font = function(n) font = function(n)
@ -740,26 +876,66 @@ function gui:newTextBase(typ, txt, x, y, w, h, sx, sy, sw, sh)
end end
end end
else else
isdefault = true
font = function(n) return love.graphics.setNewFont(n) end font = function(n) return love.graphics.setNewFont(n) end
end end
local x, y, width, height = self:getAbsolutes() local text = self.text
local Font, text = self.Font, self.text local x, y, max_width, max_height = self:getAbsolutes()
local s = 3 local min_size = min_size or 1
Font = font(s) local max_size = max_size or 100 -- You can adjust the maximum font size as needed
while height < max and Font:getHeight() < height and Font:getWidth(text) < width do local tolerance = 0.1
s = s + 1 local f
Font = font(s) while max_size - min_size > tolerance do
local size = (min_size + max_size) / 2
f = font(size)
local text_width = f:getWidth(text)
local text_height = f:getHeight()
if text_width > max_width or text_height > max_height then
max_size = size
else
min_size = size
end end
Font = font(s - (4 + (n or 0)))
Font:setFilter("linear", "nearest", 4)
self.font = Font
self.textOffsetY = 0
local top, bottom = self:calculateFontOffset(Font, 0)
self.textOffsetY = floor(((height - bottom) - top) / 2)
self.OnFontUpdated:Fire(self)
return s - (4 + (n or 0))
end end
self:setFont(f)
return min_size
end
-- function c:fitFont(n, max)
-- local max = max or math.huge
-- local font
-- local isdefault = false
-- if self.fontFile then
-- if self.fontFile:match("ttf") then
-- font = function(n)
-- return love.graphics.newFont(self.fontFile, n, "normal")
-- end
-- else
-- font = function(n)
-- return love.graphics.newFont(self.fontFile, n)
-- end
-- end
-- else
-- isdefault = true
-- font = function(n) return love.graphics.setNewFont(n) end
-- end
-- local x, y, width, height = self:getAbsolutes()
-- local Font, text = self.Font, self.text
-- local s = 3
-- Font = font(s)
-- while height < max and Font:getHeight() < height and Font:getWidth(text) < width do
-- s = s + 1
-- Font = font(s)
-- end
-- Font = font(s - (4 + (n or 0)))
-- Font:setFilter("linear", "nearest", 4)
-- self.font = Font
-- self.textOffsetY = 0
-- local top, bottom = self:calculateFontOffset(Font, 0)
-- self.textOffsetY = floor(((height - bottom) - top) / 2)
-- self.OnFontUpdated:Fire(self)
-- return s - (4 + (n or 0))
-- end
function c:centerFont() function c:centerFont()
local x, y, width, height = self:getAbsolutes() local x, y, width, height = self:getAbsolutes()
@ -842,7 +1018,7 @@ function gui:newTextBox(txt, x, y, w, h, sx, sy, sw, sh)
c:respectHierarchy(true) c:respectHierarchy(true)
c.doSelection = false c.doSelection = false
c.OnReturn = multi:newConnection() c.OnReturn = testVisual .. multi:newConnection()
c.cur_pos = 0 c.cur_pos = 0
c.selection = {0, 0} c.selection = {0, 0}
@ -1027,12 +1203,12 @@ local load_images = THREAD:newFunction(function(paths)
require("love.image") require("love.image")
local images = #paths local images = #paths
for i = 1, #paths do for i = 1, #paths do
sThread.pushStatus(i, images, love.image.newImageData(paths[i])) _G.THREAD.pushStatus(i, images, love.image.newImageData(paths[i]))
end end
end) end)
-- Loads a resource and adds it to the cache -- Loads a resource and adds it to the cache
gui.cacheImage = thread:newFunction(function(self, path_or_paths) gui.cacheImage = updater:newFunction(function(self, path_or_paths)
if type(path_or_paths) == "string" then if type(path_or_paths) == "string" then
-- runs thread to load image then cache it for faster loading -- runs thread to load image then cache it for faster loading
load_image(path_or_paths).OnReturn(function(img) load_image(path_or_paths).OnReturn(function(img)
@ -1048,10 +1224,48 @@ gui.cacheImage = thread:newFunction(function(self, path_or_paths)
end end
end) end)
function gui:applyGradient(direction, ...)
local colors = {...}
if direction == "horizontal" then
direction = true
elseif direction == "vertical" then
direction = false
else
error("Invalid direction '" .. tostring(direction) .. "' for gradient. Horizontal or vertical expected.")
end
local result = love.image.newImageData(direction and 1 or #colors, direction and #colors or 1)
for i, color in ipairs(colors) do
local x, y
if direction then
x, y = 0, i - 1
else
x, y = i - 1, 0
end
result:setPixel(x, y, color[1], color[2], color[3], color[4] or 255)
end
local img = love.graphics.newImage(result)
img:setFilter('linear', 'linear')
local x, y, w, h = self:getAbsolutes()
self.imageColor = color.white
self.imageVisibility = 1
self.image = img
self.image:setWrap("repeat", "repeat")
self.imageHeight = img:getHeight()
self.imageWidth = img:getWidth()
self.quad = love.graphics.newQuad(0, 0, self.imageWidth, self.imageHeight, self.imageWidth, self.imageHeight)
if not (band(self.type, image) == image) then
self.type = self.type + image
end
end
function gui:newImageBase(typ, x, y, w, h, sx, sy, sw, sh) function gui:newImageBase(typ, x, y, w, h, sx, sy, sw, sh)
local c = self:newBase(image + typ, x, y, w, h, sx, sy, sw, sh) local c = self:newBase(image + typ, x, y, w, h, sx, sy, sw, sh)
c.color = color.white c.color = color.white
c.visibility = 0 c.visibility = 0
c.scaleX = 1
c.scaleY = 1
local IMAGE local IMAGE
function c:getUniques() function c:getUniques()
@ -1061,28 +1275,39 @@ function gui:newImageBase(typ, x, y, w, h, sx, sy, sw, sh)
}) })
end end
function c:flip(vert)
if vert then
c.scaleY = c.scaleY * -1
else
c.scaleX = c.scaleX * -1
end
end
function c:getSource()
return IMAGE
end
c.setImage = function(self, i, x, y, w, h) c.setImage = function(self, i, x, y, w, h)
if i == nil then return end if i == nil then return end
local img = load_image(i) img = love.image.newImageData(i)
load_image(i).OnReturn(function(img)
img = love.graphics.newImage(img) img = love.graphics.newImage(img)
IMAGE = i IMAGE = i
if type(i) == "string" then i = image_cache[i] or i end if type(i) == "string" then i = image_cache[i] or i end
if i and x then if i and x then
self.imageHeigth = h c.imageHeight = h
self.imageWidth = w c.imageWidth = w
if type(i) == "string" then if type(i) == "string" then
image_cache[i] = img image_cache[i] = img
i = image_cache[i] i = image_cache[i]
end end
self.image = i c.image = i
self.image:setWrap("repeat", "repeat") c.image:setWrap("repeat", "repeat")
self.imageColor = color.white c.imageColor = color.white
self.quad = love.graphics.newQuad(x, y, w, h, self.image:getWidth(), self.image:getHeight()) c.quad = love.graphics.newQuad(x, y, w, h, c.image:getWidth(), c.image:getHeight())
self.imageVisibility = 1 c.imageVisibility = 1
return return
end end
@ -1091,15 +1316,14 @@ function gui:newImageBase(typ, x, y, w, h, sx, sy, sw, sh)
img = i img = i
end end
local x, y, w, h = self:getAbsolutes() local x, y, w, h = c:getAbsolutes()
self.imageColor = color.white c.imageColor = color.white
self.imageVisibility = 1 c.imageVisibility = 1
self.image = img c.image = img
self.image:setWrap("repeat", "repeat") c.image:setWrap("repeat", "repeat")
self.imageHeigth = img:getHeight() c.imageHeight = img:getHeight()
self.imageWidth = img:getWidth() c.imageWidth = img:getWidth()
self.quad = love.graphics.newQuad(0, 0, self.imageWidth, self.imageHeigth, self.imageWidth, self.imageHeigth) c.quad = love.graphics.newQuad(0, 0, c.imageWidth, c.imageHeight, c.imageWidth, c.imageHeight)
end)
end end
return c return c
end end
@ -1200,9 +1424,24 @@ local drawtypes = {
[0] = function(child, x, y, w, h) end, [0] = function(child, x, y, w, h) end,
[1] = function(child, x, y, w, h) [1] = function(child, x, y, w, h)
if child.image then if child.image then
if child.scaleX < 0 or child.scaleY < 0 then
local sx, sy = child.scaleX, child.scaleY
local adjustX, adjustY = child.scaleX * w, child.scaleY * h
love.graphics.setColor(child.imageColor[1], child.imageColor[2], love.graphics.setColor(child.imageColor[1], child.imageColor[2],
child.imageColor[3], child.imageVisibility) child.imageColor[3], child.imageVisibility)
love.graphics.draw(child.image, child.quad, x, y, rad(child.rotation), w / child.imageWidth, h / child.imageHeigth) if sx < 0 and sy < 0 then
love.graphics.draw(child.image, child.quad, x - adjustX, y - adjustY, rad(child.rotation), (w / child.imageWidth) * child.scaleX, (h / child.imageHeight) * child.scaleY)
elseif sx < 0 then
love.graphics.draw(child.image, child.quad, x - adjustX, y, rad(child.rotation), (w / child.imageWidth) * child.scaleX, h / child.imageHeight)
else
love.graphics.draw(child.image, child.quad, x, y - adjustY, rad(child.rotation), w / child.imageWidth, (h / child.imageHeight) * child.scaleY)
end
else
love.graphics.setColor(child.imageColor[1], child.imageColor[2],
child.imageColor[3], child.imageVisibility)
love.graphics.draw(child.image, child.quad, x, y, rad(child.rotation), w / child.imageWidth, h / child.imageHeight)
end
end end
end, end,
[2] = function(child, x, y, w, h) [2] = function(child, x, y, w, h)
@ -1251,7 +1490,7 @@ local drawtypes = {
if child.video and child.playing then if child.video and child.playing then
love.graphics.setColor(child.videoColor[1], child.videoColor[2], love.graphics.setColor(child.videoColor[1], child.videoColor[2],
child.videoColor[3], child.videoVisibility) child.videoColor[3], child.videoVisibility)
if w ~= child.imageWidth and h ~= child.imageHeigth then if w ~= child.imageWidth and h ~= child.imageHeight then
love.graphics.draw(child.video, x, y, rad(child.rotation), love.graphics.draw(child.video, x, y, rad(child.rotation),
w / child.videoWidth, h / child.videoHeigth) w / child.videoWidth, h / child.videoHeigth)
else else
@ -1266,7 +1505,7 @@ local drawtypes = {
end end
} }
local draw_handler = function(child) local draw_handler = function(child, no_draw)
local bg = child.color local bg = child.color
local bbg = child.borderColor local bbg = child.borderColor
local ctype = child.type local ctype = child.type
@ -1280,6 +1519,8 @@ local draw_handler = function(child)
child.w = w child.w = w
child.h = h child.h = h
if no_draw then return end
if child.clipDescendants then if child.clipDescendants then
local children = child:getAllChildren() local children = child:getAllChildren()
for c = 1, #children do -- Tell the children to clip themselves for c = 1, #children do -- Tell the children to clip themselves
@ -1292,29 +1533,37 @@ local draw_handler = function(child)
end end
end end
if child.shader and band(ctype, image) == 2 then
love.graphics.setShader(child.shader)
end
if child.__variables.clip[1] then if child.__variables.clip[1] then
local clip = child.__variables.clip local clip = child.__variables.clip
love.graphics.setScissor(clip[2], clip[3], clip[4], clip[5]) love.graphics.setScissor(clip[2], clip[3], clip[4], clip[5])
elseif type(roundness) == "string" then elseif type(roundness) == "string" then
love.graphics.setScissor(x - 1, y - 2, w + 2, h + 3) love.graphics.setScissor(x - 1, y - 2, w + 2, h + 3)
end end
local drawB = child.drawBorder
-- Set color -- Set color
love.graphics.setLineStyle("smooth") love.graphics.setLineStyle("smooth")
love.graphics.setLineWidth(3) love.graphics.setLineWidth(3)
if drawB then
love.graphics.setColor(bbg[1], bbg[2], bbg[3], vis) love.graphics.setColor(bbg[1], bbg[2], bbg[3], vis)
love.graphics.rectangle("line", x, y, w, h, rx, ry, segments) love.graphics.rectangle("line", x, y, w, h, rx, ry, segments)
end
love.graphics.setColor(bg[1], bg[2], bg[3], vis) love.graphics.setColor(bg[1], bg[2], bg[3], vis)
love.graphics.rectangle("fill", x, y, w, h, rx, ry, segments) love.graphics.rectangle("fill", x, y, w, h, rx, ry, segments)
if drawB then
if roundness == "top" then if roundness == "top" then
love.graphics.rectangle("fill", x, y + ry / 2, w, h - ry / 2 + 1) love.graphics.rectangle("fill", x, y + ry / 2, w, h - ry / 2 + 1)
love.graphics.setLineStyle("rough") love.graphics.setLineStyle("rough")
love.graphics.setColor(bbg[1], bbg[2], bbg[3], 1) love.graphics.setColor(bbg[1], bbg[2], bbg[3], 1)
love.graphics.setLineWidth(1) love.graphics.setLineWidth(1)
love.graphics.line(x, y + ry, x, y + h + 1, x + 1 + w, y + h + 1, love.graphics.line(x, y + ry, x, y + h + 1, x + 1 + w, y + h + 1,
x + 1 + w, y + ry) x + 1 + w, y + ry)
love.graphics.line(x, y + h, x + 1 + w, y + h) love.graphics.line(x, y + h, x + 1 + w, y + h)
love.graphics.setScissor() love.graphics.setScissor()
love.graphics.setColor(bbg[1], bbg[2], bbg[3], .6) love.graphics.setColor(bbg[1], bbg[2], bbg[3], .6)
love.graphics.line(x - 1, y + ry / 2 + 2, x - 1, y + h + 2) love.graphics.line(x - 1, y + ry / 2 + 2, x - 1, y + h + 2)
@ -1334,18 +1583,27 @@ local draw_handler = function(child)
love.graphics.line(x - 1, y + 2, x - 1, y + h - 4 - ry / 2) love.graphics.line(x - 1, y + 2, x - 1, y + h - 4 - ry / 2)
love.graphics.line(x + w + 1, y + 2, x + w + 1, y + h - 4 - ry / 2) love.graphics.line(x + w + 1, y + 2, x + w + 1, y + h - 4 - ry / 2)
end end
end
-- Start object specific stuff -- Start object specific stuff
drawtypes[band(ctype, video)](child, x, y, w, h) drawtypes[band(ctype, video)](child, x, y, w, h)
drawtypes[band(ctype, image)](child, x, y, w, h) drawtypes[band(ctype, image)](child, x, y, w, h)
drawtypes[band(ctype, text)](child, x, y, w, h) drawtypes[band(ctype, text)](child, x, y, w, h)
drawtypes[band(ctype, box)](child, x, y, w, h) drawtypes[band(ctype, box)](child, x, y, w, h)
if child.post then child:post() end if child.post then child:post() end
if child.__variables.clip[1] then if child.__variables.clip[1] then
love.graphics.setScissor() -- Remove the scissor love.graphics.setScissor() -- Remove the scissor
end end
if child.shader then
love.graphics.setShader()
end
end end
gui.draw_handler = draw_handler
drawer:newLoop(function() drawer:newLoop(function()
local children = gui:getAllChildren() local children = gui:getAllChildren()
for i = 1, #children do for i = 1, #children do
@ -1359,9 +1617,39 @@ drawer:newLoop(function()
first_loop = true first_loop = true
end) end)
drawer:newThread(function()
while true do
thread.sleep(.01)
local children = gui.virtual:getAllChildren()
for i = 1, #children do
local child = children[i]
if child.effect then
child.effect(function() draw_handler(child, true) end)
else
draw_handler(child, true)
end
end
first_loop = true
end
end)
local processors = {
updater.run
}
-- Drawing and Updating -- Drawing and Updating
gui.draw = drawer.run gui.draw = drawer.run
gui.update = updater.run gui.update = function()
for i = 1, #processors do
processors[i]()
end
end
function gui:newProcessor(name)
local proc = multi:newProcessor(name or "UnNamedProcess_"..multi.randomString(8), true)
table.insert(processors, proc.run)
return proc
end
-- Virtual gui -- Virtual gui
gui.virtual.type = frame gui.virtual.type = frame
@ -1376,8 +1664,10 @@ gui.virtual.dualDim.offset.size.x = w
gui.virtual.dualDim.offset.size.y = h gui.virtual.dualDim.offset.size.y = h
gui.virtual.w = w gui.virtual.w = w
gui.virtual.h = h gui.virtual.h = h
gui.virtual.parent = gui.virtual
-- Root gui -- Root gui
gui.parent = gui
gui.type = frame gui.type = frame
gui.children = {} gui.children = {}
gui.dualDim = gui:newDualDim() gui.dualDim = gui:newDualDim()
@ -1390,48 +1680,58 @@ gui.dualDim.offset.size.y = h
gui.w = w gui.w = w
gui.h = h gui.h = h
local g_width, g_height function gui:GetSizeAdjustedToAspectRatio(dWidth, dHeight)
local function GetSizeAdjustedToAspectRatio(dWidth, dHeight)
local isLandscape = g_width > g_height
local newHeight = 0 local newHeight = 0
local newWidth = 0 local newWidth = 0
if g_width / g_height > dWidth / dHeight then if self.g_width / self.g_height > dWidth / dHeight then
newHeight = dWidth * g_height / g_width newHeight = dWidth * self.g_height / self.g_width
newWidth = dWidth newWidth = dWidth
else else
newWidth = dHeight * g_width / g_height newWidth = dHeight * self.g_width / self.g_height
newHeight = dHeight newHeight = dHeight
end end
return newWidth, newHeight, (dWidth-newWidth)/2, (dHeight-newHeight)/2 return newWidth, newHeight, (dWidth-newWidth)/2, (dHeight-newHeight)/2
end end
--gui.GetSizeAdjustedToAspectRatio = GetSizeAdjustedToAspectRatio
function gui:setAspectSize(w, h) function gui:setAspectSize(w, h)
if w and h then if w and h then
g_width, g_height = w, h self.g_width, self.g_height = w, h
gui.aspect_ratio = true
else else
gui.aspect_ratio = false self.g_width, self.g_height = 0, 0
end end
end end
gui.Events.OnResized(function(w, h) gui.Events.OnResized(function(w, h)
if gui.aspect_ratio then if gui.aspect_ratio then
local nw, nh, xt, yt = GetSizeAdjustedToAspectRatio(w, h) local nw, nh, xt, yt = gui:GetSizeAdjustedToAspectRatio(w, h)
print(nw, nh, xt, yt)
gui.x = xt gui.x = xt
gui.y = yt gui.y = yt
gui.dualDim.offset.size.x = nw gui.dualDim.offset.size.x = nw
gui.dualDim.offset.size.y = nh gui.dualDim.offset.size.y = nh
gui.w = nw gui.w = nw
gui.h = nh gui.h = nh
gui.virtual.x = xt
gui.virtual.y = yt
gui.virtual.dualDim.offset.size.x = nw
gui.virtual.dualDim.offset.size.y = nh
gui.virtual.w = nw
gui.virtual.h = nh
else else
gui.dualDim.offset.size.x = w gui.dualDim.offset.size.x = w
gui.dualDim.offset.size.y = h gui.dualDim.offset.size.y = h
gui.w = w gui.w = w
gui.h = h gui.h = h
gui.virtual.dualDim.offset.size.x = w
gui.virtual.dualDim.offset.size.y = h
gui.virtual.w = w
gui.virtual.h = h
end end
end) end)