]> git.lyx.org Git - lyx.git/blob - src/mathed/formula.C
Re-introduction of a BraceInset to handle "extra braces"
[lyx.git] / src / mathed / formula.C
1 /*
2 *  File:        formula.C
3 *  Purpose:     Implementation of formula inset
4 *  Author:      Alejandro Aguilar Sierra <asierra@servidor.unam.mx>
5 *  Created:     January 1996
6 *  Description: Allows the edition of math paragraphs inside Lyx.
7 *
8 *  Copyright: 1996-1998 Alejandro Aguilar Sierra
9 *
10 *  Version: 0.4, Lyx project.
11 *
12 *   You are free to use and modify this code under the terms of
13 *   the GNU General Public Licence version 2 or later.
14 */
15
16 #ifdef __GNUG__
17 #pragma implementation
18 #endif
19
20 #include <config.h>
21
22 #include "formula.h"
23 #include "commandtags.h"
24 #include "math_cursor.h"
25 #include "math_parser.h"
26 #include "math_charinset.h"
27 #include "lyx_main.h"
28 #include "BufferView.h"
29 #include "gettext.h"
30 #include "debug.h"
31 #include "lyx_gui_misc.h"
32 #include "support/LOstream.h"
33 #include "support/LAssert.h"
34 #include "support/lyxlib.h"
35 #include "support/syscall.h"
36 #include "support/lstrings.h"
37 #include "support/filetools.h" // LibFileSearch
38 #include "LyXView.h"
39 #include "Painter.h"
40 #include "lyxrc.h"
41 #include "math_matrixinset.h"
42 #include "mathed/support.h"
43
44 using std::ostream;
45 using std::ifstream;
46 using std::istream;
47 using std::pair;
48 using std::endl;
49 using std::vector;
50
51
52 namespace {
53
54         void stripFromLastEqualSign(MathArray & ar)
55         {
56                 // find position of last '=' in the array
57                 MathArray::size_type pos = ar.size();
58                 for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it)
59                         if ((*it)->getChar() == '=')
60                                 pos = it - ar.begin();
61
62                 // delete everything behind this position
63                 ar.erase(pos, ar.size());
64         }
65
66
67         MathArray pipeThroughExtern(string const & arg, MathArray const & ar)
68         {
69                 string lang;
70                 string extra;
71                 istringstream iss(arg.c_str());
72                 iss >> lang >> extra;
73                 if (extra.empty())
74                         extra = "noextra";      
75
76                 // create normalized expression
77                 string outfile = lyx::tempName(string(), "mathextern");
78                 ostringstream os;
79                 os << "[" << extra << ' ';
80                 ar.writeNormal(os); 
81                 os << "]";
82                 string code = os.str().c_str();
83
84                 // run external sript
85                 string file = LibFileSearch(string(), "lyx2" + lang);
86                 if (file.empty()) {
87                         lyxerr << "converter to '" << lang << "' not found\n";
88                         return MathArray();
89                 }
90                 string script = file + " '" + code + "' " + outfile;
91                 lyxerr << "calling: " << script << endl;
92                 Systemcalls cmd(Systemcalls::System, script, 0);
93
94                 // append result
95                 MathArray res;
96                 mathed_parse_cell(res, GetFileContents(outfile));
97                 return res;
98         }
99
100 }
101
102
103 InsetFormula::InsetFormula()
104         : par_(MathAtom(new MathMatrixInset))
105 {}
106
107
108 InsetFormula::InsetFormula(MathInsetTypes t)
109         : par_(MathAtom(new MathMatrixInset(t)))
110 {}
111
112
113 InsetFormula::InsetFormula(string const & s) 
114 {
115         if (s.size()) {
116                 bool res = mathed_parse_normal(par_, s);
117
118                 if (!res)
119                         res = mathed_parse_normal(par_, "$" + s + "$");
120
121                 if (!res) {
122                         lyxerr << "cannot interpret '" << s << "' as math\n";
123                         par_ = MathAtom(new MathMatrixInset(LM_OT_SIMPLE));
124                 }
125         }
126         metrics();
127 }
128
129
130 Inset * InsetFormula::clone(Buffer const &, bool) const
131 {
132         return new InsetFormula(*this);
133 }
134
135
136 void InsetFormula::write(Buffer const * buf, ostream & os) const
137 {
138         os << "Formula ";
139         latex(buf, os, false, false);
140 }
141
142
143 int InsetFormula::latex(Buffer const * buf, ostream & os, bool fragil, bool)
144         const
145 {
146         MathWriteInfo wi(buf, os, fragil);
147         par_->write(wi);
148         return 1;
149 }
150
151
152 int InsetFormula::ascii(Buffer const * buf, ostream & os, int) const
153 {
154         MathWriteInfo wi(buf, os, false);
155         par_->write(wi);
156         return 1;
157 }
158
159
160 int InsetFormula::linuxdoc(Buffer const * buf, ostream & os) const
161 {
162         return ascii(buf, os, 0);
163 }
164
165
166 int InsetFormula::docbook(Buffer const * buf, ostream & os) const
167 {
168         return ascii(buf, os, 0);
169 }
170
171
172 void InsetFormula::read(Buffer const *, LyXLex & lex)
173 {
174         mathed_parse_normal(par_, lex);
175         metrics();
176 }
177
178
179 void InsetFormula::draw(BufferView * bv, LyXFont const & font,
180                         int y, float & xx, bool) const
181 {
182         int x = int(xx) - 1;
183         y -= 2;
184
185         Painter & pain = bv->painter();
186
187         metrics(bv, font);
188         int w = par_->width();
189         int h = par_->height();
190         int a = par_->ascent();
191         pain.fillRectangle(x, y - a, w, h, LColor::mathbg);
192
193         if (mathcursor && mathcursor->formula() == this) {
194                 mathcursor->drawSelection(pain);
195                 pain.rectangle(x, y - a, w, h, LColor::mathframe);
196         }
197
198         par_->draw(pain, x, y);
199         xx += par_->width();
200         xo_ = x;
201         yo_ = y;
202
203         setCursorVisible(false);
204 }
205
206
207 vector<string> const InsetFormula::getLabelList() const
208 {
209         return mat()->getLabelList();
210 }
211
212
213 UpdatableInset::RESULT
214 InsetFormula::localDispatch(BufferView * bv, kb_action action,
215          string const & arg)
216 {
217         RESULT result = DISPATCHED;
218
219         switch (action) {
220
221                 case LFUN_BREAKLINE: 
222                         bv->lockedInsetStoreUndo(Undo::INSERT);
223                         mathcursor->breakLine();
224                         mathcursor->normalize();
225                         updateLocal(bv, true);
226                         break;
227
228                 case LFUN_MATH_NUMBER:
229                 {
230                         //lyxerr << "toggling all numbers\n";
231                         if (display()) {
232                                 bv->lockedInsetStoreUndo(Undo::INSERT);
233                                 bool old = mat()->numberedType();
234                                 for (MathInset::row_type row = 0; row < par_->nrows(); ++row)
235                                         mat()->numbered(row, !old);
236                                 bv->owner()->message(old ? _("No number") : _("Number"));
237                                 updateLocal(bv, true);
238                         }
239                         break;
240                 }
241
242                 case LFUN_MATH_NONUMBER:
243                 {
244                         //lyxerr << "toggling line number\n";
245                         if (display()) {
246                                 bv->lockedInsetStoreUndo(Undo::INSERT);
247                                 MathCursor::row_type row = mathcursor->row();
248                                 bool old = mat()->numbered(row);
249                                 bv->owner()->message(old ? _("No number") : _("Number"));
250                                 mat()->numbered(row, !old);
251                                 updateLocal(bv, true);
252                         }
253                         break;
254                 }
255
256                 case LFUN_INSERT_LABEL:
257                 {
258                         bv->lockedInsetStoreUndo(Undo::INSERT);
259
260                         MathCursor::row_type row = mathcursor->row();
261                         string old_label = mat()->label(row);
262                         string new_label = arg;
263
264                         if (new_label.empty()) {
265                                 string const default_label =
266                                         (lyxrc.label_init_length >= 0) ? "eq:" : "";
267                                 pair<bool, string> const res = old_label.empty()
268                                         ? askForText(_("Enter new label to insert:"), default_label)
269                                         : askForText(_("Enter label:"), old_label);
270                                 
271                                 lyxerr << "res: " << res.first << " - '" << res.second << "'\n";
272                                 if (!res.first)
273                                         break;
274                                 new_label = frontStrip(strip(res.second));
275                         }
276
277                         //if (new_label == old_label)
278                         //      break;  // Nothing to do
279
280                         if (!new_label.empty()) {
281                                 lyxerr << "setting label to '" << new_label << "'\n";
282                                 mat()->numbered(row, true);
283                         }
284
285                         if (!new_label.empty() && bv->ChangeRefsIfUnique(old_label, new_label))
286                                 bv->redraw();
287
288                         mat()->label(row, new_label);
289
290                         updateLocal(bv, true);
291                         break;
292                 }
293
294                 case LFUN_MATH_MUTATE:
295                 {
296                         bv->lockedInsetStoreUndo(Undo::EDIT);
297                         int x;
298                         int y;
299                         mathcursor->getPos(x, y);
300                         mat()->mutate(arg);
301                         mathcursor->setPos(x, y);
302                         mathcursor->normalize();
303                         updateLocal(bv, true);
304                         break;
305                 }
306
307                 case LFUN_MATH_EXTERN:
308                 {
309                         bv->lockedInsetStoreUndo(Undo::EDIT);
310                         handleExtern(arg);
311                         // re-compute inset dimension
312                         metrics(bv);
313                         updateLocal(bv, true);
314                         break;
315                 }
316
317                 case LFUN_MATH_DISPLAY:
318                 {
319                         int x;
320                         int y;
321                         mathcursor->getPos(x, y);
322                         if (mat()->getType() == LM_OT_SIMPLE)
323                                 mat()->mutate(LM_OT_EQUATION);
324                         else
325                                 mat()->mutate(LM_OT_SIMPLE);
326                         mathcursor->setPos(x, y);
327                         mathcursor->normalize();
328                         updateLocal(bv, true);
329                         break;
330                 }
331                 
332                 case LFUN_PASTESELECTION:
333                 {
334                         string const clip = bv->getClipboard();
335                 if (!clip.empty())
336                                 mathed_parse_normal(par_, clip);
337                         break;
338                 }
339
340                 case LFUN_MATH_COLUMN_INSERT:
341                 {
342                         if (mat()->getType() == LM_OT_ALIGN)
343                                 mat()->mutate(LM_OT_ALIGNAT);
344                         mat()->addCol(mat()->ncols());
345                         mathcursor->normalize();
346                         updateLocal(bv, true);
347                 }
348
349                 default:
350                         result = InsetFormulaBase::localDispatch(bv, action, arg);
351         }
352
353         return result;
354 }
355
356
357 void InsetFormula::handleExtern(const string & arg)
358 {
359         // where are we?
360         if (!mathcursor)
361                 return; 
362
363         bool selected = mathcursor->selection();
364
365         MathArray ar;
366         if (selected) {
367                 mathcursor->selGet(ar);
368                 lyxerr << "use selection: " << ar << "\n";
369         } else {
370                 mathcursor->end();
371                 ar = mathcursor->cursor().cell();
372                 stripFromLastEqualSign(ar);
373                 mathcursor->insert(MathAtom(new MathCharInset('=', LM_TC_VAR)));
374                 lyxerr << "use whole cell: " << ar << "\n";
375         }
376
377         mathcursor->insert(pipeThroughExtern(arg, ar));
378 }
379
380
381 bool InsetFormula::display() const
382 {
383         return mat()->getType() != LM_OT_SIMPLE;
384 }
385
386
387 MathMatrixInset const * InsetFormula::mat() const
388 {
389         lyx::Assert(par_->asMatrixInset());
390         return par_->asMatrixInset();
391 }
392
393
394 MathMatrixInset * InsetFormula::mat()
395 {
396         lyx::Assert(par_->asMatrixInset());
397         return par_->asMatrixInset();
398 }
399
400
401 Inset::Code InsetFormula::lyxCode() const
402 {
403         return Inset::MATH_CODE;
404 }
405
406
407 void InsetFormula::validate(LaTeXFeatures & features) const
408 {
409         par_->validate(features);
410 }
411
412
413 bool InsetFormula::insetAllowed(Inset::Code code) const
414 {
415         return code == Inset::LABEL_CODE && display(); 
416 }
417
418
419 int InsetFormula::ascent(BufferView *, LyXFont const &) const
420 {
421         return par_->ascent() + 2;
422 }
423
424
425 int InsetFormula::descent(BufferView *, LyXFont const &) const
426 {
427         return par_->descent() - 2;
428 }
429
430
431 int InsetFormula::width(BufferView * bv, LyXFont const & font) const
432 {
433         metrics(bv, font);
434         return par_->width();
435 }
436
437
438 MathInsetTypes InsetFormula::getType() const
439 {
440         return mat()->getType();
441 }