Cursor shape only updated on 1 instance of UI in main scene

Godot Version

4.2.1 Stable

Question

Hi All,

I made a base UI window including a script that I can resize and move. The cursor shape is changed when you are on the side (resizing) or on the top (moving) to indicate that you can apply some action. Everything worked as intended when working on the separate scene. Now I have added 2 instances of this ‘base window’ and added an extra UI item on each of them. (As I’m fairly new to Godot I’m still trying to learn how it works). I do see both of the UI windows in my main scene, they both work as intended, but the cursor shape is only updated on the first instance. Here the code that I use for changing the cursor shape:

	var IconState : E_ACTION_STATES
	if ActState == E_ACTION_STATES.IDLE:
		IconState = ReqState
	else:
		IconState = ActState
	
	match IconState:
		E_ACTION_STATES.IDLE:
			state_changed.emit(IconState)
			Input.set_custom_mouse_cursor(load("res://Content/UI/Icons/cursor_arrow.png"), Input.CURSOR_ARROW, Vector2(3, 2))
		
		E_ACTION_STATES.MOVE:
			if Input.is_action_pressed("MouseLeftButton"):
				state_changed.emit(IconState)
				Input.set_custom_mouse_cursor(load("res://Content/UI/Icons/cursor_drag.png"), Input.CURSOR_ARROW, Vector2(16, 16))
			else:
				state_changed.emit(IconState)
				Input.set_custom_mouse_cursor(load("res://Content/UI/Icons/cursor_move.png"), Input.CURSOR_ARROW, Vector2(16, 16))
		
		E_ACTION_STATES.V_RESIZE:
			state_changed.emit(IconState)
			Input.set_custom_mouse_cursor(load("res://Content/UI/Icons/cursor_vsize.png"), Input.CURSOR_ARROW, Vector2(6, 12))
		
		E_ACTION_STATES.H_RESIZE:
			state_changed.emit(IconState)
			Input.set_custom_mouse_cursor(load("res://Content/UI/Icons/cursor_hsize.png"), Input.CURSOR_ARROW, Vector2(16, 6))
		
		E_ACTION_STATES.BDIAG_RESIZE:
			state_changed.emit(IconState)
			Input.set_custom_mouse_cursor(load("res://Content/UI/Icons/cursor_bdiagsize.png"), Input.CURSOR_ARROW , Vector2(9, 9))
		
		E_ACTION_STATES.FDIAG_RESIZE:
			state_changed.emit(IconState)
			Input.set_custom_mouse_cursor(load("res://Content/UI/Icons/cursor_fdiagsize.png"), Input.CURSOR_ARROW , Vector2(9, 9))

The scenes:
Schermafbeelding 2024-02-18 203831
Schermafbeelding 2024-02-18 203930

A short movie with the issue:

What do I have to do to get this working for all instances?

In which function do you embed the above code?
I would venture a guess, that you put it into _process and in that case it happens, that both subroutines are executed and one overwrites the cursor settings of the other.

Also my understanding is, that set_custom_mouse_cursor should be called once during initialization and get_cursor_shape can be used to specify which cursor should be displayed over specific locations of a Control node.

Hello Sauermann

Thank you for your reply. I call this at func _input(event):. So yes both instances get executed with the same mouse movement. But regarding the overwriting, then I would expect that the 2nd instance would ‘win’ as this is further down the tree (I thus expect also later executed). But in my case the 1st instance is updating the cursor.

To be honest, I still have not fully understand the functionality of the mentioned set_custom_mouse_cursor. But I understood that the get_cursor_shape only returns the value of the active enumeration. Unfortunately all online examples that I have found only set a single image.

I already thought that maybe I have to set the cursor in a global location, and that the windows only send a ‘request signal’ to change it. I’m now looking to the ‘signal’ for this (see the state_changed.emit(IconState) part), but I do not yet know how to ‘listen’ globally to a not yet known amount of windows at this time. In the game that I’m trying to create, multiple ‘status’ and ‘info’ windows will be active at the same time. And the cursor should change on all of them.

Godot comes with a set of default cursors. If you don’t want the default cursors, but provide your own, then you can use set_custom_mouse_cursor() in order to achieve it.

_input gets called on all nodes within a viewport as mentioned in the docs: Using InputEvent — Godot Engine (stable) documentation in English “in a reverse depth-first order, starting with the node at the bottom of the scene tree, and ending at the root node”. So it fits the behavior, you are experiencing.

Godot has a system in place to change the mouse cursor shape based on the Control node, that the mouse is over. You can configure for each Control node the cursor shape by setting Control.mouse_default_cursor_shape or by overriding get_cursor_shape(). So I believe, that your approach (continuously change the custom mouse cursor and emit state_changed) can be simplified a lot by using the already provided functionalities.

Hi All

I found the solution :smiley:
It can be solved with mouse_default_cursor_shape

I add it to my code and now it works (not the correct image)

Here is my test code

I added the mouse_default_cursor_shape at the places where I want to change them. See the green part. In my original code I only updated the image for the CURSOR_ARROW. Now I’m changing the cursor shape type. The part in the orange rectangle can now be only called in the _ready() function.

So in short:

  1. Update the image with Input.set_custom_mouse_cursor(<ENUM: CursorShape>) on loading of the node
  2. Within the code change the cursor shape with mouse_default_cursor_shape = <ENUM: CursorShape>

I still don’t know why the other method doesn’t work though. (so if someone has this info, please share)

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.