~ubuntu-branches/ubuntu/precise/ipe/precise

« back to all changes in this revision

Viewing changes to src/ipelib/ipetext.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Steve M. Robbins
  • Date: 2004-06-08 00:44:02 UTC
  • Revision ID: james.westby@ubuntu.com-20040608004402-72yu51xlh7vt6p9m
Tags: upstream-6.0pre16
ImportĀ upstreamĀ versionĀ 6.0pre16

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// --------------------------------------------------------------------
 
2
// The Text object.
 
3
// --------------------------------------------------------------------
 
4
/*
 
5
 
 
6
    This file is part of the extensible drawing editor Ipe.
 
7
    Copyright (C) 1993-2004  Otfried Cheong
 
8
 
 
9
    Ipe is free software; you can redistribute it and/or modify it
 
10
    under the terms of the GNU General Public License as published by
 
11
    the Free Software Foundation; either version 2 of the License, or
 
12
    (at your option) any later version.
 
13
 
 
14
    As a special exception, you have permission to link Ipe with the
 
15
    CGAL library and distribute executables, as long as you follow the
 
16
    requirements of the Gnu General Public License in regard to all of
 
17
    the software in the executable aside from CGAL.
 
18
 
 
19
    Ipe is distributed in the hope that it will be useful, but WITHOUT
 
20
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
21
    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 
22
    License for more details.
 
23
 
 
24
    You should have received a copy of the GNU General Public License
 
25
    along with Ipe; if not, you can find it at
 
26
    "http://www.gnu.org/copyleft/gpl.html", or write to the Free
 
27
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
28
 
 
29
*/
 
30
 
 
31
#include "ipetext.h"
 
32
#include "ipevisitor.h"
 
33
#include "ipepainter.h"
 
34
 
 
35
/*! \class IpeText
 
36
  \ingroup obj
 
37
  \brief The text object.
 
38
 
 
39
  The text object is a tricky Ipe object.  It has a Latex-source
 
40
  representation, which needs to be translated into PDF by Pdflatex
 
41
  before it can be saved as PDF.
 
42
 
 
43
  There are two main types of text objects, labels and minipages.  The
 
44
  IsMiniPage() method tells you which.  The title and textbox types
 
45
  are variations on these that indicate the function of the text
 
46
  object in a document---that is useful to reposition text objects
 
47
  after the style sheet has been changed.  Use Type() to determine the
 
48
  precise type of a text object.
 
49
 
 
50
  The dimensions of a text object are given by Width(), Height(), and
 
51
  Depth().  They are recomputed by Ipe when running LaTeX, with the
 
52
  exception of the width for minipage objects (whose width is fixed).
 
53
  Before Latex has been run, the dimensions are not reliable.
 
54
 
 
55
  The position of the reference point relative to the text box is
 
56
  given by VerticalAlignment() and HorizontalAlignment().
 
57
 
 
58
  Text can be either transformable, or fixed.  In the first case, the
 
59
  Matrix() is applied to the complete text box, in the second case,
 
60
  the Matrix() is only applied to the reference point Position(), and
 
61
  the text box remains fixed relative to the reference point.
 
62
 
 
63
  The Text() must be a legal LaTeX fragment that can be interpreted by
 
64
  LaTeX inside \hbox, possibly using the macros or packages defined in
 
65
  the preamble.
 
66
*/
 
67
 
 
68
//! Create from XML stream.
 
69
IpeText::IpeText(IpeRepository *rep, const IpeXmlAttributes &attr,
 
70
                 IpeString data)
 
71
  : IpeObject(rep, attr)
 
72
{
 
73
  iXForm = 0;
 
74
  iText = data;
 
75
  iSize = rep->MakeScalar(IpeAttribute::ETextSize, attr["size"]);
 
76
  // parse position
 
77
  IpeLex st(attr["pos"]);
 
78
  st >> iPos.iX >> iPos.iY;
 
79
 
 
80
  iTransformable = false;
 
81
  IpeString str;
 
82
  if (attr.Has("transformable", str) && str == "yes")
 
83
    iTransformable = true;
 
84
 
 
85
  iType = ELabel;
 
86
  bool hasType = attr.Has("type", str);
 
87
  if (hasType) {
 
88
    if (str == "minipage")
 
89
      iType = EMinipage;
 
90
    else if (str == "title")
 
91
      iType = ETitle;
 
92
    else if (str == "textbox")
 
93
      iType = ETextbox;
 
94
  }
 
95
 
 
96
  iWidth = 10.0;
 
97
  if (attr.Has("width", str)) {
 
98
    iWidth = IpeLex(str).GetDouble();
 
99
    if (!hasType)
 
100
      iType = EMinipage;
 
101
  }
 
102
 
 
103
#if 1
 
104
  // obsolete - remove later
 
105
  if (attr.Has("textstretch", str)) {
 
106
    iWidth *= IpeLex(str).GetDouble();
 
107
  }
 
108
#endif
 
109
 
 
110
  iHeight = 10.0;
 
111
  if (attr.Has("height", str))
 
112
    iHeight = IpeLex(str).GetDouble();
 
113
 
 
114
  iDepth = 0.0;
 
115
  if (attr.Has("depth", str))
 
116
    iDepth = IpeLex(str).GetDouble();
 
117
 
 
118
  iVerticalAlignment = IsMiniPage() ? ETop : EBottom;
 
119
  if (attr.Has("valign", str)) {
 
120
    if (str == "top")
 
121
      iVerticalAlignment = ETop;
 
122
    else if (str == "bottom")
 
123
      iVerticalAlignment = EBottom;
 
124
    else if (str == "baseline")
 
125
      iVerticalAlignment = EBaseline;
 
126
    else if (str == "center")
 
127
      iVerticalAlignment = EVCenter;
 
128
  }
 
129
  iHorizontalAlignment = ELeft;
 
130
  if (attr.Has("halign", str)) {
 
131
    if (str == "left")
 
132
      iHorizontalAlignment = ELeft;
 
133
    else if (str == "right")
 
134
      iHorizontalAlignment = ERight;
 
135
    else if (str == "center")
 
136
      iHorizontalAlignment = EHCenter;
 
137
  }
 
138
}
 
139
 
 
140
//! Create text object.
 
141
IpeText::IpeText(const IpeAllAttributes &attr, IpeString data,
 
142
                 const IpeVector &pos, TType type, IpeScalar width)
 
143
  : IpeObject(attr)
 
144
{
 
145
  iXForm = 0;
 
146
  iText = data;
 
147
  iSize = attr.iTextSize;
 
148
  iPos = pos;
 
149
  iType = type;
 
150
  iWidth = width;
 
151
  iHeight = 10.0;
 
152
  iDepth = 0.0;
 
153
  if (iType == ELabel || iType == ETitle)
 
154
    iVerticalAlignment = EBottom;
 
155
  else
 
156
    iVerticalAlignment = ETop;
 
157
  iHorizontalAlignment = ELeft;
 
158
  iTransformable = attr.iTransformable;
 
159
}
 
160
 
 
161
//! Clone object
 
162
IpeObject *IpeText::Clone() const
 
163
{
 
164
  return new IpeText(*this);
 
165
}
 
166
 
 
167
//! Copy constructor.
 
168
IpeText::IpeText(const IpeText &rhs)
 
169
  : IpeObject(rhs)
 
170
{
 
171
  iPos = rhs.iPos;
 
172
  iText = rhs.iText;
 
173
  iSize = rhs.iSize;
 
174
  iWidth = rhs.iWidth;
 
175
  iHeight = rhs.iHeight;
 
176
  iDepth = rhs.iDepth;
 
177
  iType = rhs.iType;
 
178
  iVerticalAlignment = rhs.iVerticalAlignment;
 
179
  iHorizontalAlignment = rhs.iHorizontalAlignment;
 
180
  iXForm = rhs.iXForm;
 
181
  iTransformable = rhs.iTransformable;
 
182
  if (iXForm) iXForm->iRefCount++;
 
183
}
 
184
 
 
185
//! Destructor.
 
186
IpeText::~IpeText()
 
187
{
 
188
  if (iXForm && --iXForm->iRefCount == 0)
 
189
    delete iXForm;
 
190
}
 
191
 
 
192
 
 
193
//! Return pointer to this object.
 
194
IpeText *IpeText::AsText()
 
195
{
 
196
  return this;
 
197
}
 
198
 
 
199
//! Call VisitText of visitor.
 
200
void IpeText::Accept(IpeVisitor &visitor) const
 
201
{
 
202
  visitor.VisitText(this);
 
203
}
 
204
 
 
205
//! Save object to XML stream.
 
206
void IpeText::SaveAsXml(IpePainter &painter, IpeStream &stream,
 
207
                        IpeString layer) const
 
208
{
 
209
  stream << "<text";
 
210
  SaveAttributesAsXml(painter, stream, layer);
 
211
  stream << " pos=\"" << iPos.iX << " " << iPos.iY << "\"";
 
212
  switch (iType) {
 
213
  case ELabel:
 
214
    stream << " type=\"label\"";
 
215
    break;
 
216
  case EMinipage:
 
217
    stream << " type=\"minipage\"";
 
218
    break;
 
219
  case ETextbox:
 
220
    stream << " type=\"textbox\"";
 
221
    break;
 
222
  case ETitle:
 
223
    stream << " type=\"title\"";
 
224
    break;
 
225
  }
 
226
  if (iXForm || IsMiniPage())
 
227
    stream << " width=\"" << iWidth << "\"";
 
228
  if (iXForm)
 
229
    stream << " height=\"" << iHeight << "\""
 
230
           << " depth=\"" << iDepth << "\"";
 
231
  switch (iHorizontalAlignment) {
 
232
  case ELeft:
 
233
    break;
 
234
  case EHCenter:
 
235
    stream << " halign=\"center\"";
 
236
    break;
 
237
  case ERight:
 
238
    stream << " halign=\"right\"";
 
239
    break;
 
240
  }
 
241
  switch (iVerticalAlignment) {
 
242
  case ETop:
 
243
    stream << " valign=\"top\"";
 
244
    break;
 
245
  case EBottom:
 
246
    stream << " valign=\"bottom\"";
 
247
    break;
 
248
  case EBaseline:
 
249
    stream << " valign=\"baseline\"";
 
250
    break;
 
251
  case EVCenter:
 
252
    stream << " valign=\"center\"";
 
253
    break;
 
254
  }
 
255
  if (iTransformable)
 
256
    stream << " transformable=\"yes\"";
 
257
  if (painter.TextSize().IsNull())
 
258
    stream << " size=\"" << painter.Repository()->String(iSize) << "\">";
 
259
  stream.PutXmlString(iText);
 
260
  stream << "</text>\n";
 
261
}
 
262
 
 
263
//! Save text as PDF.
 
264
void IpeText::Draw(IpePainter &painter) const
 
265
{
 
266
  IpeVector pos(iPos);
 
267
  painter.Push();
 
268
  painter.Transform(Matrix());
 
269
  painter.Translate(pos);
 
270
  if (!iTransformable)
 
271
    painter.Untransform(false);
 
272
  painter.SetStroke(Stroke());
 
273
  painter.SetTextSize(Size()); // this size isn't actually used
 
274
  // Adjust alignment: make lower left corner of text box the origin
 
275
  painter.Translate(-Align());
 
276
  painter.DrawText(this);
 
277
  painter.Pop();
 
278
}
 
279
 
 
280
double IpeText::Distance(const IpeVector &v, const IpeMatrix &m,
 
281
                         double bound) const
 
282
{
 
283
  IpeVector u[5];
 
284
  Quadrilateral(m, u);
 
285
  u[4] = u[0];
 
286
 
 
287
  double d = bound;
 
288
  double d1;
 
289
  for (int i = 0; i < 4; ++i) {
 
290
    if ((d1 = IpeSegment(u[i], u[i+1]).Distance(v, d)) < d)
 
291
      d = d1;
 
292
  }
 
293
  return d1;
 
294
}
 
295
 
 
296
void IpeText::AddToBBox(IpeRect &box, const IpeMatrix &m) const
 
297
{
 
298
  IpeVector v[4];
 
299
  Quadrilateral(m, v);
 
300
 
 
301
  for (int i = 0; i < 4; ++i)
 
302
    box.AddPoint(v[i]);
 
303
}
 
304
 
 
305
// void IpeText::SnapVtx(const IpeVector &mouse, const IpeMatrix &m,
 
306
//                    IpeVector &pos, double &bound) const
 
307
void IpeText::SnapVtx(const IpeVector &, const IpeMatrix &,
 
308
                      IpeVector &, double &) const
 
309
{
 
310
  // nothing
 
311
}
 
312
 
 
313
// --------------------------------------------------------------------
 
314
 
 
315
//! Set width of paragraph.
 
316
/*! This invalidates (and destroys) the XForm.
 
317
  The function panics if object is not a minipage. */
 
318
void IpeText::SetWidth(IpeScalar width)
 
319
{
 
320
  assert(IsMiniPage());
 
321
  iWidth = width;
 
322
  SetXForm(0);
 
323
}
 
324
 
 
325
//! Set font size of text.
 
326
/*! This invalidates (and destroys) the XForm. */
 
327
void IpeText::SetSize(IpeAttribute size)
 
328
{
 
329
  iSize = size;
 
330
  SetXForm(0);
 
331
}
 
332
 
 
333
//! Set whether the text object can be transformed.
 
334
/*! This invalidates (and destroys) the XForm. */
 
335
void IpeText::SetTransformable(bool transf)
 
336
{
 
337
  iTransformable = transf;
 
338
  SetXForm(0);
 
339
}
 
340
 
 
341
//! Sets the text of the text object.
 
342
/*! This invalidates (and destroys) the XForm. */
 
343
void IpeText::SetText(IpeString text)
 
344
{
 
345
  iText = text;
 
346
  SetXForm(0);
 
347
}
 
348
 
 
349
//! Change type.
 
350
void IpeText::SetType(TType type)
 
351
{
 
352
  iType = type;
 
353
}
 
354
 
 
355
//! Change horizontal alignment (text moves with respect to reference point).
 
356
void IpeText::SetHorizontalAlignment(THorizontalAlignment align)
 
357
{
 
358
  iHorizontalAlignment = align;
 
359
}
 
360
 
 
361
//! Change vertical alignment (text moves with respect to reference point).
 
362
void IpeText::SetVerticalAlignment(TVerticalAlignment align)
 
363
{
 
364
  iVerticalAlignment = align;
 
365
}
 
366
 
 
367
// --------------------------------------------------------------------
 
368
 
 
369
//! Check symbolic size attribute.
 
370
void IpeText::CheckStyle(const IpeStyleSheet *sheet,
 
371
                          IpeAttributeSeq &seq) const
 
372
{
 
373
  CheckSymbol(iSize, sheet, seq);
 
374
  IpeObject::CheckStyle(sheet, seq);
 
375
}
 
376
 
 
377
//! Return quadrilateral including the text.
 
378
/*! This is the bounding box, correctly transformed by Matrix(),
 
379
  taking into consideration whether the object is transformable.
 
380
 */
 
381
void IpeText::Quadrilateral(const IpeMatrix &m, IpeVector v[4]) const
 
382
{
 
383
  IpeScalar wid = iWidth;
 
384
  IpeScalar ht = TotalHeight();
 
385
  IpeVector offset = -Align();
 
386
  v[0] = offset + IpeVector(0, 0);
 
387
  v[1] = offset + IpeVector(wid, 0);
 
388
  v[2] = offset + IpeVector(wid, ht);
 
389
  v[3] = offset + IpeVector(0, ht);
 
390
 
 
391
  IpeMatrix m1 = m * Matrix();
 
392
  if (iTransformable) {
 
393
    IpeLinear m2 = m1.Linear();
 
394
    for (int i = 0; i < 4; ++i)
 
395
      v[i] = m2 * v[i];
 
396
  }
 
397
  IpeVector pos = m1 * iPos;
 
398
  for (int i = 0; i < 4; ++i)
 
399
    v[i] = v[i] + pos;
 
400
}
 
401
 
 
402
//! Update the PDF code for this object.
 
403
void IpeText::SetXForm(XForm *xform) const
 
404
{
 
405
  if (iXForm && --iXForm->iRefCount == 0)
 
406
    delete iXForm;
 
407
  iXForm = xform;
 
408
  if (iXForm) {
 
409
    iXForm->iRefCount = 1;
 
410
    iDepth = iXForm->iStretch.iY * iXForm->iDepth / 100.0;
 
411
    iHeight = iXForm->iStretch.iY * iXForm->iBBox.Height() - iDepth;
 
412
    if (!IsMiniPage())
 
413
      iWidth = iXForm->iStretch.iX * iXForm->iBBox.Width();
 
414
  }
 
415
}
 
416
 
 
417
//! Return position of reference point in text box coordinate system.
 
418
/*! Assume a coordinate system where the text box has corners (0,0)
 
419
  and (Width(), TotalHeight()).  This function returns the coordinates
 
420
  of the reference point in this coordinate system. */
 
421
IpeVector IpeText::Align() const
 
422
{
 
423
  IpeVector align(0.0, 0.0);
 
424
  switch (iVerticalAlignment) {
 
425
  case ETop:
 
426
    align.iY = TotalHeight();
 
427
    break;
 
428
  case EBottom:
 
429
    break;
 
430
  case EVCenter:
 
431
    align.iY = 0.5 * TotalHeight();
 
432
    break;
 
433
  case EBaseline:
 
434
    align.iY = Depth();
 
435
    break;
 
436
  }
 
437
  switch (iHorizontalAlignment) {
 
438
  case ELeft:
 
439
    break;
 
440
  case ERight:
 
441
    align.iX = Width();
 
442
    break;
 
443
  case EHCenter:
 
444
    align.iX = 0.5 * Width();
 
445
    break;
 
446
  }
 
447
  return align;
 
448
}
 
449
 
 
450
// --------------------------------------------------------------------