Skip to content

Commit

Permalink
Merge pull request flutter#864 from eseidelGoogle/render_grid
Browse files Browse the repository at this point in the history
Add support for RenderGrid
  • Loading branch information
eseidelGoogle committed Aug 26, 2015
2 parents 982f5ab + 13926c3 commit 3a73fd6
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 43 deletions.
46 changes: 3 additions & 43 deletions examples/rendering/flex.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,47 +5,7 @@
import 'dart:sky' as sky;

import 'package:sky/rendering.dart';

class RenderSolidColor extends RenderDecoratedBox {
final sky.Size desiredSize;
final sky.Color backgroundColor;

RenderSolidColor(sky.Color backgroundColor, { this.desiredSize: sky.Size.infinite })
: backgroundColor = backgroundColor,
super(decoration: new BoxDecoration(backgroundColor: backgroundColor)) {
}

double getMinIntrinsicWidth(BoxConstraints constraints) {
return constraints.constrainWidth(desiredSize.width);
}

double getMaxIntrinsicWidth(BoxConstraints constraints) {
return constraints.constrainWidth(desiredSize.width);
}

double getMinIntrinsicHeight(BoxConstraints constraints) {
return constraints.constrainHeight(desiredSize.height);
}

double getMaxIntrinsicHeight(BoxConstraints constraints) {
return constraints.constrainHeight(desiredSize.height);
}

void performLayout() {
size = constraints.constrain(desiredSize);
}

EventDisposition handleEvent(sky.Event event, BoxHitTestEntry entry) {
if (event.type == 'pointerdown') {
decoration = new BoxDecoration(backgroundColor: const sky.Color(0xFFFF0000));
return EventDisposition.processed;
} else if (event.type == 'pointerup') {
decoration = new BoxDecoration(backgroundColor: backgroundColor);
return EventDisposition.processed;
}
return super.handleEvent(event, entry);
}
}
import 'solid_color_box.dart';

RenderBox buildFlexExample() {
RenderFlex flexRoot = new RenderFlex(direction: FlexDirection.vertical);
Expand All @@ -56,7 +16,7 @@ RenderBox buildFlexExample() {
);

void addFlexChildSolidColor(RenderFlex parent, sky.Color backgroundColor, { int flex: 0 }) {
RenderSolidColor child = new RenderSolidColor(backgroundColor);
RenderSolidColorBox child = new RenderSolidColorBox(backgroundColor);
parent.add(child);
child.parentData.flex = flex;
}
Expand All @@ -65,7 +25,7 @@ RenderBox buildFlexExample() {
addFlexChildSolidColor(flexRoot, const sky.Color(0xFFFFFF00), flex: 1);

// Turquoise box
flexRoot.add(new RenderSolidColor(const sky.Color(0x7700FFFF), desiredSize: new sky.Size(100.0, 100.0)));
flexRoot.add(new RenderSolidColorBox(const sky.Color(0x7700FFFF), desiredSize: new sky.Size(100.0, 100.0)));

var renderDecoratedBlock = new RenderDecoratedBox(
decoration: new BoxDecoration(backgroundColor: const sky.Color(0xFFFFFFFF))
Expand Down
25 changes: 25 additions & 0 deletions examples/rendering/render_grid.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// 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 'dart:math' as math;

import 'package:sky/rendering.dart';
import 'package:sky/theme/colors.dart' as colors;
import 'solid_color_box.dart';

Color randomColor() {
final List<Color> allColors = [
colors.Blue,
colors.Indigo
].map((p) => p.values).fold([], (a, b) => a..addAll(b));
final random = new math.Random();
return allColors[random.nextInt(allColors.length)];
}

RenderBox buildGridExample() {
List<RenderBox> children = new List.generate(30, (_) => new RenderSolidColorBox(randomColor()));
return new RenderGrid(children: children, maxChildExtent: 100.0);
}

main() => new SkyBinding(root: buildGridExample());
1 change: 1 addition & 0 deletions sky/packages/sky/lib/rendering.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export 'rendering/auto_layout.dart';
export 'rendering/block.dart';
export 'rendering/box.dart';
export 'rendering/flex.dart';
export 'rendering/grid.dart';
export 'rendering/image.dart';
export 'rendering/layer.dart';
export 'rendering/object.dart';
Expand Down
141 changes: 141 additions & 0 deletions sky/packages/sky/lib/rendering/grid.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// 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:sky/rendering/box.dart';
import 'package:sky/rendering/object.dart';

class GridParentData extends BoxParentData with ContainerParentDataMixin<RenderBox> {}

class GridMetrics {
// Grid is width-in, height-out. We fill the max width and adjust height
// accordingly.
factory GridMetrics({ double width, int childCount, double childExtent }) {
assert(width != null);
assert(childCount != null);
assert(childExtent != null);
int childrenPerRow = (width / childExtent).floor() + 1;
double totalPadding = 0.0;
if (childrenPerRow * childExtent > width) {
// TODO(eseidel): We should snap to pixel bounderies.
childExtent = width / childrenPerRow;
} else {
totalPadding = width - (childrenPerRow * childExtent);
}
double childPadding = totalPadding / (childrenPerRow + 1.0);
int rowCount = (childCount / childrenPerRow).ceil();

double height = childPadding * (rowCount + 1) + (childExtent * rowCount);
Size childSize = new Size(childExtent, childExtent);
Size size = new Size(width, height);
return new GridMetrics._(size, childSize, childrenPerRow, childPadding, rowCount);
}

const GridMetrics._(this.size, this.childSize, this.childrenPerRow, this.childPadding, this.rowCount);

final Size size;
final Size childSize;
final int childrenPerRow; // aka columnCount
final double childPadding;
final int rowCount;
}

class RenderGrid extends RenderBox with ContainerRenderObjectMixin<RenderBox, GridParentData>,
RenderBoxContainerDefaultsMixin<RenderBox, GridParentData> {
RenderGrid({ List<RenderBox> children, double maxChildExtent }) {
addAll(children);
_maxChildExtent = maxChildExtent;
}

double _maxChildExtent;
bool _hasVisualOverflow = false;

void setupParentData(RenderBox child) {
if (child.parentData is! GridParentData)
child.parentData = new GridParentData();
}

// getMinIntrinsicWidth() should return the minimum width that this box could
// be without failing to render its contents within itself.
double getMinIntrinsicWidth(BoxConstraints constraints) {
// We can render at any width.
return constraints.constrainWidth(0.0);
}

// getMaxIntrinsicWidth() should return the smallest width beyond which
// increasing the width never decreases the height.
double getMaxIntrinsicWidth(BoxConstraints constraints) {
double maxWidth = childCount * _maxChildExtent;
return constraints.constrainWidth(maxWidth);
}

// getMinIntrinsicHeight() should return the minimum height that this box could
// be without failing to render its contents within itself.
double getMinIntrinsicHeight(BoxConstraints constraints) {
double desiredHeight = _computeMetrics().size.height;
return constraints.constrainHeight(desiredHeight);
}

// getMaxIntrinsicHeight should return the smallest height beyond which
// increasing the height never decreases the width.
// If the layout algorithm used is width-in-height-out, i.e. the height
// depends on the width and not vice versa, then this will return the same
// as getMinIntrinsicHeight().
double getMaxIntrinsicHeight(BoxConstraints constraints) {
return getMinIntrinsicHeight(constraints);
}

double computeDistanceToActualBaseline(TextBaseline baseline) {
return defaultComputeDistanceToHighestActualBaseline(baseline);
}

GridMetrics _computeMetrics() {
return new GridMetrics(
width: constraints.maxWidth,
childCount: childCount,
childExtent: _maxChildExtent
);
}

void performLayout() {
// We could shrink-wrap our contents when infinite, but for now we don't.
assert(constraints.maxWidth < double.INFINITY);
GridMetrics metrics = _computeMetrics();
size = constraints.constrain(metrics.size);
if (constraints.maxHeight < size.height)
_hasVisualOverflow = true;

int row = 0;
int column = 0;
RenderBox child = firstChild;
while (child != null) {
child.layout(new BoxConstraints.tight(metrics.childSize));

double x = (column + 1) * metrics.childPadding + (column * metrics.childSize.width);
double y = (row + 1) * metrics.childPadding + (row * metrics.childSize.height);
child.parentData.position = new Point(x, y);

column += 1;
if (column >= metrics.childrenPerRow) {
row += 1;
column = 0;
}
child = child.parentData.nextSibling;
}
}

void hitTestChildren(HitTestResult result, { Point position }) {
defaultHitTestChildren(result, position: position);
}

void paint(PaintingContext context, Offset offset) {
if (_hasVisualOverflow) {
context.canvas.save();
context.canvas.clipRect(offset & size);
defaultPaint(context, offset);
context.canvas.restore();
} else {
defaultPaint(context, offset);
}
}
}

0 comments on commit 3a73fd6

Please sign in to comment.