source: trunk/src/org/expeditee/items/Dot.java@ 1102

Last change on this file since 1102 was 1102, checked in by davidb, 6 years ago

Reworking of the code-base to separate logic from graphics. This version of Expeditee now supports a JFX graphics as an alternative to SWING

File size: 10.7 KB
Line 
1/**
2 * Dot.java
3 * Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19package org.expeditee.items;
20
21import java.util.ArrayList;
22import java.util.LinkedList;
23import java.util.List;
24
25import org.expeditee.core.Colour;
26import org.expeditee.core.Dimension;
27import org.expeditee.core.Fill;
28import org.expeditee.core.Point;
29import org.expeditee.core.bounds.AxisAlignedBoxBounds;
30import org.expeditee.core.bounds.Bounds;
31import org.expeditee.core.bounds.PolygonBounds;
32import org.expeditee.gio.EcosystemManager;
33import org.expeditee.gio.GraphicsManager;
34import org.expeditee.gui.DisplayController;
35import org.expeditee.gui.Frame;
36import org.expeditee.gui.FrameGraphics;
37
38/**
39 * Represents a point on the screen. All Point objects are stored as x,y pairs
40 * with an Item ID. Note: Lines and all combinates of lines (rectangles, etc)
41 * are represented only as Points that share line IDs.
42 *
43 * @author jdm18
44 *
45 */
46public class Dot extends Item {
47
48 // Standard Item variables
49
50 // private static final int _MINIMUM_DOT_SIZE = 6;
51
52 private static final int MINIMUM_DOT_SIZE = 2;
53
54 public Dot(int id) {
55 super();
56 setID(id);
57 }
58
59 /**
60 * Constructs a new Point with the given x,y coordinates and Item ID.
61 *
62 * @param x
63 * The x coordinate of this point
64 * @param y
65 * The y coordinate of this point
66 * @param id
67 * The Item ID of this Point
68 */
69 public Dot(int x, int y, int id) {
70 super();
71 setID(id);
72 setPosition(x, y);
73 }
74
75 @Override
76 public void setColor(Colour c) {
77 super.setColor(c);
78
79 // update the colour of any lines
80 for (Line line : getLines())
81 line.setColor(c);
82 }
83
84 @Override
85 public void setAnchorLeft(Integer anchor) {
86 if (!isLineEnd()) {
87 super.setAnchorLeft(anchor);
88 return;
89 }
90
91 invalidateFill();
92 invalidateCommonTrait(ItemAppearence.PreMoved);
93
94 this._anchoring.setLeftAnchor(anchor);
95
96 int oldX = getX();
97 if (anchor != null) {
98 float deltaX = anchor - oldX;
99 anchorConnected(AnchorEdgeType.Left, deltaX);
100 }
101
102 invalidateCommonTrait(ItemAppearence.PostMoved);
103 invalidateFill();
104 }
105
106 @Override
107 public void setAnchorRight(Integer anchor) {
108 if (!isLineEnd()) {
109 super.setAnchorRight(anchor);
110 return;
111 }
112 invalidateFill();
113 invalidateCommonTrait(ItemAppearence.PreMoved);
114
115 this._anchoring.setRightAnchor(anchor);
116
117 int oldX = getX();
118 if (anchor != null) {
119 float deltaX = DisplayController.getFramePaintArea().getWidth() - anchor - getBoundsWidth() - oldX;
120
121 anchorConnected(AnchorEdgeType.Right, deltaX);
122 }
123
124 invalidateCommonTrait(ItemAppearence.PostMoved);
125 invalidateFill();
126 }
127
128 @Override
129 public void setAnchorTop(Integer anchor) {
130 if (!isLineEnd()) {
131 super.setAnchorTop(anchor);
132 return;
133 }
134 invalidateFill();
135 invalidateCommonTrait(ItemAppearence.PreMoved);
136
137 this._anchoring.setTopAnchor(anchor);
138
139 int oldY = getY();
140 if (anchor != null) {
141 float deltaY = anchor - oldY;
142 anchorConnected(AnchorEdgeType.Top, deltaY);
143 }
144
145 invalidateCommonTrait(ItemAppearence.PostMoved);
146 invalidateFill();
147 }
148
149 @Override
150 public void setAnchorBottom(Integer anchor) {
151 if (!isLineEnd()) {
152 super.setAnchorBottom(anchor);
153 return;
154 }
155 invalidateFill();
156 invalidateCommonTrait(ItemAppearence.PreMoved);
157
158 this._anchoring.setBottomAnchor(anchor);
159
160 int oldY = getY();
161 if (anchor != null) {
162 float deltaY = DisplayController.getFramePaintArea().getHeight() - anchor - getBoundsHeight() - oldY;
163 anchorConnected(AnchorEdgeType.Bottom, deltaY);
164 }
165
166 invalidateCommonTrait(ItemAppearence.PostMoved);
167 invalidateFill();
168 }
169
170
171
172 @Override
173 public void paint() {
174 GraphicsManager g = EcosystemManager.getGraphicsManager();
175 if (isHighlighted() /* && !FreeItems.getInstance().contains(this) */) {
176 Colour highlightColor = getHighlightColor();
177 Fill fill = new Fill(highlightColor);
178 // g.setStroke()
179 // Draw the highlighting rectangle surrounding the dot
180 // this is drawn even if its part of a rectangle
181
182 if (isVectorItem()) invalidateBounds();
183
184 AxisAlignedBoxBounds bounds = getBoundingBox();
185 if (_highlightMode == HighlightMode.Enclosed || this.getConnected().size() <= 1) { // Make sure single dots are highlighted filled
186 g.drawRectangle(bounds.getTopLeft(), bounds.getSize(), 0.0f, fill, highlightColor, DOT_STROKE, null);
187 } else if (_highlightMode == HighlightMode.Connected) {
188 g.drawRectangle(bounds.getTopLeft(), bounds.getSize(), 0.0f, null, highlightColor, HIGHLIGHT_STROKE, null);
189 } else if (_highlightMode == HighlightMode.Normal) {
190 g.drawOval(bounds.getCentre(), bounds.getSize(), 0.0f, fill, highlightColor, DOT_STROKE);
191 }
192 // System.out.println(_mode.toString());
193 }
194
195 // dots on lines are hidden
196 if (getLines().size() > 0) return;
197
198 int thick = (int) getThickness();
199 if (thick < MINIMUM_DOT_SIZE) thick = MINIMUM_DOT_SIZE;
200
201 Fill fill = _filled ? new Fill(getPaintColor()) : null;
202
203 // TODO: On testing, this code doesn't seem to work (can't change to any type except square). cts16
204 switch (_type) {
205 case circle:
206 g.drawOval(
207 new Point(getX(), getY()),
208 new Dimension(thick, thick),
209 0.0,
210 fill,
211 getPaintColor(),
212 null
213 );
214 break;
215 case diamond:
216 PolygonBounds diamond = PolygonBounds.getDiamond(thick, thick).translate(getX(), getY()).close();
217 g.drawPolygon(diamond, null, null, 0.0, fill, getPaintColor(), null);
218 break;
219 case triangle:
220 PolygonBounds triangle = PolygonBounds.getTriangle(thick, thick).translate(getX(), getY()).close();
221 g.drawPolygon(triangle, null, null, 0.0, fill, getPaintColor(), null);
222 break;
223 case roundSquare:
224 int arc = thick / 4;
225 g.drawRectangle(
226 new Point(getX(), getY()),
227 new Dimension(thick, thick),
228 0.0,
229 fill,
230 getPaintColor(),
231 null,
232 new Dimension(arc, arc)
233 );
234 break;
235 default:
236 g.drawRectangle(
237 new Point(getX(), getY()),
238 new Dimension(thick, thick),
239 0.0,
240 fill,
241 getPaintColor(),
242 null,
243 null
244 );
245 }
246
247 }
248
249 /**
250 * Updates the bounds surrounding this Dot.
251 * TODO: Standardise Dot minimum size. cts16
252 */
253 public Bounds updateBounds()
254 {
255 int thick = Math.round(getThickness());
256
257 // Sets a minimum size for the dot
258 thick = Math.max(thick, getGravity() * 2);
259
260 // Include the gravity in the thickness
261 thick += 2 * getGravity();
262
263
264 int x = getX() - thick / 2;
265 int y = getY() - thick / 2;
266
267 return new AxisAlignedBoxBounds(x, y, thick, thick);
268 }
269
270 @Override
271 public Item copy() {
272 Dot copy = new Dot(getX(), getY(), getID());
273
274 Item.DuplicateItem(this, copy);
275
276 return copy;
277 }
278
279 @Override
280 public void setHighlightColorToDefault() {
281 super.setHighlightColorToDefault();
282
283 //return Item.DEFAULT_CURSOR;
284 }
285
286 @Override
287 public void setAnnotation(boolean val) {
288 DisplayController.setCursorPosition(this.getPosition());
289 Item.replaceDot(this, '@');
290 }
291
292 @Override
293 public Item merge(Item merger, int mouseX, int mouseY) {
294 // if the item being merged with is another Dot
295 if (merger instanceof Dot) {
296 if (merger.hasEnclosures() || hasEnclosures())
297 return merger;
298
299 Item dot = (Item) merger;
300 merger.setPosition(this.getPosition());
301 // prevent concurrency issues if removing lines
302 List<Line> lines = new ArrayList<Line>();
303 lines.addAll(dot.getLines());
304
305 for (Line line : lines) {
306 // remove lines that are in common
307 if (getLines().contains(line)) {
308 dot.removeLine(line);
309 removeLine(line);
310 } else {
311 // check for duplicated lines as a result of merging
312 Item check = (Item) line.getOppositeEnd(dot);
313 boolean dup = false;
314
315 for (Line l : getLines()) {
316 Item opposite = l.getOppositeEnd(this);
317
318 if (check == opposite) {
319 line.getStartItem().removeLine(line);
320 line.getEndItem().removeLine(line);
321 dup = true;
322 break;
323 }
324 }
325
326 if (!dup)
327 line.replaceLineEnd(dot, this);
328 }
329 }
330
331 setThickness(dot.getThickness());
332 setColor(dot.getColor());
333 setFillColor(dot.getFillColor());
334
335 return null;
336 }
337
338 if (merger instanceof Text) {
339 merger.setPosition(this.getPosition());
340 List<Line> lines = new LinkedList<Line>();
341 lines.addAll(getLines());
342 for (Line line : lines)
343 line.replaceLineEnd(this, merger);
344 this.delete();
345 return merger;
346 }
347
348 // if the item being merged with is a Line
349 if (merger instanceof Line) {
350 Line line = (Line) merger;
351 // if this dot is part of the line then keep it, otherwise it
352 // can be removed
353 if (line.getOppositeEnd(this) != null && getLines().contains(line))
354 return merger;
355 else
356 return null;
357 }
358
359 return merger;
360 }
361
362 @Override
363 public String getTypeAndID() {
364 return "P " + getID();
365 }
366
367 @Override
368 public void delete() {
369 super.delete();
370
371 for (Line l : this.getLines())
372 l.delete();
373 }
374
375 @Override
376 public void anchor() {
377 Frame current = getParentOrCurrentFrame();
378 // This is to make lines anchored across frames be on one frame
379 for (Line l : getLines()) {
380 Frame parent = l.getOppositeEnd(this).getParent();
381 if (parent != null && parent != current) {
382 this.setParent(parent);
383 if (DisplayController.getCurrentSide() == DisplayController.TwinFramesSide.LEFT)
384 this.setX(this.getX() - DisplayController.getTwinFramesSeparatorX());
385 else
386 this.setX(this.getX() + DisplayController.getTwinFramesSeparatorX());
387 }
388 break;
389 }
390
391 super.anchor();
392
393 // TODO is the code below needed... what for?
394 for (Line line : getLines()) {
395 if (line.getID() < 0 && !current.getItems().contains(line)) {
396 line.setID(current.getNextItemID());
397 line.setHighlightColorToDefault();
398 // Mike: Why was this line here?
399 // anchor(line);
400 }
401 }
402 }
403
404 @Override
405 public void addLine(Line line) {
406 super.addLine(line);
407 line.setColor(getColor());
408 line.setThickness(getThickness());
409 line.setLinePattern(getLinePattern());
410 }
411
412 @Override
413 public void lineColorChanged(Colour c) {
414 if (getColor() != c) {
415 setColor(c);
416 }
417 }
418
419 @Override
420 public boolean dontSave() {
421 if (getThickness() <= 1 && (getLines().size() == 0)
422 && getConstraints().size() == 0) {
423 return true;
424 }
425 return super.dontSave();
426 }
427
428 @Override
429 public float getSize()
430 {
431 return getThickness();
432 }
433}
Note: See TracBrowser for help on using the repository browser.