slint icon indicating copy to clipboard operation
slint copied to clipboard

Custom Cursor

Open TheColorRed opened this issue 1 year ago • 9 comments

Allows the user to use a custom window cursor.

Example usage:

import { Button } from "std-widgets.slint";

export component AppWindow inherits Window {
  property <int> counter: 0;
  property <[image]> cursors: [
    @image-url("cursors/red.png"),
    @image-url("cursors/green.png"),
    @image-url("cursors/blue.png"),
    @image-url("cursors/pink.png"),
  ];

  cursor: cursors[counter];
  cursor-hotspot-x: 20px;
  cursor-hotspot-y: 0px;

  width: 800px;
  height: 600px;

  TouchArea {
    clicked => {
      root.counter += 1;
      if (root.counter >= root.cursors.length) {
        root.counter = 0;
      }
    }
  }
}

TheColorRed avatar Nov 26 '24 23:11 TheColorRed

Looking for feedback, There are a few things I was unsure of.

The TODO. Not sure if it should only update when the input changes, as I am not sure if it should run on every frame.

TheColorRed avatar Nov 26 '24 23:11 TheColorRed

Thanks for the contribution! Custom cursor images is a nice feature. However, I think this would fit better as an extension of the existing mouse-cursor property on TouchArea rather than adding new properties to Window.

We could change the type of the mouse-cursor property to support either the predefined MouseCursor enum or a custom cursor struct (e.g., { cursor: image, hotspot-x: int, hotspot-y: int }). That's be IMHO a more intuitive and flexible API.

That said, I realize this would be a more complex change, especially around adding implicit conversions or supporting both the enum and a struct. So, I’d be happy to guide you through it if you’re interested. Or we could still consider to add a simpler approach with a custom-mouse-cursor property on the TouchArea.

(Note that the hotspot values would need to be integers (in the cursor image's coordinate system), not lengths. It's not impacted by the scale factor.)

Thanks again for contributing to Slint! We really appreciate your effort. Sorry that we’re not taking that as is, but we want to make sure the API is well-designed since we need to maintain it and keep compatibility in the long run. 😊

ogoffart avatar Nov 27 '24 12:11 ogoffart

So, I’d be happy to guide you through it if you’re interested.

Yeah, that would be great!

  • I tried implementing the enum: MouseCursor::Custom { image: crate::graphics::Image, hotspot_x: int, hotspot_y: int }. However, the macro didn't understand it, and I am not very familiar with creating macros (just using them).
  • I am not sure if you know or saw in my PR that adding a custom cursor does require access to the event_loop: event_loop.create_custom_cursor(source.unwrap()), so I am not sure how much that would change the implementation, as I wasn't sure how to access it in the set_mouse_cursor() function or the WindowAdapterInternal impl.

TheColorRed avatar Nov 27 '24 15:11 TheColorRed

Indeed, enums in data aren't currently supported by the macro for declaring Slint enums in enums.rs. So, there are two alternatives:

  1. Implement it manually, similar to how EasingCurve is done.
  2. Introduce an extra type, like we have for Brush and Color.

Either way, we'd likely need an enum similar to EasingCurve and ensure the type is in langtype::Type.

As for accessing the winit event loop, you can use crate::event_loop::with_window_target from the WindowAdapterInternal.

Let me know if you need any further guidance! 😊

ogoffart avatar Nov 28 '24 11:11 ogoffart

This would be a great feature for the live-preview tools. There are a couple of areas where a custom cursor to indicate numbers can be scrolled would help. The current list of cursors doens't cover this or look a bit old fashioned on Mac. Color picker (as in select pixels color under the mouse to copy), and also some tools that would manipulate objects in the live-preview visual editor.

NigelBreslaw avatar Mar 19 '25 09:03 NigelBreslaw

@TheColorRed I happen to need this feature, do you have interest in continuing the PR? I can take it over

redstrate avatar Dec 09 '25 14:12 redstrate

@redstrate Please take it over. It's been sitting there for a year now. Maybe continue with the branch so you both get commit credit? I also have several uses for this and would love to make an example unless you also want to do this.

NigelBreslaw avatar Dec 09 '25 19:12 NigelBreslaw

@TheColorRed I happen to need this feature, do you have interest in continuing the PR? I can take it over

Sure go ahead and take it over.

TheColorRed avatar Dec 10 '25 02:12 TheColorRed

I continued it in https://github.com/slint-ui/slint/pull/10256, however it's not quite ready to review yet :smiley: I also need to pull in this branch for the winit support

redstrate avatar Dec 10 '25 15:12 redstrate