Skip to content

feat: Component Mixin to Receive Cursor Hover Events#1834

Closed
garysm wants to merge 27 commits into
flame-engine:mainfrom
garysm:cursor-handler-components
Closed

feat: Component Mixin to Receive Cursor Hover Events#1834
garysm wants to merge 27 commits into
flame-engine:mainfrom
garysm:cursor-handler-components

Conversation

@garysm
Copy link
Copy Markdown

@garysm garysm commented Aug 5, 2022

Description

This PR adds the HasCursorHandlerComponents mixin on FlameGame, and the CursorHandler mixin on Component. Heavily inspired by HasKeyboardHandlerComponents.

HasCursorHandlerComponents propagates cursor hover events to child CursorHandler Components, making these events easier to handle.

Checklist

  • The title of my PR starts with a Conventional Commit prefix (fix:, feat:, docs: etc).
  • I have read the Contributor Guide and followed the process outlined for submitting PRs.
  • I have updated/added tests for ALL new/updated/fixed functionality.
  • I have updated/added relevant documentation in docs and added dartdoc comments with ///.
  • I have updated/added relevant examples in examples.

Breaking Change

  • Yes, this is a breaking change.
  • No, this is not a breaking change.

Related Issues

Closes #1818

Copy link
Copy Markdown
Member

@spydon spydon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lgtm except for the too long lines!

Comment thread packages/flame/lib/src/gestures/detectors.dart Outdated
@spydon spydon requested a review from a team August 8, 2022 16:25
@spydon
Copy link
Copy Markdown
Member

spydon commented Aug 12, 2022

@garysm I fixed the too long lines, could you add some docs for the functionality?
Possibly also an example for the examples directory.

@garysm
Copy link
Copy Markdown
Author

garysm commented Aug 13, 2022

@spydon Yes, I will work on docs and provide an example. Thank you for fixing the too long lines.

@alestiago
Copy link
Copy Markdown
Contributor

Would we like to remove this mixin if #1733 gets done?

@garysm
Copy link
Copy Markdown
Author

garysm commented Aug 20, 2022

@alestiago, that would probably make sense. I can finish up with this, then convert to a class once #1733 is implemented.

@garysm
Copy link
Copy Markdown
Author

garysm commented Aug 30, 2022

Added docs and example @spydon . Let me know if you'd like a test to be written as well.

@spydon
Copy link
Copy Markdown
Member

spydon commented Aug 30, 2022

Good job @garysm, I'll hopefully have time to have a look in the coming days!

@st-pasha didn't you have some feedback on this PR?

@st-pasha
Copy link
Copy Markdown
Contributor

Yes, I'll re-review this PR. But first we need to fix up this branch -- currently it shows 54 files changed.

@garysm
Copy link
Copy Markdown
Author

garysm commented Aug 31, 2022

Yes, I'll re-review this PR. But first we need to fix up this branch -- currently it shows 54 files changed.

I performed a rebase, that is probably why.

@spydon
Copy link
Copy Markdown
Member

spydon commented Aug 31, 2022

I performed a rebase, that is probably why.

GitHub should be able to understand rebases, but maybe not when the branch is outdated, can you press "Update branch" in the UI and see if one of those merges help?

@garysm
Copy link
Copy Markdown
Author

garysm commented Aug 31, 2022

@spydon that suggestion worked, thanks!

@garysm garysm requested a review from spydon September 12, 2022 17:37
Copy link
Copy Markdown
Contributor

@st-pasha st-pasha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some general comments:

  1. Tests are currently missing. Generally, in order to test mouse movement events in a test, you would testWidgets(), and then tester.createGesture() + gesture.moveBy().

  2. The interaction between this mixin and HasDraggableComponents is unclear: would they coexist peacefully, or will one preempt the other? This needs to be documented. Also, if both mixins are present and the user drags the mouse - would both mixins process this event?

  3. We're slowly trying to move towards more uniform approach for event handling, see the lib/src/events/ folder. I'm not sure whether you'd want to modify your PR to use this newer approach, but that would save us some work in the future.

Comment thread doc/flame/inputs/gesture-input.md Outdated
Comment thread doc/flame/inputs/gesture-input.md Outdated
'game also mixed with HasCursorHandlerComponents. Do not mix with both, '
'HasCursorHandlerComponents removes the necessity of '
'MouseMovementDetector.',
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assert is probably unnecessary.
If the user did have MouseMovementDetector on their Game, and then added HasCursorHandlerComponent, then the assert wouldn't trigger since onMouseMove would be overridden anyway.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you see this comment @garysm?

@garysm
Copy link
Copy Markdown
Author

garysm commented Sep 20, 2022

Thanks for the feedback @st-pasha , I'll work on this.

[`PointerHoverEvent`](https://api.flutter.dev/flutter/gestures/PointerHoverEvent-class.html)

```{warning}
This should not be used on platforms that do not support mouse cursors.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we make this warning more clear as to what happens?
is the handler ignored?
or will it error?
that is relevant to multi-platform games

add(
CursorFollowerCircle(
radius: 20.0,
)..position = Vector2(100.0, 100.0),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vector2.all

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
)..position = Vector2(100.0, 100.0),
)..position = Vector2.all(100),

_radius,
_paint,
);
canvas.drawLine(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(not part of this PR)
we should have a renderLine ext similar to renderPoint
https://github.com/flame-engine/flame/blob/main/packages/flame/lib/src/extensions/canvas.dart#L21

add(
CursorFollowerCircle(
radius: 20.0,
)..position = Vector2(100.0, 100.0),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
)..position = Vector2(100.0, 100.0),
)..position = Vector2.all(100),

@spydon
Copy link
Copy Markdown
Member

spydon commented Apr 16, 2023

@garysm are you interested in continuing working on this? :)

@spydon spydon marked this pull request as draft April 16, 2023 14:22
@garysm
Copy link
Copy Markdown
Author

garysm commented Apr 19, 2023

@garysm are you interested in continuing working on this? :)

Yes, has been on the backburner for me @spydon, but I need to finish this off. I need to take a look at the event handling as @st-pasha mentioned and catch up on Flame in general, to save you all some effort :)

@garysm
Copy link
Copy Markdown
Author

garysm commented Apr 28, 2023

@spydon taking a look at #2450, this makes a lot more sense and aligns to what I'd like to achieve. Since there is no existing cursor component mixin, there shouldn't be a need for a bridge either. I can re-work this PR for "new-style" components and event handling. Or I can close and create a new one for that, whatever works.

@spydon
Copy link
Copy Markdown
Member

spydon commented Apr 28, 2023

@spydon taking a look at #2450, this makes a lot more sense and aligns to what I'd like to achieve. Since there is no existing cursor component mixin, there shouldn't be a need for a bridge either. I can re-work this PR for "new-style" components and event handling. Or I can close and create a new one for that, whatever works.

Whatever is the easiest for you :)

@garysm garysm changed the title feat: Propagate cursor hover events to child Components feat: Component Mixin to Receive Cursor Hover Events Apr 28, 2023
@garysm
Copy link
Copy Markdown
Author

garysm commented Jun 13, 2023

It seems to me that I cannot add a hover listener directly to the game from my new CursorHoverDispatcher as (to my knowledge) Flutter does not have a built-in hover GestureRecognizer, which is required to add to the GestureRecognizerBuilder. Should there be a new method created which specifically adds only mouse detectors, and isn't dependent on a mixin on Game?

@garysm
Copy link
Copy Markdown
Author

garysm commented Jun 17, 2023

@spydon any thoughts on this?

@spydon
Copy link
Copy Markdown
Member

spydon commented Jun 17, 2023

@garysm I missed that you had written! If it is possible (which it should be) it should be done in the same manner as the other ones, i.e. without a mixin in the game, there should be some hints on what to connect the game to in the old hover functionality.

@garysm
Copy link
Copy Markdown
Author

garysm commented Jun 24, 2023

@garysm I missed that you had written! If it is possible (which it should be) it should be done in the same manner as the other ones, i.e. without a mixin in the game, there should be some hints on what to connect the game to in the old hover functionality.

I don't think that the current GestureDetectorBuilder is suitable to handle a PointerHoverEvent, as (to my knowledge) the RawGestureDetector returned by the builder will not accept non-contact gestures. The solution I think would be to create a separate MouseDetectorBuilder, which would similarly rebuild the game widget when a new listener is added:

class MouseDetectorBuilder {
  MouseDetectorBuilder([this._onChange]);

  final Map _listeners = {};
  final void Function()? _onChange;

  Widget build(Widget child) {
    // Return mouse listeners
  }
}

My question then would be, what should the widget returned from this builder be? I am unsure, since the listeners cannot be passed into a RawGestureDetector, but should still be consolidated into a single widget.

What are your thoughts @spydon ?

@spydon
Copy link
Copy Markdown
Member

spydon commented Jul 17, 2023

My question then would be, what should the widget returned from this builder be? I am unsure, since the listeners cannot be passed into a RawGestureDetector, but should still be consolidated into a single widget.

What are your thoughts @spydon ?

Sorry for the late reply, it's been very busy with FlutterCon!
Couldn't this be transformed to the new system: https://github.com/flame-engine/flame/blob/main/packages/flame/lib/src/game/game_widget/gesture_detector_builder.dart#L180-L194 ?

@garysm
Copy link
Copy Markdown
Author

garysm commented Jul 18, 2023

My question then would be, what should the widget returned from this builder be? I am unsure, since the listeners cannot be passed into a RawGestureDetector, but should still be consolidated into a single widget.
What are your thoughts @spydon ?

Sorry for the late reply, it's been very busy with FlutterCon! Couldn't this be transformed to the new system: https://github.com/flame-engine/flame/blob/main/packages/flame/lib/src/game/game_widget/gesture_detector_builder.dart#L180-L194 ?

No problem! The issue would be that there is no way to dynamically add onMouseMove or similar callbacks like GestureDetectorBuilder, as applyMouseDetectors still relies on the old system to apply each callback when needed. That's why I think it might be appropriate to create a separate builder with those capabilities, but I'm not sure what that might look like.

@spydon
Copy link
Copy Markdown
Member

spydon commented Jul 18, 2023

No problem! The issue would be that there is no way to dynamically add onMouseMove or similar callbacks like GestureDetectorBuilder, as applyMouseDetectors still relies on the old system to apply each callback when needed. That's why I think it might be appropriate to create a separate builder with those capabilities, but I'm not sure what that might look like.

Ah right, now I understand the problem.
Yeah, seems like a separate builder would be needed then, but that builder would contain pretty much everything (and some more, like in the other builder) from the snippet I sent previously I think?

@spydon spydon mentioned this pull request Sep 4, 2023
6 tasks
@spydon
Copy link
Copy Markdown
Member

spydon commented Sep 8, 2023

Superseded by #2706, thanks a lot for this PR though @garysm even though not merged it gave a lot of insights!

@spydon spydon closed this Sep 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add cursor components mixin to Game

7 participants