Commit c09aac3f authored by Hixie's avatar Hixie

Rationalise hit testing in the new RenderNode world

- makes the event logic not involve a boolean return value (since we ignored it anyway)
- splits the event handling logic into two steps, hit testing and event dispatch
- introduces an App class on the Dart side to factor out the interaction with the C++ side
- ports sector-layout and simple_render_tree to the new App infrastructure
- port simple_render_tree to the new event handling logic
- implement hit testing for the sector-layout demo

R=eseidel@chromium.org

Review URL: https://codereview.chromium.org/1143343004
parent 3976cd7b
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'dart:math' as math; import 'dart:math' as math;
import 'dart:sky' as sky; import 'dart:sky' as sky;
import 'package:sky/framework/app.dart';
import 'package:sky/framework/layout2.dart'; import 'package:sky/framework/layout2.dart';
const double kTwoPi = 2 * math.PI; const double kTwoPi = 2 * math.PI;
...@@ -77,6 +78,17 @@ abstract class RenderSector extends RenderNode { ...@@ -77,6 +78,17 @@ abstract class RenderSector extends RenderNode {
layoutDone(); layoutDone();
} }
bool hitTest(HitTestResult result, { double radius, double theta }) {
assert(parentData is SectorParentData);
if (radius < parentData.radius || radius >= parentData.radius + deltaRadius ||
theta < parentData.theta || theta >= parentData.theta + deltaTheta)
return false;
hitTestChildren(result, radius: radius, theta: theta);
result.add(this);
return true;
}
void hitTestChildren(HitTestResult result, { double radius, double theta }) { }
double deltaRadius; double deltaRadius;
double deltaTheta; double deltaTheta;
} }
...@@ -119,7 +131,21 @@ class RenderDecoratedSector extends RenderSector { ...@@ -119,7 +131,21 @@ class RenderDecoratedSector extends RenderSector {
class SectorChildListParentData extends SectorParentData with ContainerParentDataMixin<RenderSector> { } class SectorChildListParentData extends SectorParentData with ContainerParentDataMixin<RenderSector> { }
class RenderSectorRing extends RenderDecoratedSector with ContainerRenderNodeMixin<RenderSector, SectorChildListParentData> { class RenderSectorWithChildren extends RenderDecoratedSector with ContainerRenderNodeMixin<RenderSector, SectorChildListParentData> {
RenderSectorWithChildren(BoxDecoration decoration) : super(decoration);
void hitTestChildren(HitTestResult result, { double radius, double theta }) {
RenderSector child = lastChild;
while (child != null) {
assert(child.parentData is SectorChildListParentData);
if (child.hitTest(result, radius: radius, theta: theta))
return;
child = child.parentData.previousSibling;
}
}
}
class RenderSectorRing extends RenderSectorWithChildren {
// lays out RenderSector children in a ring // lays out RenderSector children in a ring
RenderSectorRing({ RenderSectorRing({
...@@ -229,8 +255,6 @@ class RenderSectorRing extends RenderDecoratedSector with ContainerRenderNodeMix ...@@ -229,8 +255,6 @@ class RenderSectorRing extends RenderDecoratedSector with ContainerRenderNodeMix
deltaTheta = innerTheta; deltaTheta = innerTheta;
} }
// TODO(ianh): hit testing et al is pending on adam's patch
// paint origin is 0,0 of our circle // paint origin is 0,0 of our circle
// each sector then knows how to paint itself at its location // each sector then knows how to paint itself at its location
void paint(RenderNodeDisplayList canvas) { void paint(RenderNodeDisplayList canvas) {
...@@ -246,7 +270,7 @@ class RenderSectorRing extends RenderDecoratedSector with ContainerRenderNodeMix ...@@ -246,7 +270,7 @@ class RenderSectorRing extends RenderDecoratedSector with ContainerRenderNodeMix
} }
class RenderSectorSlice extends RenderDecoratedSector with ContainerRenderNodeMixin<RenderSector, SectorChildListParentData> { class RenderSectorSlice extends RenderSectorWithChildren {
// lays out RenderSector children in a stack // lays out RenderSector children in a stack
RenderSectorSlice({ RenderSectorSlice({
...@@ -351,8 +375,6 @@ class RenderSectorSlice extends RenderDecoratedSector with ContainerRenderNodeMi ...@@ -351,8 +375,6 @@ class RenderSectorSlice extends RenderDecoratedSector with ContainerRenderNodeMi
deltaRadius = childRadius - this.parentData.radius; deltaRadius = childRadius - this.parentData.radius;
} }
// TODO(ianh): hit testing et al is pending on adam's patch
// paint origin is 0,0 of our circle // paint origin is 0,0 of our circle
// each sector then knows how to paint itself at its location // each sector then knows how to paint itself at its location
void paint(RenderNodeDisplayList canvas) { void paint(RenderNodeDisplayList canvas) {
...@@ -436,8 +458,6 @@ class RenderBoxToRenderSectorAdapter extends RenderBox { ...@@ -436,8 +458,6 @@ class RenderBoxToRenderSectorAdapter extends RenderBox {
double width; double width;
double height; double height;
// TODO(ianh): hit testing et al is pending on adam's patch
// paint origin is 0,0 of our circle // paint origin is 0,0 of our circle
void paint(RenderNodeDisplayList canvas) { void paint(RenderNodeDisplayList canvas) {
super.paint(canvas); super.paint(canvas);
...@@ -445,16 +465,38 @@ class RenderBoxToRenderSectorAdapter extends RenderBox { ...@@ -445,16 +465,38 @@ class RenderBoxToRenderSectorAdapter extends RenderBox {
canvas.paintChild(child, width/2.0, height/2.0); canvas.paintChild(child, width/2.0, height/2.0);
} }
bool hitTest(HitTestResult result, { double x, double y }) {
if (child == null)
return false;
// translate to our origin
x -= width/2.0;
y -= height/2.0;
// convert to radius/theta
double radius = math.sqrt(x*x+y*y);
double theta = (math.atan2(x, -y) - math.PI/2.0) % kTwoPi;
if (radius < innerRadius)
return false;
if (radius >= innerRadius + child.deltaRadius)
return false;
if (theta > child.deltaTheta)
return false;
child.hitTest(result, radius: radius, theta: theta);
result.add(this);
return true;
}
} }
class RenderSolidColor extends RenderDecoratedSector { class RenderSolidColor extends RenderDecoratedSector {
RenderSolidColor(int backgroundColor, { RenderSolidColor(int backgroundColor, {
this.desiredDeltaRadius: double.INFINITY, this.desiredDeltaRadius: double.INFINITY,
this.desiredDeltaTheta: kTwoPi this.desiredDeltaTheta: kTwoPi
}) : super(new BoxDecoration(backgroundColor: backgroundColor)); }) : this.backgroundColor = backgroundColor,
super(new BoxDecoration(backgroundColor: backgroundColor));
double desiredDeltaRadius; double desiredDeltaRadius;
double desiredDeltaTheta; double desiredDeltaTheta;
final int backgroundColor;
SectorDimensions getIntrinsicDimensions(SectorConstraints constraints, double radius) { SectorDimensions getIntrinsicDimensions(SectorConstraints constraints, double radius) {
return new SectorDimensions.withConstraints(constraints, deltaTheta: 1.0); // 1.0 radians return new SectorDimensions.withConstraints(constraints, deltaTheta: 1.0); // 1.0 radians
...@@ -465,39 +507,28 @@ class RenderSolidColor extends RenderDecoratedSector { ...@@ -465,39 +507,28 @@ class RenderSolidColor extends RenderDecoratedSector {
deltaTheta = constraints.constrainDeltaTheta(desiredDeltaTheta); deltaTheta = constraints.constrainDeltaTheta(desiredDeltaTheta);
layoutDone(); layoutDone();
} }
}
RenderView renderView; void handlePointer(sky.PointerEvent event) {
if (event.type == 'pointerdown')
void beginFrame(double timeStamp) { setBoxDecoration(new BoxDecoration(backgroundColor: 0xFFFF0000));
RenderNode.flushLayout(); else if (event.type == 'pointerup')
setBoxDecoration(new BoxDecoration(backgroundColor: backgroundColor));
renderView.paintFrame(); }
} }
bool handleEvent(sky.Event event) { AppView app;
if (event is! sky.PointerEvent)
return false;
return renderView.handlePointer(event, x: event.x, y: event.y);
}
void main() { void main() {
print("test...");
sky.view.setEventCallback(handleEvent); var rootCircle = new RenderSectorRing(padding: 20.0);
sky.view.setBeginFrameCallback(beginFrame); rootCircle.add(new RenderSolidColor(0xFF00FFFF, desiredDeltaTheta: kTwoPi * 0.15));
rootCircle.add(new RenderSolidColor(0xFF0000FF, desiredDeltaTheta: kTwoPi * 0.4));
var rootCircle = new RenderSectorRing(padding: 10.0); var stack = new RenderSectorSlice(padding: 2.0);
rootCircle.add(new RenderSolidColor(0xFF00FFFF, desiredDeltaTheta: kTwoPi * 0.25));
rootCircle.add(new RenderSolidColor(0xFF0000FF, desiredDeltaTheta: kTwoPi * 0.3));
var stack = new RenderSectorSlice(padding: 10.0);
stack.add(new RenderSolidColor(0xFFFFFF00, desiredDeltaRadius: 20.0)); stack.add(new RenderSolidColor(0xFFFFFF00, desiredDeltaRadius: 20.0));
stack.add(new RenderSolidColor(0xFFFF9000, desiredDeltaRadius: 20.0)); stack.add(new RenderSolidColor(0xFFFF9000, desiredDeltaRadius: 20.0));
stack.add(new RenderSolidColor(0xFF00FF00, desiredDeltaRadius: 20.0)); stack.add(new RenderSolidColor(0xFF00FF00));
rootCircle.add(stack); rootCircle.add(stack);
var root = new RenderBoxToRenderSectorAdapter(innerRadius: 50.0, child: rootCircle); var root = new RenderBoxToRenderSectorAdapter(innerRadius: 50.0, child: rootCircle);
renderView = new RenderView(root: root); app = new AppView(root);
renderView.layout(newWidth: sky.view.width, newHeight: sky.view.height);
sky.view.scheduleFrame();
} }
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:math';
import 'dart:sky'; import 'dart:sky';
import 'package:sky/framework/app.dart';
import 'package:sky/framework/layout2.dart'; import 'package:sky/framework/layout2.dart';
class RenderSolidColor extends RenderDecoratedBox { class RenderSolidColor extends RenderDecoratedBox {
...@@ -28,39 +28,17 @@ class RenderSolidColor extends RenderDecoratedBox { ...@@ -28,39 +28,17 @@ class RenderSolidColor extends RenderDecoratedBox {
layoutDone(); layoutDone();
} }
bool handlePointer(PointerEvent event, { double x: 0.0, double y: 0.0 }) { void handlePointer(PointerEvent event) {
if (event.type == 'pointerdown') { if (event.type == 'pointerdown')
setBoxDecoration(new BoxDecoration(backgroundColor: 0xFFFF0000)); setBoxDecoration(new BoxDecoration(backgroundColor: 0xFFFF0000));
return true; else if (event.type == 'pointerup')
}
if (event.type == 'pointerup') {
setBoxDecoration(new BoxDecoration(backgroundColor: backgroundColor)); setBoxDecoration(new BoxDecoration(backgroundColor: backgroundColor));
return true;
} }
return false;
}
}
RenderView renderView;
void beginFrame(double timeStamp) {
RenderNode.flushLayout();
renderView.paintFrame();
} }
bool handleEvent(Event event) { AppView app;
if (event is! PointerEvent)
return false;
return renderView.handlePointer(event, x: event.x, y: event.y);
}
void main() { void main() {
view.setEventCallback(handleEvent);
view.setBeginFrameCallback(beginFrame);
var root = new RenderFlex( var root = new RenderFlex(
direction: FlexDirection.Vertical, direction: FlexDirection.Vertical,
decoration: new BoxDecoration(backgroundColor: 0xFF000000)); decoration: new BoxDecoration(backgroundColor: 0xFF000000));
...@@ -98,8 +76,6 @@ void main() { ...@@ -98,8 +76,6 @@ void main() {
root.add(row); root.add(row);
row.parentData.flex = 3; row.parentData.flex = 3;
renderView = new RenderView(root: root); app = new AppView(root);
renderView.layout(newWidth: view.width, newHeight: view.height);
view.scheduleFrame();
} }
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'dart:math'; import 'dart:math';
import 'dart:sky'; import 'dart:sky';
import 'package:sky/framework/app.dart';
import 'package:sky/framework/layout2.dart'; import 'package:sky/framework/layout2.dart';
// Material design colors. :p // Material design colors. :p
...@@ -40,7 +41,7 @@ class RenderTouchDemo extends RenderBox { ...@@ -40,7 +41,7 @@ class RenderTouchDemo extends RenderBox {
RenderTouchDemo(); RenderTouchDemo();
bool handlePointer(PointerEvent event, { double x: 0.0, double y: 0.0 }) { void handlePointer(PointerEvent event) {
switch (event.type) { switch (event.type) {
case 'pointerdown': case 'pointerdown':
int color = colors[event.pointer.remainder(colors.length)]; int color = colors[event.pointer.remainder(colors.length)];
...@@ -57,7 +58,6 @@ class RenderTouchDemo extends RenderBox { ...@@ -57,7 +58,6 @@ class RenderTouchDemo extends RenderBox {
break; break;
} }
markNeedsPaint(); markNeedsPaint();
return true;
} }
void paint(RenderNodeDisplayList canvas) { void paint(RenderNodeDisplayList canvas) {
...@@ -67,25 +67,8 @@ class RenderTouchDemo extends RenderBox { ...@@ -67,25 +67,8 @@ class RenderTouchDemo extends RenderBox {
} }
} }
RenderView renderView; AppView app;
void beginFrame(double timeStamp) {
RenderNode.flushLayout();
renderView.paintFrame();
}
bool handleEvent(Event event) {
if (event is! PointerEvent)
return false;
return renderView.handlePointer(event, x: event.x, y: event.y);
}
void main() { void main() {
view.setEventCallback(handleEvent); app = new AppView(new RenderTouchDemo());
view.setBeginFrameCallback(beginFrame);
renderView = new RenderView(root: new RenderTouchDemo());
renderView.layout(newWidth: view.width, newHeight: view.height);
view.scheduleFrame();
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment