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