Source code: com/xerox/VTM/engine/StdViewPanel.java
1 /* FILE: StdViewPanel.java
2 * DATE OF CREATION: Jul 11 2000
3 * AUTHOR : Emmanuel Pietriga (emmanuel.pietriga@xrce.xerox.com)
4 * MODIF: Tue Aug 05 14:54:52 2003 by Emmanuel Pietriga (emmanuel@w3.org, emmanuel@claribole.net)
5 * Copyright (c) Xerox Corporation, XRCE/Contextual Computing, 2002. All Rights Reserved
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * For full terms see the file COPYING.
18 */
19
20 package com.xerox.VTM.engine;
21
22 import com.xerox.VTM.glyphs.*;
23 import javax.swing.*;
24 import java.awt.*;
25 import java.awt.geom.*;
26 import java.awt.image.*;
27 import java.awt.event.*;
28 import java.util.Vector;
29 import java.util.Date;
30 import java.util.Enumeration;
31
32 /**
33 * Each view runs in its own thread - uses double buffering
34 * @author Emmanuel Pietriga
35 */
36 public class StdViewPanel extends ViewPanel implements Runnable {
37
38 /**for Double Buffering*/
39 BufferedImage buffImg;
40
41 //get the BufferedImage or VolatileImage for this view
42 protected BufferedImage getImage(){
43 return this.buffImg;
44 }
45
46 public StdViewPanel(Vector cameras,View v) {
47 addHierarchyListener(
48 new HierarchyListener() {
49 public void hierarchyChanged(HierarchyEvent e) {
50 if (isShowing()) {
51 start();
52 } else {
53 stop();
54 }
55 }
56 }
57 );
58 parent=v;
59 //init of camera array
60 cams=new Camera[cameras.size()]; //array of Camera
61 for (int nbcam=0;nbcam<cameras.size();nbcam++){
62 cams[nbcam]=(Camera)(cameras.get(nbcam));
63 }
64 //init other stuff
65 setBackground(Color.lightGray);
66 this.addMouseListener(this);
67 this.addMouseMotionListener(this);
68 start();
69 // for (int i=0;i<cams.length;i++){
70 // System.out.println(cams[i].toString());
71 // }
72 // BufferedImage cImage=new BufferedImage(1,1,BufferedImage.TYPE_INT_ARGB); //create a BufferedImage with transparent background
73 // try {//this buffer represents the mouse cursor shape (it does not appear since it is transparent)
74 // awtCursor=Toolkit.getDefaultToolkit().createCustomCursor(cImage,new Point(0,0),"myCursor");
75 // this.setCursor(awtCursor);
76 // }
77 // catch(IndexOutOfBoundsException e){if (parent.parent.debug){System.err.println("Error while creating custom cursor "+e);setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));}}
78 setAWTCursor(Cursor.CUSTOM_CURSOR); //custom cursor means VTM cursor
79 if (parent.parent.debug){System.out.println("View refresh time set to "+frameTime+"ms");}
80 }
81
82 public void start(){
83 Dimension size = getSize();
84 runView = new Thread(this);
85 runView.setPriority(Thread.NORM_PRIORITY);
86 runView.start();
87 }
88
89 public synchronized void stop() {
90 runView = null;
91 notify();
92 }
93
94 public void run() {
95 Thread me = Thread.currentThread();
96 while (getSize().width <= 0) { //Wait until the window actually exists
97 try {
98 runView.sleep(500);
99 }
100 catch (InterruptedException e) {
101 if (parent.parent.debug){System.err.println("viewpanel.run.runview.sleep "+e);}
102 return;
103 }
104 }
105 Graphics2D g2d = null;
106 Graphics2D BufferG2D = null;
107 Dimension oldSize=getSize();
108 //clipRect=new Rectangle(0,0,oldSize.width,oldSize.height);
109 while (runView==me) {
110 if (notBlank){
111 if (active){
112 if (repaintNow){
113 try {
114 repaintNow=false;//do this first as the thread can be interrupted inside this branch and we want to catch new requests for repaint
115 updateMouseOnly=false;
116 d1=System.currentTimeMillis();
117 Dimension size=getSize();
118 if (size.width != oldSize.width || size.height != oldSize.height) {
119 //each time the parent window is resized, adapt the buffer image size
120 buffImg=null;
121 if (BufferG2D!=null) {
122 BufferG2D.dispose();
123 BufferG2D=null;
124 }
125 //clipRect=new Rectangle(0,0,size.width,size.height);
126 if (parent.parent.debug){System.out.println("Resizing JPanel: ("+oldSize.width+"x"+oldSize.height+") -> ("+size.width+"x"+size.height+")");}
127 oldSize=size;
128 updateAntialias=true;
129 updateFont=true;
130 }
131 if (buffImg==null) {
132 buffImg=(BufferedImage) createImage(size.width,size.height);
133 updateAntialias=true;
134 updateFont=true;
135 }
136 if (BufferG2D == null) {
137 BufferG2D = buffImg.createGraphics();
138 updateAntialias=true;
139 updateFont=true;
140 }
141 if (updateFont){BufferG2D.setFont(VirtualSpaceManager.mainFont);updateFont=false;}
142 if (updateAntialias){if (antialias){BufferG2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);} else {BufferG2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);}updateAntialias=false;}
143 g2d = BufferG2D;
144 standardStroke=g2d.getStroke();
145 standardTransform=g2d.getTransform();
146 //parent.parent.constMgr.updateAttribsFromMvars();
147 synchronized(this){
148 g2d.setPaintMode();
149 g2d.setBackground(backColor);
150 g2d.clearRect(0,0,getWidth(),getHeight());
151 //begin actual drawing here
152 for (int nbcam=0;nbcam<cams.length;nbcam++){
153 if ((cams[nbcam]!=null) && (cams[nbcam].enabled) && ((cams[nbcam].eager) || (cams[nbcam].shouldRepaint()))){
154 camIndex=cams[nbcam].getIndex();
155 drawnGlyphs=cams[nbcam].parentSpace.getDrawnGlyphs(camIndex);
156 //synchronized(cams[nbcam].parentSpace.getDrawnGlyphs(camIndex)){
157 synchronized(drawnGlyphs){
158 //cams[nbcam].parentSpace.getDrawnGlyphs(camIndex).removeAllElements();
159 drawnGlyphs.removeAllElements();
160 uncoef=(float)((cams[nbcam].focal+cams[nbcam].altitude)/cams[nbcam].focal);
161 viewW=this.getSize().width;//compute region's width and height
162 viewH=this.getSize().height;
163 viewWHu=(long)(cams[nbcam].posx+this.getSize().width/2*uncoef);//compute region seen from this view
164 viewHHu=(long)(cams[nbcam].posy+this.getSize().height/2*uncoef);//through camera
165 viewWLu=(long)(cams[nbcam].posx-this.getSize().width/2*uncoef);
166 viewHLu=(long)(cams[nbcam].posy-this.getSize().height/2*uncoef);
167 if (parent.detectMultipleFullFills){//if detect multiple fills option is ON
168 for (Enumeration en=cams[nbcam].parentSpace.getVisibleGlyphs().elements();en.hasMoreElements();){
169 gl=(Glyph)(en.nextElement());
170 if (gl.drawMe(viewWHu,viewHHu,viewWLu,viewHLu,camIndex)){
171 cams[nbcam].parentSpace.drewGlyph(gl,camIndex);
172 gl.project(cams[nbcam],this);
173 }
174 }
175 //drawnGlyphs=cams[nbcam].parentSpace.getDrawnGlyphs(camIndex);
176 beginAt=0;
177 for (int j=drawnGlyphs.size()-1;j>=0;j--){//glyphs must have been projected because fillsView uses
178 if (((Glyph)drawnGlyphs.elementAt(j)).fillsView(viewW,viewH,cams[nbcam].getIndex())){//projected coords
179 beginAt=j;
180 break;
181 }
182 }
183 for (int j=beginAt;j<drawnGlyphs.size();j++){
184 gl=(Glyph)drawnGlyphs.elementAt(j);
185 if (gl.isVisible()){
186 gl.draw(g2d,size.width,size.height,cams[nbcam].getIndex(),standardStroke,standardTransform);
187 }
188 }
189 }
190 else {//if detect multiple fills option is OFF
191 for (Enumeration en=cams[nbcam].parentSpace.getVisibleGlyphs().elements();en.hasMoreElements();){
192 gl=(Glyph)(en.nextElement());
193 if (gl.drawMe(viewWHu,viewHHu,viewWLu,viewHLu,camIndex)){
194 //if glyph is at least partially visible in the reg. seen from this view, display
195 synchronized(gl){
196 gl.project(cams[nbcam],this);
197 if (gl.isVisible()){
198 gl.draw(g2d,size.width,size.height,cams[nbcam].getIndex(),standardStroke,standardTransform);
199 cams[nbcam].parentSpace.drewGlyph(gl,camIndex);
200 }
201 }
202 }
203 }
204 }
205 }
206 }
207 }
208 if (inside){//deal with mouse glyph only if mouse cursor is inside this window
209 try {
210 parent.mouse.unProject(cams[activeLayer],this); //we project the mouse cursor wrt the appropriate coord sys
211 if (computeListAtEachRepaint && parent.mouse.isSensitive()){
212 parent.mouse.computeMouseOverList(evH,cams[activeLayer]);
213 }
214 }
215 catch (NullPointerException ex) {if (parent.parent.debug){System.err.println("viewpanel.run.drawdrag "+ex);}}
216 g2d.setColor(parent.mouse.color);
217 if (drawDrag){g2d.drawLine(origDragx,origDragy,parent.mouse.mx,parent.mouse.my);}
218 if (drawRect){g2d.drawRect(Math.min(origDragx,parent.mouse.mx),Math.min(origDragy,parent.mouse.my),Math.max(origDragx,parent.mouse.mx)-Math.min(origDragx,parent.mouse.mx),Math.max(origDragy,parent.mouse.my)-Math.min(origDragy,parent.mouse.my));}
219 if (drawOval){
220 if (circleOnly){
221 g2d.drawOval(origDragx-Math.abs(origDragx-parent.mouse.mx),origDragy-Math.abs(origDragx-parent.mouse.mx),2*Math.abs(origDragx-parent.mouse.mx),2*Math.abs(origDragx-parent.mouse.mx));
222 }
223 else {
224 g2d.drawOval(origDragx-Math.abs(origDragx-parent.mouse.mx),origDragy-Math.abs(origDragy-parent.mouse.my),2*Math.abs(origDragx-parent.mouse.mx),2*Math.abs(origDragy-parent.mouse.my));
225 }
226 }
227 if (drawVTMcursor){
228 synchronized(this){
229 g2d.setXORMode(backColor);
230 parent.mouse.draw(g2d);
231 oldX=parent.mouse.mx;
232 oldY=parent.mouse.my;
233 }
234 }
235 }
236 //end drawing here
237 if (g2d == BufferG2D) {
238 repaint();
239 }
240 d2=System.currentTimeMillis();
241 timeToSleep=frameTime-d2+d1; //40-(d2-d1) = wanted refresh rate - time needed to do the actual repaint operations
242 }
243 }
244 catch (NullPointerException ex0){if (parent.parent.debug){System.err.println("viewpanel.run (probably due to buffImg.createGraphics()) "+ex0);}}
245 //either we do - BETTER UNDER Win32
246 try {
247 //if (waitingForCapture){runView.yield();}
248 //else {runView.sleep((timeToSleep>10) ? timeToSleep : 10);} //sleep ... ms
249 runView.sleep((timeToSleep>10) ? timeToSleep : 10);
250 }
251 catch (InterruptedException e) {
252 if (parent.parent.debug){System.err.println("viewpanel.run.runview.sleep2 "+e);}
253 return;
254 }
255 //or this both seem to work well (have to test on several config) - BETTER UNDER SOLARIS
256 //Thread.yield();
257 }
258 else if (updateMouseOnly){
259 updateMouseOnly=false;//do this first as the thread can be interrupted inside this branch and we want to catch new requests for repaint
260 d1=System.currentTimeMillis();
261 try {
262 parent.mouse.unProject(cams[activeLayer],this); //we project the mouse cursor wrt the appropriate coord sys
263 if (computeListAtEachRepaint && parent.mouse.isSensitive()){parent.mouse.computeMouseOverList(evH,cams[activeLayer]);}
264 }
265 catch (NullPointerException ex) {if (parent.parent.debug){System.err.println("viewpanel.run.drawdrag "+ex);}}
266 if (drawVTMcursor){
267 synchronized(this){
268 try {
269 g2d.setXORMode(backColor);
270 g2d.setColor(parent.mouse.color);
271 g2d.drawLine(oldX-10,oldY,oldX+10,oldY);
272 g2d.drawLine(oldX,oldY-10,oldX,oldY+10);
273 g2d.drawLine(parent.mouse.mx-10,parent.mouse.my,parent.mouse.mx+10,parent.mouse.my);
274 g2d.drawLine(parent.mouse.mx,parent.mouse.my-10,parent.mouse.mx,parent.mouse.my+10);
275 oldX=parent.mouse.mx;
276 oldY=parent.mouse.my;
277 }//a nullpointerex on g2d seems to occur from time to time when going in or exiting from blank mode - just catch it and wait for next loop until we find out what's causing this
278 catch (NullPointerException ex47){if (parent.parent.debug){System.err.println("viewpanel.run.runview.drawVTMcursor "+ex47);}}
279 }
280 }
281 repaint();
282 d2=System.currentTimeMillis();
283 timeToSleep=frameTime-d2+d1; //40-(d2-d1) = wanted refresh rate - time needed to do the actual repaint operations
284 try {
285 //if (waitingForCapture){runView.yield();}
286 //else {runView.sleep((timeToSleep>10) ? timeToSleep : 10);} //sleep ... ms
287 runView.sleep((timeToSleep>10) ? timeToSleep : 10);
288 }
289 catch (InterruptedException e) {
290 if (parent.parent.debug){System.err.println("viewpanel.run.runview.sleep3 "+e);}
291 return;
292 }
293 }
294 else {
295 try {
296 runView.sleep(frameTime+20); //sleep ... ms
297 }
298 catch (InterruptedException e) {
299 if (parent.parent.debug){System.err.println("viewpanel.run.runview.sleep4 "+e);}
300 return;
301 }
302 }
303 }
304 else {
305 try {
306 runView.sleep(deactiveTime); //sleep ... ms
307 }
308 catch (InterruptedException e) {
309 if (parent.parent.debug){System.err.println("viewpanel.run.runview.sleep5 "+e);}
310 return;
311 }
312 }
313 }
314 else {
315 Dimension size=getSize();
316 if (size.width != oldSize.width || size.height != oldSize.height) {
317 //each time the parent window is resized, adapt the buffer image size
318 buffImg=null;
319 if (BufferG2D!=null) {
320 BufferG2D.dispose();
321 BufferG2D=null;
322 }
323 if (parent.parent.debug){System.out.println("Resizing JPanel in blank mode: ("+oldSize.width+"x"+oldSize.height+") -> ("+size.width+"x"+size.height+")");}
324 oldSize=size;
325 updateAntialias=true;
326 updateFont=true;
327 }
328 if (buffImg==null) {
329 buffImg=(BufferedImage) createImage(size.width,size.height);
330 updateAntialias=true;
331 updateFont=true;
332 }
333 if (BufferG2D == null) {
334 BufferG2D = buffImg.createGraphics();
335 updateAntialias=true;
336 updateFont=true;
337 }
338 if (updateFont){BufferG2D.setFont(VirtualSpaceManager.mainFont);updateFont=false;}
339 if (updateAntialias){if (antialias){BufferG2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);} else {BufferG2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);}updateAntialias=false;}
340 g2d = BufferG2D;
341 standardStroke=g2d.getStroke();
342 standardTransform=g2d.getTransform();
343 g2d.setPaintMode();
344 g2d.setColor(blankColor);
345 g2d.fillRect(0,0,getWidth(),getHeight());
346 repaint();
347 try {
348 runView.sleep(deactiveTime); //sleep ... ms
349 }
350 catch (InterruptedException e) {
351 if (parent.parent.debug){System.err.println("viewpanel.run.runview.sleep5 "+e);}
352 return;
353 }
354 }
355 }
356 if (g2d != null) {
357 g2d.dispose();
358 }
359 }
360
361 public void paint(Graphics g) {
362 synchronized (this) {
363 g2 = (Graphics2D) g;
364 if (buffImg != null) {
365 g2.drawImage(buffImg, null, 0, 0);
366 }
367 }
368 }
369
370 }