From e84ae751b29a47b32106c426ed27699eb0c98f73 Mon Sep 17 00:00:00 2001 From: Ryan Ward Date: Sun, 13 Feb 2022 22:44:09 -0500 Subject: [PATCH] Can now drag items, clipDescendants now work --- gui/init.lua | 211 ++++++++++++++++++++++++++++++++++++++++++--------- test.lua | 40 ++++++++++ 2 files changed, 215 insertions(+), 36 deletions(-) create mode 100644 test.lua diff --git a/gui/init.lua b/gui/init.lua index e09b821..c6cd670 100644 --- a/gui/init.lua +++ b/gui/init.lua @@ -6,13 +6,81 @@ local updater = multi:newProcessor("UpdateManager",true) local drawer = multi:newProcessor("DrawManager",true) local bit = require("bit") local band, bor = bit.band, bit.bor -local floor, ceil = math.floor,math.ceil +local clips = {} +local max, min, abs, rad, floor, ceil = math.max, math.min, math.abs, math.rad, math.floor,math.ceil gui.__index = gui gui.MOUSE_PRIMARY = 1 gui.MOUSE_SECONDARY = 2 gui.MOUSE_MIDDLE = 3 -local frame, image, text, button, box, video = 0, 1, 2, 4, 8, 16 +local frame, image, text, box, video = 0, 1, 2, 4, 8 + +-- Utils + +function gui:move(x,y) + self.dualDim.offset.pos.x = self.dualDim.offset.pos.x + x + self.dualDim.offset.pos.y = self.dualDim.offset.pos.y + y +end + +function gui:moveInBounds(dx,dy) + local x, y, w, h = self:getAbsolutes() + local x1, y1, w1, h1 = self.parent:getAbsolutes() + if (x + dx >= x1 or dx > 0) and (x + w + dx <= x1 + w1 or dx < 0) and (y + dy >= y1 or dy > 0) and (y + h + dy <= y1 + h1 or dy < 0) then + self:move(dx,dy) + end +end + +local function intersecpt(x1,y1,x2,y2,x3,y3,x4,y4) + + -- gives bottom-left point + -- of intersection rectangle + local x5 = max(x1, x3) + local y5 = max(y1, y3) + + -- gives top-right point + -- of intersection rectangle + local x6 = min(x2, x4); + local y6 = min(y2, y4); + + -- no intersection + if x5 > x6 or y5 > y6 then + return 0, 0, 0, 0 -- Return a no + end + + -- gives top-left point + -- of intersection rectangle + local x7 = x5 + local y7 = y6 + + -- gives bottom-right point + -- of intersection rectangle + local x8 = x6 + local y8 = y5 + + return x7, y7, abs(x7-x8), abs(y7-y8) +end + +local function toCoordPoints(x, y, w, h) + return x,y,x+w,y+h +end + +function gui:intersecpt(x, y, w, h) + local x1,y1,x2,y2 = toCoordPoints(self:getAbsolutes()) + local x3,y3,x4,y4 = toCoordPoints(x,y,w,h) + + return intersecpt(x1,y1,x2,y2,x3,y3,x4,y4) +end + +function gui:isDescendantOf(obj) + local parent = self.parent + while parent~=gui do + if parent==obj then + return true + end + parent = parent.parent + end + return false +end function gui:getChildren() return self.children @@ -41,7 +109,7 @@ function gui:getAllChildren() local Objs = self:getChildren() for i=1,#Objs do if Objs[i].visible==true then - table.insert(Stuff,Objs[i]) + table.insert(Stuff, Objs[i]) local Items = Objs[i]:getChildren() if Items ~= nil then Seek(Items) @@ -68,14 +136,33 @@ end local mainupdater = updater:newLoop().OnLoop + +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 + if self.__variables.clip[1] then + local clip = self.__variables.clip + x, y, w, h = self:intersecpt(clip[2], clip[3], clip[4], clip[5]) + --x1, y1, w1, h1 = self:getAbsolutes() + return mx < x + w and mx > x and my+h < y + h and my+h > y + else + x, y, w, h = self:getAbsolutes() + end + return not(mx > x + w or mx < x or my > y + h or my < y) +end + -- Base Library function gui:newBase(typ,x, y, w, h, sx, sy, sw, sh) local c = {} local centerX = false local centerY = false local centering = false - local pressed = false + local dragbutton = 2 + local draggable = false + setmetatable(c, gui) + c.__variables = { + clip = {false,0,0,0,0} + } c.parent = self c.type = typ c.dualDim = self:newDualDim(x, y, w, h, sx, sy, sw, sh) @@ -85,41 +172,70 @@ function gui:newBase(typ,x, y, w, h, sx, sy, sw, sh) c.color = {.6,.6,.6} c.borderColor = color.black c.rotation = 0 + c.maxMouseButtons = 5 c.WhilePressing = multi:newConnection() c.OnPressed = multi:newConnection() c.OnReleased = multi:newConnection() - c.maxMouseButtons = 5 + c.OnDragStart = multi:newConnection() + c.OnDragging = multi:newConnection() + c.OnDragEnd = multi:newConnection() + + -- Mouse event thread c:newThread(function() + local dragging = false + local waiting = {} + local pressed = {} + local ox, oy = 0, 0 while true do - thread.sleep(.1) + thread.sleep(.005) -- Limits the potiential speed for events to 1/200. So 200 fps max, to be fair pressing mouse click 200 times by hand in a second is probably not possible local x, y, w, h = c:getAbsolutes() local mx, my = love.mouse.getPosition() for i=1,c.maxMouseButtons do - if love.mouse.isDown(i) and not(mx > x + w or mx < x or my > y + h or my < y) then - if not pressed then - c.OnPressed:Fire(c, i, mx, my) - end - pressed = true - c.WhilePressing:Fire(c, i, mx, my) - c:newThread(function() - thread.hold(function() return not(love.mouse.isDown(i)) end) - if pressed then - c.OnReleased:Fire(c, i, mx, my) + if dragging and i == dragbutton then + c.OnDragging:Fire(c, mx - ox, my - oy) + ox = mx + oy = my + end + if love.mouse.isDown(i) and c:canPress(mx,my) then + if not pressed[i] then + if draggable and love.mouse.isDown(dragbutton) then + if not dragging then + c.OnDragStart:Fire(c, mx, my) + ox, oy = mx, my + c:newThread(function() + thread.hold(function() return not(love.mouse.isDown(dragbutton)) end) + if dragging then + dragging = false + c.OnDragEnd:Fire(c,mx,my) + end + end) + end + dragging = true end - pressed = false - end) + c:newThread(function() + c.OnPressed:Fire(c, i, mx, my) + end) + end + pressed[i] = true + -- Only process when the drag button turn is active + c.WhilePressing:Fire(c, i, mx, my) + if not waiting[i] then + waiting[i] = true + c:newThread(function() + thread.hold(function() return not(love.mouse.isDown(i)) end) + if pressed[i] then + pressed[i] = false + waiting[i] = false + c.OnReleased:Fire(c, i, mx, my) + end + end) + end end end end end) - c:WhilePressing(function(x,y,self) - if not pressed then - pressed = true - c.OnPressed:Fire(x,y,self) - end - end) function c:OnUpdate(func) -- Not crazy about this approach, will probably rework this if type(self)=="function" then func = self end @@ -144,12 +260,23 @@ function gui:newBase(typ,x, y, w, h, sx, sy, sw, sh) end end) end + + function c:enableDragging(but) + if not but then + draggable = false + return + end + dragbutton = but or dragbutton + draggable = true + end + function c:centerX(bool) centerX = bool if centering then return end centering = true centerthread() end + function c:centerY(bool) centerY = bool if centering then return end @@ -396,9 +523,9 @@ local drawtypes = { if child.image then love.graphics.setColor(child.imageColor[1],child.imageColor[2],child.imageColor[3],child.imageVisibility) if w~=child.imageWidth and h~=child.imageHeigth then - love.graphics.draw(child.image,x,y,math.rad(child.rotation),w/child.imageWidth,h/child.imageHeigth) + love.graphics.draw(child.image,x,y,rad(child.rotation),w/child.imageWidth,h/child.imageHeigth) else - love.graphics.draw(child.image,child.quad,x,y,math.rad(child.rotation),w/child.imageWidth,h/child.imageHeigth) + love.graphics.draw(child.image,child.quad,x,y,rad(child.rotation),w/child.imageWidth,h/child.imageHeigth) end end end, @@ -408,18 +535,15 @@ local drawtypes = { love.graphics.printf(child.text, x + child.textOffsetX, y + child.textOffsetY, w, child.align, child.rotation, child.textScaleX, child.textScaleY, 0, 0, child.textShearingFactorX, child.textShearingFactorY) end, [4] = function(child, x, y, w, h) - -- button - end, - [8] = function(child, x, y, w, h) -- box end, - [16] = function(child, x, y, w, h) + [8] = function(child, x, y, w, h) if child.video and child.playing then love.graphics.setColor(child.videoColor[1],child.videoColor[2],child.videoColor[3],child.videoVisibility) if w~=child.imageWidth and h~=child.imageHeigth then - love.graphics.draw(child.video,x,y,math.rad(child.rotation),w/child.videoWidth,h/child.videoHeigth) + love.graphics.draw(child.video,x,y,rad(child.rotation),w/child.videoWidth,h/child.videoHeigth) else - love.graphics.draw(child.video,child.quad,x,y,math.rad(child.rotation),w/child.videoWidth,h/child.videoHeigth) + love.graphics.draw(child.video,child.quad,x,y,rad(child.rotation),w/child.videoWidth,h/child.videoHeigth) end end end, @@ -438,11 +562,24 @@ drawer:newLoop(function() child.y = y child.w = w child.h = h - -- local x = (child.parent.dualDim.offset.size.x*child.dualDim.scale.pos.x)+child.dualDim.offset.pos.x+child.parent.dualDim.offset.pos.x - -- local y = (child.parent.dualDim.offset.size.y*child.dualDim.scale.pos.y)+child.dualDim.offset.pos.y+child.parent.dualDim.offset.pos.y - -- local w = (child.parent.dualDim.offset.size.x*child.dualDim.scale.size.x)+child.dualDim.offset.size.x - -- local h = (child.parent.dualDim.offset.size.y*child.dualDim.scale.size.y)+child.dualDim.offset.size.y + if child.clipDescendants then + local children = child:getAllChildren() + for c = 1, #children do -- Tell the children to clip themselves + local clip = children[c].__variables.clip + clip[1] = true + clip[2] = x + clip[3] = y + clip[4] = w + clip[5] = h + end + end + + if child.__variables.clip[1] then + local clip = child.__variables.clip + love.graphics.setScissor(clip[2], clip[3], clip[4], clip[5]) + end + -- Set color love.graphics.setColor(bg[1],bg[2],bg[3],vis) love.graphics.rectangle("fill", x, y, w, h--[[, rx, ry, segments]]) @@ -452,6 +589,8 @@ drawer:newLoop(function() drawtypes[band(type,video)](child,x,y,w,h) drawtypes[band(type,image)](child,x,y,w,h) drawtypes[band(type,text)](child,x,y,w,h) + + love.graphics.setScissor() -- Remove the scissor end end) diff --git a/test.lua b/test.lua new file mode 100644 index 0000000..8a373bc --- /dev/null +++ b/test.lua @@ -0,0 +1,40 @@ +local function intersecpt(x1,y1,x2,y2,x3,y3,x4,y4) + + -- gives bottom-left point + -- of intersection rectangle + local x5 = math.max(x1, x3) + local y5 = math.max(y1, y3) + + -- gives top-right point + -- of intersection rectangle + local x6 = math.min(x2, x4); + local y6 = math.min(y2, y4); + + -- no intersection + if x5 > x6 or y5 > y6 then + return 0,0,0,0 -- Return a no + end + + -- gives top-left point + -- of intersection rectangle + local x7 = x5 + local y7 = y6 + + -- gives bottom-right point + -- of intersection rectangle + local x8 = x6 + local y8 = y5 + + return x7, y7, math.abs(x7-x8), math.abs(y7-y8) +end + +local function toCoordPoints(x,y,w,h) + return x,y,x+w,y+h +end + +function gui:intersecpt(obj) + local x1,y1,x2,y2 = toCoordPoints(self:getAbsolutes()) + local x3,y3,x4,y4 = toCoordPoints(obj:getAbsolutes()) + + return intersecpt(x1,y1,x2,y2,x3,y3,x4,y4) +end