/*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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 org.uberfire.client.views.pfly.dnd;
import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import com.allen_sauer.gwt.dnd.client.DragContext;
import com.allen_sauer.gwt.dnd.client.VetoDragException;
import com.allen_sauer.gwt.dnd.client.util.CoordinateArea;
import com.allen_sauer.gwt.dnd.client.util.CoordinateLocation;
import com.allen_sauer.gwt.dnd.client.util.Location;
import com.allen_sauer.gwt.dnd.client.util.WidgetArea;
import com.google.gwt.core.client.GWT;
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.Unit;
import com.google.gwt.dom.client.Style.Visibility;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.Widget;
import org.uberfire.client.resources.WorkbenchResources;
import org.uberfire.client.workbench.widgets.dnd.CompassWidget;
import org.uberfire.workbench.model.CompassPosition;
import org.uberfire.workbench.model.Position;
/**
* A pop-up widget with arrows in the four cardinal directions, each of which is a separate drop target. The center of
* the widget is a fifth drop target representing the parent widget itself. The compass centers itself over its parent's
* Drop Target when displayed.
*/
@ApplicationScoped
public class CompassWidgetImpl implements CompassWidget {
public static final String FA_ACTIVE = "fa-active";
private static CompassWidgetBinder uiBinder = GWT.create(CompassWidgetBinder.class);
@UiField
DockLayoutPanel container;
@UiField
PopupPanel popup;
@UiField
Widget south;
@UiField
Widget north;
@UiField
Widget west;
@UiField
Widget east;
@UiField
Widget centre;
private Element dropTargetHighlight;
private CompassPosition dropTargetPosition = CompassPosition.NONE;
@PostConstruct
private void init() {
popup = uiBinder.createAndBindUi(this);
//Setup drop indicator
if (dropTargetHighlight == null) {
dropTargetHighlight = Document.get().createDivElement();
dropTargetHighlight.getStyle().setPosition(Style.Position.ABSOLUTE);
dropTargetHighlight.getStyle().setVisibility(Visibility.HIDDEN);
dropTargetHighlight.setClassName(WorkbenchResources.INSTANCE.CSS().dropTargetHighlight());
Document.get().getBody().appendChild(dropTargetHighlight);
}
north.ensureDebugId("CompassWidget-north");
south.ensureDebugId("CompassWidget-south");
east.ensureDebugId("CompassWidget-east");
west.ensureDebugId("CompassWidget-west");
centre.ensureDebugId("CompassWidget-centre");
}
@Override
public void onEnter(DragContext context) {
show(context);
}
@Override
public void onLeave(DragContext context) {
popup.hide();
}
@Override
public void onMove(DragContext context) {
final Location l = new CoordinateLocation(context.mouseX,
context.mouseY);
final WidgetArea northWidgetArea = new WidgetArea(north,
null);
final WidgetArea southWidgetArea = new WidgetArea(south,
null);
final WidgetArea eastWidgetArea = new WidgetArea(east,
null);
final WidgetArea westWidgetArea = new WidgetArea(west,
null);
final WidgetArea centreWidgetArea = new WidgetArea(centre,
null);
CompassPosition p = CompassPosition.NONE;
if (northWidgetArea.intersects(l)) {
p = CompassPosition.NORTH;
} else if (southWidgetArea.intersects(l)) {
p = CompassPosition.SOUTH;
} else if (eastWidgetArea.intersects(l)) {
p = CompassPosition.EAST;
} else if (westWidgetArea.intersects(l)) {
p = CompassPosition.WEST;
} else if (centreWidgetArea.intersects(l)) {
p = CompassPosition.SELF;
}
if (p != dropTargetPosition) {
dropTargetPosition = p;
showDropTarget(context,
p);
}
}
@Override
public Position getDropPosition() {
return this.dropTargetPosition;
}
@Override
public Widget getDropTarget() {
throw new UnsupportedOperationException();
}
@Override
public void onDrop(DragContext context) {
this.dropTargetPosition = CompassPosition.NONE;
highlightActiveDropTarget(null);
hideDropTarget();
}
@Override
public void onPreviewDrop(DragContext context) throws VetoDragException {
throw new UnsupportedOperationException();
}
private void show(final DragContext context) {
//Get centre of DropTarget
final Widget dropTargetParent = context.dropController.getDropTarget();
int cxmin = dropTargetParent.getElement().getAbsoluteLeft();
int cymin = dropTargetParent.getElement().getAbsoluteTop();
int cxmax = dropTargetParent.getElement().getAbsoluteRight();
int cymax = dropTargetParent.getElement().getAbsoluteBottom();
final CoordinateArea ca = new CoordinateArea(cxmin,
cymin,
cxmax,
cymax);
//Display Compass if not already visible
if (!popup.isAttached()) {
popup.setPopupPositionAndShow(new PopupPanel.PositionCallback() {
@Override
public void setPosition(int offsetWidth,
int offsetHeight) {
popup.setPopupPosition(ca.getCenter().getLeft() - (offsetWidth / 2),
ca.getCenter().getTop() - (offsetHeight / 2));
}
});
} else {
popup.setPopupPosition(ca.getCenter().getLeft() - (popup.getOffsetWidth() / 2),
ca.getCenter().getTop() - (popup.getOffsetHeight() / 2));
}
}
private void showDropTarget(final DragContext context,
final CompassPosition p) {
int x = 0;
int y = 0;
int width = 0;
int height = 0;
final Widget dropTargetParent = context.dropController.getDropTarget();
switch (p) {
case SELF:
x = dropTargetParent.getAbsoluteLeft();
y = dropTargetParent.getAbsoluteTop();
width = dropTargetParent.getOffsetWidth();
height = dropTargetParent.getOffsetHeight();
highlightActiveDropTarget(centre);
showDropTarget(x,
y,
width,
height);
break;
case NORTH:
x = dropTargetParent.getAbsoluteLeft();
y = dropTargetParent.getAbsoluteTop();
width = dropTargetParent.getOffsetWidth();
height = (int) (dropTargetParent.getOffsetHeight() * 0.50);
highlightActiveDropTarget(north);
showDropTarget(x,
y,
width,
height);
break;
case SOUTH:
x = dropTargetParent.getAbsoluteLeft();
height = (int) (dropTargetParent.getOffsetHeight() * 0.50);
y = dropTargetParent.getOffsetHeight() + dropTargetParent.getAbsoluteTop() - height;
width = dropTargetParent.getOffsetWidth();
highlightActiveDropTarget(south);
showDropTarget(x,
y,
width,
height);
break;
case EAST:
width = (int) (dropTargetParent.getOffsetWidth() * 0.50);
x = dropTargetParent.getOffsetWidth() + dropTargetParent.getAbsoluteLeft() - width;
y = dropTargetParent.getAbsoluteTop();
height = dropTargetParent.getOffsetHeight();
highlightActiveDropTarget(east);
showDropTarget(x,
y,
width,
height);
break;
case WEST:
x = dropTargetParent.getAbsoluteLeft();
y = dropTargetParent.getAbsoluteTop();
width = (int) (dropTargetParent.getOffsetWidth() * 0.50);
height = dropTargetParent.getOffsetHeight();
highlightActiveDropTarget(west);
showDropTarget(x,
y,
width,
height);
break;
default:
highlightActiveDropTarget(null);
hideDropTarget();
}
}
private void highlightActiveDropTarget(final Widget target) {
south.removeStyleName(FA_ACTIVE);
north.removeStyleName(FA_ACTIVE);
west.removeStyleName(FA_ACTIVE);
east.removeStyleName(FA_ACTIVE);
centre.removeStyleName(FA_ACTIVE);
if (target != null) {
target.addStyleName(FA_ACTIVE);
}
}
private void showDropTarget(int x,
int y,
int width,
int height) {
dropTargetHighlight.getStyle().setLeft(x,
Unit.PX);
dropTargetHighlight.getStyle().setWidth(width,
Unit.PX);
dropTargetHighlight.getStyle().setTop(y,
Unit.PX);
dropTargetHighlight.getStyle().setHeight(height,
Unit.PX);
dropTargetHighlight.getStyle().setVisibility(Visibility.VISIBLE);
dropTargetHighlight.getStyle().setDisplay(Display.BLOCK);
}
private void hideDropTarget() {
dropTargetHighlight.getStyle().setVisibility(Visibility.HIDDEN);
dropTargetHighlight.getStyle().setDisplay(Display.NONE);
dropTargetPosition = CompassPosition.NONE;
}
interface CompassWidgetBinder extends UiBinder<PopupPanel, CompassWidgetImpl> {
}
}