| /* |
| * 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(); |
| } |
| } |