HoverOverhaul - A really short overhaul of MouseLeave/MouseEnter with support for BaseParts

HoverOverhaul


It’s just a really short remake of MouseLeave and MouseEnter (112 lines) but it actually works properly.
Resisting the urge to call it Hoverhaul
There’s also support for BaseParts and MouseHovering/MouseNotHovering stuff too.
I’ll just paste the code here, or you can get it from the link below. I appreciate feedback because I mostly made this for fun!

I don’t really expect anyone to actually use this since there are other alternatives and it’s really easy to make.

Code
-- @FloofyNezzled | HoverOverhaul

local Hover = {}

if game:GetService("RunService"):IsServer() then 
	error(string.format("Cannot use %s in a server script!", script.Name)) 
end

local mouse = game:GetService("Players").LocalPlayer:GetMouse()

local function hovering(obj : GuiBase | BasePart)
	if obj:IsA("GuiBase") then
		local posX = obj.AbsolutePosition.X
		local posY = obj.AbsolutePosition.Y
		local totalX = posX + obj.AbsoluteSize.X
		local totalY = posY + obj.AbsoluteSize.Y

		return mouse.X >= posX and mouse.Y > posY and mouse.X <= totalX and mouse.Y <= totalY
	else
		return mouse.Target and mouse.Target == obj
	end

end

local function signal(sig : RBXScriptSignal, fn : () -> ())
	local breakable = false
	
	local signal = sig and sig:Connect(fn) or function()
		while true do
			if breakable then break end
			task.wait()
			fn()
		end
	end
	
	if not sig then
		task.spawn(signal)
	end
	
	return {Disconnect = function()
		if signal:IsA("RBXScriptSignal") then
			signal:Disconnect()
		else
			breakable = true
		end
	end, ChangeFunction = function(newFn : () -> ())
		if signal:IsA("RBXScriptSignal") then
			signal:Disconnect()
			signal = sig:Connect(newFn)
		else
			breakable = true
			signal = function()
				while true do
					if breakable then break end
					task.wait()
					fn()
				end
			end
			task.spawn(signal)
		end
	end}
end

function Hover.MouseEnter(obj : GuiBase | BasePart, fn : () -> ())
	local canEnter = true
	local signal = signal(mouse.Move, function()
		if hovering(obj) and canEnter then
			canEnter = false
			fn()
		elseif not hovering(obj) then
			canEnter = true
		end
	end)
	
	return signal
end

function Hover.MouseLeave(obj : GuiBase | BasePart, fn : () -> ())
	local canLeave = true
	local signal = signal(mouse.Move, function()
		if not hovering(obj) and canLeave then
			canLeave = false
			fn()
		elseif hovering(obj) then
			canLeave = true
		end
	end)
	
	return signal
end

function Hover.MouseHovering(obj : GuiBase | BasePart, fn : () -> ())
	local signal = signal(nil, function()
		if hovering(obj) then
			fn()
		end
	end)
	
	return signal
end

function Hover.MouseNotHovering(obj : GuiBase | BasePart, fn : () -> ())
	local signal = signal(game:GetService("RunService").RenderStepped, function()
		if not hovering(obj) then
			fn()
		end
	end)

	return signal
end

return Hover
Preview


Functions and usage
MouseEnter(obj, function)
MouseLeave(obj, function)
MouseHovering(obj, function)
MouseNotHovering(obj, function)

Example code:

local Hover = require(game:GetService("ReplicatedStorage").HoverOverhaul)

Hover.MouseEnter(label, function()
	label.BackgroundColor3 = Color3.new()
end)

Hover.MouseLeave(label, function()
	label.BackgroundColor3 = Color3.new(1, 1, 1)
	label.BackgroundTransparency = 0
end)

Limitation I found: When using ScrollingFrames, it detects hovers on ui elements that aren’t in focus. Don’t know how to fix this.

7 Likes

can you add a video of a showcase?

Added, fixed something that wasn’t working. RIP 85 lines ;(

1 Like

anyways, thanks for posting this! this is truly amazing of what you did!

1 Like

Hope it helps since the built in MouseEnter system sucks