/* * 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> { } }