#6065·aseprite

API: Add mouse enter/exit events to Dialog:canvas() component

Author: lajawiCreated Sep 28, 2026Updated Sep 28, 2026
Labelsfeaturetriage

Did other users suggest similar ideas?

  • No
  • Yes/Links to similar ideas

Is your feature request related to a problem? Please describe.

In an extension I am developing, I wanted to use some custom UI using the Dialog:canvas() component, but noticed that the mouse position isn't updated any more if the mouse isn't actually over the canvas, and onmouseover isn't being called any more.

In the example script below I save and update the mouse's position when onmousemove is called, making a responsive design. However, when a button is touching the edge of the canvas, it will still be considered hovered over on the last time the onmousemove is being called when you move the mouse out of the canvas.

Example Script, put it in your scripts folder
lua
local mouse = { position = Point(-1, -1), leftClick = false }
local states = {
    normal = "button_normal",
    hot = "button_hot",
    pushed = "buttonpushed",
    focused = "button_focused"
}
local bounds = Rectangle(0, 0, 100, 20)
local text = "Not initialized"

local dlg = Dialog("Dialog"):separator{ text = "Button in a canvas" }
dlg:canvas{
	width = bounds.w,
	height = bounds.h,
	onpaint = function (ev)
		local ctx = ev.context

		local state = states.normal
		text = "Idle"

		local isMouseOver = bounds:contains(mouse.position)
		if isMouseOver then
			state = states.hot or state
			text = "Mouse pos.: (" .. mouse.position.x .. ", " .. mouse.position.y .. ")"
			if mouse.leftClick then
				state = states.pushed
				text = "Mouse clicked"
			end
		end

		dlg:modify{ id = "text", text = text }
		ctx:drawThemeRect(state, bounds)
	end,
	onmousemove = function (ev)
		mouse.position = Point(ev.x, ev.y)
		dlg:repaint()
	end,
	onmousedown = function (ev)
		mouse.leftClick = ev.button == MouseButton.LEFT
		dlg:repaint()
	end,
	onmouseup = function (_)
		if not mouse.leftClick then
			return
		end
		mouse.leftClick = false
		dlg:repaint()
	end
}
:label{ id = "text",text = text }
:separator{ text = "Normal buttons" }
:button{ height = bounds.h, width = bounds.w, onclick = function (_) end }
:newrow()
:button{ height = bounds.h, width = bounds.w, onclick = function (_) end }

dlg:show{ wait = true }

https://github.com/user-attachments/assets/0c9aeac1-598c-413c-b35d-4c7539508c46

Describe the solution you'd like

In my case, an event that triggers when the mouse exits the canvas could reset the saved mouse position to something that will be outside of any of the custom UI elements.

Add an event on the Dialog:canvas() component called something like onmouseexit or onmouseout. To keep it consistent, also add a onmouseenter or onmousein event, to be set/reset something as soon as the mouse enters the canvas.

lua
dlg:canvas{
	-- ...
	onmouseexit = function (ev)
		mouse.position = Point(-1, -1)
	end
}

Describe alternatives you've considered

This alternative uses a Timer to reset the mouse position after 0.5 seconds of no onmousemove event call.

lua
-- ...
local dlg = Dialog("Dialog"):separator{ text = "Button in a canvas" }

local timer
timer = Timer{
	interval = 0.5,
	ontick = function ()
		mouse.position = Point(-1, -1)
		dlg:repaint()
		timer:stop()
	end
}

dlg:canvas{
	width = bounds.w,
-- ...
	onmousemove = function (ev)
		mouse.position = Point(ev.x, ev.y)
		timer:start()
		dlg:repaint()
	end,
-- ...

This results in delayed reset of the UI, sometimes even while the mouse technically is still hovering over the UI element, which is not the best experience.

https://github.com/user-attachments/assets/9da6532e-b15a-43e8-9c25-573e87ce7741