From: Leif Åstrand Date: Wed, 8 Feb 2012 14:44:50 +0000 (+0200) Subject: Measure borders, margins and paddings (#8313) X-Git-Tag: 7.0.0.alpha2~434^2~78 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=cccbe9644aa31fc8a027d9ee256be7edfd5d75c5;p=vaadin-framework.git Measure borders, margins and paddings (#8313) --- diff --git a/src/com/vaadin/terminal/gwt/client/MeasureManager.java b/src/com/vaadin/terminal/gwt/client/MeasureManager.java index cab4822ef4..b4a16fc8c2 100644 --- a/src/com/vaadin/terminal/gwt/client/MeasureManager.java +++ b/src/com/vaadin/terminal/gwt/client/MeasureManager.java @@ -1,5 +1,6 @@ package com.vaadin.terminal.gwt.client; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; @@ -14,30 +15,59 @@ public class MeasureManager { public static final class MeasuredSize { private int width = -1; private int height = -1; + + private int[] paddings = new int[4]; + private int[] borders = new int[4]; + private int[] margins = new int[4]; + + private final VPaintableWidget paintable; + private boolean isDirty = true; private final Map dependencySizes = new HashMap(); - public int getHeight() { + public MeasuredSize(VPaintableWidget paintable) { + this.paintable = paintable; + } + + public int getOuterHeight() { return height; } - public int getWidth() { + public int getOuterWidth() { return width; } - public void setHeight(int height) { + private static int sumWidths(int[] sizes) { + return sizes[1] + sizes[3]; + } + + private static int sumHeights(int[] sizes) { + return sizes[0] + sizes[2]; + } + + public int getInnerHeight() { + return height - sumHeights(margins) - sumHeights(borders) + - sumHeights(paddings); + } + + public int getInnerWidth() { + return width - sumWidths(margins) - sumWidths(borders) + - sumWidths(paddings); + } + + public void setOuterHeight(int height) { if (this.height != height) { isDirty = true; + this.height = height; } - this.height = height; } - public void setWidth(int width) { - if (width != this.width) { + public void setOuterWidth(int width) { + if (this.width != width) { isDirty = true; + this.width = width; } - this.width = width; } public boolean isDirty() { @@ -59,11 +89,11 @@ public class MeasureManager { dependencySizes.remove(element); } - public int getDependencyWidth(Element e) { + public int getDependencyOuterWidth(Element e) { return getDependencySize(e, 0); } - public int getDependencyHeight(Element e) { + public int getDependencyOuterHeight(Element e) { return getDependencySize(e, 1); } @@ -75,6 +105,145 @@ public class MeasureManager { return sizes[index]; } } + + public int getBorderHeight() { + return sumHeights(borders); + } + + public int getBorderWidth() { + return sumWidths(borders); + } + + public int getPaddingHeight() { + return sumHeights(paddings); + } + + public int getPaddingWidth() { + return sumWidths(paddings); + } + + public int getMarginHeight() { + return sumHeights(margins); + } + + public int getMarginWidth() { + return sumWidths(margins); + } + + public int getMarginTop() { + return margins[0]; + } + + public int getMarginRight() { + return margins[1]; + } + + public int getMarginBottom() { + return margins[2]; + } + + public int getMarginLeft() { + return margins[3]; + } + + public int getBorderTop() { + return margins[0]; + } + + public int getBorderRight() { + return margins[1]; + } + + public int getBorderBottom() { + return margins[2]; + } + + public int getBorderLeft() { + return margins[3]; + } + + public int getPaddingTop() { + return paddings[0]; + } + + public int getPaddingRight() { + return paddings[1]; + } + + public int getPaddingBottom() { + return paddings[2]; + } + + public int getPaddingLeft() { + return paddings[3]; + } + + private void measure() { + boolean changed = isDirty; + + Widget widget = paintable.getWidgetForPaintable(); + ComputedStyle computedStyle = new ComputedStyle(widget.getElement()); + + int[] paddings = computedStyle.getPadding(); + if (!changed && !Arrays.equals(this.paddings, paddings)) { + changed = true; + this.paddings = paddings; + } + + int[] margins = computedStyle.getMargin(); + if (!changed && !Arrays.equals(this.margins, margins)) { + changed = true; + this.margins = margins; + } + + int[] borders = computedStyle.getBorder(); + if (!changed && !Arrays.equals(this.borders, borders)) { + changed = true; + this.borders = borders; + } + + int offsetHeight = widget.getOffsetHeight(); + int marginHeight = sumHeights(margins); + setOuterHeight(offsetHeight + marginHeight); + + int offsetWidth = widget.getOffsetWidth(); + int marginWidth = sumWidths(margins); + setOuterWidth(offsetWidth + marginWidth); + + // int i = 0; + for (Entry entry : dependencySizes.entrySet()) { + Element element = entry.getKey(); + // int[] elementMargin = new ComputedStyle(element).getMargin(); + int[] sizes = entry.getValue(); + + int elementWidth = element.getOffsetWidth(); + // elementWidth += elementMargin[1] + elementMargin[3]; + if (elementWidth != sizes[0]) { + // System.out.println(paintable.getId() + " dependency " + i + // + " width changed from " + sizes[0] + " to " + // + elementWidth); + sizes[0] = elementWidth; + changed = true; + } + + int elementHeight = element.getOffsetHeight(); + // Causes infinite loops as a negative margin based on the + // measured height is currently used for captions + // elementHeight += elementMargin[0] + elementMargin[1]; + if (elementHeight != sizes[1]) { + // System.out.println(paintable.getId() + " dependency " + i + // + " height changed from " + sizes[1] + " to " + // + elementHeight); + sizes[1] = elementHeight; + changed = true; + } + // i++; + } + + if (changed) { + setDirty(true); + } + } } public void doLayout(ApplicationConnection client) { @@ -178,37 +347,9 @@ public class MeasureManager { FastStringSet changed = FastStringSet.create(); for (VPaintableWidget paintableWidget : paintableWidgets) { - Widget widget = paintableWidget.getWidgetForPaintable(); - MeasureManager.MeasuredSize measuredSize = paintableWidget .getMeasuredSize(); - - measuredSize.setWidth(widget.getOffsetWidth()); - measuredSize.setHeight(widget.getOffsetHeight()); - - boolean dirtyDependency = false; - for (Entry entry : measuredSize.dependencySizes - .entrySet()) { - Element element = entry.getKey(); - int[] sizes = entry.getValue(); - - int offsetWidth = element.getOffsetWidth(); - if (offsetWidth != sizes[0]) { - sizes[0] = offsetWidth; - dirtyDependency = true; - } - - int offsetHeight = element.getOffsetHeight(); - if (offsetHeight != sizes[1]) { - sizes[1] = offsetHeight; - dirtyDependency = true; - } - - } - - if (dirtyDependency) { - measuredSize.setDirty(true); - } + measuredSize.measure(); if (measuredSize.isDirty()) { changed.add(paintableMap.getPid(paintableWidget)); diff --git a/src/com/vaadin/terminal/gwt/client/ui/VMeasuringOrderedLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VMeasuringOrderedLayout.java index 1154585191..46ae614591 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VMeasuringOrderedLayout.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VMeasuringOrderedLayout.java @@ -16,7 +16,6 @@ import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.ui.ComplexPanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.RenderSpace; import com.vaadin.terminal.gwt.client.VCaption; import com.vaadin.terminal.gwt.client.VPaintableMap; import com.vaadin.terminal.gwt.client.VPaintableWidget; @@ -26,25 +25,19 @@ public class VMeasuringOrderedLayout extends ComplexPanel { public static final String CLASSNAME = "v-orderedlayout"; - private static final int MARGIN_SIZE = 20; - final boolean isVertical; ApplicationConnection client; String id; - private RenderSpace space; - ValueMap expandRatios; ValueMap alignments; Map captions = new HashMap(); - boolean spacing; - - VMarginInfo activeMarginsInfo; + final DivElement spacingMeasureElement; protected VMeasuringOrderedLayout(String className, boolean isVertical) { DivElement element = Document.get().createDivElement(); @@ -54,6 +47,11 @@ public class VMeasuringOrderedLayout extends ComplexPanel { style.setOverflow(Overflow.HIDDEN); style.setPosition(Position.RELATIVE); + spacingMeasureElement = Document.get().createDivElement(); + Style spacingStyle = spacingMeasureElement.getStyle(); + spacingStyle.setPosition(Position.ABSOLUTE); + getElement().appendChild(spacingMeasureElement); + setStyleName(className); this.isVertical = isVertical; } @@ -66,30 +64,6 @@ public class VMeasuringOrderedLayout extends ComplexPanel { add(widget, (com.google.gwt.user.client.Element) wrapper.cast()); } - int getEndMarginInDirection(boolean isVertical) { - if (isVertical) { - return activeMarginsInfo.hasBottom() ? MARGIN_SIZE : 0; - } else { - return activeMarginsInfo.hasRight() ? MARGIN_SIZE : 0; - } - } - - int getStartMarginInDirection(boolean isVertical) { - if (isVertical) { - return activeMarginsInfo.hasTop() ? MARGIN_SIZE : 0; - } else { - return activeMarginsInfo.hasLeft() ? MARGIN_SIZE : 0; - } - } - - int getSpacingInDirection(boolean isVertical) { - if (spacing) { - return 20; - } else { - return 0; - } - } - AlignmentInfo getAlignment(VPaintableWidget child) { String pid = VPaintableMap.get(client).getPid(child); if (alignments.containsKey(pid)) { @@ -113,6 +87,9 @@ public class VMeasuringOrderedLayout extends ComplexPanel { wrapper.getStyle().setPosition(Position.ABSOLUTE); getElement().appendChild(wrapper); add(widget, wrapper); + widget.getElement().getStyle() + .setProperty("MozBoxSizing", "border-box"); + widget.getElement().getStyle().setProperty("boxSizing", "border-box"); } void addCaption(VCaption caption, Widget widget) { @@ -129,7 +106,28 @@ public class VMeasuringOrderedLayout extends ComplexPanel { adopt(caption); } - void remove(VCaption caption) { - remove(caption); + private void togglePrefixedStyleName(String name, boolean enabled) { + if (enabled) { + addStyleName(CLASSNAME + name); + } else { + removeStyleName(CLASSNAME + name); + } + } + + void updateMarginStyleNames(VMarginInfo marginInfo) { + togglePrefixedStyleName("-margin-top", marginInfo.hasTop()); + togglePrefixedStyleName("-margin-right", marginInfo.hasRight()); + togglePrefixedStyleName("-margin-bottom", marginInfo.hasBottom()); + togglePrefixedStyleName("-margin-left", marginInfo.hasLeft()); + } + + void updateSpacingStyleName(boolean spacingEnabled) { + if (spacingEnabled) { + spacingMeasureElement.addClassName(CLASSNAME + "-spacing-on"); + spacingMeasureElement.removeClassName(CLASSNAME + "-spacing-off"); + } else { + spacingMeasureElement.removeClassName(CLASSNAME + "-spacing-on"); + spacingMeasureElement.addClassName(CLASSNAME + "-spacing-off"); + } } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VMeasuringOrderedLayoutPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VMeasuringOrderedLayoutPaintable.java index 48375d38cd..8d97f8ba44 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VMeasuringOrderedLayoutPaintable.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VMeasuringOrderedLayoutPaintable.java @@ -11,6 +11,7 @@ import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.CalculatingLayout; import com.vaadin.terminal.gwt.client.MeasureManager; +import com.vaadin.terminal.gwt.client.MeasureManager.MeasuredSize; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.VCaption; import com.vaadin.terminal.gwt.client.VPaintableMap; @@ -19,6 +20,11 @@ import com.vaadin.terminal.gwt.client.VPaintableWidget; public abstract class VMeasuringOrderedLayoutPaintable extends VAbstractPaintableWidgetContainer implements CalculatingLayout { + public VMeasuringOrderedLayoutPaintable() { + getMeasuredSize().registerDependency( + getWidgetForPaintable().spacingMeasureElement); + } + public void updateCaption(VPaintableWidget component, UIDL uidl) { if (VCaption.isNeeded(uidl)) { VCaption caption = getWidgetForPaintable().captions.get(component); @@ -60,9 +66,6 @@ public abstract class VMeasuringOrderedLayoutPaintable extends return; } - long start = System.currentTimeMillis(); - // long childTime = 0; - HashSet previousChildren = new HashSet(); for (Widget child : getWidgetForPaintable()) { if (!(child instanceof VCaption)) { @@ -103,12 +106,12 @@ public abstract class VMeasuringOrderedLayoutPaintable extends } int bitMask = uidl.getIntAttribute("margins"); - if (getWidgetForPaintable().activeMarginsInfo == null - || getWidgetForPaintable().activeMarginsInfo.getBitMask() != bitMask) { - getWidgetForPaintable().activeMarginsInfo = new VMarginInfo(bitMask); - } + getWidgetForPaintable() + .updateMarginStyleNames(new VMarginInfo(bitMask)); + + getWidgetForPaintable().updateSpacingStyleName( + uidl.getBooleanAttribute("spacing")); - getWidgetForPaintable().spacing = uidl.getBooleanAttribute("spacing"); getWidgetForPaintable().expandRatios = uidl .getMapAttribute("expandRatios"); getWidgetForPaintable().alignments = uidl.getMapAttribute("alignments"); @@ -120,14 +123,15 @@ public abstract class VMeasuringOrderedLayoutPaintable extends if (caption == null) { return 0; } else { - return getMeasuredSize().getDependencyWidth(caption.getElement()); + return getMeasuredSize().getDependencyOuterWidth( + caption.getElement()); } } private int getCaptionHeight(VPaintableWidget child) { VCaption caption = getWidgetForPaintable().captions.get(child); if (caption != null) { - int captionHeight = getMeasuredSize().getDependencyHeight( + int captionHeight = getMeasuredSize().getDependencyOuterHeight( caption.getElement()); caption.getElement().getStyle() @@ -138,20 +142,23 @@ public abstract class VMeasuringOrderedLayoutPaintable extends } } - private static boolean isRelativeInDirection(Widget widget, + private static boolean isRelativeInDirection(VPaintableWidget paintable, boolean isVertical) { - String dimension = getDimensionInDirection(widget, isVertical); - return dimension != null && dimension.endsWith("%"); + if (isVertical) { + return paintable.isRelativeHeight(); + } else { + return paintable.isRelativeWidth(); + } } - private static String getDimensionInDirection(Widget widget, - boolean vertical) { - com.google.gwt.user.client.Element element = widget.getElement(); - Style style = element.getStyle(); - if (vertical) { - return style.getHeight(); + private int getSizeForInnerSize(int size, boolean isVertical) { + MeasuredSize measuredSize = getMeasuredSize(); + if (isVertical) { + return size + measuredSize.getBorderHeight() + + measuredSize.getPaddingHeight(); } else { - return style.getWidth(); + return size + measuredSize.getBorderWidth() + + measuredSize.getPaddingWidth(); } } @@ -163,23 +170,30 @@ public abstract class VMeasuringOrderedLayoutPaintable extends return isVertical ? "top" : "left"; } - private static String getMinPropertyName(boolean isVertical) { - return isVertical ? "minHeight" : "minWidth"; - } - - private static boolean isUndefinedInDirection(Widget widget, + private static boolean isUndefinedInDirection(VPaintableWidget paintable, boolean isVertical) { - String dimension = getDimensionInDirection(widget, isVertical); - return dimension == null || dimension.length() == 0; + if (isVertical) { + return paintable.isUndefinedHeight(); + } else { + return paintable.isUndefinedWidth(); + } } - private int getMeasuredInDirection(VPaintableWidget paintable, + private static int getOuterSizeInDirection(VPaintableWidget paintable, boolean isVertical) { MeasureManager.MeasuredSize measuredSize = paintable.getMeasuredSize(); if (isVertical) { - return measuredSize.getHeight(); + return measuredSize.getOuterHeight(); } else { - return measuredSize.getWidth(); + return measuredSize.getOuterWidth(); + } + } + + private int getInnerSizeInDirection(boolean isVertical) { + if (isVertical) { + return getMeasuredSize().getInnerHeight(); + } else { + return getMeasuredSize().getInnerWidth(); } } @@ -227,39 +241,40 @@ public abstract class VMeasuringOrderedLayoutPaintable extends captionAllocation = 0; } - if (!isRelativeInDirection(widget, + if (!isRelativeInDirection(child, getWidgetForPaintable().isVertical)) { - totalAllocated += getMeasuredInDirection(child, - getWidgetForPaintable().isVertical) + captionAllocation; + int childSize = getOuterSizeInDirection(child, + getWidgetForPaintable().isVertical); + if (getWidgetForPaintable().isVertical) { + childSize += captionAllocation; + } else { + childSize = Math.max(childSize, getCaptionWidth(child)); + } + totalAllocated += childSize; } } - int startMargin = getWidgetForPaintable().getStartMarginInDirection( - getWidgetForPaintable().isVertical); - int totalMargins = startMargin - + getWidgetForPaintable().getEndMarginInDirection( - getWidgetForPaintable().isVertical); - totalAllocated += totalMargins - + (getWidgetForPaintable().getSpacingInDirection( - getWidgetForPaintable().isVertical) * (children.size() - 1)); + totalAllocated += getSpacingInDirection(getWidgetForPaintable().isVertical) + * (children.size() - 1); Style ownStyle = getWidgetForPaintable().getElement().getStyle(); double ownSize; - if (isUndefinedInDirection(getWidgetForPaintable(), - getWidgetForPaintable().isVertical)) { + if (isUndefinedInDirection(this, getWidgetForPaintable().isVertical)) { ownSize = totalAllocated; - ownStyle.setProperty( - getMinPropertyName(getWidgetForPaintable().isVertical), - totalAllocated, Unit.PX); + ownStyle.setPropertyPx( + getSizeProperty(getWidgetForPaintable().isVertical), + getSizeForInnerSize(totalAllocated, + getWidgetForPaintable().isVertical)); } else { - ownSize = getMeasuredInDirection(this, - getWidgetForPaintable().isVertical); - ownStyle.clearProperty(getMinPropertyName(getWidgetForPaintable().isVertical)); + ownSize = getInnerSizeInDirection(getWidgetForPaintable().isVertical); + ownStyle.setProperty( + getSizeProperty(getWidgetForPaintable().isVertical), + getDefinedSize(getWidgetForPaintable().isVertical)); } double unallocatedSpace = Math.max(0, ownSize - totalAllocated); - double currentLocation = startMargin; + double currentLocation = getStartPadding(getWidgetForPaintable().isVertical); for (VPaintableWidget child : children) { Widget widget = child.getWidgetForPaintable(); Element wrapper = getWidgetForPaintable().getWrapper(widget); @@ -275,10 +290,10 @@ public abstract class VMeasuringOrderedLayoutPaintable extends double extraPixels = unallocatedSpace * childExpandRatio; - boolean relative = isRelativeInDirection(widget, + boolean relative = isRelativeInDirection(child, getWidgetForPaintable().isVertical); - double size = getMeasuredInDirection(child, + double size = getOuterSizeInDirection(child, getWidgetForPaintable().isVertical); int captionHeight = getCaptionHeight(child); @@ -321,8 +336,17 @@ public abstract class VMeasuringOrderedLayoutPaintable extends startPosition, Unit.PX); currentLocation += allocatedSpace - + getWidgetForPaintable().getSpacingInDirection( - getWidgetForPaintable().isVertical); + + getSpacingInDirection(getWidgetForPaintable().isVertical); + } + } + + private int getSpacingInDirection(boolean isVertical) { + if (isVertical) { + return getMeasuredSize().getDependencyOuterHeight( + getWidgetForPaintable().spacingMeasureElement); + } else { + return getMeasuredSize().getDependencyOuterWidth( + getWidgetForPaintable().spacingMeasureElement); } } @@ -342,34 +366,30 @@ public abstract class VMeasuringOrderedLayoutPaintable extends captionAllocation = 0; } - if (!isRelativeInDirection(widget, + if (!isRelativeInDirection(child, !getWidgetForPaintable().isVertical)) { - int childSize = getMeasuredInDirection(child, + int childSize = getOuterSizeInDirection(child, !getWidgetForPaintable().isVertical) + captionAllocation; maxSize = Math.max(maxSize, childSize); } } - int startMargin = getWidgetForPaintable().getStartMarginInDirection( - !getWidgetForPaintable().isVertical); - int totalMargins = startMargin - + getWidgetForPaintable().getEndMarginInDirection( - !getWidgetForPaintable().isVertical); - double availableSpace; Style ownStyle = getWidgetForPaintable().getElement().getStyle(); - if (isUndefinedInDirection(getWidgetForPaintable(), - !getWidgetForPaintable().isVertical)) { - ownStyle.setProperty( - getMinPropertyName(!getWidgetForPaintable().isVertical), - maxSize + totalMargins, Unit.PX); + if (isUndefinedInDirection(this, !getWidgetForPaintable().isVertical)) { + ownStyle.setPropertyPx( + getSizeProperty(!getWidgetForPaintable().isVertical), + getSizeForInnerSize(maxSize, + !getWidgetForPaintable().isVertical)); + availableSpace = maxSize; } else { - ownStyle.clearProperty(getMinPropertyName(!getWidgetForPaintable().isVertical)); - availableSpace = getMeasuredInDirection(this, - !getWidgetForPaintable().isVertical) - totalMargins; + ownStyle.setProperty( + getSizeProperty(!getWidgetForPaintable().isVertical), + getDefinedSize(!getWidgetForPaintable().isVertical)); + availableSpace = getInnerSizeInDirection(!getWidgetForPaintable().isVertical); } for (VPaintableWidget child : children) { @@ -377,12 +397,12 @@ public abstract class VMeasuringOrderedLayoutPaintable extends Element wrapper = getWidgetForPaintable().getWrapper(widget); Style wrapperStyle = wrapper.getStyle(); - boolean relative = isRelativeInDirection(widget, + boolean relative = isRelativeInDirection(child, !getWidgetForPaintable().isVertical); int captionHeight = getCaptionHeight(child); - double allocatedSize = getMeasuredInDirection(child, + double allocatedSize = getOuterSizeInDirection(child, !getWidgetForPaintable().isVertical); if (!getWidgetForPaintable().isVertical) { allocatedSize += captionHeight; @@ -393,7 +413,7 @@ public abstract class VMeasuringOrderedLayoutPaintable extends int alignment = getAlignmentInDirection(getWidgetForPaintable() .getAlignment(child), !getWidgetForPaintable().isVertical); - double startPosition = startMargin; + double startPosition = getStartPadding(getWidgetForPaintable().isVertical); if (alignment == 0) { startPosition += (availableSpace - allocatedSize) / 2; // Centered @@ -419,6 +439,22 @@ public abstract class VMeasuringOrderedLayoutPaintable extends } } + private String getDefinedSize(boolean isVertical) { + if (isVertical) { + return getDefinedHeight(); + } else { + return getDefinedWidth(); + } + } + + private int getStartPadding(boolean isVertical) { + if (isVertical) { + return getMeasuredSize().getPaddingTop(); + } else { + return getMeasuredSize().getPaddingLeft(); + } + } + public void updateHorizontalSizes() { if (getWidgetForPaintable().isVertical) { layoutSecondaryDirection();