Introducing UIDragDetectors [Studio-only Beta]

This is cool. I can see this being used in new ways in stuff that is already made to make it more easier or fun.

Please release it into roblox client also as a beta feature… We don’t want to test it. We want to USE it.

Ah yes, having a tool selected disables the usage of UIDragDetectors. Same goes for plugins, although that will change to being disabled only when UIEditor specifically is on, soon.

Which values did you need converting between-- GuiLayercollector space to reference / parent?

Additionally, for client release timelines-- I’m happy to announce that it’s finally looking like it will be enabled in client soon-ish (1-2 weeks).

I apologize for how long it has taken-- I’ll have some updates here this week for new features that needed to be implemented first.

1 Like

This is interesting-- we’ll take a look into it. Thank you for the report.

1 Like

So, the UI Drag detectors doesnt seem to work in plugin widgets until I use them somewhere else, then they somehow start working again. Here’s a video

So, basically what happens here is:

  • I cant use the drag detectors, doesn’t detect any input.
  • I get out of the plugin widget, I drag the frame inside the Drag screengui which has a UIDragDetector with default properties.
  • It dissapears and moves 5,000 pixels
  • Everything works fine :DD

It’s so weird, It’s funny because have this screengui already prepared only as a ritual before using the plugin XD

I get the exact same behaviour.
Also happend when creating a whole new screengui + frame inside a baseplate.

Weird :thinking:

Only happends before runtime though, Inside playmode everything works as normal.

It moving 5000 pixels and disappearing is concerning and I’ve had reports of it-- I haven’t been able to reproduce it but it is something I’m continuously checking for.

As for usage during plugins: At the moment, it’s disabled for use when a tool or any plugin is active.

Next week’s release will come with a patch that disables it only when tools or the UIEditor plugin is active, so that should resolve the issue.

1 Like

It might have something to do with the UI editor conflicting with UIDragDetector.

This only happens when I use them somewhere where I can also edit the UI (StarterGui).

It doesnt happen in play mode, in plugin widgets, in ScreenGuis inside CoreGui, it only happens in StarterGui in Edit Mode, which is also the only place where I can edit and resize the frame

Also this only happens when the UI editor is not active, but that might be because as you said, it gets disabled if a tool is active

are they relaced for the client yet?

That’s valuable information-- I’ll add in the details to the ticket and hopefully be more successful in reproducing locally!

For your other comment, yes, having the tool active disabling the UIDragDetector is an intended behavior. Soon, it’ll be disabled only for tools and UIEditor instead of all plugins.

Soon! We’re in the final testing steps to enable it for client.

Update 10/3:

  • Rounding behavior had been adjusted. The numbers for DragUDim2 should be more accurate now. @700000002

Coming next week:

  • UIDragDetectors will be disabled only when Tools and UIEditor is active, instead of when any plugins are active.
  • MicroProfiler information for UIDragDetectors will be added.

Coming in two weeks:

  • MinMax dragTranslation issues with insets, and bounds not functioning as intended when changing them during a drag will be fixed.
  • Support for dragging in UI Selection Mode

We realize there is a lot of demand for the instance to be enabled in Client-- we very strongly expect us to be able to turn this on in non-mobile clients in two weeks. There were features (Such as the UI Selection Mode support) and performance improvements (which will make it in in two weeks) that we determined was a requirement before proceeding. Apologies for the delay.

2 Likes

here’s something I did with the new drag detectors, I’m still having the issue where the sliders are limited to the bounds of the bar, preventing them from hitting completely 100 or completely 0

the colours uses the dragging event for creating a client-side preview, where the dragging end event is what applies the colour on the server, so it prevents the server from being overwhelmed (and helps the colour to properly reflect without server latency!)

had a great time figuring out the calculations, the example place saved a lot of headache in setting up and reading values, and I probably wouldn’t be able to pull this off without the UIDragDetectors, so thank you!

(edit to fix the file type ^^')

2 Likes

Unfortunately, you will be bound to stay within the size of the bounding UI in default settings.

If you want the middle of the slider to be able to reach the edge of the boxes, I believe setting the MinDragTranslation / MaxDragTranslation to {0.5, 0} / {-0.5, 0} should work, with the ReferenceUIInstance being the slider box (without defining a BoundingUI-- the MinMax are calculated so that you can drag the amount defined, accounting for the size of the dragging UI).

  • Note that MinMax has a bug at the moment that I would’ve had a fix for this week, but it had to be rolled back. It will be fully ready in 2 weeks.

Another way is to have a invisible boundingUI that is slightly longer than the slider, which will allow the drag to go beyond the visual slider’s box by half of the slider’s width.

I’m sorry that the cleaner solution using MinMax translate is a bit broken right now :frowning:

1 Like

I was hoping that the location within a bound would give a precentage or value (with a upper bound and lower bound).

1 Like

FR!? I already made it. it’s not that hard.
The local script:

local Slider = script.Parent
local Inner = Slider.InnerSlider
task.wait()
Inner.UIDragDetector.Enabled = true
local Config = require(script.Config)

while true do
	task.wait()
	local SliderPos = Slider.AbsolutePosition
	local InnerPos = Inner.AbsolutePosition
	local InnerSize = Inner.AbsoluteSize
	local SliderSize = Slider.AbsoluteSize
local SliderPosX = SliderPos.X
local SliderSizeX = SliderSize.X
local InnerSizeX = InnerSize.X
local InnerPosX = InnerPos.X
local lowerBound = SliderPosX
local upperBound = SliderPosX+SliderSizeX-InnerSizeX -- Just don't ask me how this works.
local precentage = (InnerPosX-lowerBound)/(upperBound-lowerBound) -- I can't explain this sorcery.
Slider.Precentage.Value = precentage
	Slider.Value.Value = Config.floor(Config.lowerNum+(Config.upperNum-Config.lowerNum)*precentage) -- Please don't ask me, I can't explain it.
end

The module script:

local Configuration = script.Parent.Parent.Configuration
local Floor = Configuration["floor?"].Value
local Config = {
	["upperNum"] = Configuration.upperNum.Value,
	["lowerNum"] = Configuration.lowerNum.Value,
	["floor"] = nil
}
function Config.floor(x: Number) -- Floors the value if necessary
	if Floor then
		return math.floor(x)
	else 
		return x
	end
end
return Config

for the other stuff… It cosists of some stuff not related so… I’ll not show that.
and yes. It’s very complicated. I have no idea how I made it.

2 Likes

Also, here’s the function whereas you can click a plugin button and create a slider:

local CHS = game:GetService("ChangeHistoryService")

toolbar = plugin:CreateToolbar("Your toolbar name")
addSlider = toolbar:CreateButton("Add Slider", "Adds a slider.", "An image that you want to use")

function createSlider(v: Instance)
	local Slider = Instance.new("Frame")
	local RoundSlider = Instance.new("UICorner")
	local precentage = Instance.new("NumberValue")
	local Value = Instance.new("NumberValue")
	local LocalScript = Instance.new("LocalScript")
	local Config = Instance.new("ModuleScript")
	local InnerSlider = Instance.new("ImageLabel")
	local InnerSliderRound = Instance.new("UICorner")
	local UIDragDetector = Instance.new("UIDragDetector")
	local Configuration = Instance.new("Configuration")
	local floor = Instance.new("BoolValue")
	local upperNum = Instance.new("NumberValue")
	local lowerNum = Instance.new("NumberValue")
	Value.Name = "Value"
	Slider.Size = UDim2.new(0, 250, 0, 40)
	InnerSlider.Size = UDim2.new(0, 40, 0, 40)
	Slider.BackgroundColor3 = Color3.fromRGB(113, 113, 113)
	InnerSlider.BackgroundColor3 = Color3.fromRGB(130, 130, 130)
	InnerSlider.Parent = Slider
	precentage.Name = "Precentage"
	lowerNum.Parent = Configuration
	lowerNum.Value = 0
	lowerNum.Name = "lowerNum"
	upperNum.Parent = Configuration
	upperNum.Value = 100
	upperNum.Name = "upperNum"
	floor.Parent = Configuration
	floor.Value = true
	floor.Name = "floor?"
	Configuration.Parent = Slider
	UIDragDetector.Parent = InnerSlider
	UIDragDetector.BoundingUI = Slider
	UIDragDetector.Enabled = false
	UIDragDetector.DragStyle = Enum.UIDragDetectorDragStyle.TranslateLine
	Slider.Name = "Slider"
	InnerSlider.Name = "InnerSlider"
	Config.Name = "Config"
	InnerSliderRound.Parent = InnerSlider
	InnerSlider.Image = "rbxassetid://11432865277"
	Config.Parent = LocalScript
	Config.Source = [[
local Configuration = script.Parent.Parent.Configuration
local Floor = Configuration["floor?"].Value
local Config = {
	["upperNum"] = Configuration.upperNum.Value,
	["lowerNum"] = Configuration.lowerNum.Value,
	["floor"] = nil
}
function Config.floor(x: Number)
	if Floor then
		return math.floor(x)
	else 
		return x
	end
end
return Config
]]
	LocalScript.Source = [[
	local Slider = script.Parent
local Inner = Slider.InnerSlider
Inner.UIDragDetector.Enabled = true
local Config = require(script.Config)

while true do
	wait()
	local SliderPos = Slider.AbsolutePosition
	local InnerPos = Inner.AbsolutePosition
	local InnerSize = Inner.AbsoluteSize
	local SliderSize = Slider.AbsoluteSize
local SliderPosX = SliderPos.X
local SliderSizeX = SliderSize.X
local InnerSizeX = InnerSize.X
local InnerPosX = InnerPos.X
local lowerBound = SliderPosX
local upperBound = SliderPosX+SliderSizeX-InnerSizeX
local precentage = (InnerPosX-lowerBound)/(upperBound-lowerBound)
Slider.Precentage.Value = precentage
	Slider.Value.Value = Config.floor(Config.lowerNum+(Config.upperNum-Config.lowerNum)*precentage)
end
]]
	LocalScript.Parent = Slider
	Value.Parent = Slider
	RoundSlider.Parent = Slider
	precentage.Parent = Slider
	Slider.Parent = v
end

addSlider.Click:Connect(function()
	local selection = game:GetService("Selection"):Get()
	if selection then
		for _, v in pairs(selection) do
			for _, b in pairs (Supported) do
				if v:IsA(b) then
					local slider = createSlider(v)
				end
			end
		end
	end
end)
1 Like

Ah, like if you pass in a Vector2 coordinate, it gives an X/Y percentage of relatively where it’s at (with 0.5/0.5 being the middle)?

That sounds more like a feature for GuiObject itself-- I’m not quite sure if it’s something that will go through, especially as it’s not too complicated to compute-- but it might be worth bringing up.

2 Likes