Drag n drop and DModelPanel not working properly, how to fix
7 replies, posted
I had issues with DModelPanel and drag'n'drop not working properly, and I originally was writing this post to get help, but half way underway I found the issue and set out to solve it by myself, I'll post this thread as a guide on how to fix the issue in case anyone Googles this in the future.
Inventory slot
https://lolihaven.org/13LYy
When dragging
https://lolihaven.org/FUvR5
The UI structure is as follows
Grid layout
Grid
Box (the name label box)
Modelpanel
I haven't overwritten the DModelPanel's Paint function, and if I do and just draw a white box, it'll correctly show the white box upon dragging.
https://lolihaven.org/Uhsfr
My conclusion is that the 3D model itself isn't getting rendered probably, most likely because of the 2D vector being in a relative context normally, but when dragging it should be using a vector in absolute context. So I'll try dragging it to the top left of the screen (closest to 0, 0)
https://files.facepunch.com/forum/upload/317874/397ea9d6-52c1-4c09-a2bf-b4b93d7a51b6/image.png
As the image demonstrate, my assumption was right. This also confirms that the drag 'n' drop temporary panel is rendered in a global (absolute) context which was pretty obvious considering it doesn't have a parent panel, but proving it will help us understand how to fix it.
We have to look at how DModelPanel works and we can look at that here garrysmod/dmodelpanel.lua at master · Facepunch/garrysmod · GitH..
Looking at the rendering process, PANEL:DrawModel is where the rendering of the model happens, and therefore we'll need to change that.
First we add a way to identify if the panel is getting dragging.
https://lolihaven.org/11x2G
Now we have that, we need to alter the rendering process itself.
We go down to where it renders the models, which is line 96 on GitHub.
We still need to render it the relative model so it doesn't disappear from the grid slot when we drag, and we have to draw another model in an absolute context.
https://lolihaven.org/upDfB
It should work in theory, now lets test it in practice
https://lolihaven.org/kLvPt
It works.
Please be aware that if you drag it outside the screen (x or y being 0) it wont render. This is most likely due to limitations with the implementation of rendering this, but I'm not sure. Also this code assumes that the panel getting dragged is the parent of the DModelPanel, this might not be the case in your GUI, but feel free to change the code if it doesn't fit your exact uses.
Full DrawModel code
https://pastebin.com/GShUbEAQ
function PANEL:DrawModel()
local curparent = self
local rightx = self:GetWide()
local leftx = 0
local topy = 0
local bottomy = self:GetTall()
local previous = curparent
if ( curparent:GetParent() == nil ) then -- This is the fix
leftx, topy = self:LocalToScreen( 0, 0 )
rightx, bottomy = self:LocalToScreen( self:GetWide(), self:GetTall() )
end
while ( curparent:GetParent() != nil ) do
curparent = curparent:GetParent()
local x, y = previous:GetPos()
topy = math.max( y, topy + y )
leftx = math.max( x, leftx + x )
bottomy = math.min( y + previous:GetTall(), bottomy + y )
rightx = math.min( x + previous:GetWide(), rightx + x )
previous = curparent
end
render.SetScissorRect( leftx, topy, rightx, bottomy, true )
local ret = self:PreDrawModel( self.Entity )
if ( ret != false ) then
self.Entity:DrawModel()
self:PostDrawModel( self.Entity )
end
render.SetScissorRect( 0, 0, 0, 0, false )
end
Here's what seems to be a better solution.
I will be including this fix into the game if you cannot find any issues with it.
It only renders the model with relative coordinates
https://streamable.com/a1xo7
Seems like an issue with Panel/PaintAt's implementation
I may have been needlessly complicated about it, but when I did something similar years ago I just made my own drag-drop system. On pickup I made a complete copy of the element and just moved it in real time.
Another possible solution would be to use RTs instead of keeping DModelPanels.
How are you testing it? Because it works for me properly:
https://files.facepunch.com/forum/upload/1804/60c61b12-8eda-4a97-99dd-197736d669ca/222222222.gif
concommand.Add( "test2", function()
local frame = vgui.Create( "DFrame" )
frame:SetSize( 500, 300 )
frame:SetTitle( "Frame" )
frame:MakePopup()
frame:Center()
local left = vgui.Create( "DScrollPanel", frame )
left:Dock( LEFT )
left:SetWidth( frame:GetWide() / 2 - 7 )
left:SetPaintBackground( true )
left:DockMargin( 0, 0, 4, 0 )
left:Receiver( "myDNDname", DoDrop ) -- Make the panel a receiver for drag and drop events
local right = vgui.Create( "DScrollPanel", frame )
right:Dock( FILL )
right:SetPaintBackground( true )
right:Receiver( "myDNDname", DoDrop )
for i = 1, 3 do
local but = vgui.Create( "DModelPanel" )
but:SetModel( "models/alyx.mdl" )
but:SetSize( 64, 64 )
but:Dock( TOP )
but:Droppable( "myDNDname" ) -- make the panel be able to be drag'n'dropped onto other panels
right:AddItem( but )
end
end )
I figure the difference is that the DModelPanels are children of the dragged elements, not the dragged elements
function PANEL:DrawModel()
local curparent = self
local leftx, topy = self:LocalToScreen( 0, 0 )
local rightx, bottomy = self:LocalToScreen( self:GetWide(), self:GetTall() )
while ( curparent:GetParent() != nil ) do
curparent = curparent:GetParent()
local x1, y1 = curparent:LocalToScreen( 0, 0 )
local x2, y2 = curparent:LocalToScreen( curparent:GetWide(), curparent:GetTall() )
leftx = math.max( leftx, x1 )
topy = math.max( topy, y1 )
rightx = math.min( rightx, x2 )
bottomy = math.min( bottomy, y2 )
previous = curparent
end
render.SetScissorRect( leftx, topy, rightx, bottomy, true )
local ret = self:PreDrawModel( self.Entity )
if ( ret != false ) then
self.Entity:DrawModel()
self:PostDrawModel( self.Entity )
end
render.SetScissorRect( 0, 0, 0, 0, false )
end
Missed that bit, this should fix that as well as still preserve the ModelPanels in scroll panels not overflowing.
Yep, that works
Sorry, you need to Log In to post a reply to this thread.