SecondHalfGames / yakui

yakui is a declarative Rust UI library for games
Apache License 2.0
222 stars 18 forks source link

Allow changing cursor #129

Open Uriopass opened 6 months ago

Uriopass commented 6 months ago

There are lots of useful cases where changing the cursor is important to indicate what action is about to be done. For example links, resizing, dragging, text-editable... See cursor-icon

Since the cursor-icon crate is independent of winit and only exposes that type, I think yakui can expose it directly.

I don't know yakui that well yet but I'm guessing this new API would be added:

impl InputState {
    pub fn set_cursor_icon(&self, icon: cursor_icon::CursorIcon);
    pub fn get_cursor_icon(&self) -> cursor_icon::CursorIcon;
}

Note that it can be easy to lead to a "permanent inappropriate cursor" if a widget forgets to reset the state to cursor_icon::Default. It could be better to always reset the cursor to Default every frame and force required widgets (like links/resize bars) to set the cursor every frame.

EDIT: Forgot to do a search :facepalm:, duplicate of #20 But if @LPGhatguy agrees to the proposal I could go and implement it.

LPGhatguy commented 6 months ago

This API sounds great to me!

I'm glad you brought up the "permanent inappropriate cursor" problem! I think we should make widgets set the mouse cursor every time they want it to be updated. What widget method do you think would be the best place to do that in? update doesn't have access to any state right now and layout and paint won't always be run every frame once we're caching.

We should also think about how this API interacts with games and the code they might have to update the mouse cursor as well.

Uriopass commented 6 months ago

I think update is the right place for this. It has access to the widget's state that can be updated during the event phase.

For a link/button, have a hovered state that's updated using mouse events and set the cursor in update appropriately. (It can even be returned as part of the Response!)

For a resize bar, you want to display the ↔ icon if it is hovered or it is currently being dragged (as because of the frame lag, the cursor can go out of the bar momentarily). Which is all state that can/should belong in the widget anyway.

We should also think about how this API interacts with games and the code they might have to update the mouse cursor as well.

If you want that kind of customisation, the platform's integration (like yakui-winit) can probably be transparent about this so that the user can wrap around it.