Custom Draggable GUI

Hey developers,

I’m wondering If I can make a gui draggable without using the deprecated “guiPath.Draggable = true”.
There is not much I can really add, but if you need help think of dragging a computer window ar’ound. Thats what I’m trying to achieve without deprecated events. Thanks!

5 Likes

(almost) anything in possible.

You’ll need to combine these events to make a draggable window

GuiObject.InputBegan - Listen for MouseButton1 on the draggable window
UserInputService.InputChanged – Listen for MouseMovement while MouseButton1 is still down, move your window to the current position of the mouse (± offset from where the mouse is in relation to the window’s AboslutePosition)
GuiObject.InputEnded – Listen for MouseButton1 again, so you know that the window is no longer being dragged.

11 Likes

Just FYI, a couple of years ago I did the same (with success, highly recommended). However, I found that the MouseEnter and MouseLeave events wouldn’t always fire reliably. This might have been fixed meanwhile, but if you run into weird behaviour with this at least you won’t spend hours debugging that :stuck_out_tongue:

Can anyone confirm/deny if this has been fixed?

2 Likes

Cant confirm nor deny, but possibly lag effects it.

MouseEnter and MouseLeave have always, and do still, have issues firing - As does the .Draggable property. InputBegan/InputEnded are much, much more reliable.

2 Likes

MouseLeave/MouseEnter have gotten significantly more reliable, but still have some remaining issues we’re working to fix:

  • MouseEnter can sometimes fire before MouseLeave on the previous object.
  • MouseEnter/MouseLeave fire for all objects under the cursor, instead of the one on top (and this is hard to fix without breaking games).
  • Objects can get stuck in hovered state if they were the last hovered element when the mouse leaves the game window.

Currently, implementing your own draggable is a little complicated because of the need to bind to UserInputService, but I’m currently working on a change which will make it so that if you mouse down on a button, it will capture your mouse until you release the mouse button. This makes it very easy to implement sliders, scrollbars, and drag+drop because the only events you need are GuiObject’s InputBegan, InputChanged, and InputEnded.

Here’s an old code snippet I wrote when Draggable got deprecated, which you can base your code off of in the mean time. This code should continue working after the changes above are shipped, but you won’t have to write as much code to implement dragging once those changes go live. This snippet uses the same strategy described by @Fm_Trick, but also handles touch input.

local UserInputService = game:GetService("UserInputService")

local gui = script.Parent

local dragging
local dragInput
local dragStart
local startPos

local function update(input)
	local delta = input.Position - dragStart
	gui.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y)
end

gui.InputBegan:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
		dragging = true
		dragStart = input.Position
		startPos = gui.Position
		
		input.Changed:Connect(function()
			if input.UserInputState == Enum.UserInputState.End then
				dragging = false
			end
		end)
	end
end)

gui.InputChanged:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch then
		dragInput = input
	end
end)

UserInputService.InputChanged:Connect(function(input)
	if input == dragInput and dragging then
		update(input)
	end
end)
27 Likes

The UDim2 constructor uses Offset as it’s dependent for changing the position, could you convert this to scale so it appears the same across devices / screen sizes?

3 Likes

I found this thread looking for information on how to handle doing some drag and drop for an inventory script and the code provided by Tiffblocks is super valuable, it pretty much does exactly what was needed and I was able to use it in my game, but then I started noticing some weirdness where more than one thing was moving and realized that events were happening on items I had previously moved… the input.Changed event listener inside the InputBegan listener is created every click. Anyway the following modification to that section of the code will remove the listener when input ends and save someone their sanity down the line maybe. I tried to highlight my changes but I’m not sure if I can (the formatting doesn’t work in a quoted post)

P.S. Sorry for the thread necro.

2 Likes

Holy thanks, I was trying to figure out what the problem is. By the way, do you know if the Changes that Tiffblocks mentioned already came out?

I don’t know. If they had come out ideally we wouldn’t find this thread and would find the new information but the world isn’t ideal.