]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/handler/PickRequest.java
Allow PickSorter access to the PickRequest used for pick operation
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / diagram / handler / PickRequest.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2020 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  *     Semantum Oy - gitlab #454
12  *******************************************************************************/
13 package org.simantics.g2d.diagram.handler;
14
15 import java.awt.Shape;
16 import java.awt.geom.AffineTransform;
17 import java.awt.geom.Area;
18 import java.awt.geom.Point2D;
19 import java.awt.geom.Rectangle2D;
20 import java.util.Collections;
21 import java.util.Comparator;
22 import java.util.List;
23
24 import org.simantics.g2d.canvas.ICanvasContext;
25 import org.simantics.g2d.connection.handler.ConnectionHandler;
26 import org.simantics.g2d.element.IElement;
27 import org.simantics.g2d.element.handler.BendsHandler;
28 import org.simantics.g2d.element.handler.TerminalTopology;
29 import org.simantics.g2d.element.handler.impl.ConnectionSelectionOutline;
30 import org.simantics.g2d.elementclass.BranchPoint;
31 import org.simantics.g2d.elementclass.MonitorHandler;
32 import org.simantics.g2d.utils.GeometryUtils;
33 import org.simantics.scenegraph.utils.TransformedRectangle;
34
35 /**
36  *
37  * @See {@link GeometryUtils} for intersect and contains tests
38  * @See {@link TransformedRectangle}
39  * @See {@link Area} intersects operations for complex shapes
40  * @author Toni Kalajainen
41  */
42 public class PickRequest {
43
44     public static enum PickPolicy {
45         PICK_INTERSECTING_OBJECTS,
46         PICK_CONTAINED_OBJECTS
47     }
48
49     public Shape      pickArea;
50     public PickPolicy pickPolicy = PickPolicy.PICK_INTERSECTING_OBJECTS;
51     /** Pick filter (null == everything is accepted) */
52     public PickFilter pickFilter = null;
53     public PickSorter pickSorter = null;
54
55     /**
56      * Used to optimize picking if provided via R-tree traversal to find
57      * intersecting elements, not everything.
58      */
59     public ICanvasContext pickContext;
60
61     public PickRequest(double x, double y)
62     {
63         pickArea = new Rectangle2D.Double(x, y, 1, 1);
64     }
65     public PickRequest(Point2D p)
66     {
67         pickArea = new Rectangle2D.Double(p.getX(), p.getY(), 0.0001, 0.0001);
68     }
69     public PickRequest(Shape shape)
70     {
71         pickArea = shape;
72     }
73     public PickRequest(Shape shape, AffineTransform transform)
74     {
75         pickArea = GeometryUtils.transformShape(shape, transform);
76     }
77
78     public PickRequest context(ICanvasContext ctx) {
79         this.pickContext = ctx;
80         return this;
81     }
82
83     public static interface PickFilter {
84         boolean accept(IElement e);
85
86         public static final PickFilter FILTER_ALL = new PickFilter() {
87             @Override
88             public boolean accept(IElement e) {
89                 return true;
90             }
91         };
92         // Connections
93         public static final PickFilter FILTER_CONNECTIONS = new PickFilter() {
94             @Override
95             public boolean accept(IElement e) {
96                 return e.getElementClass().containsClass(ConnectionHandler.class);
97             }
98             @Override
99             public String toString() { return "FILTER_CONNECTIONS"; }
100         };
101         // Connection edges
102         public static final PickFilter FILTER_CONNECTION_EDGES = new PickFilter() {
103             @Override
104             public boolean accept(IElement e) {
105                 return e.getElementClass().containsClass(BendsHandler.class) || e.getElementClass().containsClass(ConnectionSelectionOutline.class);
106             }
107             @Override
108             public String toString() { return "FILTER_CONNECTION_EDGES"; }
109         };
110         // Connections
111         public static final PickFilter FILTER_BRANCH_POINT = new PickFilter() {
112             @Override
113             public boolean accept(IElement e) {
114                 return e.getElementClass().containsClass(BranchPoint.class);
115             }
116             @Override
117             public String toString() { return "FILTER_BRANCH_POINTS"; }
118         };
119         // Anything that has terminals
120         public static final PickFilter FILTER_NODES = new PickFilter() {
121             @Override
122             public boolean accept(IElement e) {
123                 return e.getElementClass().containsClass(TerminalTopology.class);
124             }
125             @Override
126             public String toString() { return "FILTER_NODES"; }
127         };
128         public static final PickFilter FILTER_MONITORS = new PickFilter() {
129             @Override
130             public boolean accept(IElement e) {
131                 return e.getElementClass().containsClass(MonitorHandler.class);
132             }
133             @Override
134             public String toString() { return "FILTER_MONITORS"; }
135         };
136     }
137
138     public static interface PickSorter {
139         /**
140          * Sorts the specified element list.
141          * 
142          * @param elements the element list to sort
143          */
144         void sort(List<IElement> elements);
145
146         /**
147          * Extended interface-method that receives the pick request in addition to the
148          * picked elements to be sorted. Allows e.g. looking at the pick area in the
149          * sorter.
150          * 
151          * <p>
152          * The default implementation just invokes {@link #sort(List)} ignoring the pick
153          * request. The default implementation also keeps PickSorter API/ABI-compatible.
154          * 
155          * @param request  the original pick request that produced the hits listed in
156          *                 <code>elements</code>
157          * @param elements the element list to sort
158          * 
159          * @author Tuukka Lehtonen
160          * @since 1.43.0, 1.35.3
161          */
162         default void sort(PickRequest request, List<IElement> elements) {
163             sort(elements);
164         }
165
166         //
167         public static final PickSorter CONNECTIONS_LAST = new PickSorter() {
168             @Override
169             public void sort(List<IElement> elements) {
170                 Collections.sort(elements, new Comparator<IElement>() {
171                     @Override
172                     public int compare(IElement e1, IElement e2) {
173                         boolean isConn1 = PickFilter.FILTER_CONNECTION_EDGES.accept(e1);
174                         boolean isConn2 = PickFilter.FILTER_CONNECTION_EDGES.accept(e2);
175                         if (!isConn1 && isConn2)
176                             return -1;
177                         if (isConn1 && !isConn2)
178                             return 1;
179                         return 0;
180                     }
181                 });
182             }
183         };
184         public static final PickSorter CONNECTIONS_FIRST = new PickSorter() {
185             @Override
186             public void sort(List<IElement> elements) {
187                 Collections.sort(elements, new Comparator<IElement>() {
188                     @Override
189                     public int compare(IElement e1, IElement e2) {
190                         boolean isConn1 = PickFilter.FILTER_CONNECTION_EDGES.accept(e1);
191                         boolean isConn2 = PickFilter.FILTER_CONNECTION_EDGES.accept(e2);
192                         if (!isConn1 && isConn2)
193                             return 1;
194                         if (isConn1 && !isConn2)
195                             return -1;
196                         return 0;
197                     }
198                 });
199             }
200         };
201     }
202
203 }