Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/xerox/VTM/glyphs/VText.java


1   /*   FILE: VText.java
2    *   DATE OF CREATION:   Nov 23 2000
3    *   AUTHOR :            Emmanuel Pietriga (emmanuel.pietriga@xrce.xerox.com)
4    *   MODIF:              Thu Jul 10 17:11:40 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.glyphs;
21  
22  import java.awt.Color;
23  import java.awt.Graphics2D;
24  import java.awt.Stroke;
25  import java.awt.Font;
26  import java.awt.geom.AffineTransform;
27  import java.lang.Math;
28  import java.util.Vector;
29  import com.xerox.VTM.engine.*;
30  
31  /**
32   * Standalone Text  (font properties are set in the view, but can be changed for each VText using setSpecialFont())
33   * vx and vy are coordinates of lower-left corner of String because it would be too time-consuming to compute the String's center (needs to be computed at each repaint: it requires access to Graphics2D) (besides it makes the VTM unstable)
34   * @author Emmanuel Pietriga
35   */
36  
37  public class VText extends Glyph implements Cloneable {
38  
39      /**text alignment (for text anchor) used to align a VText relative to its (vx,vy coordinates coincides with start of String)*/
40      public static short TEXT_ANCHOR_START=0;
41      /**text alignment (for text anchor) used to align a VText relative to its (vx,vy coordinates coincides with middle of String)*/
42      public static short TEXT_ANCHOR_MIDDLE=1;
43      /**text alignment (for text anchor) used to align a VText relative to its (vx,vy coordinates coincides with end of String)*/
44      public static short TEXT_ANCHOR_END=2;
45  
46      private short text_anchor=TEXT_ANCHOR_START;
47  
48      AffineTransform at;
49  
50      ProjText[] pc;
51  
52      boolean zoomSensitive=true;
53  
54      public VText(String t){
55    vx=0;
56    vy=0;
57    vz=0;
58    sensit=false;
59    text=t;
60    setColor(Color.white);
61    setBorderColor(Color.black);
62      }
63  
64      /**
65       *@param x coordinate in virtual space
66       *@param y coordinate in virtual space
67       *@param z altitude
68       *@param c fill color
69       *@param t text string
70       */
71      public VText(long x,long y,float z,Color c,String t){
72    vx=x;
73    vy=y;
74    vz=z;
75    sensit=false;
76    text=t;
77    setColor(c);
78    setBorderColor(Color.black);
79      }
80  
81      /**
82       *@param x coordinate in virtual space
83       *@param y coordinate in virtual space
84       *@param z altitude
85       *@param c fill color
86       *@param t text string
87       *@param ta text-anchor (for alignment: one of TEXT_ANCHOR_*)
88       */
89      public VText(long x,long y,float z,Color c,String t,short ta){
90    vx=x;
91    vy=y;
92    vz=z;
93    sensit=false;
94    text=t;
95    setColor(c);
96    setBorderColor(Color.black);
97    text_anchor=ta;
98      }
99  
100     /**called when glyph is created in order to create the initial set of projected coordinates wrt the number of cameras in the space
101      *@param nbCam current number of cameras in the virtual space
102      */
103     public void initCams(int nbCam){
104   pc=new ProjText[nbCam];
105   for (int i=0;i<nbCam;i++){
106       pc[i]=new ProjText();
107   }
108     }
109 
110     /**used internally to create new projected coordinates to use with the new camera
111      *@param verifIndex camera index, just to be sure that the number of projected coordinates is consistent with the number of cameras
112      */
113     public void addCamera(int verifIndex){
114   if (pc!=null){
115       if (verifIndex==pc.length){
116     ProjText[] ta=pc;
117     pc=new ProjText[ta.length+1];
118     for (int i=0;i<ta.length;i++){
119         pc[i]=ta[i];
120     }
121     pc[pc.length-1]=new ProjText();
122       }
123       else {System.err.println("VText:Error while adding camera "+verifIndex);}
124   }
125   else {
126       if (verifIndex==0){
127     pc=new ProjText[1];
128     pc[0]=new ProjText();
129       }
130       else {System.err.println("VText:Error while adding camera "+verifIndex);}
131   }
132     }
133 
134     /**if a camera is removed from the virtual space, we should delete the corresponding projected coordinates, but do not modify the array it self because we do not want to change other cameras' index - just point to null*/
135     public void removeCamera(int index){
136   pc[index]=null;
137     }
138 
139     /**reset prevMouseIn for projected coordinates nb i*/
140     public void resetMouseIn(int i){
141   if (pc[i]!=null){pc[i].prevMouseIn=false;}
142     }
143 
144     /**set size (absolute) - has no effect*/
145     public void sizeTo(float factor){}
146 
147     /**set size (relative) - has no effect*/
148     public void reSize(float factor){}
149 
150     /**set size (absolute) - has no effect*/
151 //     public void sizeToNS(float factor){}
152 
153     /**set orientation (absolute) - has no effect*/
154     public void orientTo(float angle){}
155 
156     /**set orientation (absolute) - has no effect*/
157 //     public void orientToNS(float angle){}
158 
159     /**get size (always =1)*/
160     public float getSize(){return 1.0f;}
161 
162     /**get orientation*/
163     public float getOrient(){return orient;}
164 
165     /**if false, text size is not sensitive to zoom*/
166     public void setZoomSensitive(boolean b){
167   if (zoomSensitive!=b){
168       zoomSensitive=b;
169       try{vsm.repaintNow();}catch(NullPointerException e){/*System.err.println("VSM null in Glyph "+e);*/}
170   }
171     }
172 
173     /**if false, text size is not sensitive to zoom*/
174     public boolean isZoomSensitive(){
175   return zoomSensitive;
176     }
177 
178     /**used to find out if it is necessary to project and draw the glyph in the current view*/
179     public boolean drawMe(long w1,long h1,long w2,long h2,int i){//it should be the camera's index
180   if ((vx>=w2) && (vx<=w1) && (vy>=h2) && (vy<=h1)){ //if glyph hotspot is in the region, it is obviously visible
181       return true;
182   }
183   else {
184       if (text_anchor==TEXT_ANCHOR_START){
185     if ((vx<=w1) && ((vx+pc[i].cw)>=w2) && (vy<=h1) && ((vy+pc[i].ch)>=h2)){
186         //if glyph is at least partially in region  (we approximate using the glyph bounding circle, meaning that some
187         return true;  //glyphs not actually visible can be projected and drawn  (but they won't be displayed))
188     }
189     else return false;   //otherwise the glyph is not visible
190       }
191       else if (text_anchor==TEXT_ANCHOR_MIDDLE){
192     if ((vx-pc[i].cw/2<=w1) && ((vx+pc[i].cw/2)>=w2) && (vy<=h1) && ((vy+pc[i].ch)>=h2)){
193         //if glyph is at least partially in region  (we approximate using the glyph bounding circle, meaning that some
194         return true;  //glyphs not actually visible can be projected and drawn  (but they won't be displayed))
195     }
196     else return false;   //otherwise the glyph is not visible
197       }
198       else {//TEXT_ANCHOR_END
199     if ((vx-pc[i].cw<=w1) && (vx>=w2) && (vy<=h1) && ((vy+pc[i].ch)>=h2)){
200         //if glyph is at least partially in region  (we approximate using the glyph bounding circle, meaning that some
201         return true;  //glyphs not actually visible can be projected and drawn  (but they won't be displayed))
202     }
203     else return false;   //otherwise the glyph is not visible
204       }
205   }
206     }
207 
208     /**used to find out if glyph completely fills the view (in which case it is not necessary to repaint objects at a lower altitude)*/
209     public boolean fillsView(long w,long h,int camIndex){
210   return false;
211     }
212 
213     /**detects whether the given point is inside this glyph or not 
214      *@param x EXPECTS PROJECTED JPanel COORDINATE
215      *@param y EXPECTS PROJECTED JPanel COORDINATE
216      */
217     public boolean coordInside(int x,int y,int camIndex){
218   return false;
219     }
220 
221     /**returns 1 if mouse has entered the glyph, -1 if it has exited the glyph, 0 if nothing has changed (meaning it was already inside or outside it)*/
222     public int mouseInOut(int x,int y,int camIndex){
223   return 0;
224     }
225 
226     /**project shape in camera coord sys prior to actual painting*/
227     public void project(Camera c,ViewPanel v){
228   int i=c.getIndex();
229   coef=(float)(c.focal/(c.focal+c.altitude));
230   //find coordinates of object's geom center wrt to camera center and project
231   pc[i].cx=Math.round((vx-c.posx)*coef);
232   pc[i].cy=Math.round((vy-c.posy)*coef);
233   //translate in JPanel coords
234   pc[i].cx=(v.getSize().width/2)+pc[i].cx;
235   pc[i].cy=(v.getSize().height/2)-pc[i].cy;
236     }
237 
238     /**draw glyph 
239      *@param i camera index in the virtual space
240      */
241     public void draw(Graphics2D g,int vW,int vH,int i,Stroke stdS,AffineTransform stdT){
242   g.setColor(this.color);
243   if (coef*fontSize>vsm.getTextDisplayedAsSegCoef() || !zoomSensitive){//if this value is < to about 0.5, AffineTransform.scale does not work properly (anyway, font is too small to be readable)
244       if (font!=null){
245     g.setFont(font);
246     if (!pc[i].valid){
247         java.awt.geom.Rectangle2D r=g.getFontMetrics().getStringBounds(text,g);
248         pc[i].cw=(int)r.getWidth();
249         pc[i].ch=(int)r.getHeight();
250         pc[i].valid=true;
251     }
252     if (text_anchor==TEXT_ANCHOR_START){at=AffineTransform.getTranslateInstance(pc[i].cx,pc[i].cy);}
253     else if (text_anchor==TEXT_ANCHOR_MIDDLE){at=AffineTransform.getTranslateInstance(pc[i].cx-pc[i].cw*coef/2,pc[i].cy);}
254     else {at=AffineTransform.getTranslateInstance(pc[i].cx-pc[i].cw*coef,pc[i].cy);}
255     if (zoomSensitive){at.concatenate(AffineTransform.getScaleInstance(coef,coef));}
256     g.setTransform(at);
257     try {g.drawString(text,0.0f,0.0f);}
258     catch (NullPointerException ex){/*text could be null*/}
259     g.setFont(VirtualSpaceManager.getMainFont());
260       }
261       else {
262     if (!pc[i].valid){
263         java.awt.geom.Rectangle2D r=g.getFontMetrics().getStringBounds(text,g);
264         pc[i].cw=(int)r.getWidth();
265         pc[i].ch=(int)r.getHeight();
266         pc[i].valid=true;
267     }
268     if (text_anchor==TEXT_ANCHOR_START){at=AffineTransform.getTranslateInstance(pc[i].cx,pc[i].cy);}
269     else if (text_anchor==TEXT_ANCHOR_MIDDLE){at=AffineTransform.getTranslateInstance(pc[i].cx-pc[i].cw*coef/2,pc[i].cy);}
270     else {at=AffineTransform.getTranslateInstance(pc[i].cx-pc[i].cw*coef,pc[i].cy);}
271     if (zoomSensitive){at.concatenate(AffineTransform.getScaleInstance(coef,coef));}
272     g.setTransform(at);
273     try {g.drawString(text,0.0f,0.0f);}
274     catch(NullPointerException ex){/*text could be null*/}
275       }
276       g.setTransform(stdT);
277   }
278   else {
279       g.fillRect(pc[i].cx,pc[i].cy,1,1);
280   }
281     }
282 
283     /**set text that should be painted with this glyph - override Glyph method to call invalidate*/
284     public void setText(String t){
285   super.setText(t);
286   invalidate();
287     }
288 
289     /**force computing of text's bounding box at next paint call*/
290     public void invalidate(){
291   try {for (int i=0;i<pc.length;i++){pc[i].valid=false;}}
292   catch (NullPointerException ex){}
293     }
294 
295     /**returns width and height of the bounding box as a Point (so this is not a real Point)
296      *@param i index of camera (Camera.getIndex())
297      */
298     public LongPoint getBounds(int i){
299   return new LongPoint(pc[i].cw,pc[i].ch);
300     }
301 
302     /**tells whether the bounds of the text are valid at this time or not (can be invalid if the thread in charge of painting has not dealt with this glyph since invalidate() was called on it) - might be useful to test this before calling getBounds()*/
303     public boolean validBounds(int i){
304   return pc[i].valid;
305     }
306 
307     /**change font for this specific text object - f=null to get back to default font*/
308     public void setSpecialFont(Font f){
309   super.setSpecialFont(f);
310   invalidate();
311     }
312 
313 
314     /** Set the text anchor
315      *@param ta one of TEXT_ANCHOR_START, TEXT_ANCHOR_MIDDLE, TEXT_ANCHOR_END
316      */
317     public void setTextAnchor(short ta){
318   text_anchor=ta;
319     }
320 
321     /**
322      *get text anchor (one of TEXT_ANCHOR_START, TEXT_ANCHOR_MIDDLE, TEXT_ANCHOR_END)
323      */
324     public short getTextAnchor(){
325   return text_anchor;
326     }
327 
328     /**returns a clone of this object (only basic information is cloned for now: shape, orientation, position, size)*/
329     public Object clone(){
330   VText res=new VText(vx,vy,0,color,(new StringBuffer(text)).toString(),text_anchor);
331   res.borderColor=this.borderColor;
332   res.selectedColor=this.selectedColor;
333   res.mouseInsideColor=this.mouseInsideColor;
334   res.bColor=this.bColor;
335   return res;
336     }
337 
338 }