]> git.lyx.org Git - lyx.git/blob - src/mathed/MathMacro.cpp
use bald pointers in clone()
[lyx.git] / src / mathed / MathMacro.cpp
1 /**
2  * \file MathMacro.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alejandro Aguilar Sierra
7  * \author André Pönitz
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "MathMacro.h"
15 #include "MathSupport.h"
16 #include "MathExtern.h"
17 #include "MathStream.h"
18
19 #include "Buffer.h"
20 #include "Cursor.h"
21 #include "debug.h"
22 #include "BufferView.h"
23 #include "LaTeXFeatures.h"
24 #include "frontends/Painter.h"
25
26
27 namespace lyx {
28
29 using std::string;
30 using std::max;
31
32
33 /// This class is the value of a macro argument, technically
34 /// a wrapper of the cells of MathMacro.
35 class MathMacroArgumentValue : public InsetMath {
36 public:
37         ///
38         MathMacroArgumentValue(MathMacro const & mathMacro, size_t idx)
39                 : mathMacro_(mathMacro), idx_(idx) {}
40         ///
41         bool metrics(MetricsInfo & mi, Dimension & dim) const;
42         ///
43         void draw(PainterInfo &, int x, int y) const;
44         ///
45         int kerning() const { return mathMacro_.cell(idx_).kerning(); }
46
47 private:
48         Inset * clone() const;
49         MathMacro const & mathMacro_;
50         size_t idx_;
51 };
52
53
54 Inset * MathMacroArgumentValue::clone() const
55 {
56         return new MathMacroArgumentValue(*this);
57 }
58
59
60 bool MathMacroArgumentValue::metrics(MetricsInfo & mi, Dimension & dim) const
61 {
62         // unlock outer macro in arguments, and lock it again later
63         MacroData const & macro = MacroTable::globalMacros().get(mathMacro_.name());
64         macro.unlock();
65         mathMacro_.cell(idx_).metrics(mi, dim);
66         macro.lock();
67         if (dim_ == dim)
68                 return false;
69         dim_ = dim;
70         return true;
71 }
72
73
74 void MathMacroArgumentValue::draw(PainterInfo & pi, int x, int y) const
75 {
76         // unlock outer macro in arguments, and lock it again later
77         MacroData const & macro = MacroTable::globalMacros().get(mathMacro_.name());
78         macro.unlock();
79         mathMacro_.cell(idx_).draw(pi, x, y);
80         macro.lock();
81 }
82
83
84 MathMacro::MathMacro(docstring const & name, int numargs)
85         : InsetMathNest(numargs), name_(name), editing_(false)
86 {}
87
88
89 Inset * MathMacro::clone() const
90 {
91         MathMacro * x = new MathMacro(*this);
92         x->expanded_ = MathData();
93         x->macroBackup_ = MacroData();
94         return x;
95 }
96
97
98 docstring MathMacro::name() const
99 {
100         return name_;
101 }
102
103
104 void MathMacro::cursorPos(BufferView const & bv,
105                 CursorSlice const & sl, bool boundary, int & x, int & y) const
106 {
107         // We may have 0 arguments, but InsetMathNest requires at least one.
108         if (nargs() > 0)
109                 InsetMathNest::cursorPos(bv, sl, boundary, x, y);
110 }
111
112
113 bool MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const
114 {
115         kerning_ = 0;
116         if (!MacroTable::globalMacros().has(name())) {
117                 mathed_string_dim(mi.base.font, "Unknown: " + name(), dim);
118         } else {
119                 MacroData const & macro = MacroTable::globalMacros().get(name());
120
121                 if (macroBackup_ != macro)
122                         updateExpansion();
123
124                 if (macro.locked()) {
125                         mathed_string_dim(mi.base.font, "Self reference: " + name(), dim);
126                 } else if (editing(mi.base.bv)) {
127                         Font font = mi.base.font;
128                         augmentFont(font, from_ascii("lyxtex"));
129                         tmpl_.metrics(mi, dim);
130                         // FIXME UNICODE
131                         dim.wid += mathed_string_width(font, name()) + 10;
132                         // FIXME UNICODE
133                         int ww = mathed_string_width(font, from_ascii("#1: "));
134                         for (idx_type i = 0; i < nargs(); ++i) {
135                                 MathData const & c = cell(i);
136                                 c.metrics(mi);
137                                 dim.wid  = max(dim.wid, c.width() + ww);
138                                 dim.des += c.height() + 10;
139                         }
140                         editing_ = true;
141                 } else {
142                         macro.lock();
143                         expanded_.metrics(mi, dim);
144                         macro.unlock();
145                         kerning_ = expanded_.kerning();
146                         editing_ = false;
147                 }
148         }
149         if (dim_ == dim)
150                 return false;
151         dim_ = dim;
152         return true;
153 }
154
155
156 void MathMacro::draw(PainterInfo & pi, int x, int y) const
157 {
158         if (!MacroTable::globalMacros().has(name())) {
159                 // FIXME UNICODE
160                 drawStrRed(pi, x, y, "Unknown: " + name());
161         } else {
162                 MacroData const & macro = MacroTable::globalMacros().get(name());
163
164                 // warm up cache
165                 for (size_t i = 0; i < nargs(); ++i)
166                         cell(i).setXY(*pi.base.bv, x, y);
167
168                 if (macro.locked()) {
169                         // FIXME UNICODE
170                         drawStrRed(pi, x, y, "Self reference: " + name());
171                 } else if (editing_) {
172                         Font font = pi.base.font;
173                         augmentFont(font, from_ascii("lyxtex"));
174                         int h = y - dim_.ascent() + 2 + tmpl_.ascent();
175                         pi.pain.text(x + 3, h, name(), font);
176                         int const w = mathed_string_width(font, name());
177                         tmpl_.draw(pi, x + w + 12, h);
178                         h += tmpl_.descent();
179                         Dimension ldim;
180                         docstring t = from_ascii("#1: ");
181                         mathed_string_dim(font, t, ldim);
182                         for (idx_type i = 0; i < nargs(); ++i) {
183                                 MathData const & c = cell(i);
184                                 h += max(c.ascent(), ldim.asc) + 5;
185                                 c.draw(pi, x + ldim.wid, h);
186                                 char_type str[] = { '#', '1', ':', '\0' };
187                                 str[1] += static_cast<char_type>(i);
188                                 pi.pain.text(x + 3, h, str, font);
189                                 h += max(c.descent(), ldim.des) + 5;
190                         }
191                 } else {
192                         macro.lock();
193                         expanded_.draw(pi, x, y);
194                         macro.unlock();
195                 }
196
197                 // edit mode changed?
198                 if (editing_ != editing(pi.base.bv) || macroBackup_ != macro)
199                         pi.base.bv->cursor().updateFlags(Update::Force);
200         }
201 }
202
203
204 void MathMacro::drawSelection(PainterInfo & pi, int x, int y) const
205 {
206         // We may have 0 arguments, but InsetMathNest requires at least one.
207         if (nargs() > 0)
208                 InsetMathNest::drawSelection(pi, x, y);
209 }
210
211
212 void MathMacro::validate(LaTeXFeatures & features) const
213 {
214         string const require = MacroTable::globalMacros().get(name()).requires();
215         if (!require.empty())
216                 features.require(require);
217
218         if (name() == "binom" || name() == "mathcircumflex")
219                 features.require(to_utf8(name()));
220 }
221
222
223 Inset * MathMacro::editXY(Cursor & cur, int x, int y)
224 {
225         // We may have 0 arguments, but InsetMathNest requires at least one.
226         if (nargs() > 0) {
227                 // Prevent crash due to cold coordcache
228                 // FIXME: This is only a workaround, the call of
229                 // InsetMathNest::editXY is correct. The correct fix would
230                 // ensure that the coordcache of the arguments is valid.
231                 if (!editing(&cur.bv())) {
232                         edit(cur, true);
233                         return this;
234                 }
235                 return InsetMathNest::editXY(cur, x, y);
236         }
237         return this;
238 }
239
240
241 bool MathMacro::idxFirst(Cursor & cur) const
242 {
243         cur.updateFlags(Update::Force);
244         return InsetMathNest::idxFirst(cur);
245 }
246
247
248 bool MathMacro::idxLast(Cursor & cur) const
249 {
250         cur.updateFlags(Update::Force);
251         return InsetMathNest::idxLast(cur);
252 }
253
254
255 bool MathMacro::idxUpDown(Cursor & cur, bool up) const
256 {
257         if (up) {
258                 if (cur.idx() == 0)
259                         return false;
260                 --cur.idx();
261         } else {
262                 if (cur.idx() + 1 >= nargs())
263                         return false;
264                 ++cur.idx();
265         }
266         cur.pos() = cell(cur.idx()).x2pos(cur.x_target());
267         return true;
268 }
269
270
271 bool MathMacro::notifyCursorLeaves(Cursor & cur)
272 {
273         cur.updateFlags(Update::Force);
274         return InsetMathNest::notifyCursorLeaves(cur);
275 }
276
277
278 void MathMacro::maple(MapleStream & os) const
279 {
280         updateExpansion();
281         lyx::maple(expanded_, os);
282 }
283
284
285 void MathMacro::mathmlize(MathStream & os) const
286 {
287         updateExpansion();
288         lyx::mathmlize(expanded_, os);
289 }
290
291
292 void MathMacro::octave(OctaveStream & os) const
293 {
294         updateExpansion();
295         lyx::octave(expanded_, os);
296 }
297
298
299 void MathMacro::updateExpansion() const
300 {
301         MacroData const & macro = MacroTable::globalMacros().get(name());
302
303         // create MathMacroArgumentValue object pointing to the cells of the macro
304         std::vector<MathData> values(nargs());
305         for (size_t i = 0; i != nargs(); ++i)
306                                 values[i].insert(0, MathAtom(new MathMacroArgumentValue(*this, i)));
307         macro.expand(values, expanded_);
308         asArray(macro.def(), tmpl_);
309         macroBackup_ = macro;
310 }
311
312
313 void MathMacro::infoize(odocstream & os) const
314 {
315         os << "Macro: " << name();
316 }
317
318
319 void MathMacro::infoize2(odocstream & os) const
320 {
321         os << "Macro: " << name();
322
323 }
324
325
326 } // namespace lyx