com.gwtplatform.mvp.client.view.RelativeToWidgetPopupPositioner Maven / Gradle / Ivy
/*
* Copyright 2014 ArcBees 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.gwtplatform.mvp.client.view;
import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;
/**
* Positions the popup relative to a widget.
*/
public class RelativeToWidgetPopupPositioner extends PopupPositioner {
private final Widget widget;
private final boolean clipToWindow;
/**
* @param widget - the widget relative to which the popup will be shown.
*
* If there is enough space to the right, the left edge of the popup will be positioned flush with
* the left edge of the widget.
*
* --------
* |widget|
* -------------
* |popup panel|
* -------------
*
*
* Otherwise if there is enough space on the left the right edge of the popup will be positioned
* flush with the right edge of the widget.
*
* --------
* |widget|
* -------------
* |popup panel|
* -------------
*
*
* If there is not enough space to the left or the right and clipToWindow is on. The popup will be
* positioned on the left edge of the screen.
*
* | --------
* | |widget|
* |-------------
* ||popup panel|
* |-------------
*
*
* If you would prefer the popupPanel to always be flush with the widget call
* {@link #RelativeToWidgetPopupPositioner(IsWidget, boolean)}
* and set clipToWindow to false
*/
public RelativeToWidgetPopupPositioner(IsWidget widget) {
this(widget, true);
}
/**
* @param widget - the widget relative to which the popup will be shown.
* @param clipToWindow - set to false to always position the popup flush to an edge of the widget.
*
* If there is enough space to the right, the left edge of the popup will be positioned flush with
* the left edge of the widget.
*
* --------
* |widget|
* -------------
* |popup panel|
* -------------
*
*
* Otherwise if there is enough space on the left the right edge of the popup will be positioned
* flush with the right edge of the widget.
*
* --------
* |widget|
* -------------
* |popup panel|
* -------------
*
*
* If there is not enough space to the left or the right and clipToWindow is on. The popup will be
* positioned on the left edge of the screen.
*
* | --------
* | |widget|
* |-------------
* ||popup panel|
* |-------------
*
*
* Set clipToWindow to false to always position the popup flush to an edge of the widget and expand
* the screen when it will not fit.
*/
public RelativeToWidgetPopupPositioner(IsWidget widget, boolean clipToWindow) {
this.widget = widget.asWidget();
this.clipToWindow = clipToWindow;
}
@Override
protected int getTop(int popupHeight) {
int top = widget.getAbsoluteTop();
int windowTop = Window.getScrollTop();
int windowBottom = Window.getScrollTop() + Window.getClientHeight();
int distanceFromWindowTop = top - windowTop;
int distanceToWindowBottom = windowBottom - (top + widget.getOffsetHeight());
if (distanceToWindowBottom < popupHeight && distanceFromWindowTop >= popupHeight) {
top -= popupHeight;
} else {
top += widget.getOffsetHeight();
}
return top;
}
@Override
protected int getLeft(int popupWidth) {
return LocaleInfo.getCurrentLocale().isRTL() ? getRtlLeft(popupWidth) : getLtrLeft(popupWidth);
}
protected int getLtrLeft(int popupWidth) {
if (!canFitOnLeftEdge(popupWidth) && (canFitOnRightEdge(popupWidth) || clipToWindow)) {
return Math.max(0, getRightEdge(popupWidth));
} else {
return widget.getAbsoluteLeft();
}
}
protected int getRtlLeft(int popupWidth) {
if (!canFitOnRightEdge(popupWidth) && (canFitOnLeftEdge(popupWidth) || !clipToWindow)) {
return widget.getAbsoluteLeft();
} else {
return Math.max(0, getRightEdge(popupWidth));
}
}
private int getRightEdge(int popupWidth) {
return widget.getAbsoluteLeft() + widget.getOffsetWidth() - popupWidth;
}
private boolean canFitOnLeftEdge(int popupWidth) {
int windowRight = Window.getClientWidth() + Window.getScrollLeft();
return windowRight - popupWidth > widget.getAbsoluteLeft();
}
private boolean canFitOnRightEdge(int popupWidth) {
return getRightEdge(popupWidth) >= Window.getScrollLeft();
}
}