| Index: client/layout/ViewLayout.dart
|
| ===================================================================
|
| --- client/layout/ViewLayout.dart (revision 4144)
|
| +++ client/layout/ViewLayout.dart (working copy)
|
| @@ -1,237 +0,0 @@
|
| -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -/** The interface that the layout algorithms use to talk to the view. */
|
| -interface Positionable {
|
| - ViewLayout get layout();
|
| -
|
| - /** Gets our custom CSS properties, as provided by the CSS preprocessor. */
|
| - Map<String, String> get customStyle();
|
| -
|
| - /** Gets the root DOM used for layout. */
|
| - Element get node();
|
| -
|
| - /** Gets the collection of child views. */
|
| - Collection<Positionable> get childViews();
|
| -
|
| - /** Causes a view to layout its children. */
|
| - void doLayout();
|
| -}
|
| -
|
| -
|
| -/**
|
| - * Caches the layout parameters that were specified in CSS during a layout
|
| - * computation. These values are immutable during a layout.
|
| - */
|
| -class LayoutParams {
|
| - // TODO(jmesserly): should be const, but there's a bug in DartC preventing us
|
| - // from calling "window." in an initializer. See b/5332777
|
| - Future<CSSStyleDeclaration> style;
|
| -
|
| - int get layer() => 0;
|
| -
|
| - LayoutParams(Element node) {
|
| - style = node.computedStyle;
|
| - }
|
| -}
|
| -
|
| -// TODO(jmesserly): enums would really help here
|
| -class Dimension {
|
| - // TODO(jmesserly): perhaps this should be X and Y
|
| - static final WIDTH = const Dimension._internal('width');
|
| - static final HEIGHT = const Dimension._internal('height');
|
| -
|
| - final String name; // for debugging
|
| - const Dimension._internal(this.name);
|
| -}
|
| -
|
| -class ContentSizeMode {
|
| - /** Minimum content size, e.g. min-width and min-height in CSS. */
|
| - static final MIN = const ContentSizeMode._internal('min');
|
| -
|
| - /** Maximum content size, e.g. min-width and min-height in CSS. */
|
| - static final MAX = const ContentSizeMode._internal('max');
|
| -
|
| - // TODO(jmesserly): we probably want some sort of "auto" or "best fit" mode
|
| - // Don't need it yet though.
|
| -
|
| - final String name; // for debugging
|
| - const ContentSizeMode._internal(this.name);
|
| -}
|
| -
|
| -/**
|
| - * Abstract base class for View layout. Tracks relevant layout state.
|
| - * This code was inspired by code in Android's View.java; it's needed for the
|
| - * rest of the layout system.
|
| - */
|
| -class ViewLayout {
|
| - /**
|
| - * The layout parameters associated with this view and used by the parent
|
| - * to determine how this view should be laid out.
|
| - */
|
| - LayoutParams layoutParams;
|
| - Future<ElementRect> _cachedViewRect;
|
| -
|
| - /** The view that this layout belongs to. */
|
| - final Positionable view;
|
| -
|
| - /**
|
| - * To get a perforant positioning model on top of the DOM, we read all
|
| - * properties in the first pass while computing positions. Then we have a
|
| - * second pass that actually moves everything.
|
| - */
|
| - int _measuredLeft, _measuredTop, _measuredWidth, _measuredHeight;
|
| -
|
| - ViewLayout(this.view);
|
| -
|
| - /**
|
| - * Creates the appropriate view layout, depending on the properties.
|
| - */
|
| - // TODO(jmesserly): we should support user defined layouts somehow. Perhaps
|
| - // registered with a LayoutProvider.
|
| - factory ViewLayout.fromView(Positionable view) {
|
| - if (hasCustomLayout(view)) {
|
| - return new GridLayout(view);
|
| - } else {
|
| - return new ViewLayout(view);
|
| - }
|
| - }
|
| -
|
| - static bool hasCustomLayout(Positionable view) {
|
| - return view.customStyle['display'] == "-dart-grid";
|
| - }
|
| -
|
| - CSSStyleDeclaration get _style() => layoutParams.style.value;
|
| -
|
| - void cacheExistingBrowserLayout() {
|
| - _cachedViewRect = view.node.rect;
|
| - }
|
| -
|
| - int get currentWidth() {
|
| - return _cachedViewRect.value.offset.width;
|
| - }
|
| -
|
| - int get currentHeight() {
|
| - return _cachedViewRect.value.offset.height;
|
| - }
|
| -
|
| - int get borderLeftWidth() => _toPixels(_style.borderLeftWidth);
|
| - int get borderTopWidth() => _toPixels(_style.borderTopWidth);
|
| - int get borderRightWidth() => _toPixels(_style.borderRightWidth);
|
| - int get borderBottomWidth() => _toPixels(_style.borderBottomWidth);
|
| - int get borderWidth() => borderLeftWidth + borderRightWidth;
|
| - int get borderHeight() => borderTopWidth + borderBottomWidth;
|
| -
|
| - /** Implements the custom layout computation. */
|
| - void measureLayout(Future<Size> size, Completer<bool> changed) {
|
| - }
|
| -
|
| - /**
|
| - * Positions the view within its parent container.
|
| - * Also performs a layout of its children.
|
| - */
|
| - void setBounds(int left, int top, int width, int height) {
|
| - assert(width >= 0 && height >= 0);
|
| -
|
| - _measuredLeft = left;
|
| - _measuredTop = top;
|
| -
|
| - // Note: we need to save the client height
|
| - _measuredWidth = width - borderWidth;
|
| - _measuredHeight = height - borderHeight;
|
| - final completer = new Completer<Size>();
|
| - completer.complete(new Size(_measuredWidth, _measuredHeight));
|
| - measureLayout(completer.future, null);
|
| - }
|
| -
|
| - /** Applies the layout to the node. */
|
| - void applyLayout() {
|
| - if (_measuredLeft != null) {
|
| - // TODO(jmesserly): benchmark the performance of this DOM interaction
|
| - final style = view.node.style;
|
| - style.position = 'absolute';
|
| - style.left = '${_measuredLeft}px';
|
| - style.top = '${_measuredTop}px';
|
| - style.width = '${_measuredWidth}px';
|
| - style.height = '${_measuredHeight}px';
|
| - style.zIndex = '${layoutParams.layer}';
|
| -
|
| - _measuredLeft = null;
|
| - _measuredTop = null;
|
| - _measuredWidth = null;
|
| - _measuredHeight = null;
|
| -
|
| - // Ensure we can handle our custom layout when it is a child of a
|
| - // DOM-positioned node. For example, say we have a View tree like this:
|
| - //
|
| - // ViewWithLayout <-- uses our layout engine
|
| - // childView1 <-- is positioned by our layout engine, but uses
|
| - // HTML layout internally
|
| - // childOfChild <-- uses our layout engine for its own children
|
| - if (!hasCustomLayout(view)) {
|
| - for (final child in view.childViews) {
|
| - child.doLayout();
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - int measureContent(ViewLayout parent, Dimension dimension,
|
| - [ContentSizeMode mode = null]) {
|
| - switch (dimension) {
|
| - case Dimension.WIDTH:
|
| - return measureWidth(parent, mode);
|
| - case Dimension.HEIGHT:
|
| - return measureHeight(parent, mode);
|
| - }
|
| - }
|
| -
|
| - int measureWidth(ViewLayout parent, ContentSizeMode mode) {
|
| - final style = layoutParams.style.value;
|
| - switch (mode) {
|
| - case ContentSizeMode.MIN:
|
| - return _styleToPixels(
|
| - style.minWidth, currentWidth, parent.currentWidth);
|
| -
|
| - case ContentSizeMode.MAX:
|
| - return _styleToPixels(
|
| - style.maxWidth, currentWidth, parent.currentWidth);
|
| - }
|
| - }
|
| -
|
| - int measureHeight(ViewLayout parent, ContentSizeMode mode) {
|
| - final style = layoutParams.style.value;
|
| - switch (mode) {
|
| - case ContentSizeMode.MIN:
|
| - return _styleToPixels(
|
| - style.minHeight, currentHeight, parent.currentHeight);
|
| -
|
| - case ContentSizeMode.MAX:
|
| - return _styleToPixels(
|
| - style.maxHeight, currentHeight, parent.currentHeight);
|
| - }
|
| - }
|
| -
|
| - static int _toPixels(String style) {
|
| - if (style.endsWith('px')) {
|
| - return Math.parseInt(style.substring(0, style.length - 2));
|
| - } else {
|
| - // TODO(jmesserly): other size units
|
| - throw new UnsupportedOperationException(
|
| - 'Unknown min/max content size format: "$style"');
|
| - }
|
| - }
|
| -
|
| - static int _styleToPixels(String style, num size, num parentSize) {
|
| - if (style == 'none') {
|
| - // For an unset max-content size, use the actual size
|
| - return size;
|
| - }
|
| - if (style.endsWith('%')) {
|
| - num percent = Math.parseDouble(style.substring(0, style.length - 1));
|
| - return ((percent / 100) * parentSize).toInt();
|
| - }
|
| - return _toPixels(style);
|
| - }
|
| -}
|
|
|