1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.g2d.dnd;
14 import java.awt.AlphaComposite;
15 import java.awt.geom.AffineTransform;
16 import java.awt.geom.Point2D;
17 import java.awt.geom.Rectangle2D;
19 import org.simantics.g2d.canvas.ICanvasContext;
20 import org.simantics.g2d.canvas.impl.AbstractCanvasParticipant;
21 import org.simantics.g2d.canvas.impl.SGNodeReflection.SGCleanup;
22 import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit;
23 import org.simantics.g2d.diagram.DiagramHints;
24 import org.simantics.g2d.participant.TransformUtil;
25 import org.simantics.scenegraph.g2d.G2DParentNode;
26 import org.simantics.scenegraph.g2d.IG2DNode;
27 import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler;
28 import org.simantics.scenegraph.g2d.events.command.CommandEvent;
29 import org.simantics.scenegraph.g2d.events.command.Commands;
30 import org.simantics.scenegraph.g2d.nodes.SingleElementNode;
31 import org.simantics.scenegraph.g2d.snap.ISnapAdvisor;
32 import org.simantics.utils.datastructures.context.IContext;
33 import org.simantics.utils.datastructures.context.IContextListener;
36 * This participant paints an array of icons of a drag operation.
38 * @author Toni Kalajainen
40 public class DragPainter extends AbstractCanvasParticipant {
41 // Priority of drag event, eats ecs key
42 public final static int DRAG_EVENT_PRIORITY = Integer.MAX_VALUE - 1500;
43 public final static int DRAG_PAINT_PRIORITY = Integer.MAX_VALUE - 1100;
44 public final static int MARGIN = 5;
46 final IDnDContext dropCtx;
47 Point2D mouseControlPos;
49 public DragPainter(IDnDContext dropCtx, Point2D mouseControlPos) {
51 this.dropCtx = dropCtx;
52 this.mouseControlPos = (Point2D) mouseControlPos.clone();
55 IContextListener<IDragItem> contextListener = new IContextListener<IDragItem>() {
57 public void itemAdded(IContext<IDragItem> sender, IDragItem item) {
58 updateItemPositions();
59 getContext().getContentContext().setDirty();
62 public void itemRemoved(IContext<IDragItem> sender, IDragItem item) {
63 updateItemPositions();
64 getContext().getContentContext().setDirty();
69 public void addedToContext(ICanvasContext ctx) {
70 super.addedToContext(ctx);
71 dropCtx.addContextListener(getContext().getThreadAccess(), contextListener);
75 public void removedFromContext(ICanvasContext ctx) {
76 dropCtx.removeContextListener(getContext().getThreadAccess(), contextListener);
77 super.removedFromContext(ctx);
80 public boolean setMousePos(Point2D mouseControlPos) {
81 return setMousePos(mouseControlPos, false);
84 public boolean setMousePos(Point2D mouseControlPos, boolean forceUpdate) {
85 if (!forceUpdate && mouseControlPos.equals(this.mouseControlPos))
87 this.mouseControlPos = (Point2D) mouseControlPos.clone();
88 getContext().getContentContext().setDirty();
89 updateItemPositions();
94 * Get the size of the largest drop item
98 private Point2D calcItemSize(IDragItem[] items)
100 double w = Double.MIN_VALUE;
101 double h = Double.MIN_VALUE;
102 for (IDragItem i : items) {
103 Rectangle2D bounds = i.getBounds();
104 if (bounds == null) bounds = new Rectangle2D.Double(0,0,1,1);
105 if (w < bounds.getWidth())
106 w = bounds.getWidth();
107 if (h < bounds.getHeight())
108 h = bounds.getHeight();
110 return new Point2D.Double(w, h);
113 private void updateItemPositions() {
114 // Calculate mouse position on diagram
115 TransformUtil vi = getContext().getSingleItem(TransformUtil.class);
116 AffineTransform controlToDiagram = vi.getInverseTransform();
117 if (controlToDiagram==null) return;
118 Point2D mouseDiagramPos = controlToDiagram.transform(mouseControlPos, new Point2D.Double());
120 //System.out.println("updateItemPositions: mousepos: " + mouseControlPos + " - " + mouseDiagramPos);
122 IDragItem items[] = dropCtx.toArray();
123 int count = items.length;
124 int columns = (int) Math.ceil( Math.sqrt( count) );
125 Integer columnsHint = dropCtx.getHints().getHint(DnDHints.KEY_DND_GRID_COLUMNS);
126 if (columnsHint != null)
127 columns = columnsHint;
128 int rows = (int) Math.ceil((double)count / (double)columns);
130 // Size of the largest item
131 Point2D size = calcItemSize(items);
133 // Calculate center point of the whole item mass
134 double cx = ((columns-1)*(size.getX()+margin))/2 + size.getX()/2;
135 double cy = ((rows -1)*(size.getY()+margin))/2 + size.getY()/2;
136 //double cx = ((columns)*(size.getX()+margin)-margin)/2 /*- size.getX()/2*/;
137 //double cy = ((rows )*(size.getY()+margin)-margin)/2 /*- size.getY()/2*/;
142 for (IDragItem i : items) {
143 Rectangle2D bounds = i.getBounds();
144 double x = (index % columns) * (margin + size.getX());
145 double y = (index / columns) * (margin + size.getY());
146 // Point2D pos = new Point2D.Double(x, y);
151 x += mouseDiagramPos.getX();
152 y += mouseDiagramPos.getY();
157 Point2D p = new Point2D.Double(x, y);
158 ISnapAdvisor snap = getHint(DiagramHints.SNAP_ADVISOR);
161 dropCtx.setItemPosition(i, p);
166 protected G2DParentNode node = null;
169 public void initSG(G2DParentNode parent) {
170 node = parent.addNode(G2DParentNode.class);
171 node.setZIndex(DRAG_PAINT_PRIORITY);
176 public void cleanupSG() {
181 private void updateSG() {
182 IDragItem items[] = dropCtx.toArray();
183 // updateItemPositions();
184 for (IDragItem item : items) {
185 Point2D pos = dropCtx.getItemPosition(item);
186 if(pos != null) { // Position can (or at least seems to be) be null on the first frame
187 AffineTransform subt = AffineTransform.getTranslateInstance(pos.getX(), pos.getY());
189 IG2DNode itemHolder = node.getNode(""+item.hashCode());
190 if (itemHolder != null && !(itemHolder instanceof SingleElementNode)) {
191 System.err.println("BUG: item hash codes collide within the dragged item context - found unrecognized item " + itemHolder + " with node id '" + item.hashCode() + "'");
195 SingleElementNode elementHolder = (SingleElementNode) itemHolder;
196 if (elementHolder == null) {
197 elementHolder = node.getOrCreateNode(""+item.hashCode(), SingleElementNode.class);
198 elementHolder.setTransform(subt);
199 elementHolder.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.75f));
200 item.paint(elementHolder);
202 elementHolder.setTransform(subt);
208 @EventHandler(priority = DRAG_EVENT_PRIORITY)
209 public boolean handleEvent(CommandEvent e) {
210 if (e.command.equals( Commands.CANCEL) )