]> git.lyx.org Git - lyx.git/blob - src/mathed/MathMacro.cpp
Rename .C ==> .cpp for files in src, part one
[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 "LCursor.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 InsetMathDim {
39 public:
40         ///
41         MathMacroArgumentValue(MathArray const * value, docstring const & macroName) 
42                 : value_(value), macroName_(macroName) {}
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<InsetBase> doClone() const;
50         MathArray const * value_;
51         docstring macroName_;
52 };
53
54
55 auto_ptr<InsetBase> MathMacroArgumentValue::doClone() const 
56 {
57         return auto_ptr<InsetBase>(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         MacroTable::globalMacros().get(macroName_).unlock();
65         value_->metrics(mi, dim);
66         MacroTable::globalMacros().get(macroName_).lock();
67         metricsMarkers2(dim);
68         if (dim_ == dim)
69                 return false;
70         dim_ = dim;
71         return true;
72 }
73
74
75 void MathMacroArgumentValue::draw(PainterInfo & pi, int x, int y) const 
76 {
77         // unlock outer macro in arguments, and lock it again later
78         MacroTable::globalMacros().get(macroName_).unlock();
79         value_->draw(pi, x, y);
80         MacroTable::globalMacros().get(macroName_).lock();
81 }
82
83
84 MathMacro::MathMacro(docstring const & name, int numargs)
85         : InsetMathNest(numargs), name_(name)
86 {}
87
88
89 auto_ptr<InsetBase> MathMacro::doClone() const
90 {
91         return auto_ptr<InsetBase>(new MathMacro(*this));
92 }
93
94
95 docstring MathMacro::name() const
96 {
97         return name_;
98 }
99
100
101 void MathMacro::cursorPos(BufferView const & bv,
102                 CursorSlice const & sl, bool boundary, int & x, int & y) const
103 {
104         // We may have 0 arguments, but InsetMathNest requires at least one.
105         if (nargs() > 0)
106                 InsetMathNest::cursorPos(bv, sl, boundary, x, y);
107 }
108
109
110 bool MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const
111 {
112         if (!MacroTable::globalMacros().has(name())) {
113                 mathed_string_dim(mi.base.font, "Unknown: " + name(), dim);
114         } else {
115                 MacroData const & macro = MacroTable::globalMacros().get(name());
116                 if (macro.locked()) {
117                         mathed_string_dim(mi.base.font, "Self reference: " + name(), dim);
118                         expanded_ = MathArray();
119                 } else if (editing(mi.base.bv)) {
120                         // FIXME UNICODE
121                         asArray(macro.def(), tmpl_);
122                         LyXFont font = mi.base.font;
123                         augmentFont(font, from_ascii("lyxtex"));
124                         tmpl_.metrics(mi, dim);
125                         // FIXME UNICODE
126                         dim.wid += mathed_string_width(font, name()) + 10;
127                         // FIXME UNICODE
128                         int ww = mathed_string_width(font, from_ascii("#1: "));
129                         for (idx_type i = 0; i < nargs(); ++i) {
130                                 MathArray const & c = cell(i);
131                                 c.metrics(mi);
132                                 dim.wid  = max(dim.wid, c.width() + ww);
133                                 dim.des += c.height() + 10;
134                         }
135                 } else {
136                         // create MathMacroArgumentValue object pointing to the cells of the macro
137                         MacroData const & macro = MacroTable::globalMacros().get(name());
138                         vector<MathArray> values(nargs());
139                         for (size_t i = 0; i != nargs(); ++i) 
140                                 values[i].insert(0, MathAtom(new MathMacroArgumentValue(&cells_[i], name())));
141                         macro.expand(values, expanded_);
142                         
143                         MacroTable::globalMacros().get(name()).lock();
144                         expanded_.metrics(mi, dim);
145                         MacroTable::globalMacros().get(name()).unlock();
146                 }
147         }
148         metricsMarkers2(dim);
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                 if (macro.locked()) {
164                         // FIXME UNICODE
165                         drawStrRed(pi, x, y, "Self reference: " + name());
166                 } else if (editing(pi.base.bv)) {
167                         LyXFont font = pi.base.font;
168                         augmentFont(font, from_ascii("lyxtex"));
169                         int h = y - dim_.ascent() + 2 + tmpl_.ascent();
170                         pi.pain.text(x + 3, h, name(), font);
171                         int const w = mathed_string_width(font, name());
172                         tmpl_.draw(pi, x + w + 12, h);
173                         h += tmpl_.descent();
174                         Dimension ldim;
175                         docstring t = from_ascii("#1: ");
176                         mathed_string_dim(font, t, ldim);
177                         for (idx_type i = 0; i < nargs(); ++i) {
178                                 MathArray const & c = cell(i);
179                                 h += max(c.ascent(), ldim.asc) + 5;
180                                 c.draw(pi, x + ldim.wid, h);
181                                 char_type str[] = { '#', '1', ':', '\0' };
182                                 str[1] += static_cast<char_type>(i);
183                                 pi.pain.text(x + 3, h, str, font);
184                                 h += max(c.descent(), ldim.des) + 5;
185                         }
186                 } else {
187                         MacroTable::globalMacros().get(name()).lock();
188                         expanded_.draw(pi, x, y);
189                         MacroTable::globalMacros().get(name()).unlock();
190                 }
191         }
192         drawMarkers2(pi, x, y);
193 }
194
195
196 void MathMacro::drawSelection(PainterInfo & pi, int x, int y) const
197 {
198         // We may have 0 arguments, but InsetMathNest requires at least one.
199         if (nargs() > 0)
200                 InsetMathNest::drawSelection(pi, x, y);
201 }
202
203
204 void MathMacro::validate(LaTeXFeatures & features) const
205 {
206         if (name() == "binom" || name() == "mathcircumflex")
207                 features.require(to_utf8(name()));
208 }
209
210
211 InsetBase * MathMacro::editXY(LCursor & cur, int x, int y)
212 {
213         // We may have 0 arguments, but InsetMathNest requires at least one.
214         if (nargs() > 0) {
215                 // Prevent crash due to cold coordcache
216                 // FIXME: This is only a workaround, the call of
217                 // InsetMathNest::editXY is correct. The correct fix would
218                 // ensure that the coordcache of the arguments is valid.
219                 if (!editing(&cur.bv())) {
220                         edit(cur, true);
221                         return this;
222                 }
223                 return InsetMathNest::editXY(cur, x, y);
224         }
225         return this;
226 }
227
228
229 bool MathMacro::idxFirst(LCursor & cur) const 
230 {
231         cur.updateFlags(Update::Force);
232         return InsetMathNest::idxFirst(cur);
233 }
234
235
236 bool MathMacro::idxLast(LCursor & cur) const 
237 {
238         cur.updateFlags(Update::Force);
239         return InsetMathNest::idxLast(cur);
240 }
241
242
243 bool MathMacro::notifyCursorLeaves(LCursor & cur)
244 {
245         cur.updateFlags(Update::Force);
246         return InsetMathNest::notifyCursorLeaves(cur);
247 }
248
249
250 void MathMacro::maple(MapleStream & os) const
251 {
252         updateExpansion();
253         lyx::maple(expanded_, os);
254 }
255
256
257 void MathMacro::mathmlize(MathStream & os) const
258 {
259         updateExpansion();
260         lyx::mathmlize(expanded_, os);
261 }
262
263
264 void MathMacro::octave(OctaveStream & os) const
265 {
266         updateExpansion();
267         lyx::octave(expanded_, os);
268 }
269
270
271 void MathMacro::updateExpansion() const
272 {
273         //expanded_.substitute(*this);
274 }
275
276
277 void MathMacro::infoize(odocstream & os) const
278 {
279         os << "Macro: " << name();
280 }
281
282
283 void MathMacro::infoize2(odocstream & os) const
284 {
285         os << "Macro: " << name();
286
287 }
288
289
290 } // namespace lyx