package org.ovirt.engine.ui.common.utils; import com.google.gwt.dom.client.Style; import com.google.gwt.dom.client.Style.Overflow; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.i18n.client.LocaleInfo; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.MenuBar; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.UIObject; //TODO: add support to RTL locale public class PopupUtils { public static void adjustPopupLocationToFitScreenAndShow(final PopupPanel popup, int left, int top, MenuBar parentMenu, int itemHeight) { Style style = popup.getElement().getStyle(); style.setLeft(0, Unit.PX); style.setTop(0, Unit.PX); style.setProperty("height", "auto"); //$NON-NLS-1$ //$NON-NLS-2$ style.setProperty("width", "auto"); //$NON-NLS-1$ //$NON-NLS-2$ popup.show(); adjustPopupLocationToFitScreenAndShow(popup, left, top, -parentMenu.getOffsetWidth(), 0, itemHeight); } private static void adjustPopupLocationToFitScreenAndShow(final PopupPanel popup, int relativeLeft, int relativeTop, int relativeWidth, int relativeHeight, int itemHeight) { Style style = popup.getElement().getStyle(); /* We need this code because the gwt MenuBar- openPopupMethod, sets the position of the subMenu popup. It can't be overridden. * If the menu doesn't fit into the screen, setting the position causes change in its width and height. * Here we need the real "auto" width/height, thats why we need to change the left/top so the popup will fit the screen. */ style.setLeft(0, Unit.PX); style.setTop(0, Unit.PX); style.setProperty("height", "auto"); //$NON-NLS-1$ //$NON-NLS-2$ style.setProperty("width", "auto"); //$NON-NLS-1$ //$NON-NLS-2$ popup.show(); // Calculate top position for the popup int top = relativeTop; // Make sure scrolling is taken into account int windowTop = Window.getScrollTop(); int windowBottom = Window.getScrollTop() + Window.getClientHeight(); // Distance from the top edge of the window to the top edge of the // relative object int distanceFromWindowTop = top - windowTop; // Distance from the bottom edge of the window to the bottom edge of // the relative object int distanceToWindowBottom = windowBottom - (top + relativeHeight); // If there is not enough space for the popup's height below the // relative target and there IS enough space for the popup's height above the // relative target, then then position the popup above the relative object. However, if there // is not enough space on either side, then stick with displaying the // popup below the relative object. if (distanceToWindowBottom >= popup.getOffsetHeight()) { // Position above the relative object top += relativeHeight; } else if (distanceFromWindowTop >= popup.getOffsetHeight()) { top -= popup.getOffsetHeight() - itemHeight; } else {// Position above the relative object and add scroll top += relativeHeight; style.setHeight(distanceToWindowBottom, Unit.PX); style.setOverflowY(Overflow.SCROLL); style.setWidth(popup.getOffsetWidth(), Unit.PX); //popup.getWidget().setWidth(String.valueOf(popup.getOffsetWidth())); } // Calculate left position for the popup. The computation for // the left position is bidi-sensitive. int relativeTargetOffsetWidth = relativeWidth; // Compute the difference between the popup's width and the // relative target's width int offsetWidthDiff = popup.getOffsetWidth() - relativeTargetOffsetWidth; int left; if (LocaleInfo.getCurrentLocale().isRTL()) { // RTL case int relativeTarget = relativeLeft; // Right-align the popup. Note that this computation is // valid in the case where offsetWidthDiff is negative. left = relativeTarget - offsetWidthDiff; // If the suggestion popup is not as wide as the relative object, always // align to the right edge of the relative object and change the width to the relative object width. // Otherwise, figure out whether to right-align or left-align the popup. if (offsetWidthDiff > 0) { // Make sure scrolling is taken into account, since // relativeTarget.getAbsoluteLeft() takes scrolling into account. int windowRight = Window.getClientWidth() + Window.getScrollLeft(); int windowLeft = Window.getScrollLeft(); // Compute the left value for the right edge of the relative target int relativeTargetLeftValForRightEdge = relativeTarget + relativeTargetOffsetWidth; // Distance from the right edge of the relative object to the right edge // of the window int distanceToWindowRight = windowRight - relativeTargetLeftValForRightEdge; // Distance from the right edge of the relative object to the left edge of the // window int distanceFromWindowLeft = relativeTargetLeftValForRightEdge - windowLeft; // If there is not enough space for the overflow of the popup's // width to the right of the relative object and there IS enough space for the // overflow to the right of the relative object, then left-align the popup. // However, if there is not enough space on either side, stick with // right-alignment and add scroll. if (distanceFromWindowLeft < popup.getOffsetWidth() && distanceToWindowRight >= offsetWidthDiff) { // Align with the left edge of the relative object. left = relativeTarget; } }else{ style.setWidth(relativeWidth, Unit.PX); } } else { // LTR case // Left-align the popup. left = relativeLeft; // If the suggestion popup is not as wide as the relative object, always align to // the left edge of the relative object and change the width to the relative object width. // Otherwise, figure out whether to left-align or right-align the popup. if (offsetWidthDiff > 0) { // Make sure scrolling is taken into account, since // relativeTarget.getAbsoluteLeft() takes scrolling into account. int windowRight = Window.getClientWidth() + Window.getScrollLeft(); int windowLeft = Window.getScrollLeft(); // Distance from the left edge of the relative object to the right edge // of the window int distanceToWindowRight = windowRight - left; // Distance from the left edge of the relative object to the left edge of the // window int distanceFromWindowLeft = left - windowLeft; // If there is not enough space for the overflow of the popup's // width to the right of the relative object, and there is enough space for the // overflow to the left of the relative object, then right-align the popup. // However, if there is not enough space on either side, then stick with // left-alignment. if (distanceToWindowRight < popup.getOffsetWidth() && distanceFromWindowLeft >= offsetWidthDiff) { // Align with the right edge of the relative object. left -= offsetWidthDiff; } }else{ style.setWidth(relativeWidth, Unit.PX); } } popup.setPopupPosition(left, top); } public static void adjustPopupLocationToFitScreenAndShow(final PopupPanel popup, UIObject relativeObject) { adjustPopupLocationToFitScreenAndShow(popup, relativeObject.getAbsoluteLeft(), relativeObject.getAbsoluteTop(), relativeObject.getOffsetWidth(), relativeObject.getOffsetHeight(), 0); } public static void adjustPopupLocationToFitScreenAndShow(final PopupPanel popup, int left, int top) { adjustPopupLocationToFitScreenAndShow(popup, left, top, 0, 0, 0); } }