source: trunk/src/org/expeditee/gio/swing/SwingGraphicsManager.java@ 1144

Last change on this file since 1144 was 1144, checked in by bln4, 6 years ago

Used Eclipse refactoring to encapsulate Point.X and Point.Y

File size: 18.3 KB
Line 
1package org.expeditee.gio.swing;
2
3import java.awt.AlphaComposite;
4import java.awt.Component;
5import java.awt.Container;
6import java.awt.FontMetrics;
7import java.awt.Graphics;
8import java.awt.Graphics2D;
9import java.awt.GraphicsEnvironment;
10import java.awt.RenderingHints;
11import java.awt.Toolkit;
12import java.awt.event.ComponentListener;
13import java.awt.event.KeyListener;
14import java.awt.event.WindowListener;
15import java.awt.event.WindowStateListener;
16import java.awt.geom.AffineTransform;
17import java.awt.image.ImageObserver;
18
19import javax.swing.JFrame;
20import javax.swing.JLayeredPane;
21import javax.swing.JMenuBar;
22import javax.swing.JOptionPane;
23import javax.swing.RepaintManager;
24import javax.swing.SwingUtilities;
25import javax.swing.TransferHandler;
26
27import org.expeditee.core.Clip;
28import org.expeditee.core.Colour;
29import org.expeditee.core.Cursor;
30import org.expeditee.core.Dimension;
31import org.expeditee.core.Fill;
32import org.expeditee.core.Font;
33import org.expeditee.core.GradientFill;
34import org.expeditee.core.Image;
35import org.expeditee.core.Point;
36import org.expeditee.core.Stroke;
37import org.expeditee.core.TextLayout;
38import org.expeditee.core.bounds.PolygonBounds;
39import org.expeditee.gio.GraphicsManager;
40import org.expeditee.gio.GraphicsSurfaceStack;
41import org.expeditee.gio.swing.SwingImageManager.BlockingImageObserver;
42import org.expeditee.gio.swing.SwingImageManager.SelfAnimatingImageObserver;
43import org.expeditee.gui.DisplayController;
44import org.expeditee.items.widgets.SwingWidget;
45import org.expeditee.items.widgets.Widget;
46
47// TODO: Make stack thread-safe
48public class SwingGraphicsManager extends GraphicsManager {
49
50 private static SwingGraphicsManager _instance;
51
52 public static SwingGraphicsManager getInstance() {
53 if (_instance == null) {
54 try {
55 SwingUtilities.invokeAndWait(new Runnable() {
56 @Override
57 public void run() {
58 _instance = new SwingGraphicsManager();
59 }
60 });
61 } catch (Exception e) {
62 System.err.println("Error while initialising GraphicsManager. Aborting...");
63 e.printStackTrace(System.err);
64 System.exit(1);
65 }
66
67 // Block until the window is ready
68
69 }
70
71 return _instance;
72 }
73
74 private JFrame _jFrame;
75
76 private GraphicsSurfaceStack<Graphics2D> _surfaceStack;
77
78 private SwingGraphicsManager() {
79 _jFrame = new JFrame() {
80 private static final long serialVersionUID = 5179259234365906415L;
81
82 // Override the paint() method so that Expeditee's graphics are drawn
83 // when the window refreshes.
84 @Override
85 public void paint(Graphics g) {
86 DisplayController.requestRefresh(false);
87 }
88 };
89
90 setWindowIcon();
91
92 /*
93 * See Java bug ID 4016934. They say that window closed events are called once
94 * the JFrame is disposed.
95 */
96 _jFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
97
98 // Expeditee handles its own repainting of AWT/Swing components
99 RepaintManager.setCurrentManager(ExpediteeRepaintManager.getInstance());
100
101 // required to accept TAB key
102 _jFrame.setFocusTraversalKeysEnabled(false);
103
104 _jFrame.pack();
105
106 // Moved to here to work with JFXPanel
107 // TODO: Is the above comment still relevant? cts16
108 _jFrame.getContentPane().setLayout(new AbsoluteLayout());
109
110 // Set visible must be just after DisplayIO.Init for the message box to be the
111 // right size
112 // TODO: Is the above comment still relevant? cts16
113 _jFrame.setVisible(true);
114
115 // Create the surface stack
116 _surfaceStack = new GraphicsSurfaceStack<Graphics2D>() {
117 @Override
118 public Graphics2D getSurfaceFromImage(Image image) {
119 return SwingMiscManager.getIfUsingSwingImageManager().getImageGraphics(image);
120 }
121
122 @Override
123 public void setSurfaceClip(Graphics2D surface, Clip clip) {
124 if (surface == null)
125 return;
126
127 if (clip == null) {
128 surface.setClip(null);
129 return;
130 }
131
132 if (clip.isFullyClipped())
133 return;
134
135 surface.setClip(SwingConversions.toSwingRectangle(clip.getBounds()));
136 }
137 };
138 refreshRootSurface();
139 }
140
141 @Override
142 protected GraphicsSurfaceStack<?> getGraphicsSurfaceStack() {
143 return _surfaceStack;
144 }
145
146 public Dimension getScreenSize() {
147 java.awt.Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
148
149 return SwingConversions.fromSwingDimension(size);
150 }
151
152 public Point getWindowLocation() {
153 return SwingConversions.fromSwingPoint(_jFrame.getContentPane().getLocationOnScreen());
154 }
155
156 public void setWindowLocation(Point p) {
157 _jFrame.setLocation(p.getX(), p.getY());
158 }
159
160 public Dimension getWindowSize() {
161 return SwingConversions.fromSwingDimension(_jFrame.getContentPane().getSize());
162 }
163
164 public void setWindowSize(Dimension d) {
165 _jFrame.setSize(d.width, d.height);
166 _jFrame.setPreferredSize(SwingConversions.toSwingDimension(d));
167 // Issue a command to graphics so that the JFrame draws itself white.
168 _jFrame.getGraphics().clearRect(0, 0, d.width, d.height);
169 }
170
171 public void requestFocus() {
172 _jFrame.requestFocus();
173 }
174
175 public void setCompositeAlpha(float alpha) {
176 _surfaceStack.getCurrentSurface().setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
177 }
178
179 public void setAntialiasing(boolean on) {
180 setAntialiasing(_surfaceStack.getCurrentSurface(), on);
181 }
182
183 private void setAntialiasing(Graphics2D surface, boolean on) {
184 if (surface == null)
185 return;
186
187 if (on) {
188 surface.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
189 } else {
190 surface.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
191 }
192 }
193
194 public void setFont(Font font) {
195 _surfaceStack.getCurrentSurface().setFont(SwingMiscManager.getIfUsingSwingFontManager().getInternalFont(font));
196 }
197
198 public void drawImage(Image image, Point topLeft, Dimension size, double angle, Point cropTopLeft,
199 Dimension cropSize) {
200 // Can't draw nothing
201 if (image == null)
202 return;
203
204 // Can't draw nowhere
205 if (topLeft == null)
206 return;
207
208 // If the cropped area is degenerate, abort
209 if (cropSize != null && (cropSize.width <= 0 || cropSize.height <= 0))
210 return;
211
212 // If the crop area is the entire image, pretend we are not cropping
213 if (Point.ORIGIN.equals(cropTopLeft) && image.getSize().equals(cropSize)) {
214 cropTopLeft = null;
215 cropSize = null;
216 }
217
218 SwingImageManager manager = SwingMiscManager.getIfUsingSwingImageManager();
219
220 ImageObserver animator = null;
221 if (image.isAnimated()) {
222 animator = manager.getAnimator(image);
223 if (animator != null)
224 ((SelfAnimatingImageObserver) animator).activate();
225 } else {
226 animator = new SwingImageManager.LoadCompletedImageObserver();
227 }
228
229 // Default is the entire image
230 Image croppedImage = image;
231
232 // If we are cropping, do this now into a temporary image
233 if (cropTopLeft != null && cropSize != null) {
234 croppedImage = manager.createImage(cropSize.width, cropSize.height);
235 manager.getInternalImage(croppedImage).getGraphics().drawImage(manager.getInternalImage(image), 0, 0,
236 cropSize.width - 1, cropSize.height - 1, cropTopLeft.getX(), cropTopLeft.getY(),
237 cropTopLeft.getX() + cropSize.width - 1, cropTopLeft.getY() + cropSize.height - 1, animator);
238 animator = new BlockingImageObserver();
239 }
240
241 // Transform the image
242 AffineTransform tx = new AffineTransform();
243 if (size != null)
244 tx.scale(((double) size.width) / croppedImage.getWidth(),
245 ((double) size.height) / croppedImage.getHeight());
246 if (angle != 0.0)
247 tx.rotate(angle);
248 if (topLeft != null)
249 tx.translate(topLeft.getX(), topLeft.getY());
250
251 // Draw the image to the current surface
252 boolean drawn = _surfaceStack.getCurrentSurface().drawImage(manager.getInternalImage(croppedImage), tx,
253 animator);
254
255 // If the draw didn't succeed, try again after waiting for the image to load
256 if (!drawn && animator instanceof BlockingImageObserver) {
257 ((BlockingImageObserver) animator).attemptWait();
258 _surfaceStack.getCurrentSurface().drawImage(manager.getInternalImage(croppedImage), tx, animator);
259 }
260 }
261
262 public void drawRectangle(Point topLeft, Dimension size, double angle, Fill fill, Colour borderColour,
263 Stroke borderStroke, Dimension cornerRadius) {
264 Graphics2D g = (Graphics2D) _surfaceStack.getCurrentSurface().create();
265
266 if (angle != 0.0) {
267 AffineTransform tx = new AffineTransform();
268 tx.rotate(angle);
269 g.transform(tx);
270 }
271
272 if (fill != null) {
273 if (fill instanceof GradientFill) {
274 g.setPaint(SwingConversions.toSwingGradientPaint((GradientFill) fill));
275 } else {
276 g.setColor(SwingConversions.toSwingColor(fill.getColour()));
277 }
278
279 if (cornerRadius != null) {
280 g.fillRoundRect(topLeft.getX(), topLeft.getY(), size.width, size.height, cornerRadius.width, cornerRadius.height);
281 } else {
282 g.fillRect(topLeft.getX(), topLeft.getY(), size.width, size.height);
283 }
284 }
285
286 if (borderColour != null && borderStroke != null) {
287 g.setColor(SwingConversions.toSwingColor(borderColour));
288 g.setStroke(SwingConversions.toSwingStroke(borderStroke));
289
290 if (cornerRadius != null) {
291 g.drawRoundRect(topLeft.getX(), topLeft.getY(), size.width, size.height, cornerRadius.width, cornerRadius.height);
292 } else {
293 g.drawRect(topLeft.getX(), topLeft.getY(), size.width, size.height);
294 }
295 }
296
297 g.dispose();
298 }
299
300 public void drawOval(Point centre, Dimension diameters, double angle, Fill fill, Colour borderColour,
301 Stroke borderStroke) {
302 Graphics2D g = (Graphics2D) _surfaceStack.getCurrentSurface().create();
303
304 if (angle != 0.0) {
305 AffineTransform tx = new AffineTransform();
306 tx.rotate(angle);
307 g.transform(tx);
308 }
309
310 Point topLeft = new Point(centre.getX() - diameters.width / 2, centre.getY() - diameters.height / 2);
311
312 if (fill != null) {
313 if (fill instanceof GradientFill) {
314 g.setPaint(SwingConversions.toSwingGradientPaint((GradientFill) fill));
315 } else {
316 g.setColor(SwingConversions.toSwingColor(fill.getColour()));
317 }
318
319 g.fillOval(topLeft.getX(), topLeft.getY(), diameters.width, diameters.height);
320 }
321
322 if (borderColour != null && borderStroke != null) {
323 g.setColor(SwingConversions.toSwingColor(borderColour));
324 g.setStroke(SwingConversions.toSwingStroke(borderStroke));
325
326 g.drawOval(topLeft.getX(), topLeft.getY(), diameters.width, diameters.height);
327 }
328
329 g.dispose();
330 }
331
332 public void drawPolygon(PolygonBounds points, Point offset, Dimension scale, double angle, Fill fill,
333 Colour borderColour, Stroke borderStroke) {
334 if (points == null || points.getPointCount() < 2)
335 return;
336 if (fill == null && (borderColour == null || borderStroke == null))
337 return;
338
339 Graphics2D g = (Graphics2D) _surfaceStack.getCurrentSurface().create();
340
341 AffineTransform tx = new AffineTransform();
342 Point centre = points.getCentre();
343 tx.translate(-centre.getX(), -centre.getY());
344 if (angle != 0.0)
345 tx.rotate(angle);
346 if (scale != null) {
347 double xScale = ((double) scale.width) / (points.getMaxX() - points.getMinX());
348 double yScale = ((double) scale.height) / (points.getMaxY() - points.getMinY());
349 tx.scale(xScale, yScale);
350 }
351 tx.translate(centre.getX(), centre.getY());
352 if (offset != null)
353 tx.translate(offset.getX(), offset.getY());
354 g.transform(tx);
355
356 if (fill != null) {
357 if (fill instanceof GradientFill) {
358 g.setPaint(SwingConversions.toSwingGradientPaint((GradientFill) fill));
359 } else {
360 g.setColor(SwingConversions.toSwingColor(fill.getColour()));
361 }
362
363 g.fillPolygon(SwingConversions.toSwingPolygon(points));
364 }
365
366 if (borderColour != null && borderStroke != null) {
367 g.setColor(SwingConversions.toSwingColor(borderColour));
368 g.setStroke(SwingConversions.toSwingStroke(borderStroke));
369
370 if (points.isClosed()) {
371 g.drawPolygon(SwingConversions.toSwingPolygon(points));
372 } else {
373 int nPoints = points.getPointCount();
374 int[] xPoints = new int[nPoints];
375 int[] yPoints = new int[nPoints];
376
377 for (int i = 0; i < nPoints; i++) {
378 Point point = points.getPoint(i);
379 xPoints[i] = point.getX();
380 yPoints[i] = point.getY();
381 }
382
383 g.drawPolyline(xPoints, yPoints, nPoints);
384 }
385 }
386
387 g.dispose();
388 }
389
390 @Override
391 public void drawLine(int x1, int y1, int x2, int y2, Colour colour, Stroke stroke) {
392 if (colour == null || stroke == null)
393 return;
394
395 Graphics2D g = (Graphics2D) _surfaceStack.getCurrentSurface().create();
396 g.setColor(SwingConversions.toSwingColor(colour));
397 g.setStroke(SwingConversions.toSwingStroke(stroke));
398
399 g.drawLine(x1, y1, x2, y2);
400
401 g.dispose();
402 }
403
404 @Override
405 public void drawString(String string, Point position, Font font, Colour colour) {
406 if (string == null || position == null || font == null || colour == null)
407 return;
408
409 Graphics2D g = (Graphics2D) _surfaceStack.getCurrentSurface().create();
410 g.setColor(SwingConversions.toSwingColor(colour));
411 g.setFont(SwingMiscManager.getIfUsingSwingFontManager().getInternalFont(font));
412
413 g.drawString(string, position.getX(), position.getY());
414
415 g.dispose();
416 }
417
418 @Override
419 public void drawTextLayout(TextLayout layout, Point position, Colour colour) {
420 if (layout == null)
421 return;
422
423 SwingTextLayoutManager layoutManager = SwingMiscManager.getIfUsingSwingTextLayoutManager();
424 if (layoutManager == null) {
425 drawString(layout.getLine(), position, layout.getFont(), colour);
426 return;
427 }
428
429 java.awt.font.TextLayout swingLayout = layoutManager.getInternalLayout(layout);
430
431 Graphics2D g = (Graphics2D) _surfaceStack.getCurrentSurface().create();
432 g.setColor(SwingConversions.toSwingColor(colour));
433
434 swingLayout.draw(g, position.getX(), position.getY());
435 }
436
437 private Dimension _preFullscreenSize = null;
438 private boolean _fullScreenTransitionPending = false;
439
440 /**
441 * Whether or not we are in the middle of transitioning to/from fullscreen.
442 */
443 public boolean isFullscreenTransitionPending() {
444 return _fullScreenTransitionPending;
445 }
446
447 /**
448 * Should be called when the SwingInputManager is notified that the fullscreen
449 * transition has finished.
450 */
451 public void finishFullscreenTransition() {
452 _fullScreenTransitionPending = false;
453 }
454
455 @Override
456 public boolean canGoFullscreen() {
457 return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().isFullScreenSupported();
458 }
459
460 @Override
461 public boolean isFullscreen() {
462 return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()
463 .getFullScreenWindow() == _jFrame;
464 }
465
466 @Override
467 public void goFullscreen() {
468 if (!canGoFullscreen()) {
469 System.err.println("Warning: GraphicsManager::goFullScreen() called when not available -- ignoring");
470 return;
471 }
472
473 _preFullscreenSize = getWindowSize();
474
475 _fullScreenTransitionPending = true;
476
477 _jFrame.dispose();
478 _jFrame.setUndecorated(true);
479 _jFrame.pack();
480 _jFrame.setVisible(true);
481
482 GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(_jFrame);
483 }
484
485 @Override
486 public void exitFullscreen() {
487 _fullScreenTransitionPending = true;
488
489 _jFrame.dispose();
490 _jFrame.setUndecorated(false);
491 setWindowSize(_preFullscreenSize);
492
493 GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(null);
494 _jFrame.pack();
495 _jFrame.setVisible(true);
496
497 }
498
499 @Override
500 public void setCursor(Cursor cursor) {
501 if (cursor == null)
502 return;
503
504 java.awt.Cursor swingCursor;
505 if (cursor.getType() == Cursor.CursorType.CUSTOM) {
506 SwingImageManager imageManager = SwingMiscManager.getIfUsingSwingImageManager();
507
508 if (imageManager == null)
509 return;
510
511 swingCursor = Toolkit.getDefaultToolkit().createCustomCursor(
512 imageManager.getInternalImage(cursor.getImage()),
513 SwingConversions.toSwingPoint(cursor.getHotspot()), cursor.getName());
514 } else {
515 swingCursor = new java.awt.Cursor(SwingConversions.toSwingCursorType(cursor.getType()));
516 }
517
518 _jFrame.setCursor(swingCursor);
519 }
520
521 @Override
522 public Dimension getBestCursorSize(Dimension desiredSize) {
523 Toolkit toolkit = Toolkit.getDefaultToolkit();
524 java.awt.Dimension best_cursor_dim = toolkit.getBestCursorSize(desiredSize.width, desiredSize.height);
525 return SwingConversions.fromSwingDimension(best_cursor_dim);
526 }
527
528 @Override
529 public void setWindowTitle(String title) {
530 _jFrame.setTitle(title);
531 }
532
533 @Override
534 public boolean showDialog(String title, String message) {
535 int result = JOptionPane.showConfirmDialog(_jFrame, message, title, JOptionPane.OK_CANCEL_OPTION,
536 JOptionPane.WARNING_MESSAGE);
537 return result == JOptionPane.OK_OPTION;
538 }
539
540 @Override
541 public Dimension getCurrentDrawingSurfaceSize() {
542 Image currentImage = _surfaceStack.getCurrentImage();
543
544 if (currentImage != null) {
545 return currentImage.getSize();
546 } else {
547 return getWindowSize();
548 }
549 }
550
551 public void refreshRootSurface() {
552 Graphics2D rootSurface = (Graphics2D) _jFrame.getContentPane().getGraphics();
553 setAntialiasing(rootSurface, true);
554 rootSurface.setFont(rootSurface.getFont().deriveFont(40f));
555 _surfaceStack.setRootSurface(rootSurface);
556 }
557
558 public JFrame getJFrame() {
559 return _jFrame;
560 }
561
562 public Container getContentPane() {
563 return _jFrame.getContentPane();
564 }
565
566 public JLayeredPane getLayeredPane() {
567 return _jFrame.getLayeredPane();
568 }
569
570 public void setTransferHandler(TransferHandler newHandler) {
571 _jFrame.setTransferHandler(newHandler);
572 }
573
574 public void addWindowListener(WindowListener l) {
575 _jFrame.addWindowListener(l);
576 }
577
578 public void addWindowStateListener(WindowStateListener l) {
579 _jFrame.addWindowStateListener(l);
580 }
581
582 public void addKeyListener(KeyListener l) {
583 _jFrame.addKeyListener(l);
584 }
585
586 public void addComponentListener(ComponentListener l) {
587 _jFrame.addComponentListener(l);
588 }
589
590 public void setGlassPane(Component glassPane) {
591 _jFrame.setGlassPane(glassPane);
592 }
593
594 public Component getGlassPane() {
595 return _jFrame.getGlassPane();
596 }
597
598 public JMenuBar getJMenuBar() {
599 return _jFrame.getJMenuBar();
600 }
601
602 public FontMetrics getFontMetrics(java.awt.Font font) {
603 return _jFrame.getFontMetrics(font);
604 }
605
606 public java.awt.Font getFont() {
607 return _jFrame.getFont();
608 }
609
610 public Graphics2D getCurrentSurface() {
611 //System.err.println("Getting image y: " + _surfaceStack.getCurrentImage().getBounds().getMinY());
612 return _surfaceStack.getCurrentSurface();
613 }
614
615 @Override
616 public boolean addInteractiveWidget(Widget iw) {
617 if (super.addInteractiveWidget(iw)) {
618 _jFrame.add(((SwingWidget) iw).getComponent());
619 return true;
620 }
621
622 return false;
623 }
624
625 @Override
626 public boolean removeInteractiveWidget(Widget iw) {
627 if (super.removeInteractiveWidget(iw)) {
628 _jFrame.remove(((SwingWidget) iw).getComponent());
629 return true;
630 }
631
632 return false;
633 }
634
635 @Override
636 protected void setWindowIcon(Image image) {
637 SwingImageManager imageManager = SwingMiscManager.getIfUsingSwingImageManager();
638
639 if (imageManager != null) {
640 _jFrame.setIconImage(imageManager.getInternalImage(image));
641 }
642 }
643}
Note: See TracBrowser for help on using the repository browser.