package org.geogebra.web.web.gui.layout; import java.util.ArrayList; import org.geogebra.common.awt.GDimension; import org.geogebra.common.euclidian.event.PointerEventType; import org.geogebra.common.gui.layout.DockComponent; import org.geogebra.common.javax.swing.SwingConstants; import org.geogebra.ggbjdk.java.awt.geom.Rectangle; import org.geogebra.web.html5.gui.util.ClickEndHandler; import org.geogebra.web.html5.util.ArticleElement; import com.google.gwt.dom.client.Style; import com.google.gwt.dom.client.Style.Position; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.MouseMoveEvent; import com.google.gwt.event.dom.client.MouseMoveHandler; import com.google.gwt.event.dom.client.TouchMoveEvent; import com.google.gwt.event.dom.client.TouchMoveHandler; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.AbsolutePanel; import com.google.gwt.user.client.ui.SimplePanel; /** * Glass pane is used to draw the drag-preview area on the panels if the user * enters the drag'n'drop mode. * * @author Florian Sonner, adapted by G.Sturr */ public class DockGlassPaneW extends AbsolutePanel implements MouseMoveHandler, TouchMoveHandler { private boolean dragInProgress = false; private DockManagerW dockManager; private DockPanelW[] dockPanels; private Rectangle[] dockPanelsBounds; private DnDState dndState; private String color; private static final String COLOR_DEFAULT = "lightgray"; private static final String COLOR_NOT_ENOUGH_SPACE = "lightgray";// Color.red; private static final String COLOR_SAME_PLACE = "white"; private static final int BORDER_WIDTH = 4; private SimplePanel previewPanel; private com.google.gwt.event.shared.HandlerRegistration reg0, reg1, reg2; private ArticleElement ae; /********************************************** * Constructs a DockGlassPane */ public DockGlassPaneW(GDimension size) { setVisible(false); setStyleName("DockGlassPane"); if (size != null) { this.getElement().getStyle().setPosition(Position.ABSOLUTE); this.setWidth(size.getWidth() + "px"); this.setHeight(size.getHeight() + "px"); this.getElement().getStyle().setTop(0, Unit.PX); this.getElement().getStyle().setLeft(0, Unit.PX); } previewPanel = new SimplePanel(); previewPanel.getElement().getStyle() .setBorderWidth(BORDER_WIDTH, Style.Unit.PX); previewPanel.getElement().getStyle() .setBorderStyle(Style.BorderStyle.SOLID); previewPanel.getElement().getStyle().setBorderColor("gray"); previewPanel.setVisible(false); add(previewPanel); this.getElement().getStyle().setZIndex(5000); } public void setArticleElement(ArticleElement ae){ this.ae = ae; } public void attach(DockManagerW dockManager) { this.dockManager = dockManager; } public boolean isDragInProgress() { return dragInProgress; } /** * Start the dragging process by adding the mouse listeners. * * @param state */ public void startDrag(DnDState state) { // we need capture for touch; otherwise touch move events go to // dragPanel Event.setCapture(this.getElement()); setVisible(true); reg0 = addDomHandler(this, TouchMoveEvent.getType()); reg1 = addDomHandler(this, MouseMoveEvent.getType()); reg2 = ClickEndHandler.init(this, new ClickEndHandler() { @Override public void onClickEnd(int x, int y, PointerEventType type) { onMouseUp(); } }); // this.getElement().getStyle().setZIndex(50); if (dragInProgress) { return; } dragInProgress = true; dndState = state; dndState.setTarget(state.getSource()); // cache the absolute bounds of all DockPanels dockPanels = dockManager.getPanels(); ArrayList<DockPanelW> dockPanelsList = new ArrayList<DockPanelW>(); ArrayList<Rectangle> bounds = new ArrayList<Rectangle>(); Rectangle tmpRect; for (int i = 0; i < dockPanels.length; ++i) { // we don't need to care about invisible or views in a different // window for the drag'n'drop if (!dockPanels[i].isVisible() || dockPanels[i].isOpenInFrame()) { continue; } // tmpRect = dockPanels[i].getBounds(); tmpRect = new Rectangle(dockPanels[i].getAbsoluteLeft(), dockPanels[i].getAbsoluteTop(), dockPanels[i].getOffsetWidth(), dockPanels[i].getOffsetHeight()); dockPanelsList.add(dockPanels[i]); bounds.add(tmpRect); } dockPanelsBounds = new Rectangle[bounds.size()]; dockPanelsBounds = (bounds.toArray(dockPanelsBounds)); dockPanels = new DockPanelW[dockPanelsList.size()]; dockPanels = (dockPanelsList.toArray(dockPanels)); } /** * The mouse was released, quit the drag'n'drop mode. */ public void stopDrag() { Event.releaseCapture(this.getElement()); if (!dragInProgress) { return; } reg0.removeHandler(); reg1.removeHandler(); reg2.removeHandler(); setVisible(false); previewPanel.setVisible(false); dragInProgress = false; // this.getElement().getStyle().setZIndex(-5000); dockManager.drop(dndState); dndState = null; } private void setColorEnoughHeight(DockPanelW target) { if (target.getHeight() < DockComponent.MIN_SIZE * 2) { color = COLOR_NOT_ENOUGH_SPACE; } } private void setColorEnoughWidth(DockPanelW target) { if (target.getWidth() < DockComponent.MIN_SIZE * 2) { color = COLOR_NOT_ENOUGH_SPACE; } } /** * Calculate where the panel would be placed if the mouse is released. * * @param event */ public void mouseDragged(int mouseX, int mouseY) { int x2, y2, w, h; boolean update = false; // Check if the mouse intersects with any DockPanel for (int i = 0; i < dockPanelsBounds.length; ++i) { if (mouseX >= dockPanelsBounds[i].getX() && mouseX <= dockPanelsBounds[i].getX() + dockPanelsBounds[i].getWidth() && mouseY >= dockPanelsBounds[i].getY() && mouseY <= dockPanelsBounds[i].getY() + dockPanelsBounds[i].getHeight()) { update = true; dndState.setTarget(dockPanels[i]); break; } } if (update) { DockPanelW target = dndState.getTarget(); x2 = (int) (target.getAbsoluteLeft() / ae.getScaleX()); y2 = (int) (target.getAbsoluteTop() / ae.getScaleY()); w = target.getOffsetWidth(); h = target.getOffsetHeight(); int relativeLeft = mouseX - x2; int relativeTop = mouseY - y2; int orientation = ((DockSplitPaneW) target.getParent()) .getOrientation(); double leftPercent = relativeLeft * 1.0 / target.getOffsetWidth(); double topPercent = relativeTop * 1.0 / target.getOffsetHeight(); double maxDist = 0.35; color = COLOR_DEFAULT; // calculate the preview rectangle if (orientation == SwingConstants.VERTICAL_SPLIT) { if (leftPercent < maxDist) { if (leftPercent < maxDist / 2) { dndState.setRegion(DnDState.LEFT_OUT); setColorEnoughWidth(target); DockSplitPaneW splitPane = (DockSplitPaneW) target .getParent(); x2 = (int) (splitPane.getAbsoluteLeft() / ae.getScaleX()); y2 = (int) (splitPane.getAbsoluteTop() / ae.getScaleY()); w *= maxDist / 2; h = splitPane.getOffsetHeight(); } else { dndState.setRegion(DnDState.LEFT); setColorEnoughWidth(target); w *= maxDist; } } else if (leftPercent > 1 - maxDist) { if (leftPercent > 1 - maxDist / 2) { dndState.setRegion(DnDState.RIGHT_OUT); setColorEnoughWidth(target); DockSplitPaneW splitPane = (DockSplitPaneW) target .getParent(); x2 = (int) (splitPane.getAbsoluteLeft() / ae.getScaleX()); y2 = (int) (splitPane.getAbsoluteTop() / ae.getScaleY()); x2 += w * (1 - maxDist / 2); w *= maxDist / 2; h = splitPane.getOffsetHeight(); } else { dndState.setRegion(DnDState.RIGHT); setColorEnoughWidth(target); x2 += w * (1 - maxDist); w *= maxDist; } } else { if (topPercent < 0.5) { dndState.setRegion(DnDState.TOP); setColorEnoughHeight(target); h *= 0.5f; } else { dndState.setRegion(DnDState.BOTTOM); setColorEnoughHeight(target); y2 += h * 0.5f; h *= 0.5f; } } } else { if (topPercent < maxDist) { if (topPercent < maxDist / 2) { dndState.setRegion(DnDState.TOP_OUT); setColorEnoughHeight(target); DockSplitPaneW splitPane = (DockSplitPaneW) target .getParent(); x2 = (int) (splitPane.getAbsoluteLeft() / ae.getScaleX()); y2 = (int) (splitPane.getAbsoluteTop() / ae.getScaleY()); h *= maxDist / 2; w = splitPane.getOffsetWidth(); } else { dndState.setRegion(DnDState.TOP); setColorEnoughHeight(target); h *= maxDist; } } else if (topPercent > 1 - maxDist) { if (topPercent > 1 - maxDist / 2) { dndState.setRegion(DnDState.BOTTOM_OUT); setColorEnoughHeight(target); DockSplitPaneW splitPane = (DockSplitPaneW) target .getParent(); x2 = (int) (splitPane.getAbsoluteLeft() / ae.getScaleX()); y2 = (int) (splitPane.getAbsoluteTop() / ae.getScaleY()); y2 += h * (1 - maxDist / 2); h *= maxDist / 2; w = splitPane.getOffsetWidth(); } else { dndState.setRegion(DnDState.BOTTOM); setColorEnoughHeight(target); y2 += h * (1 - maxDist); h *= maxDist; } } else { if (leftPercent < 0.5) { dndState.setRegion(DnDState.LEFT); setColorEnoughWidth(target); w *= 0.5f; } else { dndState.setRegion(DnDState.RIGHT); setColorEnoughWidth(target); x2 += w * 0.5f; w *= 0.5f; } } } // nothing changed if (target == dndState.getSource() && !dndState.isRegionOut()) { x2 = (int) (target.getAbsoluteLeft() / ae.getScaleX()); y2 = (int) (target.getAbsoluteTop() / ae.getScaleY()); w = target.getOffsetWidth(); h = target.getOffsetHeight(); color = COLOR_SAME_PLACE; } // x2 += (int) (Math.ceil(stroke.getLineWidth() / 2)); // y2 += (int) (Math.ceil(stroke.getLineWidth() / 2)); w -= 2 * BORDER_WIDTH; h -= 2 * BORDER_WIDTH; setWidgetPosition(previewPanel, x2 - (int) (this.getAbsoluteLeft() / ae.getScaleX()), y2 - (int) (this.getAbsoluteTop() / ae.getScaleY())); previewPanel.setPixelSize(w, h); previewPanel.getElement().getStyle().setBackgroundColor(color); previewPanel.getElement().getStyle().setOpacity(0.6f); previewPanel.setVisible(true); } else { dndState.setTarget(null); previewPanel.setVisible(false); } } @Override public void onMouseMove(MouseMoveEvent event) { if (dragInProgress) { // It is not exactly known what should event.getX() and event.getY() mean // mouseDragged(event.getX(), event.getY()); // Thus trying to use the following solution instead, // because it fits to the contents of that method (for more info, see #4049) mouseDragged(event.getClientX() + Window.getScrollLeft(), event.getClientY() + Window.getScrollTop()); } } @Override public void onTouchMove(TouchMoveEvent event) { if (dragInProgress) { if (event.getTouches().length() == 1) { event.preventDefault(); mouseDragged( event.getTouches().get(0).getClientX() + Window.getScrollLeft(), event.getTouches() .get(0).getClientY() + Window.getScrollTop()); } } } public void onMouseUp() { if (dragInProgress) { stopDrag(); } } public ArticleElement getArticleElement() { return ae; } }