-- Finalize changes to parts when the handle is let go
Support.AddUserInputListener('Ended', 'MouseButton1', true, function (Input)

	-- Ensure handle dragging is ongoing
	if not HandleDragging then
		return;
	end;

	-- Disable dragging
	HandleDragging = false;

	-- Clear this connection to prevent it from firing again
	ClearConnection 'HandleRelease';

	-- Make joints, restore original anchor and collision states
	for Part, State in pairs(InitialState) do
		Part:MakeJoints();
		Core.RestoreJoints(State.Joints);
		Part.CanCollide = State.CanCollide;
		Part.Anchored = State.Anchored;
	end;

	-- Register the change
	RegisterChange();

	-- Resume normal bounding box updating
	BoundingBox.RecalculateStaticExtents();
	BoundingBox.ResumeMonitoring();

end);

function HideHandles()
	-- Hides the resizing handles

	-- Make sure handles exist and are visible
	if not Handles or not Handles.Visible then
		return;
	end;

	-- Hide the handles
	Handles.Visible = false;
	Handles.Parent = nil;

	-- Disable handle autofocus
	ClearConnection 'AutofocusHandle';

end;

function MovePartsAlongAxesByFace(Face, Distance, Axes, BasePart, InitialStates)
	-- Moves the given parts in `InitialStates`, along the given axis mode, in the given face direction, by the given distance

	-- Get the axis multiplier for this face
	local AxisMultiplier = AxisMultipliers[Face];

	-- Get starting state for `BasePart`
	local InitialBasePartState = InitialStates[BasePart];

	-- Move each part
	for Part, InitialState in pairs(InitialStates) do

		-- Move along standard axes
		if Axes == 'Global' then
			Part.CFrame = InitialState.CFrame + (Distance * AxisMultiplier);

		-- Move along item's axes
		elseif Axes == 'Local' then
			Part.CFrame = InitialState.CFrame * CFrame.new(Distance * AxisMultiplier);

		-- Move along focused part's axes
		elseif Axes == 'Last' then

			-- Calculate the focused part's position
			local RelativeTo = InitialBasePartState.CFrame * CFrame.new(Distance * AxisMultiplier);

			-- Calculate how far apart we should be from the focused part
			local Offset = InitialBasePartState.CFrame:toObjectSpace(InitialState.CFrame);

			-- Move relative to the focused part by this part's offset from it
			Part.CFrame = RelativeTo * Offset;

		end;

	end;

end;

function BindShortcutKeys()
	-- Enables useful shortcut keys for this tool

	-- Track user input while this tool is equipped
	table.insert(Connections, UserInputService.InputBegan:connect(function (InputInfo, GameProcessedEvent)

		-- Make sure this is an intentional event
		if GameProcessedEvent then
			return;
		end;

		-- Make sure this input is a key press
		if InputInfo.UserInputType ~= Enum.UserInputType.Keyboard then
			return;
		end;

		-- Make sure it wasn't pressed while typing
		if UserInputService:GetFocusedTextBox() then
			return;
		end;

		-- Check if the enter key was pressed
		if InputInfo.KeyCode == Enum.KeyCode.Return or InputInfo.KeyCode == Enum.KeyCode.KeypadEnter then

			-- Toggle the current axis mode
			if MoveTool.Axes == 'Global' then
				SetAxes('Local');

			elseif MoveTool.Axes == 'Local' then
				SetAxes('Last');

			elseif MoveTool.Axes == 'Last' then
				SetAxes('Global');
			end;

		-- Check if the - key was pressed
		elseif InputInfo.KeyCode == Enum.KeyCode.Minus or InputInfo.KeyCode == Enum.KeyCode.KeypadMinus then

			-- Focus on the increment input
			if MoveTool.UI then
				MoveTool.UI.IncrementOption.Increment.TextBox:CaptureFocus();
			end;

		-- Check if the R key was pressed down, and it's not the selection clearing hotkey
		elseif InputInfo.KeyCode == Enum.KeyCode.R and not Selection.Multiselecting then

			-- Start tracking snap points nearest to the mouse
			StartSnapping();

		-- Nudge up if the 8 button on the keypad is pressed
		elseif InputInfo.KeyCode == Enum.KeyCode.KeypadEight then
			NudgeSelectionByFace(Enum.NormalId.Top);

		-- Nudge down if the 2 button on the keypad is pressed
		elseif InputInfo.KeyCode == Enum.KeyCode.KeypadTwo then
			NudgeSelectionByFace(Enum.NormalId.Bottom);

		-- Nudge forward if the 9 button on the keypad is pressed
		elseif InputInfo.KeyCode == Enum.KeyCode.KeypadNine then
			NudgeSelectionByFace(Enum.NormalId.Front);

		-- Nudge backward if the 1 button on the keypad is pressed
		elseif InputInfo.KeyCode == Enum.KeyCode.KeypadOne then
			NudgeSelectionByFace(Enum.NormalId.Back);

		-- Nudge left if the 4 button on the keypad is pressed
		elseif InputInfo.KeyCode == Enum.KeyCode.KeypadFour then
			NudgeSelectionByFace(Enum.NormalId.Left);

		-- Nudge right if the 6 button on the keypad is pressed
		elseif InputInfo.KeyCode == Enum.KeyCode.KeypadSix then
			NudgeSelectionByFace(Enum.NormalId.Right);

		-- Align the selection to the current target surface if T is pressed
		elseif InputInfo.KeyCode == Enum.KeyCode.T then
			AlignSelectionToTarget();

		end;

	end));

	-- Track ending user input while this tool is equipped
	table.insert(Connections, UserInputService.InputEnded:connect(function (InputInfo, GameProcessedEvent)

		-- Make sure this is an intentional event
		if GameProcessedEvent then
			return;
		end;

		-- Make sure this is input from the keyboard
		if InputInfo.UserInputType ~= Enum.UserInputType.Keyboard then
			return;
		end;

		-- Check if the R key was let go
		if InputInfo.KeyCode == Enum.KeyCode.R then

			-- Make sure it wasn't pressed while typing
			if UserInputService:GetFocusedTextBox() then
				return;
			end;

			-- Reset handles if not dragging
			if not Dragging then
				SetAxes(MoveTool.Axes);
			end;

			-- Stop snapping point tracking if it was enabled
			SnapTracking.StopTracking();

		end;

	end));

end;