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

Last change on this file since 1514 was 1514, checked in by bnemhaus, 4 years ago

Anchoring with AnchorCenterX and AnchorCenterY now work correctly with connected shapes.

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