Conversation
|
Close this to split it into multiple PRs, with potentially different approaches. |
|
Never mind, the "different approach" can not be done without this. |
|
Might want to update your PR description to mention the tests and any issues. |
| // Don't return `identityHashCode(value)` directly since the hash of this key | ||
| // needs to be different from that of its value. | ||
| @override | ||
| int get hashCode => identityHashCode(T) ^ identityHashCode(value); |
There was a problem hiding this comment.
| int get hashCode => identityHashCode(T) ^ identityHashCode(value); | |
| int get hashCode => hashValues(identityHashCode(T), identityHashCode(value)); |
There was a problem hiding this comment.
I really want to reduce the overhead of hashCode since it will be used a lot every frame. And since it's a private class we don't need a very secure hashing. The only feature we need is that theKey.hashCode != theKey.value.hashCode.
I changed it to a XOR with a const value. What do you think?
| }); | ||
| } | ||
|
|
||
| // Render `foreground` at the top-left corner, on top of a full-screen `background`. |
There was a problem hiding this comment.
No need for markdown here.
There was a problem hiding this comment.
The original doc was outdated. I changed it to
// Render widget `topLeft` at the top-left corner, stacking on top of the widget
// `background`.| // class. | ||
| @override | ||
| int get hashCode => _hashCodeMask ^ identityHashCode(value); | ||
| static const int _hashCodeMask = 0xc366d8df10ee8; |
There was a problem hiding this comment.
why does it need to be different? would we ever put instances of Key and instances of MouseTrackerAnnotation into the same map?
There was a problem hiding this comment.
No. If it's not required that hashCode must be different, I'm glad to remove the mask.
There was a problem hiding this comment.
If it's not required, why do we have the mask?
| bool operator ==(Object other) { | ||
| if (identical(this, other)) | ||
| return true; | ||
| return other is _IdenticalAnnotationKey && identical(other.value, value); |
There was a problem hiding this comment.
Please use the common boilerplates:
https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#common-boilerplates-for-operator-and-hashcode
| import 'dart:ui' show hashValues; | ||
|
|
||
| import 'package:meta/meta.dart'; | ||
| import './diagnostics.dart'; |
There was a problem hiding this comment.
should this be import 'diagnostics.dart';? Also should be in its own section.
| assert(unhandledEvent != null); | ||
| assert(trackedAnnotations != null); | ||
| assert(trackedAnnotationKeys != null); | ||
| // Order is important for mouse event callbacks. The `findAnnotations` |
There was a problem hiding this comment.
How do we keep the order now? Below the code is iterating over non-order preserving iterables, as far as I can tell.
There was a problem hiding this comment.
The lastAnnotations and nextAnnotations are still Lists, which is where order is kept. The lastKeys and nextKeys below are HashSets because they are only used to check if an annotation is hovered during the last frame / this frame.
There are tests that ensure the order is kept, such as the several tests that start at
| /// {@endtemplate} | ||
| /// * Attaching an annotation that has been attached will assert. | ||
| void attachAnnotation(MouseTrackerAnnotation annotation) { | ||
| void attachAnnotation(Key annotationKey) { |
There was a problem hiding this comment.
SHould this continue to tale an annotation and just internally grab the key from there?
There was a problem hiding this comment.
I've tried to keep it accepting MouseTrackerAnnotation for a long time during the development of this PR, but eventually removed it because it makes the implementation of RenderMouseRegion noticeably more complicated.
One of the problems is that, when the render object is detached, it needs to detach the current annotation. If detachAnnotation only accepts MouseTrackerAnnotations, then either the render object must keep its own hover annotation, or it builds a fake annotation when disposed. Keeping the hover annotation adds noticeably more bookkeeping overhead, since otherwise it could've built the annotation anew during every paint (which is how the PR is implemented currently, see here).
| )); | ||
| expect(exit, isNull); | ||
| expect(tester.binding.mouseTracker.isAnnotationAttached(renderListener.hoverAnnotation), isFalse); | ||
| expect(tester.binding.mouseTracker.isAnnotationAttached(renderListener.annotationKey), isFalse); |
There was a problem hiding this comment.
I believe the new breaking change policy would consider these changes as breaking.
There was a problem hiding this comment.
The isAnnotationAttached is a visibleForTest method, and is not used in g3. If this is still a concern I can use a 2-phase deprecation instead.
|
@Hixie I've changed so that |

Description
This PR adds keys to
MouseTrackerAnnotation. When determining mouse enter and exit, annotations with equal keys will be considered the same.This is a prerequisite to mouse cursors, because render objects want to change properties of
MouseTrackerAnnotations, which is a const class. Without a key to track the inherited presence, there is no way to switch properties without triggeringonExitandonEnter. The first design of mouse cursor had to use a function to resolve this, which seems odd, as pointed out by https://github.com/flutter/flutter/pull/42797/files#r342219907.This PR also
UniqueKeyandObjectKeyto the foundation package so that it's available at lower-layer packages.MouseTracker.{attach,detach}Annotationto accepting a key instead of annotations._MouseRegionElementsince they're no longer needed.MouseRegion.opaquedoesn't work.Related Issues
N/A
Tests
I added the following tests:
Checklist
Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes (
[x]). This will ensure a smooth and quick review process.///).flutter analyze --flutter-repo) does not report any problems on my PR.Breaking Change
Did any tests fail when you ran them? Please read Handling breaking changes.