/* * This is part of Geomajas, a GIS framework, http://www.geomajas.org/. * * Copyright 2008-2015 Geosparc nv, http://www.geosparc.com/, Belgium. * * The program is available in open source according to the GNU Affero * General Public License. All contributions in this program are covered * by the Geomajas Contributors License Agreement. For full licensing * details, see LICENSE.txt in the project root. */ package org.geomajas.gwt2.plugin.corewidget.example.client.sample.map; import org.geomajas.gwt2.client.map.MapPresenter; import org.geomajas.gwt2.plugin.corewidget.client.i18n.WidgetCoreInternationalization; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.PopupPanel.PositionCallback; import com.google.gwt.user.client.ui.Widget; import org.geomajas.gwt2.plugin.corewidget.client.map.mapcontrolpanel.MapControlPanel; /** * Drop down button that displays the {@link MapControlPanel}. When this widget is added to a MapPresenter's widget * panel, it will automatically try to keep the {@link MapControlPanel} within the map bounds. * * @author Pieter De Graef */ public class MapLegendDropDown extends Button { private static final WidgetCoreInternationalization MSG = GWT.create(WidgetCoreInternationalization.class); private final MapPresenter mapPresenter; private PopupPanel popup; private Timer timer; /** * Create a drop down button that displays a {@link MapControlPanel} in a popup. * * @param mapPresenter * The map to display a legend widget for. */ public MapLegendDropDown(final MapPresenter mapPresenter) { this.mapPresenter = mapPresenter; setHTML(MSG.legend()); addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { if (popup == null) { popup = new PopupPanel(); popup.setAutoHideEnabled(true); popup.setAutoHideOnHistoryEventsEnabled(true); popup.setWidget(new MapControlPanel(mapPresenter)); popup.addAutoHidePartner(MapLegendDropDown.this.getElement()); showPopup(); } else if (popup.isShowing()) { popup.hide(); } else { showPopup(); } } }); } protected void showPopup() { positionPopup(); popup.show(); popup.setPopupPositionAndShow(new PositionCallback() { public void setPosition(int offsetWidth, int offsetHeight) { positionPopup(); if (timer != null) { timer.cancel(); } timer = new Timer() { public void run() { positionPopup(); } }; timer.schedule(1); } }); } protected void positionPopup() { int top = calculateTop(0); int left = calculateLeft(0); if (getParent() == mapPresenter.getWidgetPane()) { left = calculateLeftInMap(0); } popup.setPopupPosition(left, top); } private int calculateTop(int offsetHeight) { // Calculate top position for the popup int top = this.getAbsoluteTop(); // Make sure scrolling is taken into account, since // box.getAbsoluteTop() takes scrolling 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 // text box int distanceFromWindowTop = top - windowTop; // Distance from the bottom edge of the window to the bottom edge of // the text box int distanceToWindowBottom = windowBottom - (top + this.getOffsetHeight()); // If there is not enough space for the popup's height below the text // box and there IS enough space for the popup's height above the text // box, then then position the popup above the text box. However, if there // is not enough space on either side, then stick with displaying the // popup below the text box. if (distanceToWindowBottom < offsetHeight && distanceFromWindowTop >= offsetHeight) { top -= offsetHeight; } else { // Position above the text box top += this.getOffsetHeight(); } return top; } private int calculateLeftInMap(int offsetWidth) { int left = calculateLeft(offsetWidth); int popupRight = left + popup.getOffsetWidth(); Widget widget = (Widget) mapPresenter.getWidgetPane(); int mapRight = widget.getAbsoluteLeft() + widget.getOffsetWidth(); if (popupRight > mapRight) { // Align right: int buttonRight = getAbsoluteLeft() + getOffsetWidth(); left = buttonRight - popup.getOffsetWidth(); } return left; } private int calculateLeft(int offsetWidth) { // Calculate left position for the popup. The computation for // the left position is bidi-sensitive. int textBoxOffsetWidth = this.getOffsetWidth(); // Compute the difference between the popup's width and the // textbox's width int offsetWidthDiff = offsetWidth - textBoxOffsetWidth; int left = this.getAbsoluteLeft(); // If the suggestion popup is not as wide as the text box, always align to // the left edge of the text box. Otherwise, figure out whether to // left-align or right-align the popup. if (offsetWidthDiff > 0) { // Make sure scrolling is taken into account, since // box.getAbsoluteLeft() takes scrolling into account. int windowRight = Window.getClientWidth() + Window.getScrollLeft(); int windowLeft = Window.getScrollLeft(); // Distance from the left edge of the text box to the right edge // of the window int distanceToWindowRight = windowRight - left; // Distance from the left edge of the text box 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 hte text box, and there IS enough space for the // overflow to the left of the text box, then right-align the popup. // However, if there is not enough space on either side, then stick with // left-alignment. if (distanceToWindowRight < offsetWidth && distanceFromWindowLeft >= offsetWidthDiff) { // Align with the right edge of the text box. left -= offsetWidthDiff; } } return left; } }