]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.g2d/src/org/simantics/g2d/dnd/DragPainter.java
3ebccf136a158e8fd9295f4cb9fe6a89f37b0059
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / dnd / DragPainter.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
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
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.g2d.dnd;
13
14 import java.awt.AlphaComposite;
15 import java.awt.geom.AffineTransform;
16 import java.awt.geom.Point2D;
17 import java.awt.geom.Rectangle2D;
18
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;
34
35 /**
36  * This participant paints an array of icons of a drag operation.
37  *
38  * @author Toni Kalajainen
39  */
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;
45
46     final IDnDContext       dropCtx;
47     Point2D                 mouseControlPos;
48
49     public DragPainter(IDnDContext dropCtx, Point2D mouseControlPos) {
50         super();
51         this.dropCtx = dropCtx;
52         this.mouseControlPos = (Point2D) mouseControlPos.clone();
53     }
54
55     IContextListener<IDragItem> contextListener = new IContextListener<IDragItem>() {
56         @Override
57         public void itemAdded(IContext<IDragItem> sender, IDragItem item) {
58             updateItemPositions();
59             getContext().getContentContext().setDirty();
60         }
61         @Override
62         public void itemRemoved(IContext<IDragItem> sender, IDragItem item) {
63             updateItemPositions();
64             getContext().getContentContext().setDirty();
65         }
66     };
67
68     @Override
69     public void addedToContext(ICanvasContext ctx) {
70         super.addedToContext(ctx);
71         dropCtx.addContextListener(getContext().getThreadAccess(), contextListener);
72     }
73
74     @Override
75     public void removedFromContext(ICanvasContext ctx) {
76         dropCtx.removeContextListener(getContext().getThreadAccess(), contextListener);
77         super.removedFromContext(ctx);
78     }
79
80     public boolean setMousePos(Point2D mouseControlPos) {
81         return setMousePos(mouseControlPos, false);
82     }
83
84     public boolean setMousePos(Point2D mouseControlPos, boolean forceUpdate) {
85         if (!forceUpdate && mouseControlPos.equals(this.mouseControlPos))
86             return false;
87         this.mouseControlPos = (Point2D) mouseControlPos.clone();
88         getContext().getContentContext().setDirty();
89         updateItemPositions();
90         return true;
91     }
92
93     /**
94      * Get the size of the largest drop item
95      * @param items
96      * @return
97      */
98     private Point2D calcItemSize(IDragItem[] items)
99     {
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();
109         }
110         return new Point2D.Double(w, h);
111     }
112
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());
119
120         //System.out.println("updateItemPositions: mousepos: " + mouseControlPos + " - " + mouseDiagramPos);
121
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);
129         int margin = MARGIN;
130         // Size of the largest item
131         Point2D size = calcItemSize(items);
132
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*/;
138         //double cx = 0;
139         //double cy = 0;
140
141         int index = 0;
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);
147             index++;
148
149             x -= bounds.getX();
150             y -= bounds.getY();
151             x += mouseDiagramPos.getX();
152             y += mouseDiagramPos.getY();
153
154             x -= cx;
155             y -= cy;
156
157             Point2D p = new Point2D.Double(x, y);
158             ISnapAdvisor snap = getHint(DiagramHints.SNAP_ADVISOR);
159             if (snap != null)
160                 snap.snap(p);
161             dropCtx.setItemPosition(i, p);
162         }
163         updateSG();
164     }
165
166     protected G2DParentNode node = null;
167
168     @SGInit
169     public void initSG(G2DParentNode parent) {
170         node = parent.addNode(G2DParentNode.class);
171         node.setZIndex(DRAG_PAINT_PRIORITY);
172         updateSG();
173     }
174
175     @SGCleanup
176     public void cleanupSG() {
177         node.remove();
178         node = null;
179     }
180
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());
188
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() + "'");
192                     continue;
193                 }
194
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);
201                 } else {
202                     elementHolder.setTransform(subt);
203                 }
204             }
205         }
206     }
207
208     @EventHandler(priority = DRAG_EVENT_PRIORITY)
209     public boolean handleEvent(CommandEvent e) {
210         if (e.command.equals( Commands.CANCEL) )
211         {
212             remove();
213             return true;
214         }
215         return false;
216     }
217 }