| /* | |
| * Copyright 2009 Google Inc. | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not | |
| * use this file except in compliance with the License. You may obtain a copy of | |
| * the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
| * License for the specific language governing permissions and limitations under | |
| * the License. | |
| */ | |
| package com.google.gwt.layout.client; | |
| import static com.google.gwt.dom.client.Style.Unit.EM; | |
| import static com.google.gwt.dom.client.Style.Unit.EX; | |
| import static com.google.gwt.dom.client.Style.Unit.PX; | |
| import com.google.gwt.aria.client.State; | |
| import com.google.gwt.dom.client.DivElement; | |
| import com.google.gwt.dom.client.Document; | |
| import com.google.gwt.dom.client.Element; | |
| import com.google.gwt.dom.client.Style; | |
| import com.google.gwt.dom.client.Style.Display; | |
| import com.google.gwt.dom.client.Style.Overflow; | |
| import com.google.gwt.dom.client.Style.Position; | |
| import com.google.gwt.dom.client.Style.Unit; | |
| import com.google.gwt.dom.client.Style.Visibility; | |
| import com.google.gwt.layout.client.Layout.Layer; | |
| /** | |
| * Default implementation, which works with all browsers except for IE6. It uses | |
| * only the "top", "left", "bottom", "right", "width", and "height" CSS | |
| * properties. | |
| * | |
| * Note: This implementation class has state, so {@link Layout} must create a | |
| * new instance for each layout-parent. | |
| */ | |
| class LayoutImpl { | |
| private static DivElement fixedRuler; | |
| static { | |
| fixedRuler = createRuler(Unit.CM, Unit.CM); | |
| Document.get().getBody().appendChild(fixedRuler); | |
| } | |
| protected static DivElement createRuler(Unit widthUnit, Unit heightUnit) { | |
| DivElement ruler = Document.get().createDivElement(); | |
| ruler.setInnerHTML(" "); | |
| Style style = ruler.getStyle(); | |
| style.setPosition(Position.ABSOLUTE); | |
| style.setZIndex(-32767); | |
| // Position the ruler off the top edge, double the size just to be | |
| // extra sure it doesn't show up on the screen. | |
| style.setTop(-20, heightUnit); | |
| // Note that we are making the ruler element 10x10, because some browsers | |
| // generate non-integral ratios (e.g., 1em == 13.3px), so we need a little | |
| // extra precision. | |
| style.setWidth(10, widthUnit); | |
| style.setHeight(10, heightUnit); | |
| style.setVisibility(Visibility.HIDDEN); | |
| State.HIDDEN.set(ruler, true); | |
| return ruler; | |
| } | |
| protected DivElement relativeRuler; | |
| public Element attachChild(Element parent, Element child, Element before) { | |
| DivElement container = Document.get().createDivElement(); | |
| container.appendChild(child); | |
| container.getStyle().setPosition(Position.ABSOLUTE); | |
| container.getStyle().setOverflow(Overflow.HIDDEN); | |
| fillParent(child); | |
| Element beforeContainer = null; | |
| if (before != null) { | |
| beforeContainer = before.getParentElement(); | |
| assert beforeContainer.getParentElement() | |
| == parent : "Element to insert before must be a sibling"; | |
| } | |
| parent.insertBefore(container, beforeContainer); | |
| return container; | |
| } | |
| public void fillParent(Element elem) { | |
| Style style = elem.getStyle(); | |
| style.setPosition(Position.ABSOLUTE); | |
| style.setLeft(0, PX); | |
| style.setTop(0, PX); | |
| style.setRight(0, PX); | |
| style.setBottom(0, PX); | |
| } | |
| /** | |
| * @param parent the parent element | |
| */ | |
| public void finalizeLayout(Element parent) { | |
| } | |
| public double getUnitSizeInPixels( | |
| Element parent, Unit unit, boolean vertical) { | |
| if (unit == null) { | |
| return 1; | |
| } | |
| switch (unit) { | |
| case PCT: | |
| return (vertical ? parent.getClientHeight() : parent.getClientWidth()) | |
| / 100.0; | |
| case EM: | |
| return relativeRuler.getOffsetWidth() / 10.0; | |
| case EX: | |
| return relativeRuler.getOffsetHeight() / 10.0; | |
| case CM: | |
| return fixedRuler.getOffsetWidth() * 0.1; // 1.0 cm / cm | |
| case MM: | |
| return fixedRuler.getOffsetWidth() * 0.01; // 0.1 cm / mm | |
| case IN: | |
| return fixedRuler.getOffsetWidth() * 0.254; // 2.54 cm / in | |
| case PT: | |
| return fixedRuler.getOffsetWidth() * 0.00353; // 0.0353 cm / pt | |
| case PC: | |
| return fixedRuler.getOffsetWidth() * 0.0423; // 0.423 cm / pc | |
| default: | |
| case PX: | |
| return 1; | |
| } | |
| } | |
| public void initParent(Element parent) { | |
| parent.getStyle().setPosition(Position.RELATIVE); | |
| parent.appendChild(relativeRuler = createRuler(EM, EX)); | |
| } | |
| public void layout(Layer layer) { | |
| Style style = layer.container.getStyle(); | |
| if (layer.visible) { | |
| style.clearDisplay(); | |
| } else { | |
| style.setDisplay(Display.NONE); | |
| } | |
| style.setProperty( | |
| "left", layer.setLeft ? (layer.left + layer.leftUnit.getType()) : ""); | |
| style.setProperty( | |
| "top", layer.setTop ? (layer.top + layer.topUnit.getType()) : ""); | |
| style.setProperty("right", | |
| layer.setRight ? (layer.right + layer.rightUnit.getType()) : ""); | |
| style.setProperty("bottom", | |
| layer.setBottom ? (layer.bottom + layer.bottomUnit.getType()) : ""); | |
| style.setProperty("width", | |
| layer.setWidth ? (layer.width + layer.widthUnit.getType()) : ""); | |
| style.setProperty("height", | |
| layer.setHeight ? (layer.height + layer.heightUnit.getType()) : ""); | |
| style = layer.child.getStyle(); | |
| switch (layer.hPos) { | |
| case BEGIN: | |
| style.setLeft(0, Unit.PX); | |
| style.clearRight(); | |
| break; | |
| case END: | |
| style.clearLeft(); | |
| style.setRight(0, Unit.PX); | |
| break; | |
| case STRETCH: | |
| style.setLeft(0, Unit.PX); | |
| style.setRight(0, Unit.PX); | |
| break; | |
| } | |
| switch (layer.vPos) { | |
| case BEGIN: | |
| style.setTop(0, Unit.PX); | |
| style.clearBottom(); | |
| break; | |
| case END: | |
| style.clearTop(); | |
| style.setBottom(0, Unit.PX); | |
| break; | |
| case STRETCH: | |
| style.setTop(0, Unit.PX); | |
| style.setBottom(0, Unit.PX); | |
| break; | |
| } | |
| } | |
| @SuppressWarnings("unused") | |
| public void onAttach(Element parent) { | |
| // Do nothing. This exists only to help LayoutImplIE6 avoid memory leaks. | |
| } | |
| @SuppressWarnings("unused") | |
| public void onDetach(Element parent) { | |
| // Do nothing. This exists only to help LayoutImplIE6 avoid memory leaks. | |
| } | |
| public void removeChild(Element container, Element child) { | |
| container.removeFromParent(); | |
| // We want this code to be resilient to the child having already been | |
| // removed from its container (perhaps by widget code). | |
| if (child.getParentElement() == container) { | |
| child.removeFromParent(); | |
| } | |
| // Cleanup child styles set by fillParent(). | |
| Style style = child.getStyle(); | |
| style.clearPosition(); | |
| style.clearLeft(); | |
| style.clearTop(); | |
| style.clearWidth(); | |
| style.clearHeight(); | |
| } | |
| } |