1
// --------------------------------------------------------------------
3
// --------------------------------------------------------------------
6
This file is part of the extensible drawing editor Ipe.
7
Copyright (C) 1993-2004 Otfried Cheong
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.
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.
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.
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.
32
#include "ipevisitor.h"
33
#include "ipepainter.h"
37
\brief The text object.
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.
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.
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.
55
The position of the reference point relative to the text box is
56
given by VerticalAlignment() and HorizontalAlignment().
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.
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
68
//! Create from XML stream.
69
IpeText::IpeText(IpeRepository *rep, const IpeXmlAttributes &attr,
71
: IpeObject(rep, attr)
75
iSize = rep->MakeScalar(IpeAttribute::ETextSize, attr["size"]);
77
IpeLex st(attr["pos"]);
78
st >> iPos.iX >> iPos.iY;
80
iTransformable = false;
82
if (attr.Has("transformable", str) && str == "yes")
83
iTransformable = true;
86
bool hasType = attr.Has("type", str);
88
if (str == "minipage")
90
else if (str == "title")
92
else if (str == "textbox")
97
if (attr.Has("width", str)) {
98
iWidth = IpeLex(str).GetDouble();
104
// obsolete - remove later
105
if (attr.Has("textstretch", str)) {
106
iWidth *= IpeLex(str).GetDouble();
111
if (attr.Has("height", str))
112
iHeight = IpeLex(str).GetDouble();
115
if (attr.Has("depth", str))
116
iDepth = IpeLex(str).GetDouble();
118
iVerticalAlignment = IsMiniPage() ? ETop : EBottom;
119
if (attr.Has("valign", str)) {
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;
129
iHorizontalAlignment = ELeft;
130
if (attr.Has("halign", str)) {
132
iHorizontalAlignment = ELeft;
133
else if (str == "right")
134
iHorizontalAlignment = ERight;
135
else if (str == "center")
136
iHorizontalAlignment = EHCenter;
140
//! Create text object.
141
IpeText::IpeText(const IpeAllAttributes &attr, IpeString data,
142
const IpeVector &pos, TType type, IpeScalar width)
147
iSize = attr.iTextSize;
153
if (iType == ELabel || iType == ETitle)
154
iVerticalAlignment = EBottom;
156
iVerticalAlignment = ETop;
157
iHorizontalAlignment = ELeft;
158
iTransformable = attr.iTransformable;
162
IpeObject *IpeText::Clone() const
164
return new IpeText(*this);
167
//! Copy constructor.
168
IpeText::IpeText(const IpeText &rhs)
175
iHeight = rhs.iHeight;
178
iVerticalAlignment = rhs.iVerticalAlignment;
179
iHorizontalAlignment = rhs.iHorizontalAlignment;
181
iTransformable = rhs.iTransformable;
182
if (iXForm) iXForm->iRefCount++;
188
if (iXForm && --iXForm->iRefCount == 0)
193
//! Return pointer to this object.
194
IpeText *IpeText::AsText()
199
//! Call VisitText of visitor.
200
void IpeText::Accept(IpeVisitor &visitor) const
202
visitor.VisitText(this);
205
//! Save object to XML stream.
206
void IpeText::SaveAsXml(IpePainter &painter, IpeStream &stream,
207
IpeString layer) const
210
SaveAttributesAsXml(painter, stream, layer);
211
stream << " pos=\"" << iPos.iX << " " << iPos.iY << "\"";
214
stream << " type=\"label\"";
217
stream << " type=\"minipage\"";
220
stream << " type=\"textbox\"";
223
stream << " type=\"title\"";
226
if (iXForm || IsMiniPage())
227
stream << " width=\"" << iWidth << "\"";
229
stream << " height=\"" << iHeight << "\""
230
<< " depth=\"" << iDepth << "\"";
231
switch (iHorizontalAlignment) {
235
stream << " halign=\"center\"";
238
stream << " halign=\"right\"";
241
switch (iVerticalAlignment) {
243
stream << " valign=\"top\"";
246
stream << " valign=\"bottom\"";
249
stream << " valign=\"baseline\"";
252
stream << " valign=\"center\"";
256
stream << " transformable=\"yes\"";
257
if (painter.TextSize().IsNull())
258
stream << " size=\"" << painter.Repository()->String(iSize) << "\">";
259
stream.PutXmlString(iText);
260
stream << "</text>\n";
263
//! Save text as PDF.
264
void IpeText::Draw(IpePainter &painter) const
268
painter.Transform(Matrix());
269
painter.Translate(pos);
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);
280
double IpeText::Distance(const IpeVector &v, const IpeMatrix &m,
289
for (int i = 0; i < 4; ++i) {
290
if ((d1 = IpeSegment(u[i], u[i+1]).Distance(v, d)) < d)
296
void IpeText::AddToBBox(IpeRect &box, const IpeMatrix &m) const
301
for (int i = 0; i < 4; ++i)
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
313
// --------------------------------------------------------------------
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)
320
assert(IsMiniPage());
325
//! Set font size of text.
326
/*! This invalidates (and destroys) the XForm. */
327
void IpeText::SetSize(IpeAttribute size)
333
//! Set whether the text object can be transformed.
334
/*! This invalidates (and destroys) the XForm. */
335
void IpeText::SetTransformable(bool transf)
337
iTransformable = transf;
341
//! Sets the text of the text object.
342
/*! This invalidates (and destroys) the XForm. */
343
void IpeText::SetText(IpeString text)
350
void IpeText::SetType(TType type)
355
//! Change horizontal alignment (text moves with respect to reference point).
356
void IpeText::SetHorizontalAlignment(THorizontalAlignment align)
358
iHorizontalAlignment = align;
361
//! Change vertical alignment (text moves with respect to reference point).
362
void IpeText::SetVerticalAlignment(TVerticalAlignment align)
364
iVerticalAlignment = align;
367
// --------------------------------------------------------------------
369
//! Check symbolic size attribute.
370
void IpeText::CheckStyle(const IpeStyleSheet *sheet,
371
IpeAttributeSeq &seq) const
373
CheckSymbol(iSize, sheet, seq);
374
IpeObject::CheckStyle(sheet, seq);
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.
381
void IpeText::Quadrilateral(const IpeMatrix &m, IpeVector v[4]) const
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);
391
IpeMatrix m1 = m * Matrix();
392
if (iTransformable) {
393
IpeLinear m2 = m1.Linear();
394
for (int i = 0; i < 4; ++i)
397
IpeVector pos = m1 * iPos;
398
for (int i = 0; i < 4; ++i)
402
//! Update the PDF code for this object.
403
void IpeText::SetXForm(XForm *xform) const
405
if (iXForm && --iXForm->iRefCount == 0)
409
iXForm->iRefCount = 1;
410
iDepth = iXForm->iStretch.iY * iXForm->iDepth / 100.0;
411
iHeight = iXForm->iStretch.iY * iXForm->iBBox.Height() - iDepth;
413
iWidth = iXForm->iStretch.iX * iXForm->iBBox.Width();
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
423
IpeVector align(0.0, 0.0);
424
switch (iVerticalAlignment) {
426
align.iY = TotalHeight();
431
align.iY = 0.5 * TotalHeight();
437
switch (iHorizontalAlignment) {
444
align.iX = 0.5 * Width();
450
// --------------------------------------------------------------------