/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.g2d.dnd; import java.awt.AlphaComposite; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import org.simantics.g2d.canvas.ICanvasContext; import org.simantics.g2d.canvas.impl.AbstractCanvasParticipant; import org.simantics.g2d.canvas.impl.SGNodeReflection.SGCleanup; import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit; import org.simantics.g2d.diagram.DiagramHints; import org.simantics.g2d.participant.TransformUtil; import org.simantics.scenegraph.g2d.G2DParentNode; import org.simantics.scenegraph.g2d.IG2DNode; import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler; import org.simantics.scenegraph.g2d.events.command.CommandEvent; import org.simantics.scenegraph.g2d.events.command.Commands; import org.simantics.scenegraph.g2d.nodes.SingleElementNode; import org.simantics.scenegraph.g2d.snap.ISnapAdvisor; import org.simantics.utils.datastructures.context.IContext; import org.simantics.utils.datastructures.context.IContextListener; /** * This participant paints an array of icons of a drag operation. * * @author Toni Kalajainen */ public class DragPainter extends AbstractCanvasParticipant { // Priority of drag event, eats ecs key public final static int DRAG_EVENT_PRIORITY = Integer.MAX_VALUE - 1500; public final static int DRAG_PAINT_PRIORITY = Integer.MAX_VALUE - 1100; public final static int MARGIN = 5; final IDnDContext dropCtx; Point2D mouseControlPos; public DragPainter(IDnDContext dropCtx, Point2D mouseControlPos) { super(); this.dropCtx = dropCtx; this.mouseControlPos = (Point2D) mouseControlPos.clone(); } IContextListener contextListener = new IContextListener() { @Override public void itemAdded(IContext sender, IDragItem item) { updateItemPositions(); getContext().getContentContext().setDirty(); } @Override public void itemRemoved(IContext sender, IDragItem item) { updateItemPositions(); getContext().getContentContext().setDirty(); } }; @Override public void addedToContext(ICanvasContext ctx) { super.addedToContext(ctx); dropCtx.addContextListener(getContext().getThreadAccess(), contextListener); } @Override public void removedFromContext(ICanvasContext ctx) { dropCtx.removeContextListener(getContext().getThreadAccess(), contextListener); super.removedFromContext(ctx); } public boolean setMousePos(Point2D mouseControlPos) { return setMousePos(mouseControlPos, false); } public boolean setMousePos(Point2D mouseControlPos, boolean forceUpdate) { if (!forceUpdate && mouseControlPos.equals(this.mouseControlPos)) return false; this.mouseControlPos = (Point2D) mouseControlPos.clone(); getContext().getContentContext().setDirty(); updateItemPositions(); return true; } /** * Get the size of the largest drop item * @param items * @return */ private Point2D calcItemSize(IDragItem[] items) { double w = Double.MIN_VALUE; double h = Double.MIN_VALUE; for (IDragItem i : items) { Rectangle2D bounds = i.getBounds(); if (bounds == null) bounds = new Rectangle2D.Double(0,0,1,1); if (w < bounds.getWidth()) w = bounds.getWidth(); if (h < bounds.getHeight()) h = bounds.getHeight(); } return new Point2D.Double(w, h); } private void updateItemPositions() { // Calculate mouse position on diagram TransformUtil vi = getContext().getSingleItem(TransformUtil.class); AffineTransform controlToDiagram = vi.getInverseTransform(); if (controlToDiagram==null) return; Point2D mouseDiagramPos = controlToDiagram.transform(mouseControlPos, new Point2D.Double()); //System.out.println("updateItemPositions: mousepos: " + mouseControlPos + " - " + mouseDiagramPos); IDragItem items[] = dropCtx.toArray(); int count = items.length; int columns = (int) Math.ceil( Math.sqrt( count) ); Integer columnsHint = dropCtx.getHints().getHint(DnDHints.KEY_DND_GRID_COLUMNS); if (columnsHint != null) columns = columnsHint; int rows = (int) Math.ceil((double)count / (double)columns); int margin = MARGIN; // Size of the largest item Point2D size = calcItemSize(items); // Calculate center point of the whole item mass double cx = ((columns-1)*(size.getX()+margin))/2 + size.getX()/2; double cy = ((rows -1)*(size.getY()+margin))/2 + size.getY()/2; //double cx = ((columns)*(size.getX()+margin)-margin)/2 /*- size.getX()/2*/; //double cy = ((rows )*(size.getY()+margin)-margin)/2 /*- size.getY()/2*/; //double cx = 0; //double cy = 0; int index = 0; for (IDragItem i : items) { Rectangle2D bounds = i.getBounds(); double x = (index % columns) * (margin + size.getX()); double y = (index / columns) * (margin + size.getY()); // Point2D pos = new Point2D.Double(x, y); index++; x -= bounds.getX(); y -= bounds.getY(); x += mouseDiagramPos.getX(); y += mouseDiagramPos.getY(); x -= cx; y -= cy; Point2D p = new Point2D.Double(x, y); ISnapAdvisor snap = getHint(DiagramHints.SNAP_ADVISOR); if (snap != null) snap.snap(p); dropCtx.setItemPosition(i, p); } updateSG(); } protected G2DParentNode node = null; @SGInit public void initSG(G2DParentNode parent) { node = parent.addNode(G2DParentNode.class); node.setZIndex(DRAG_PAINT_PRIORITY); updateSG(); } @SGCleanup public void cleanupSG() { node.remove(); node = null; } private void updateSG() { IDragItem items[] = dropCtx.toArray(); // updateItemPositions(); for (IDragItem item : items) { Point2D pos = dropCtx.getItemPosition(item); if(pos != null) { // Position can (or at least seems to be) be null on the first frame AffineTransform subt = AffineTransform.getTranslateInstance(pos.getX(), pos.getY()); IG2DNode itemHolder = node.getNode(""+item.hashCode()); if (itemHolder != null && !(itemHolder instanceof SingleElementNode)) { System.err.println("BUG: item hash codes collide within the dragged item context - found unrecognized item " + itemHolder + " with node id '" + item.hashCode() + "'"); continue; } SingleElementNode elementHolder = (SingleElementNode) itemHolder; if (elementHolder == null) { elementHolder = node.getOrCreateNode(""+item.hashCode(), SingleElementNode.class); elementHolder.setTransform(subt); elementHolder.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.75f)); item.paint(elementHolder); } else { elementHolder.setTransform(subt); } } } } @EventHandler(priority = DRAG_EVENT_PRIORITY) public boolean handleEvent(CommandEvent e) { if (e.command.equals( Commands.CANCEL) ) { remove(); return true; } return false; } }