mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Specs: Make pointer events go up the LayoutManager chain too; improve how you make custom event targets
Review URL: https://codereview.chromium.org/787603005
This commit is contained in:
parent
72a73fc07f
commit
b6e7ba2dfc
@ -31,20 +31,31 @@ module 'sky:core' {
|
||||
abstract class EventTarget {
|
||||
any dispatchEvent(Event event); // O(N) in total number of listeners for this type in the chain
|
||||
// sets event.handled to false and event.result to undefined
|
||||
// makes a record of the event target chain
|
||||
// makes a record of the event target chain by calling getEventDispatchChain()
|
||||
// invokes all the handlers on the chain in turn
|
||||
// returns event.result
|
||||
virtual Array<EventTarget> getEventDispatchChain(); // O(1) // returns []
|
||||
void addEventListener(String type, EventListener listener); // O(1)
|
||||
void removeEventListener(String type, EventListener listener); // O(N) in event listeners with that type
|
||||
private Array<String> getRegisteredEventListenerTypes(); // O(N)
|
||||
private Array<EventListener> getRegisteredEventListenersForType(String type); // O(N)
|
||||
}
|
||||
|
||||
class CustomEventTarget : EventTarget {
|
||||
class CustomEventTarget : EventTarget { // implemented in JS
|
||||
constructor (); // O(1)
|
||||
attribute EventTarget parentNode; // getter O(1), setter O(N) in height of tree, throws if this would make a loop
|
||||
|
||||
virtual Array<EventTarget> getEventDispatchChain(); // O(N) in height of tree // implements EventTarget.getEventDispatchChain()
|
||||
// let result = [];
|
||||
// let node = this;
|
||||
// while (node) {
|
||||
// result.push(node);
|
||||
// node = node.parentNode;
|
||||
// }
|
||||
// return result;
|
||||
|
||||
// you can inherit from this to make your object into an event target
|
||||
// or you can inherit from EventTarget and implement your own getEventDispatchChain()
|
||||
}
|
||||
|
||||
|
||||
@ -54,13 +65,16 @@ module 'sky:core' {
|
||||
typedef ChildNode (Element or Text);
|
||||
typedef ChildArgument (Element or Text or String);
|
||||
|
||||
abstract class Node : EventTarget {
|
||||
abstract class Node : EventTarget { // implemented in C++
|
||||
readonly attribute TreeScope? ownerScope; // O(1)
|
||||
|
||||
readonly attribute ParentNode? parentNode; // O(1)
|
||||
readonly attribute Element? parentElement; // O(1) // if parentNode isn't an element, returns null
|
||||
readonly attribute ChildNode? previousSibling; // O(1)
|
||||
readonly attribute ChildNode? nextSibling; // O(1)
|
||||
|
||||
virtual Array<EventTarget> getEventDispatchChain(); // O(N) in number of ancestors across shadow trees // implements EventTarget.getEventDispatchChain()
|
||||
// returns the event dispatch chain (including handling shadow trees)
|
||||
|
||||
// the following all throw if parentNode is null
|
||||
void insertBefore(ChildArgument... nodes); // O(N) in number of arguments plus all their descendants
|
||||
|
||||
@ -281,7 +281,9 @@ class StyleDeclarationList {
|
||||
Array<StyleDeclaration> getDeclarations(String? pseudoElement = null); // O(N) in number of declarations
|
||||
}
|
||||
|
||||
typedef StyleDeclaration Dictionary<ParsedValue>;
|
||||
class StyleDeclaration {
|
||||
// TODO(ianh): define this
|
||||
}
|
||||
```
|
||||
|
||||
Rule Matching
|
||||
@ -347,7 +349,7 @@ partial class Element {
|
||||
|
||||
callback any ValueResolver (any value, String propertyName, StyleNode node, Float containerWidth, Float containerHeight);
|
||||
|
||||
class StyleNode {
|
||||
class StyleNode { // implemented in C++ with no virtual tables
|
||||
// this is generated before layout
|
||||
readonly attribute String text;
|
||||
readonly attribute Node? parentNode;
|
||||
@ -434,10 +436,19 @@ sky:core by default registers:
|
||||
Layout managers inherit from the following API:
|
||||
|
||||
```javascript
|
||||
class LayoutManager {
|
||||
class LayoutManager : EventTarget {
|
||||
readonly attribute StyleNode node;
|
||||
constructor LayoutManager(StyleNode node);
|
||||
|
||||
virtual Array<EventTarget> getEventDispatchChain(); // O(N) in number of this.node's ancestors // implements EventTarget.getEventDispatchChain()
|
||||
// let result = [];
|
||||
// let node = this.node;
|
||||
// while (node && node.layoutManager) {
|
||||
// result.push(node.layoutManager);
|
||||
// node = node.parentNode;
|
||||
// }
|
||||
// return result;
|
||||
|
||||
void take(StyleNode victim); // sets victim.ownerLayoutManager = this;
|
||||
// assert: victim hasn't been take()n yet during this layout
|
||||
// assert: victim.needsLayout == true
|
||||
@ -565,7 +576,7 @@ class LayoutManager {
|
||||
// that you don't skip the children that are visible in the new coordinate space but wouldn't be
|
||||
// without the transform
|
||||
|
||||
virtual Node hitTest(Float x, Float y);
|
||||
virtual StyleNode hitTest(Float x, Float y);
|
||||
// default implementation uses the node's children nodes' x, y,
|
||||
// width, and height, skipping any that have width=0 or height=0, or
|
||||
// whose ownerLayoutManager is not |this|
|
||||
|
||||
40
specs/ui.md
40
specs/ui.md
@ -67,43 +67,51 @@ that is being clicked, and from "down" back to "up" when this ends.
|
||||
(Note that clicking a button on a stylus doesn't change it from up to
|
||||
down. A stylus can have a button pressed while "up".)
|
||||
|
||||
When one switches from "up" to "down", the position of the tap is hit
|
||||
tested and a 'pointer-down' event is fired at the target element under
|
||||
the cursor, if any, or the document otherwise. The return value, if
|
||||
it's a node, is used as the target of future move and up events until
|
||||
this touch goes up. If there is no return value, the target continues
|
||||
to be the application's document.
|
||||
When one switches from "up" to "down", the following algorithm is run:
|
||||
|
||||
1. Hit test the position of the pointer, let 'node' be the result.
|
||||
2. Fire a pointer-down event at the layoutManager for 'node'.
|
||||
Let 'result' be the returned value.
|
||||
3. If 'result' is undefined, then fire a pointer-down event at the
|
||||
Element for 'node'.
|
||||
Let 'result' be the returned value.
|
||||
4. If 'result' is undefined or is not an EventTarget, let 'result' be
|
||||
the application document.
|
||||
5. Let 'result' capture this pointer.
|
||||
|
||||
A pointer that is "down" is captured -- all events for that pointer
|
||||
will be routed to the chosen target until the pointer goes up,
|
||||
regardless of whether it's in that target's visible area.
|
||||
|
||||
When an element captures a pointer and it has no captured pointers so
|
||||
When an object captures a pointer and it has no captured pointers so
|
||||
far, if either there are no buttons (touch, stylus) or only the
|
||||
primary button is active (mouse) and this is not an inverted stylus,
|
||||
then that pointer is marked as "primary" for that element. The pointer
|
||||
then that pointer is marked as "primary" for that object. The pointer
|
||||
remains the primary pointer until the corresponding pointer-up event
|
||||
(even if the buttons change).
|
||||
|
||||
When one moves, if it is "up" then a 'pointer-moved' event is fired at
|
||||
the application's document, otherwise if it is "down" then the event
|
||||
is fired at the element or document that was selected for the
|
||||
'pointer-down' event (the capturing element). If the return value of a
|
||||
'pointer-moved' event is 'cancel', then pretend that the pointer moved
|
||||
to 'up', send 'pointer-up' as described below, and drop all events for
|
||||
this pointer until such time as it actually changes to be 'up'.
|
||||
is fired at the object or document that was selected for the
|
||||
'pointer-down' event (the capturing object). If the return value of a
|
||||
'pointer-moved' event is 'cancel' then cancel the pointer.
|
||||
|
||||
When one switches from "down" to "up", a 'pointer-up' event is fired
|
||||
at the element or document that was selected for the 'pointer-down'
|
||||
at the object or document that was selected for the 'pointer-down'
|
||||
event (the capturing target).
|
||||
|
||||
At the time of a pointer-up event, if there is another pointer that is
|
||||
already down, captured by the same element, and is of the same kind,
|
||||
already down, captured by the same object, and is of the same kind,
|
||||
and that has either no buttons or only its primary button active, then
|
||||
that becomes the new primary pointer for that element before the
|
||||
that becomes the new primary pointer for that object before the
|
||||
pointer-up event is sent. Otherwise, the primary pointer stops being
|
||||
primary just after the pointer-up.
|
||||
|
||||
When a pointer is canceled, if it is "down", pretend that the pointer
|
||||
moved to "up", send 'pointer-up' as described below, and drop all
|
||||
events for this pointer until such time as it actually changes to be
|
||||
truly "up".
|
||||
|
||||
Nothing special happens when a capturing target moves in the DOM.
|
||||
|
||||
The x and y position of an -up or -down event always match those of
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user