]> git.lyx.org Git - lyx.git/blob - src/mathed/formula.C
85617a78e3d843e63952e7ee1ab5c8280034dc9d
[lyx.git] / src / mathed / formula.C
1 /**
2  * \file formula.C
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 "formula.h"
15 #include "math_cursor.h"
16 #include "math_parser.h"
17 #include "math_hullinset.h"
18 #include "math_mathmlstream.h"
19 #include "textpainter.h"
20
21 #include "BufferView.h"
22 #include "debug.h"
23 #include "latexrunparams.h"
24 #include "LColor.h"
25
26 #include "frontends/Painter.h"
27
28 #include "graphics/PreviewedInset.h"
29 #include "graphics/PreviewImage.h"
30
31 #include "support/std_sstream.h"
32
33 #include <boost/bind.hpp>
34
35 using std::string;
36 using std::ostream;
37 using std::ostringstream;
38 using std::vector;
39 using std::auto_ptr;
40 using std::endl;
41
42
43 class InsetFormula::PreviewImpl : public PreviewedInset {
44 public:
45         ///
46         PreviewImpl(InsetFormula const & p) : parent_(p) {}
47
48 private:
49         ///
50         bool previewWanted(Buffer const &) const;
51         ///
52         string const latexString(Buffer const &) const;
53         ///
54         InsetFormula const & parent_;
55 };
56
57
58 InsetFormula::InsetFormula(bool chemistry)
59         : par_(MathAtom(new MathHullInset)),
60           preview_(new PreviewImpl(*this))
61 {
62         preview_->connect(boost::bind(&InsetFormula::statusChanged, this));
63         if (chemistry)
64                 mutate("chemistry");
65 }
66
67
68 InsetFormula::InsetFormula(InsetFormula const & other)
69         : InsetFormulaBase(other),
70           par_(other.par_),
71           preview_(new PreviewImpl(*this))
72 {
73         preview_->connect(boost::bind(&InsetFormula::statusChanged, this));
74 }
75
76
77 InsetFormula::InsetFormula(BufferView *)
78         : par_(MathAtom(new MathHullInset)),
79           preview_(new PreviewImpl(*this))
80 {
81         preview_->connect(boost::bind(&InsetFormula::statusChanged, this));
82 }
83
84
85 InsetFormula::InsetFormula(string const & data)
86         : par_(MathAtom(new MathHullInset)),
87           preview_(new PreviewImpl(*this))
88 {
89         preview_->connect(boost::bind(&InsetFormula::statusChanged, this));
90         if (!data.size())
91                 return;
92         if (!mathed_parse_normal(par_, data))
93                 lyxerr << "cannot interpret '" << data << "' as math" << endl;
94 }
95
96
97 InsetFormula::~InsetFormula()
98 {}
99
100
101 auto_ptr<InsetBase> InsetFormula::clone() const
102 {
103         return auto_ptr<InsetBase>(new InsetFormula(*this));
104 }
105
106
107 void InsetFormula::write(Buffer const &, ostream & os) const
108 {
109         WriteStream wi(os, false, false);
110         os << par_->fileInsetLabel() << ' ';
111         par_->write(wi);
112 }
113
114
115 int InsetFormula::latex(Buffer const &, ostream & os,
116                         LatexRunParams const & runparams) const
117 {
118         WriteStream wi(os, runparams.moving_arg, true);
119         par_->write(wi);
120         return wi.line();
121 }
122
123
124 int InsetFormula::ascii(Buffer const &, ostream & os, int) const
125 {
126         if (0 && display()) {
127                 Dimension dim;
128                 TextMetricsInfo mi;
129                 par()->metricsT(mi, dim);
130                 TextPainter tpain(dim.width(), dim.height());
131                 par()->drawT(tpain, 0, dim.ascent());
132                 tpain.show(os, 3);
133                 // reset metrics cache to "real" values
134                 //metrics();
135                 return tpain.textheight();
136         } else {
137                 WriteStream wi(os, false, true);
138                 wi << ' ' << (par_->asNestInset()->cell(0)) << ' ';
139                 return wi.line();
140         }
141 }
142
143
144 int InsetFormula::linuxdoc(Buffer const & buf, ostream & os) const
145 {
146         return docbook(buf, os, false);
147 }
148
149
150 int InsetFormula::docbook(Buffer const & buf, ostream & os, bool) const
151 {
152         MathMLStream ms(os);
153         ms << MTag("equation");
154         ms <<   MTag("alt");
155         ms <<    "<[CDATA[";
156         int res = ascii(buf, ms.os(), 0);
157         ms <<    "]]>";
158         ms <<   ETag("alt");
159         ms <<   MTag("math");
160         ms <<    par_;
161         ms <<   ETag("math");
162         ms << ETag("equation");
163         return ms.line() + res;
164 }
165
166
167 void InsetFormula::read(Buffer const &, LyXLex & lex)
168 {
169         mathed_parse_normal(par_, lex);
170         // remove extra 'mathrm' for chemistry stuff.
171         // will be re-added on write
172         if (par_->asHullInset()->getType() =="chemistry")  {
173                 lyxerr << "this is chemistry" << endl;
174                 if (par_->cell(0).size() == 1) {
175                         lyxerr << "this is size 1" << endl;
176                         if (par_->cell(0)[0]->asFontInset()) {
177                                 lyxerr << "this is a font inset "
178                                        << "replacing " << par_.nucleus()->cell(0) <<
179                                         " with " << par_->cell(0)[0]->cell(0) << endl;
180                         }
181                 }
182         }
183         //metrics();
184 }
185
186
187 //ostream & operator<<(ostream & os, LyXCursor const & c)
188 //{
189 //      os << '[' << c.x() << ' ' << c.y() << ' ' << c.pos() << ']';
190 //      return os;
191 //}
192
193
194 void InsetFormula::draw(PainterInfo & pi, int x, int y) const
195 {
196         BufferView * bv = pi.base.bv;
197         cache(bv);
198
199         // The previews are drawn only when we're not editing the inset.
200         bool const editing_inset = mathcursor && mathcursor->formula() == this;
201         bool const use_preview = !editing_inset && preview_->previewReady();
202
203         int const w = dim_.wid;
204         int const d = dim_.des;
205         int const a = dim_.asc;
206         int const h = a + d;
207
208         if (use_preview) {
209                 pi.pain.image(x + 1, y - a, w, h,   // one pixel gap in front
210                               *(preview_->pimage()->image()));
211         } else {
212                 PainterInfo p(bv);
213                 p.base.style = LM_ST_TEXT;
214                 p.base.font  = pi.base.font;
215                 p.base.font.setColor(LColor::math);
216                 if (lcolor.getX11Name(LColor::mathbg)
217                             != lcolor.getX11Name(LColor::background))
218                         p.pain.fillRectangle(x, y - a, w, h, LColor::mathbg);
219
220                 if (editing_inset) {
221                         mathcursor->drawSelection(pi);
222                         //p.pain.rectangle(x, y - a, w, h, LColor::mathframe);
223                 }
224
225                 par_->draw(p, x + offset_, y);
226         }
227
228         xo_ = x;
229         yo_ = y;
230 }
231
232
233 void InsetFormula::getLabelList(Buffer const & buffer,
234                                 vector<string> & res) const
235 {
236         par()->getLabelList(buffer, res);
237 }
238
239
240 InsetOld::Code InsetFormula::lyxCode() const
241 {
242         return InsetOld::MATH_CODE;
243 }
244
245
246 void InsetFormula::validate(LaTeXFeatures & features) const
247 {
248         par_->validate(features);
249 }
250
251
252 bool InsetFormula::insetAllowed(InsetOld::Code code) const
253 {
254         return
255                    code == InsetOld::LABEL_CODE
256                 || code == InsetOld::REF_CODE
257                 || code == InsetOld::ERT_CODE;
258 }
259
260
261 void InsetFormula::metrics(MetricsInfo & m, Dimension & dim) const
262 {
263         view_ = m.base.bv;
264
265         bool const editing_inset = mathcursor && mathcursor->formula() == this;
266         bool const use_preview = !editing_inset && preview_->previewReady();
267
268         if (use_preview) {
269                 dim.asc = preview_->pimage()->ascent();
270                 dim.des = preview_->pimage()->descent();
271                 // insert a one pixel gap in front of the formula
272                 dim.wid = 1 + preview_->pimage()->width();
273                 if (display())
274                         dim.des += 12;
275         } else {
276                 MetricsInfo mi = m;
277                 mi.base.style = LM_ST_TEXT;
278                 mi.base.font.setColor(LColor::math);
279                 par()->metrics(mi, dim);
280                 dim.asc += 1;
281                 dim.des += 1;
282         }
283
284         if (display()) {
285                 offset_ = (m.base.textwidth - dim.wid) / 2;
286                 dim.wid = m.base.textwidth;
287         } else {
288                 offset_ = 0;
289         }
290
291         dim_ = dim;
292 }
293
294
295 void InsetFormula::mutate(string const & type)
296 {
297         par_.nucleus()->mutate(type);
298 }
299
300
301 //
302 // preview stuff
303 //
304
305 void InsetFormula::statusChanged() const
306 {
307         if (view())
308                 view()->updateInset(this);
309 }
310
311
312 void InsetFormula::addPreview(lyx::graphics::PreviewLoader & ploader) const
313 {
314         preview_->addPreview(ploader);
315 }
316
317
318 void InsetFormula::generatePreview(Buffer const & buffer) const
319 {
320         preview_->generatePreview(buffer);
321 }
322
323
324 bool InsetFormula::PreviewImpl::previewWanted(Buffer const &) const
325 {
326         return !parent_.par_->asNestInset()->editing();
327 }
328
329
330 string const InsetFormula::PreviewImpl::latexString(Buffer const &) const
331 {
332         ostringstream ls;
333         WriteStream wi(ls, false, false);
334         parent_.par_->write(wi);
335         return ls.str();
336 }