]> git.lyx.org Git - lyx.git/blob - src/mathed/formula.C
Towards saner generation of previews code. Yeah, I know. I wrote it in
[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         if (!editing_inset && bv) {
204                 Buffer const * buffer_ptr = bv->buffer();
205                 if (buffer_ptr)
206                         preview_->generatePreview(*buffer_ptr);
207         }
208
209         int const w = dim_.wid;
210         int const d = dim_.des;
211         int const a = dim_.asc;
212         int const h = a + d;
213
214         if (use_preview) {
215                 pi.pain.image(x + 1, y - a, w, h,   // one pixel gap in front
216                               *(preview_->pimage()->image()));
217         } else {
218                 PainterInfo p(bv);
219                 p.base.style = LM_ST_TEXT;
220                 p.base.font  = pi.base.font;
221                 p.base.font.setColor(LColor::math);
222                 if (lcolor.getX11Name(LColor::mathbg)
223                             != lcolor.getX11Name(LColor::background))
224                         p.pain.fillRectangle(x, y - a, w, h, LColor::mathbg);
225
226                 if (editing_inset) {
227                         mathcursor->drawSelection(pi);
228                         //p.pain.rectangle(x, y - a, w, h, LColor::mathframe);
229                 }
230
231                 par_->draw(p, x + offset_, y);
232         }
233
234         xo_ = x;
235         yo_ = y;
236 }
237
238
239 void InsetFormula::getLabelList(Buffer const & buffer,
240                                 vector<string> & res) const
241 {
242         par()->getLabelList(buffer, res);
243 }
244
245
246 InsetOld::Code InsetFormula::lyxCode() const
247 {
248         return InsetOld::MATH_CODE;
249 }
250
251
252 void InsetFormula::validate(LaTeXFeatures & features) const
253 {
254         par_->validate(features);
255 }
256
257
258 bool InsetFormula::insetAllowed(InsetOld::Code code) const
259 {
260         return
261                    code == InsetOld::LABEL_CODE
262                 || code == InsetOld::REF_CODE
263                 || code == InsetOld::ERT_CODE;
264 }
265
266
267 void InsetFormula::metrics(MetricsInfo & m, Dimension & dim) const
268 {
269         view_ = m.base.bv;
270
271         bool const editing_inset = mathcursor && mathcursor->formula() == this;
272         bool const use_preview = !editing_inset && preview_->previewReady();
273
274         if (use_preview) {
275                 dim.asc = preview_->pimage()->ascent();
276                 dim.des = preview_->pimage()->descent();
277                 // insert a one pixel gap in front of the formula
278                 dim.wid = 1 + preview_->pimage()->width();
279                 if (display())
280                         dim.des += 12;
281         } else {
282                 MetricsInfo mi = m;
283                 mi.base.style = LM_ST_TEXT;
284                 mi.base.font.setColor(LColor::math);
285                 par()->metrics(mi, dim);
286                 dim.asc += 1;
287                 dim.des += 1;
288         }
289
290         if (display()) {
291                 offset_ = (m.base.textwidth - dim.wid) / 2;
292                 dim.wid = m.base.textwidth;
293         } else {
294                 offset_ = 0;
295         }
296
297         dim_ = dim;
298 }
299
300
301 void InsetFormula::mutate(string const & type)
302 {
303         par_.nucleus()->mutate(type);
304 }
305
306
307 //
308 // preview stuff
309 //
310
311 void InsetFormula::statusChanged() const
312 {
313         if (view())
314                 view()->updateInset(this);
315 }
316
317
318 void InsetFormula::addPreview(lyx::graphics::PreviewLoader & ploader) const
319 {
320         preview_->addPreview(ploader);
321 }
322
323
324 void InsetFormula::generatePreview(Buffer const & buffer) const
325 {
326         preview_->generatePreview(buffer);
327 }
328
329
330 bool InsetFormula::PreviewImpl::previewWanted(Buffer const &) const
331 {
332         return !parent_.par_->asNestInset()->editing();
333 }
334
335
336 string const InsetFormula::PreviewImpl::latexString(Buffer const &) const
337 {
338         ostringstream ls;
339         WriteStream wi(ls, false, false);
340         parent_.par_->write(wi);
341         return ls.str();
342 }