/* * PopupPositioner.java * * Copyright (C) 2009-12 by RStudio, Inc. * * Unless you have received this program directly from RStudio pursuant * to the terms of a commercial license agreement with RStudio, then * this program is licensed to you under the terms of version 3 of the * GNU Affero General Public License. This program is distributed WITHOUT * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT, * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details. * */ package org.rstudio.studio.client.workbench.views.console.shell.assist; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.PopupPanel.PositionCallback; import org.rstudio.core.client.Rectangle; public class PopupPositioner implements PositionCallback { private Rectangle cursorBounds_ ; private CompletionPopupDisplay popup_ ; public PopupPositioner(Rectangle cursorBounds, CompletionPopupDisplay popup) { this.cursorBounds_ = cursorBounds ; popup_ = popup ; } public void setPosition(int popupWidth, int popupHeight) { if (cursorBounds_ == null) { assert false : "Positioning popup but no cursor bounds available"; return; } Coordinates coords = getPopupPosition( popupWidth, popupHeight, cursorBounds_.getLeft(), cursorBounds_.getBottom(), 5); popup_.setPopupPosition(coords.getLeft(), coords.getTop()); } private static class Coordinates { public Coordinates(int left, int top) { left_ = left; top_ = top; } public int getLeft() { return left_; } public int getTop() { return top_; } private final int left_; private final int top_; } public static Coordinates getPopupPosition(int width, int height, int pageX, int pageY, int fudgeFactor) { int windowTop = Window.getScrollTop(); int windowLeft = Window.getScrollLeft(); int windowRight = windowLeft + Window.getClientWidth(); int windowBottom = windowTop + Window.getClientHeight(); // Compute the horizontal position. int left = pageX + fudgeFactor; // Check to see if the popup would overflow to the right. // If so, nudge the coordinates left to prevent this. int horizontalOverflow = pageX + width + fudgeFactor - windowRight; if (horizontalOverflow > 0) { left = Math.max( fudgeFactor + 10, left - horizontalOverflow); } // Compute the vertical position. Normally we want the // completion popup to appear below the rectangle, but // we may need to position it above (e.g. R completions // in the console). boolean showOnBottom = pageY + height + fudgeFactor < windowBottom; int top = showOnBottom ? pageY + fudgeFactor : pageY - height - fudgeFactor - 10; return new Coordinates(left, top); } public static void setPopupPosition(PopupPanel panel, int pageX, int pageY) { setPopupPosition(panel, pageX, pageY, 0); } public static void setPopupPosition(PopupPanel panel, int pageX, int pageY, int fudgeFactor) { Coordinates transformed = getPopupPosition( panel.getOffsetWidth(), panel.getOffsetHeight(), pageX, pageY, fudgeFactor); panel.setPopupPosition( transformed.getLeft(), transformed.getTop()); } }