Commit 2a9de0aa authored by Adam Barth's avatar Adam Barth

Add the ability to custom paint foregrounds

parent a2b8f8b9
......@@ -938,61 +938,82 @@ abstract class CustomPainter {
void paint(PaintingCanvas canvas, Size size);
bool shouldRepaint(CustomPainter oldDelegate);
bool hitTest(Point position) => true;
bool hitTest(Point position) => null;
}
/// Delegates its painting to [onPaint]
/// Delegates its painting
///
/// When asked to paint, custom paint first calls its callback with the current
/// canvas and then paints its children. The coodinate system of the canvas
/// matches the coordinate system of the custom paint object. The callback is
/// expected to paint with in a rectangle starting at the origin and
/// encompassing a region of the given size. If the callback paints outside
/// When asked to paint, custom paint first asks painter to paint with the
/// current canvas and then paints its children. After painting its children,
/// custom paint asks foregroundPainter to paint. The coodinate system of the
/// canvas matches the coordinate system of the custom paint object. The
/// painters are expected to paint with in a rectangle starting at the origin
/// and encompassing a region of the given size. If the painters paints outside
/// those bounds, there might be insufficient memory allocated to rasterize the
/// painting commands and the resulting behavior is undefined.
///
/// Note: Custom paint calls its callback during paint, which means you cannot
/// Note: Custom paint calls its painters during paint, which means you cannot
/// dirty layout or paint information during the callback.
class RenderCustomPaint extends RenderProxyBox {
RenderCustomPaint({
CustomPainter painter,
CustomPainter foregroundPainter,
RenderBox child
}) : _painter = painter, super(child) {
assert(painter != null);
}
}) : _painter = painter, _foregroundPainter = foregroundPainter, super(child);
CustomPainter get painter => _painter;
CustomPainter _painter;
void set painter (CustomPainter newPainter) {
assert(newPainter != null || !attached);
if (_painter == newPainter)
return;
CustomPainter oldPainter = _painter;
_painter = newPainter;
if (newPainter == null)
_checkForRepaint(_painter, oldPainter);
}
CustomPainter get foregroundPainter => _foregroundPainter;
CustomPainter _foregroundPainter;
void set foregroundPainter (CustomPainter newPainter) {
if (_foregroundPainter == newPainter)
return;
if (oldPainter == null
|| newPainter.runtimeType != oldPainter.runtimeType
|| newPainter.shouldRepaint(oldPainter))
CustomPainter oldPainter = _foregroundPainter;
_foregroundPainter = newPainter;
_checkForRepaint(_foregroundPainter, oldPainter);
}
void _checkForRepaint(CustomPainter newPainter, CustomPainter oldPainter) {
if (newPainter == null) {
assert(oldPainter != null); // We should be called only for changes.
markNeedsPaint();
} else if (oldPainter == null ||
newPainter.runtimeType != oldPainter.runtimeType ||
newPainter.shouldRepaint(oldPainter)) {
markNeedsPaint();
}
}
void attach() {
assert(_painter != null);
super.attach();
bool hitTestChildren(HitTestResult result, { Point position }) {
if (_foregroundPainter != null && (_foregroundPainter.hitTest(position) ?? false))
return true;
return super.hitTestChildren(result, position: position);
}
bool hitTestSelf(Point position) {
return _painter.hitTest(position);
return _painter != null && (_painter.hitTest(position) ?? true);
}
void _paintWithPainter(Canvas canvas, Offset offset, CustomPainter painter) {
canvas.translate(offset.dx, offset.dy);
painter.paint(canvas, size);
canvas.translate(-offset.dx, -offset.dy);
}
void paint(PaintingContext context, Offset offset) {
assert(_painter != null);
context.canvas.translate(offset.dx, offset.dy);
_painter.paint(context.canvas, size);
context.canvas.translate(-offset.dx, -offset.dy);
if (_painter != null)
_paintWithPainter(context.canvas, offset, _painter);
super.paint(context, offset);
if (_foregroundPainter != null)
_paintWithPainter(context.canvas, offset, _foregroundPainter);
}
}
......
......@@ -137,21 +137,25 @@ class DecoratedBox extends OneChildRenderObjectWidget {
}
class CustomPaint extends OneChildRenderObjectWidget {
CustomPaint({ Key key, this.painter, Widget child })
: super(key: key, child: child) {
assert(painter != null);
}
CustomPaint({ Key key, this.painter, this.foregroundPainter, Widget child })
: super(key: key, child: child);
final CustomPainter painter;
final CustomPainter foregroundPainter;
RenderCustomPaint createRenderObject() => new RenderCustomPaint(painter: painter);
RenderCustomPaint createRenderObject() => new RenderCustomPaint(
painter: painter,
foregroundPainter: foregroundPainter
);
void updateRenderObject(RenderCustomPaint renderObject, CustomPaint oldWidget) {
renderObject.painter = painter;
renderObject.foregroundPainter = foregroundPainter;
}
void didUnmountRenderObject(RenderCustomPaint renderObject) {
renderObject.painter = null;
renderObject.foregroundPainter = null;
}
}
......@@ -1382,4 +1386,4 @@ class StatefulBuilder extends StatefulComponent {
}
class _StatefulBuilderState extends State<StatefulBuilder> {
Widget build(BuildContext context) => config.builder(context, setState);
}
\ No newline at end of file
}
......@@ -7,7 +7,7 @@ import 'package:flutter/widgets.dart';
import 'package:test/test.dart';
void main() {
test('Can be placed in an infinte box', () {
test('Can be placed in an infinite box', () {
testWidgets((WidgetTester tester) {
tester.pumpWidget(new Block(<Widget>[new Center()]));
});
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/widgets.dart';
import 'package:test/test.dart';
class TestCustomPainter extends CustomPainter {
TestCustomPainter({ this.log, this.name });
List<String> log;
String name;
void paint(Canvas canvas, Size size) {
log.add(name);
}
bool shouldRepaint(TestCustomPainter oldPainter) => true;
}
void main() {
test('Control test for custom painting', () {
testWidgets((WidgetTester tester) {
List<String> log = <String>[];
tester.pumpWidget(new CustomPaint(
painter: new TestCustomPainter(
log: log,
name: 'background'
),
foregroundPainter: new TestCustomPainter(
log: log,
name: 'foreground'
),
child: new CustomPaint(
painter: new TestCustomPainter(
log: log,
name: 'child'
)
)
));
expect(log, equals(['background', 'child', 'foreground']));
});
});
}
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