001package com.hfg.svg;
002
003import com.hfg.css.CSS;
004import com.hfg.css.CSSProperty;
005import com.hfg.graphics.Graphics2DState;
006import com.hfg.graphics.units.GfxUnits;
007import com.hfg.graphics.units.Points;
008import com.hfg.graphics.ColorUtil;
009import com.hfg.graphics.TextUtil;
010import com.hfg.util.StringUtil;
011import com.hfg.xml.XMLTag;
012
013import java.awt.*;
014import java.awt.geom.Point2D;
015import java.awt.geom.Rectangle2D;
016
017//------------------------------------------------------------------------------
018/**
019 * Object representation of an SVG (Scalable Vector Graphics) text tag.
020 *
021 * @author J. Alex Taylor, hairyfatguy.com
022 */
023//------------------------------------------------------------------------------
024// com.hfg XML/HTML Coding Library
025//
026// This library is free software; you can redistribute it and/or
027// modify it under the terms of the GNU Lesser General Public
028// License as published by the Free Software Foundation; either
029// version 2.1 of the License, or (at your option) any later version.
030//
031// This library is distributed in the hope that it will be useful,
032// but WITHOUT ANY WARRANTY; without even the implied warranty of
033// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
034// Lesser General Public License for more details.
035//
036// You should have received a copy of the GNU Lesser General Public
037// License along with this library; if not, write to the Free Software
038// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
039//
040// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
041// jataylor@hairyfatguy.com
042//------------------------------------------------------------------------------
043
044public class SvgText extends AbstractSvgNode implements SvgNode
045{
046   private Font mFont;
047   
048   //**************************************************************************
049   // CONSTRUCTORS
050   //**************************************************************************
051
052   //---------------------------------------------------------------------------
053   public SvgText()
054   {
055      super(SVG.text);
056//      setFont(sDefaultFont);
057   }
058
059   //---------------------------------------------------------------------------
060   public SvgText(String inText)
061   {
062      this();
063      setContent(inText);
064   }
065
066   //---------------------------------------------------------------------------
067   public SvgText(String inText, Font inFont, Point2D inLocation)
068   {
069      this(inText);
070      setFont(inFont);
071
072      double x = inLocation.getX();
073      double y = inLocation.getY();
074
075      setAttribute(SvgAttr.x, (Math.floor(x) == x ? (int) x : String.format("%.3f", inLocation.getX())));
076      setAttribute(SvgAttr.y, (Math.floor(y) == y ? (int) y : String.format("%.3f", inLocation.getY())));
077   }
078
079   //---------------------------------------------------------------------------
080   public SvgText(XMLTag inXMLTag)
081   {
082      this();
083      initFromXMLTag(inXMLTag);
084   }
085
086   //**************************************************************************
087   // PUBLIC METHODS
088   //**************************************************************************
089
090   //---------------------------------------------------------------------------
091   public SvgText setX(int inValue)
092   {
093      setAttribute(SvgAttr.x, inValue);
094      return this;
095   }
096
097   //---------------------------------------------------------------------------
098   public SvgText setX(float inValue)
099   {
100      setAttribute(SvgAttr.x, inValue);
101      return this;
102   }
103
104   //---------------------------------------------------------------------------
105   public Float getX()
106   {
107      String xAttr = getAttributeValue(SvgAttr.x);
108      return (StringUtil.isSet(xAttr) ? Float.parseFloat(xAttr) : null);
109   }
110
111
112   //---------------------------------------------------------------------------
113   public SvgText setY(int inValue)
114   {
115      setAttribute(SvgAttr.y, inValue);
116      return this;
117   }
118
119   //---------------------------------------------------------------------------
120   public SvgText setY(float inValue)
121   {
122      setAttribute(SvgAttr.y, inValue);
123      return this;
124   }
125
126   //---------------------------------------------------------------------------
127   public Float getY()
128   {
129      String yAttr = getAttributeValue(SvgAttr.y);
130      return (StringUtil.isSet(yAttr) ? Float.parseFloat(yAttr) : null);
131   }
132
133
134   //---------------------------------------------------------------------------
135   /**
136    * Sets a relative (delta) X coordinate adjustment to the text position.
137    * Can be absolute (in, cm, mm, pt, pc) or relative (em, ex, px) lengths.
138    * @param inValue a relative X coordinate adjustment to the text position
139    * @return this text object to allow for method chaining
140    */
141   public SvgText setDx(String inValue)
142   {
143      setAttribute(SvgAttr.dx, inValue);
144      return this;
145   }
146
147   //---------------------------------------------------------------------------
148   public String getDx()
149   {
150      return getAttributeValue(SvgAttr.dx);
151   }
152
153
154   //---------------------------------------------------------------------------
155   /**
156    * Sets a relative (delta) Y coordinate adjustment to the text position.
157    * Can be absolute (in, cm, mm, pt, pc) or relative (em, ex, px) lengths.
158    * @param inValue a relative Y coordinate adjustment to the text position
159    * @return this text object to allow for method chaining
160    */
161   public SvgText setDy(String inValue)
162   {
163      setAttribute(SvgAttr.dy, inValue);
164      return this;
165   }
166
167   //---------------------------------------------------------------------------
168   public String getDy()
169   {
170      return getAttributeValue(SvgAttr.dy);
171   }
172
173   
174   //---------------------------------------------------------------------------
175   public int getWidth()
176   {
177      return (int) Float.parseFloat(getAttributeValue(SvgAttr.width));
178   }
179
180   //---------------------------------------------------------------------------
181   public int getHeight()
182   {
183      return (int) Float.parseFloat(getAttributeValue(SvgAttr.height));
184   }
185
186   //---------------------------------------------------------------------------
187   public SvgText setFill(Color inColor)
188   {
189      setAttribute(SvgAttr.fill, "#" + ColorUtil.colorToHex(inColor));
190      return this;
191   }
192
193   //---------------------------------------------------------------------------
194   public SvgText setFont(Font inValue)
195   {
196      if (inValue != null)
197      {
198         // TODO: Remove existing style fields relating to the font.
199
200         mFont = inValue;
201         addStyle(CSSProperty.font_family.name() + ":" + mFont.getName());
202         addStyle(CSSProperty.font_size.name() + ":" + new Points(mFont.getSize2D()).to(GfxUnits.pixels) + "px");
203         if (mFont.isBold())
204         {
205            addStyle(CSS.BOLD);
206         }
207
208         if (mFont.isItalic())
209         {
210            addStyle(CSS.ITALIC);
211         }
212      }
213
214      return this;
215   }
216
217   //---------------------------------------------------------------------------
218   @Override
219   public SvgText setFilter(String inValue)
220   {
221      return (SvgText) super.setFilter(inValue);
222   }
223
224   //---------------------------------------------------------------------------
225   public SvgText setTitle(String inValue)
226   {
227      setAttribute(SvgAttr.title, inValue);
228      return this;
229   }
230
231   //---------------------------------------------------------------------------
232   @Override
233   public SvgText setClass(String inValue)
234   {
235      return (SvgText) super.setClass(inValue);
236   }
237
238   //---------------------------------------------------------------------------
239   @Override
240   public SvgText setId(String inValue)
241   {
242      return (SvgText) super.setId(inValue);
243   }
244
245   //--------------------------------------------------------------------------
246   @Override
247   public SvgText addStyle(String inValue)
248   {
249      return (SvgText) super.addStyle(inValue);
250   }
251
252   //---------------------------------------------------------------------------
253   @Override
254   public SvgText setStyle(String inValue)
255   {
256      return (SvgText) super.setStyle(inValue);
257   }
258
259   //---------------------------------------------------------------------------
260   @Override
261   public SvgText setTransform(String inValue)
262   {
263      return (SvgText) super.setTransform(inValue);
264   }
265
266   //---------------------------------------------------------------------------
267   @Override
268   public SvgText setAttribute(String inName, Object inValue)
269   {
270      return (SvgText) super.setAttribute(inName, inValue);
271   }
272
273   //---------------------------------------------------------------------------
274   public SvgTSpan addTSpan()
275   {
276      SvgTSpan tSpan = new SvgTSpan();
277      addSubtag(tSpan);
278      
279      return tSpan;
280   }
281
282   //---------------------------------------------------------------------------
283   public SvgTSpan addTSpan(CharSequence inTitle)
284   {
285      SvgTSpan tSpan = new SvgTSpan(inTitle);
286      addSubtag(tSpan);
287      
288      return tSpan;
289   }
290   
291   //---------------------------------------------------------------------------
292   @Override
293   public Rectangle getBoundsBox()
294   {
295      float x = (getX() != null ? getX() : 0);
296      float y = (getAttributeValue(SvgAttr.y) != null ?  Float.parseFloat(getAttributeValue(SvgAttr.y)) : 0);
297
298      Rectangle textBounds = (mFont != null ? TextUtil.getStringRect(getContent(), mFont) : new Rectangle(0, 0, 0, 0));
299
300      Rectangle boundsBox = new Rectangle2D.Float(x, y - textBounds.height, textBounds.width, textBounds.height).getBounds();
301      adjustBoundsForTransform(boundsBox);
302
303      return boundsBox;
304   }
305
306   //--------------------------------------------------------------------------
307   @Override
308   public void draw(Graphics2D g2)
309   {
310      // Save settings
311      Graphics2DState origState = new Graphics2DState(g2);
312
313      Paint paint   = getG2Paint();
314      if (paint != null) g2.setPaint(paint);
315
316      if (mFont != null)
317      {
318         g2.setFont(mFont);
319      }
320      else
321      {
322         Font locallyAdjustedFont = getAdjustedFont(origState.getFont());
323         if (locallyAdjustedFont != null)
324         {
325            g2.setFont(locallyAdjustedFont);
326         }
327      }
328
329      applyTransforms(g2);
330
331      float x = (getX() != null ? getX() : 0);
332      float y = (getY() != null ? getY() : 0);
333
334      g2.drawString(getContent(), x, y);
335
336      // Restore settings
337      origState.applyTo(g2);
338   }
339
340}