f@0
|
1 /*
|
f@0
|
2 accessPD - An accessible PD patches editor
|
f@0
|
3
|
f@0
|
4 Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
|
f@0
|
5 Copyright (C) 2014 Fiore Martin
|
f@0
|
6
|
f@0
|
7 This program is free software: you can redistribute it and/or modify
|
f@0
|
8 it under the terms of the GNU General Public License as published by
|
f@0
|
9 the Free Software Foundation, either version 3 of the License, or
|
f@0
|
10 (at your option) any later version.
|
f@0
|
11
|
f@0
|
12 This program is distributed in the hope that it will be useful,
|
f@0
|
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
f@0
|
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
f@0
|
15 GNU General Public License for more details.
|
f@0
|
16
|
f@0
|
17 You should have received a copy of the GNU General Public License
|
f@0
|
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
f@0
|
19 */
|
f@0
|
20 package uk.ac.qmul.eecs.ccmi.pdsupport;
|
f@0
|
21
|
f@0
|
22 import java.awt.Color;
|
f@0
|
23 import java.awt.Graphics2D;
|
f@0
|
24 import java.awt.Shape;
|
f@0
|
25 import java.awt.geom.Point2D;
|
f@0
|
26 import java.awt.geom.Rectangle2D;
|
f@0
|
27 import java.io.InputStream;
|
f@0
|
28
|
f@0
|
29 import uk.ac.qmul.eecs.ccmi.diagrammodel.NodeProperties;
|
f@0
|
30 import uk.ac.qmul.eecs.ccmi.gui.Direction;
|
f@0
|
31 import uk.ac.qmul.eecs.ccmi.gui.Node;
|
f@0
|
32 import uk.ac.qmul.eecs.ccmi.simpletemplate.MultiLineString;
|
f@0
|
33 import uk.ac.qmul.eecs.ccmi.sound.SoundFactory;
|
f@0
|
34
|
f@0
|
35 public class PdObject extends Node implements PdElement {
|
f@0
|
36 private static final long serialVersionUID = 1L;
|
f@0
|
37 private static final int DEFAULT_WIDTH = 100;
|
f@0
|
38 private static final int DEFAULT_HEIGHT = 60;
|
f@0
|
39 private static final Rectangle2D.Double minBounds = new Rectangle2D.Double(0,0,DEFAULT_WIDTH,DEFAULT_HEIGHT);
|
f@0
|
40
|
f@0
|
41
|
f@0
|
42 private Rectangle2D.Double bounds;
|
f@0
|
43 private static InputStream sound;
|
f@0
|
44 private MultiLineString label;
|
f@0
|
45 private int orderNumber;
|
f@0
|
46
|
f@0
|
47 static{
|
f@0
|
48 sound = PdObject.class.getResourceAsStream("audio/PdObject.mp3");
|
f@0
|
49 SoundFactory.getInstance().loadSound(sound);
|
f@0
|
50 }
|
f@0
|
51
|
f@0
|
52 public PdObject(String type) {
|
f@0
|
53 super(type, NodeProperties.NULL_PROPERTIES);
|
f@0
|
54 bounds = new Rectangle2D.Double(0,0,DEFAULT_WIDTH,DEFAULT_HEIGHT);
|
f@0
|
55 label = new MultiLineString();
|
f@0
|
56 label.setText(getType());
|
f@0
|
57 }
|
f@0
|
58
|
f@0
|
59 public PdObject() {
|
f@0
|
60 this("Object");
|
f@0
|
61 }
|
f@0
|
62
|
f@0
|
63 @Override
|
f@0
|
64 protected void translateImplementation(Point2D p, double dx, double dy) {
|
f@0
|
65 bounds.setFrame(bounds.getX() + dx,
|
f@0
|
66 bounds.getY() + dy,
|
f@0
|
67 bounds.getWidth(),
|
f@0
|
68 bounds.getHeight());
|
f@0
|
69
|
f@0
|
70 }
|
f@0
|
71
|
f@0
|
72 @Override
|
f@0
|
73 public boolean contains(Point2D aPoint) {
|
f@0
|
74 return bounds.contains(aPoint);
|
f@0
|
75 }
|
f@0
|
76
|
f@0
|
77 @Override
|
f@0
|
78 public Rectangle2D getBounds() {
|
f@0
|
79 return bounds.getBounds2D();
|
f@0
|
80 }
|
f@0
|
81
|
f@0
|
82 @Override
|
f@0
|
83 public Point2D getConnectionPoint(Direction d) {
|
f@0
|
84 double slope = bounds.getHeight() / bounds.getWidth();
|
f@0
|
85 double ex = d.getX();
|
f@0
|
86 double ey = d.getY();
|
f@0
|
87 double x = bounds.getCenterX();
|
f@0
|
88 double y = bounds.getCenterY();
|
f@0
|
89
|
f@0
|
90 if (ex != 0 && -slope <= ey / ex && ey / ex <= slope){
|
f@0
|
91 // intersects at left or right boundary
|
f@0
|
92 if (ex > 0){
|
f@0
|
93 x = bounds.getMaxX();
|
f@0
|
94 y += (bounds.getWidth() / 2) * ey / ex;
|
f@0
|
95 }else{
|
f@0
|
96 x = bounds.getX();
|
f@0
|
97 y -= (bounds.getWidth() / 2) * ey / ex;
|
f@0
|
98 }
|
f@0
|
99 }else if (ey != 0){
|
f@0
|
100 // intersects at top or bottom
|
f@0
|
101 if (ey > 0){
|
f@0
|
102 x += (bounds.getHeight() / 2) * ex / ey;
|
f@0
|
103 y = bounds.getMaxY();
|
f@0
|
104 }else{
|
f@0
|
105 x -= (bounds.getHeight() / 2) * ex / ey;
|
f@0
|
106 y = bounds.getY();
|
f@0
|
107 }
|
f@0
|
108 }
|
f@0
|
109
|
f@0
|
110 return new Point2D.Double(x, y);
|
f@0
|
111
|
f@0
|
112 }
|
f@0
|
113
|
f@0
|
114 @Override
|
f@0
|
115 public Shape getShape() {
|
f@0
|
116 return getBounds();
|
f@0
|
117 }
|
f@0
|
118
|
f@0
|
119 @Override
|
f@0
|
120 public InputStream getSound() {
|
f@0
|
121 return sound;
|
f@0
|
122 }
|
f@0
|
123
|
f@0
|
124 @Override
|
f@0
|
125 public void draw(Graphics2D g2d){
|
f@0
|
126 Color oldColor = g2d.getColor();
|
f@0
|
127 g2d.setColor(Color.WHITE);
|
f@0
|
128 g2d.fill(getBounds());
|
f@0
|
129
|
f@0
|
130 g2d.setColor(oldColor);
|
f@0
|
131
|
f@0
|
132 label.draw(g2d, getBounds());
|
f@0
|
133 g2d.draw(bounds);
|
f@0
|
134 }
|
f@0
|
135
|
f@0
|
136 @Override
|
f@0
|
137 public void setName(String name, Object source){
|
f@0
|
138 label.setText(name);
|
f@0
|
139 super.setName(name, source);
|
f@0
|
140 }
|
f@0
|
141
|
f@0
|
142 @Override
|
f@0
|
143 public void setId(long id){
|
f@0
|
144 super.setId(id);
|
f@0
|
145
|
f@0
|
146 label.setText(getName());
|
f@0
|
147 /* when they are given an id nodes change name into "new <type> node <id>" *
|
f@0
|
148 * where <type> is the actual type of the node and <id> is the given id *
|
f@0
|
149 * therefore a reshape is necessary to display the new name */
|
f@0
|
150 Rectangle2D boundsBeforeReshape = getBounds();
|
f@0
|
151
|
f@0
|
152 bounds = calculateBounds(label.getBounds());
|
f@0
|
153
|
f@0
|
154 /* the reshape might change the bounds, so the shape is translated so that the top-left *
|
f@0
|
155 * point is at the same position as before just to keep it more consistent */
|
f@0
|
156 Rectangle2D boundsAfterReshape = getBounds();
|
f@0
|
157 translateImplementation(
|
f@0
|
158 new Point2D.Double(),
|
f@0
|
159 boundsBeforeReshape.getX() - boundsAfterReshape.getX(),
|
f@0
|
160 boundsBeforeReshape.getY() - boundsAfterReshape.getY()
|
f@0
|
161 );
|
f@0
|
162
|
f@0
|
163
|
f@0
|
164 }
|
f@0
|
165
|
f@0
|
166 protected Rectangle2D.Double getMinBounds(){
|
f@0
|
167 return minBounds;
|
f@0
|
168 }
|
f@0
|
169
|
f@0
|
170 private Rectangle2D.Double calculateBounds(Rectangle2D bounds){
|
f@0
|
171 return new Rectangle2D.Double(bounds.getX() , bounds.getY(),
|
f@0
|
172 Math.max(bounds.getWidth(), getMinBounds().getWidth()),
|
f@0
|
173 Math.max(bounds.getHeight(), getMinBounds().getHeight())
|
f@0
|
174 );
|
f@0
|
175 }
|
f@0
|
176
|
f@0
|
177 @Override
|
f@0
|
178 public Object clone(){
|
f@0
|
179 PdObject clone = (PdObject)super.clone();
|
f@0
|
180
|
f@0
|
181 clone.bounds = new Rectangle2D.Double(0,0,DEFAULT_WIDTH,DEFAULT_HEIGHT);
|
f@0
|
182 clone.label = new MultiLineString();
|
f@0
|
183 clone.label.setText(getType());
|
f@0
|
184
|
f@0
|
185 return clone;
|
f@0
|
186 }
|
f@0
|
187
|
f@0
|
188 public String toPdFile(){
|
f@0
|
189 Rectangle2D bounds = getBounds();
|
f@0
|
190 return getChunckType() + " obj " + ((int)bounds.getX()) +
|
f@0
|
191 ' ' + ((int)bounds.getY()) + ' ' + getName().replaceAll("\\s+","");
|
f@0
|
192 }
|
f@0
|
193
|
f@0
|
194 @Override
|
f@0
|
195 public String getChunckType() {
|
f@0
|
196 return "#X";
|
f@0
|
197 }
|
f@0
|
198
|
f@0
|
199 public void setOrderNumber(int n){
|
f@0
|
200 orderNumber = n;
|
f@0
|
201 }
|
f@0
|
202
|
f@0
|
203 @Override
|
f@0
|
204 public int getOrderNumber(){
|
f@0
|
205 return orderNumber;
|
f@0
|
206 }
|
f@0
|
207 }
|