local K={[Enum.NormalId.Top]=Vector3.new(0,1,0);[Enum.NormalId.Bottom]=Vector3.new(0,-1,0),[Enum.NormalId.Front]=Vector3.new(0,0,-1),[Enum.NormalId.Back]=Vector3.new(0,0,1),[Enum.NormalId.Left]=Vector3.new(-1,0,0),[Enum.NormalId.Right]=Vector3.new(1,0,0)}function AttachHandles(q,H)if H and not Connections.AutofocusHandle then Connections.AutofocusHandle=Selection.FocusChanged:connect(function()AttachHandles(Selection.Focus,true)end)elseif not H and Connections.AutofocusHandle then ClearConnection("\065\117\116\111\102\111\099\117\115\072\097\110\100\108\101")end if Handles then Handles.Adornee=q Handles.Visible=true Handles.Parent=q and Core.UIContainer or nil return end Handles=(Create("\072\097\110\100\108\101\115"))({Name="\066\084\077\111\118\101\109\101\110\116\072\097\110\100\108\101\115",Color=MoveTool.Color;Parent=Core.UIContainer,Adornee=q})local r Handles.MouseButton1Down:connect(function()Core.Targeting.CancelSelecting()HandleDragging=true if BoundingBox.GetBoundingBox()then InitialExtentsSize,InitialExtentsCFrame=BoundingBox.CalculateExtents(Core.Selection.Items,BoundingBox.StaticExtents)BoundingBox.PauseMonitoring()end InitialState=PreparePartsForDragging()TrackChange()if Core.Mode=="\084\111\111\108"then r=Security.GetPermissions(Security.GetSelectionAreas(Selection.Items),Core.Player)end end)Handles.MouseDrag:connect(function(q,H)if not HandleDragging then return end H=GetIncrementMultiple(H,MoveTool.Increment)MovePartsAlongAxesByFace(q,H,MoveTool.Axes,Selection.Focus,InitialState)if Core.Mode=="\084\111\111\108"and Security.ArePartsViolatingAreas(Selection.Items,Core.Player,false,r)then Selection.Focus.CFrame=InitialState[Selection.Focus].CFrame TranslatePartsRelativeToPart(Selection.Focus,InitialState)H=0 end if MoveTool.UI then MoveTool.UI.Changes.Text.Text="\109\111\118\101\100 "..(math.abs(H).." \115\116\117\100\115")end if MoveTool.Axes=="\071\108\111\098\097\108"and BoundingBox.GetBoundingBox()then(BoundingBox.GetBoundingBox()).CFrame=InitialExtentsCFrame+K[q]*H end end)end
-- Directions of movement for each handle's dragged face
local AxisMultipliers = {
	[Enum.NormalId.Top] = Vector3.new(0, 1, 0),
	[Enum.NormalId.Bottom] = Vector3.new(0, -1, 0),
	[Enum.NormalId.Front] = Vector3.new(0, 0, -1),
	[Enum.NormalId.Back] = Vector3.new(0, 0, 1),
	[Enum.NormalId.Left] = Vector3.new(-1, 0, 0),
	[Enum.NormalId.Right] = Vector3.new(1, 0, 0),
}

function AttachHandles(Part, Autofocus)
	-- Creates and attaches handles to `Part`, and optionally automatically attaches to the focused part

	-- Enable autofocus if requested and not already on
	if Autofocus and not Connections.AutofocusHandle then
		Connections.AutofocusHandle = Selection.FocusChanged:connect(function()
			AttachHandles(Selection.Focus, true)
		end)

	-- Disable autofocus if not requested and on
	elseif not Autofocus and Connections.AutofocusHandle then
		ClearConnection("AutofocusHandle")
	end

	-- Just attach and show the handles if they already exist
	if Handles then
		Handles.Adornee = Part
		Handles.Visible = true
		Handles.Parent = Part and Core.UIContainer or nil
		return
	end

	-- Create the handles
	Handles = Create("Handles")({
		Name = "BTMovementHandles",
		Color = MoveTool.Color,
		Parent = Core.UIContainer,
		Adornee = Part,
	})

	------------------------------------------------------
	-- Prepare for moving parts when the handle is clicked
	------------------------------------------------------

	local AreaPermissions

	Handles.MouseButton1Down:connect(function()
		-- Prevent selection
		Core.Targeting.CancelSelecting()

		-- Indicate dragging via handles
		HandleDragging = true

		-- Freeze bounding box extents while dragging
		if BoundingBox.GetBoundingBox() then
			InitialExtentsSize, InitialExtentsCFrame =
				BoundingBox.CalculateExtents(Core.Selection.Items, BoundingBox.StaticExtents)
			BoundingBox.PauseMonitoring()
		end

		-- Stop parts from moving, and capture the initial state of the parts
		InitialState = PreparePartsForDragging()

		-- Track the change
		TrackChange()

		-- Cache area permissions information
		if Core.Mode == "Tool" then
			AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Selection.Items), Core.Player)
		end
	end)

	------------------------------------------
	-- Update parts when the handles are moved
	------------------------------------------

	Handles.MouseDrag:connect(function(Face, Distance)
		-- Only drag if handle is enabled
		if not HandleDragging then
			return
		end

		-- Calculate the increment-aligned drag distance
		Distance = GetIncrementMultiple(Distance, MoveTool.Increment)

		-- Move the parts along the selected axes by the calculated distance
		MovePartsAlongAxesByFace(Face, Distance, MoveTool.Axes, Selection.Focus, InitialState)

		-- Make sure we're not entering any unauthorized private areas
		if
			Core.Mode == "Tool"
			and Security.ArePartsViolatingAreas(Selection.Items, Core.Player, false, AreaPermissions)
		then
			Selection.Focus.CFrame = InitialState[Selection.Focus].CFrame
			TranslatePartsRelativeToPart(Selection.Focus, InitialState)
			Distance = 0
		end

		-- Update the "distance moved" indicator
		if MoveTool.UI then
			MoveTool.UI.Changes.Text.Text = "moved " .. math.abs(Distance) .. " studs"
		end

		-- Update bounding box if enabled in global axes movements
		if MoveTool.Axes == "Global" and BoundingBox.GetBoundingBox() then
			BoundingBox.GetBoundingBox().CFrame = InitialExtentsCFrame + (AxisMultipliers[Face] * Distance)
		end
	end)
end
