]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.g2d/src/org/simantics/g2d/chassis/FullscreenChassis.java
G2DParentNode handles "undefined" child bounds separately
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / chassis / FullscreenChassis.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 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  *******************************************************************************/
12 /*
13  *
14  * @author Toni Kalajainen
15  */
16 package org.simantics.g2d.chassis;
17
18 import java.awt.AWTException;
19 import java.awt.BufferCapabilities;
20 import java.awt.Component;
21 import java.awt.Cursor;
22 import java.awt.DisplayMode;
23 import java.awt.Frame;
24 import java.awt.Graphics;
25 import java.awt.Graphics2D;
26 import java.awt.GraphicsConfiguration;
27 import java.awt.GraphicsDevice;
28 import java.awt.GraphicsEnvironment;
29 import java.awt.ImageCapabilities;
30 import java.awt.event.KeyAdapter;
31 import java.awt.event.KeyEvent;
32 import java.awt.event.KeyListener;
33 import java.awt.event.WindowAdapter;
34 import java.awt.event.WindowEvent;
35 import java.awt.geom.Rectangle2D;
36 import java.awt.image.BufferStrategy;
37 import java.lang.reflect.Method;
38
39 import org.simantics.g2d.canvas.ICanvasContext;
40 import org.simantics.g2d.canvas.IContentContext;
41 import org.simantics.g2d.canvas.IMouseCursorContext;
42 import org.simantics.g2d.canvas.IMouseCursorListener;
43 import org.simantics.g2d.canvas.IContentContext.IContentListener;
44 import org.simantics.g2d.dnd.DragInteractor;
45 import org.simantics.g2d.dnd.DropInteractor;
46 import org.simantics.g2d.participant.RenderingQualityInteractor;
47 import org.simantics.g2d.participant.TransformUtil;
48 import org.simantics.scenegraph.g2d.G2DRenderingHints;
49 import org.simantics.scenegraph.g2d.events.adapter.AWTFocusAdapter;
50 import org.simantics.scenegraph.g2d.events.adapter.AWTKeyEventAdapter;
51 import org.simantics.scenegraph.g2d.events.adapter.AWTMouseEventAdapter;
52 import org.simantics.utils.threads.AWTThread;
53 import org.simantics.utils.threads.Executable;
54 import org.simantics.utils.threads.SyncListenerList;
55 import org.simantics.utils.threads.ThreadUtils;
56
57
58 /**
59  * Full screen AWT Frame chassis for canvas editors.
60  */
61 public class FullscreenChassis extends AbstractChassis implements ICanvasChassis {
62
63     protected Frame                               frame;
64
65     protected java.awt.Canvas                     canvas;
66
67     protected BufferStrategy                      bufferStrategy;
68
69     protected Graphics2D                          g2d;
70
71     protected TransformUtil                  viewboxInteractor;
72
73     protected AWTMouseEventAdapter                mouseAdapter;
74     protected AWTFocusAdapter                                           focusAdapter;
75     protected AWTKeyEventAdapter                  keyAdapter;
76
77     transient boolean dirty = false;
78
79     KeyListener                         escapeListener = new KeyAdapter() {
80         @Override
81         public void keyPressed(KeyEvent e) {
82             if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
83                 frame.dispose();
84         }
85     };
86
87     /**
88      * Create full screen chassis in default monitor.
89      * <p>
90      * This constructor must be ran in AWT Thread.
91      * 
92      * @param canvasContext
93      * @param windowTitle
94      * @param ruler
95      */
96     public FullscreenChassis(String windowTitle, boolean ruler) {
97         this(GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(), windowTitle, ruler);
98     }
99
100     public void redraw() {
101         canvas.repaint();
102     }
103
104     /**
105      * Create full screen chassis.
106      * <p>
107      * This constructor must be ran in AWT Thread.
108      * 
109      * @param monitor the monitor device
110      * @param canvasContext
111      * @param windowTitle
112      * @param ruler
113      */
114     public FullscreenChassis(GraphicsDevice monitor, String windowTitle, boolean ruler) {
115         DisplayMode dm = monitor.getDisplayMode();
116
117         frame = new Frame(windowTitle);
118         frame.setSize(dm.getWidth(), dm.getHeight());
119         frame.setUndecorated(true);
120
121         // Close click
122         frame.addWindowListener(new WindowAdapter() {
123             @Override
124             public void windowClosing(WindowEvent e) {
125                 frame.dispose();
126             }
127
128             @Override
129             public void windowClosed(WindowEvent e) {
130                 if (g2d!=null) {
131                     g2d.dispose();
132                     g2d = null;
133                 }
134                 fireChassisClosed();
135             }
136         });
137
138         canvas = new java.awt.Canvas() {
139             private static final long serialVersionUID = -3520733232931837755L;
140
141             @Override
142             public void paint(Graphics g) {
143                 if (bufferStrategy==null)
144                 {
145                     BufferCapabilities caps = new BufferCapabilities(new ImageCapabilities(true),
146                             new ImageCapabilities(true), BufferCapabilities.FlipContents.COPIED);
147                     try {
148                         canvas.createBufferStrategy(2, caps);
149                     } catch (AWTException e) {
150                         canvas.createBufferStrategy(2);
151                     }
152                     bufferStrategy = canvas.getBufferStrategy();
153                 }
154                 if (g2d!=null && bufferStrategy.contentsLost()) {
155                     g2d.dispose();
156                     g2d = null;
157                 }
158                 if (g2d==null)
159                     g2d = (Graphics2D) bufferStrategy.getDrawGraphics();
160                 paintCanvas(g2d);
161                 bufferStrategy.show();
162             }
163
164             @Override
165             public void update(Graphics g) {
166                 paint(g);
167             }
168         };
169
170
171         // Esc listener
172         canvas.addKeyListener(escapeListener);
173         frame.addKeyListener(escapeListener);
174
175         //monitor.setFullScreenWindow(frame);
176
177         frame.add(canvas);
178
179         frame.invalidate();
180         java.awt.Rectangle awtBounds         = monitor.getDefaultConfiguration().getBounds();
181         frame.setBounds(awtBounds);
182         frame.setAlwaysOnTop(true);
183         frame.setVisible(true);
184
185
186     }
187
188     @Override
189     public void setCanvasContext(ICanvasContext canvasContext) {
190         super.setCanvasContext(canvasContext);
191
192         // quality interactor
193         RenderingQualityInteractor rq = new RenderingQualityInteractor();
194         canvasContext.add(rq);
195
196         // Set bridge for mouse cursor changing
197         IMouseCursorContext mctx = canvasContext.getMouseCursorContext();
198         mctx.addCursorListener(new IMouseCursorListener() {
199             @Override
200             public void onCursorSet(IMouseCursorContext sender, int mouseId, Cursor cursor) {
201                 if (mouseId!=0) return;
202                 canvas.setCursor(cursor);
203             }}, AWTThread.getThreadAccess());
204
205
206         // drop interactor
207         assert(canvasContext.getAtMostOneItemOfClass(DropInteractor.class)==null);
208         canvasContext.add( new DropInteractor(canvas) );
209
210         // Drag interactor
211         assert(canvasContext.getAtMostOneItemOfClass(DragInteractor.class)==null);
212         canvasContext.add( new DragInteractor(canvas) );
213
214         // Delegate events to the canvas context
215         mouseAdapter = new AWTMouseEventAdapter(canvasContext, canvasContext.getEventQueue());
216         keyAdapter = new AWTKeyEventAdapter(canvasContext, canvasContext.getEventQueue());
217         focusAdapter = new AWTFocusAdapter(canvasContext, canvasContext.getEventQueue());
218         canvas.addMouseListener(mouseAdapter);
219         canvas.addMouseMotionListener(mouseAdapter);
220         canvas.addMouseWheelListener(mouseAdapter);
221         canvas.addKeyListener(keyAdapter);
222         canvas.addFocusListener(focusAdapter);
223
224         canvasContext.getContentContext().addPaintableContextListener(new IContentListener() {
225             @Override
226             public void onDirty(IContentContext sender) {
227                 if (dirty) return;
228                 dirty = true;
229                 redraw();
230             }}
231         );
232
233         redraw();
234     }
235
236     public void paintCanvas(Graphics2D g) {
237         if (canvasContext == null)
238             return;
239         if (canvasContext.isLocked())
240             return;
241
242         dirty = false;
243
244         // Paint the canvas
245         Rectangle2D bounds = new Rectangle2D.Double(0,0, frame.getSize().width, frame.getSize().height);
246         g.setRenderingHint(G2DRenderingHints.KEY_CONTROL_BOUNDS, bounds);
247         canvasContext.getSceneGraph().render(g);
248     }
249
250
251     private final static Method CLOSED_METHOD = SyncListenerList.getMethod(IChassisListener.class, "chassisClosed");
252
253     protected void fireChassisClosed() {
254         Executable e[] = listeners.getExecutables(CLOSED_METHOD, this);
255         ThreadUtils.multiSyncExec(e);
256     }
257
258     public GraphicsConfiguration getGraphicsConfiguration() {
259         return frame.getGraphicsConfiguration();
260     }
261
262     public Component getAwtComponent() {
263         return canvas;
264     }
265
266     public Frame getFrame() {
267         return frame;
268     }
269
270
271 }