1
// --------------------------------------------------------------------
2
// The reference object.
3
// --------------------------------------------------------------------
6
This file is part of the extensible drawing editor Ipe.
7
Copyright (C) 1993-2009 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 3 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.
31
#include "ipereference.h"
33
#include "ipepainter.h"
37
/*! \class ipe::Reference
39
\brief The reference object.
41
A Reference uses a symbol, that is, an object defined in an Ipe
42
StyleSheet. The object is defined as a named symbol in the style
43
sheet, and can be reused arbitrarily often in the document. This
44
can, for instance, be used for backgrounds on multi-page documents.
46
It is admissible to refer to an undefined object (that is, the
47
current style sheet cascade does not define a symbol with the given
48
name). Nothing will be drawn in this case.
50
The Reference has a stroke, fill, and pen attribute. When drawing a
51
symbol, these attributes are made available to the symbol through
52
the names "sym-stroke", "sym-fill", and "sym-pen". These are not
53
defined by the style sheet, but resolved by the Painter when the
54
symbol sets its attributes.
56
Note that it is not possible to determine \e whether a symbol is
57
filled from the Reference object.
59
The size attribute is of type ESymbolSize, and indicates a
60
magnification factor applied to the symbol. This magnification is
61
applied after the untransformation indicated in the Reference and in
62
the Symbol has been performed, so that symbols are magnified even if
63
they specify ETransformationsTranslations.
65
The size is meant for symbols such as marks, that can be shown in
66
different sizes. Another application of symbols is for backgrounds
67
and logos. Their size should not be changed when the user changes
68
the symbolsize for the entire page. For such symbols, the size
69
attribute of the Reference should be set to the absolute value zero.
70
This means that no magnification is applied to the object, and it
71
also \e stops setAttribute() from modifying the size. (The size can
72
still be changed using setSize(), but this is not available from
76
//! Create a reference to the named object in stylesheet.
77
Reference::Reference(const AllAttributes &attr, Attribute name, Vector pos)
80
assert(name.isSymbolic());
83
iPen = Attribute::NORMAL();
84
iSize = Attribute::ONE();
85
iStroke = Attribute::BLACK();
86
iFill = Attribute::WHITE();
87
iFlags = flagsFromName(name.string());
90
if (iFlags & EHasSize)
91
iSize = attr.iSymbolSize;
92
if (iFlags & EHasStroke)
93
iStroke = attr.iStroke;
94
if (iFlags & EHasFill)
98
//! Create from XML stream.
99
Reference::Reference(const XmlAttributes &attr, String /* data */)
102
iName = Attribute(true, attr["name"]);
104
if (attr.has("pos", str)) {
106
st >> iPos.x >> iPos.y;
109
iPen = Attribute::makeScalar(attr["pen"], Attribute::NORMAL());
110
iSize = Attribute::makeScalar(attr["size"], Attribute::ONE());
111
iStroke = Attribute::makeColor(attr["stroke"], Attribute::BLACK());
112
iFill = Attribute::makeColor(attr["fill"], Attribute::WHITE());
113
iFlags = flagsFromName(iName.string());
117
Object *Reference::clone() const
119
return new Reference(*this);
122
//! Return pointer to this object.
123
Reference *Reference::asReference()
128
Object::Type Reference::type() const
133
//! Call visitReference of visitor.
134
void Reference::accept(Visitor &visitor) const
136
visitor.visitReference(this);
139
//! Save in XML format.
140
void Reference::saveAsXml(Stream &stream, String layer) const
143
saveAttributesAsXml(stream, layer);
144
stream << " name=\"" << iName.string() << "\"";
145
if (iPos != Vector::ZERO)
146
stream << " pos=\"" << iPos << "\"";
147
if ((iFlags & EHasPen) && !iPen.isNormal())
148
stream << " pen=\"" << iPen.string() << "\"";
149
if ((iFlags & EHasSize) && iSize != Attribute::ONE())
150
stream << " size=\"" << iSize.string() << "\"";
151
if ((iFlags & EHasStroke) && iStroke != Attribute::BLACK())
152
stream << " stroke=\"" << iStroke.string() << "\"";
153
if ((iFlags & EHasFill) && iFill != Attribute::WHITE())
154
stream << " fill=\"" << iFill.string() << "\"";
159
/*! If the symbolic attribute is not defined in the current style sheet,
160
nothing is drawn at all. */
161
void Reference::draw(Painter &painter) const
163
const Symbol *symbol = painter.cascade()->findSymbol(iName);
165
Attribute si = painter.cascade()->find(ESymbolSize, iSize);
166
double s = si.number().toDouble();
167
painter.pushMatrix();
168
painter.transform(matrix());
169
painter.translate(iPos);
170
painter.untransform(transformations());
171
painter.untransform(symbol->iTransformations);
172
if (iFlags & EHasSize) {
173
Matrix m(s, 0, 0, s, 0, 0);
174
painter.transform(m);
177
if (iFlags & EHasStroke)
178
painter.setSymStroke(iStroke);
179
if (iFlags & EHasFill)
180
painter.setSymFill(iFill);
181
if (iFlags & EHasPen)
182
painter.setSymPen(iPen);
183
painter.drawSymbol(iName);
189
void Reference::drawSimple(Painter &painter) const
192
painter.pushMatrix();
193
painter.transform(matrix());
194
painter.translate(iPos);
195
painter.untransform(ETransformationsTranslations);
197
painter.moveTo(Vector(-size, 0));
198
painter.lineTo(Vector(size, 0));
199
painter.moveTo(Vector(0, -size));
200
painter.lineTo(Vector(0, size));
201
painter.drawPath(EStrokedOnly);
205
/*! \copydoc Object::addToBBox
207
This only adds the position to the \a box. */
208
void Reference::addToBBox(Rect &box, const Matrix &m, bool cp) const
210
box.addPoint((m * matrix()) * iPos);
213
void Reference::checkStyle(const Cascade *sheet, AttributeSeq &seq) const
215
if (!sheet->findSymbol(iName)) {
216
if (std::find(seq.begin(), seq.end(), iName) == seq.end())
217
seq.push_back(iName);
219
if (iFlags & EHasStroke)
220
checkSymbol(EColor, iStroke, sheet, seq);
221
if (iFlags & EHasFill)
222
checkSymbol(EColor, iFill, sheet, seq);
223
if (iFlags & EHasPen)
224
checkSymbol(EPen, iPen, sheet, seq);
225
if (iFlags & EHasSize)
226
checkSymbol(ESymbolSize, iSize, sheet, seq);
229
double Reference::distance(const Vector &v, const Matrix &m, double) const
231
return (v - (m * (matrix() * iPos))).len();
234
void Reference::snapVtx(const Vector &mouse, const Matrix &m,
235
Vector &pos, double &bound) const
237
(m * (matrix() * iPos)).snap(mouse, pos, bound);
240
void Reference::snapBnd(const Vector &, const Matrix &,
241
Vector &, double &) const
246
//! Set name of symbol referenced.
247
void Reference::setName(Attribute name)
250
iFlags = flagsFromName(name.string());
254
void Reference::setPen(Attribute pen)
259
//! Set stroke color.
260
void Reference::setStroke(Attribute color)
266
void Reference::setFill(Attribute color)
271
//! Set size (magnification) of symbol.
272
void Reference::setSize(Attribute size)
277
//! \copydoc Object::setAttribute
278
bool Reference::setAttribute(Property prop, Attribute value,
279
Attribute nStroke, Attribute nFill)
283
if ((iFlags & EHasPen) && value != pen()) {
288
case EPropStrokeColor:
289
if ((iFlags & EHasStroke) && value != stroke()) {
295
if ((iFlags & EHasFill) && value != fill()) {
300
case EPropSymbolSize:
301
if ((iFlags & EHasSize) && value != size()) {
307
if ((iFlags & EIsMark) && value != name()) {
308
uint nFlags = flagsFromName(value.string());
309
if (!(iFlags & EHasStroke) && (nFlags & EHasStroke))
311
if (!(iFlags & EHasFill) && (nFlags & EHasFill))
318
return Object::setAttribute(prop, value, nStroke, nFill);
323
Attribute Reference::getAttribute(Property prop)
327
if (iFlags & EHasPen)
330
case EPropStrokeColor:
331
if (iFlags & EHasStroke)
335
if (iFlags & EHasFill)
338
case EPropSymbolSize:
339
if (iFlags & EHasSize)
343
if (iFlags & EIsMark)
349
return Object::getAttribute(prop);
352
// --------------------------------------------------------------------
354
uint Reference::flagsFromName(String name)
357
if (name.left(5) == "mark/")
359
if (name.left(6) == "arrow/")
361
int i = name.rfind('(');
362
if (i < 0 || name[name.size() - 1] != ')')
364
String letters = name.substr(i+1, name.size() - i - 2);
365
if (letters.find('x') >= 0)
367
if (letters.find('s') >= 0)
369
if (letters.find('f') >= 0)
371
if (letters.find('p') >= 0)
376
// --------------------------------------------------------------------