]> git.lyx.org Git - features.git/blob - src/mathed/formulabase.C
Part of IU.
[features.git] / src / mathed / formulabase.C
1 /**
2  * \file formulabase.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 "cursor.h"
15 #include "formulabase.h"
16 #include "formula.h"
17 #include "formulamacro.h"
18 #include "math_support.h"
19 #include "math_arrayinset.h"
20 #include "math_deliminset.h"
21 #include "math_cursor.h"
22 #include "math_factory.h"
23 #include "math_hullinset.h"
24 #include "math_parser.h"
25 #include "math_spaceinset.h"
26 #include "ref_inset.h"
27
28 #include "BufferView.h"
29 #include "bufferview_funcs.h"
30 #include "dispatchresult.h"
31 #include "debug.h"
32 #include "funcrequest.h"
33 #include "gettext.h"
34 #include "LColor.h"
35 #include "lyxtext.h"
36 #include "undo.h"
37
38 #include "frontends/LyXView.h"
39 #include "frontends/Dialogs.h"
40
41 #include "support/std_sstream.h"
42 #include "support/lstrings.h"
43 #include "support/lyxlib.h"
44
45 using lyx::support::atoi;
46 using lyx::support::split;
47 using lyx::support::token;
48
49 using std::string;
50 using std::abs;
51 using std::endl;
52 using std::max;
53 using std::istringstream;
54 using std::ostringstream;
55
56
57 namespace {
58
59 // local global
60 int first_x;
61 int first_y;
62
63 bool openNewInset(LCursor & cur, UpdatableInset * inset)
64 {
65         if (!cur.bv().insertInset(inset)) {
66                 delete inset;
67                 return false;
68         }
69         inset->edit(cur, true);
70         return true;
71 }
72
73
74 } // namespace anon
75
76
77
78 InsetFormulaBase::InsetFormulaBase()
79 {
80         // This is needed as long the math parser is not re-entrant
81         initMath();
82         //lyxerr << "sizeof MathInset: " << sizeof(MathInset) << endl;
83         //lyxerr << "sizeof MetricsInfo: " << sizeof(MetricsInfo) << endl;
84         //lyxerr << "sizeof MathCharInset: " << sizeof(MathCharInset) << endl;
85         //lyxerr << "sizeof LyXFont: " << sizeof(LyXFont) << endl;
86 }
87
88
89 // simply scrap this function if you want
90 void InsetFormulaBase::mutateToText()
91 {
92 #if 0
93         // translate to latex
94         ostringstream os;
95         latex(NULL, os, false, false);
96         string str = os.str();
97
98         // insert this text
99         LyXText * lt = view_->getLyXText();
100         string::const_iterator cit = str.begin();
101         string::const_iterator end = str.end();
102         for (; cit != end; ++cit)
103                 view_->owner()->getIntl()->getTransManager().TranslateAndInsert(*cit, lt);
104
105         // remove ourselves
106         //view_->owner()->dispatch(LFUN_ESCAPE);
107 #endif
108 }
109
110
111 void InsetFormulaBase::handleFont
112         (LCursor & cur, string const & arg, string const & font)
113 {
114         // this whole function is a hack and won't work for incremental font
115         // changes...
116         recordUndo(cur, Undo::ATOMIC);
117
118         if (cur.inset()->asMathInset()->name() == font)
119                 mathcursor::handleFont(cur, font);
120         else {
121                 mathcursor::handleNest(cur, createMathInset(font));
122                 mathcursor::insert(cur, arg);
123         }
124 }
125
126
127 void InsetFormulaBase::handleFont2(LCursor & cur, string const & arg)
128 {
129         recordUndo(cur, Undo::ATOMIC);
130         LyXFont font;
131         bool b;
132         bv_funcs::string2font(arg, font, b);
133         if (font.color() != LColor::inherit) {
134                 MathAtom at = createMathInset("color");
135                 asArray(lcolor.getGUIName(font.color()), at.nucleus()->cell(0));
136                 mathcursor::handleNest(cur, at, 1);
137         }
138 }
139
140
141
142 void InsetFormulaBase::validate(LaTeXFeatures &) const
143 {}
144
145
146 string const InsetFormulaBase::editMessage() const
147 {
148         return _("Math editor mode");
149 }
150
151
152 void InsetFormulaBase::insetUnlock(BufferView & bv)
153 {
154         if (inMathed()) {
155                 if (mathcursor::inMacroMode(bv.cursor()))
156                         mathcursor::macroModeClose(bv.cursor());
157                 releaseMathCursor(bv.cursor());
158         }
159         if (bv.buffer())
160                 generatePreview(*bv.buffer());
161         bv.update();
162 }
163
164
165 void InsetFormulaBase::getCursorPos(BufferView & bv, int & x, int & y) const
166 {
167         if (inMathed()) {
168                 mathcursor::getScreenPos(bv.cursor(), x, y);
169                 x = mathcursor::targetX(bv.cursor());
170                 x -= xo_;
171                 y -= yo_;
172                 lyxerr << "InsetFormulaBase::getCursorPos: " << x << ' ' << y << endl;
173         } else {
174                 x = 0;
175                 y = 0;
176                 lyxerr << "getCursorPos - should not happen";
177         }
178 }
179
180
181 void InsetFormulaBase::getCursorDim(int & asc, int & desc) const
182 {
183         if (inMathed()) {
184                 asc = 10;
185                 desc = 2;
186                 //math_font_max_dim(font_, asc, des);
187         }
188 }
189
190
191 DispatchResult
192 InsetFormulaBase::lfunMouseRelease(LCursor & cur, FuncRequest const & cmd)
193 {
194         if (!inMathed())
195                 return DispatchResult(false);
196         cur.bv().update();
197         //lyxerr << "lfunMouseRelease: buttons: " << cmd.button() << endl;
198
199         if (cmd.button() == mouse_button::button3) {
200                 // try to dispatch to enclosed insets first
201                 if (!mathcursor::dispatch(cur, cmd).dispatched()) {
202                         // launch math panel for right mouse button
203                         lyxerr << "lfunMouseRelease: undispatched: " << cmd.button() << endl;
204                         cur.bv().owner()->getDialogs().show("mathpanel");
205                 }
206                 return DispatchResult(true, true);
207         }
208
209         if (cmd.button() == mouse_button::button2) {
210                 MathArray ar;
211                 asArray(cur.bv().getClipboard(), ar);
212                 mathcursor::selClear(cur);
213                 mathcursor::setScreenPos(cur, cmd.x + xo_, cmd.y + yo_);
214                 mathcursor::insert(cur, ar);
215                 cur.bv().update();
216                 return DispatchResult(true, true);
217         }
218
219         if (cmd.button() == mouse_button::button1) {
220                 // try to dispatch to enclosed insets first
221                 mathcursor::dispatch(cur, cmd);
222                 cur.bv().stuffClipboard(mathcursor::grabSelection(cur));
223                 // try to set the cursor
224                 //delete mathcursor;
225                 //mathcursor = new MathCursor(bv, this, x == 0);
226                 //metrics(bv);
227                 //mathcursor::setScreenPos(x + xo_, y + yo_);
228                 return DispatchResult(true, true);
229         }
230
231         return DispatchResult(false);
232 }
233
234
235 DispatchResult
236 InsetFormulaBase::lfunMousePress(LCursor & cur, FuncRequest const & cmd)
237 {
238         //lyxerr << "lfunMousePress: buttons: " << cmd.button() << endl;
239
240         if (!inMathed() || mathcursor::formula() != this) {
241                 lyxerr[Debug::MATHED] << "re-create cursor" << endl;
242                 releaseMathCursor(cur);
243                 mathcursor::formula_ = this;
244                 cur.idx() = 0;
245                 //metrics(bv);
246                 mathcursor::setScreenPos(cur, cmd.x + xo_, cmd.y + yo_);
247         }
248
249         if (cmd.button() == mouse_button::button3) {
250                 mathcursor::dispatch(cur, cmd);
251                 return DispatchResult(true, true);
252         }
253
254         if (cmd.button() == mouse_button::button1) {
255                 first_x = cmd.x;
256                 first_y = cmd.y;
257                 mathcursor::selClear(cur);
258                 mathcursor::setScreenPos(cur, cmd.x + xo_, cmd.y + yo_);
259                 mathcursor::dispatch(cur, cmd);
260                 return DispatchResult(true, true);
261         }
262
263         cur.bv().update();
264         return DispatchResult(true, true);
265 }
266
267
268 DispatchResult
269 InsetFormulaBase::lfunMouseMotion(LCursor & cur, FuncRequest const & cmd)
270 {
271         if (!inMathed())
272                 return DispatchResult(true, true);
273
274         if (mathcursor::dispatch(cur, FuncRequest(cmd)).dispatched())
275                 return DispatchResult(true, true);
276
277         // only select with button 1
278         if (cmd.button() != mouse_button::button1)
279                 return DispatchResult(true, true);
280
281         if (abs(cmd.x - first_x) < 2 && abs(cmd.y - first_y) < 2)
282                 return DispatchResult(true, true);
283
284         first_x = cmd.x;
285         first_y = cmd.y;
286
287         if (!cur.selection())
288                 mathcursor::selStart(cur);
289
290         mathcursor::setScreenPos(cur, cmd.x + xo_, cmd.y + yo_);
291         cur.bv().update();
292         return DispatchResult(true, true);
293 }
294
295
296 void InsetFormulaBase::edit(LCursor & cur, bool /*left*/)
297 {
298         lyxerr << "Called FormulaBase::edit" << endl;
299         mathcursor::formula_ = this;
300         cur.push(this);
301         cur.idx() = 0;
302         cur.pos() = 0;
303 #warning FIXME
304         cur.push(par().nucleus()->asHullInset());
305         //cur.idx() = left ? 0 : cur.lastidx();
306         cur.idx() = 0;
307         cur.pos() = 0;
308         cur.resetAnchor();
309 }
310
311
312 void InsetFormulaBase::edit(LCursor & cur, int x, int y)
313 {
314         lyxerr << "Called FormulaBase::EDIT with '" << x << ' ' << y << "'" << endl;
315         releaseMathCursor(cur);
316         //metrics(bv);
317         cur.push(this);
318         cur.idx() = 0;
319         cur.pos() = 0;
320         mathcursor::setScreenPos(cur, x + xo_, y + yo_);
321         cur.push(par().nucleus()->asHullInset());
322         //cur.idx() = left ? 0 : cur.lastidx();
323         cur.idx() = 0;
324         cur.pos() = 0;
325         // if that is removed, we won't get the magenta box when entering an
326         // inset for the first time
327         cur.bv().update();
328 }
329
330
331 DispatchResult
332 InsetFormulaBase::priv_dispatch(LCursor & cur, FuncRequest const & cmd)
333 {
334         return par().nucleus()->dispatch(cur, cmd);
335
336         //lyxerr << "InsetFormulaBase::localDispatch: act: " << cmd.action
337         //      << " arg: '" << cmd.argument
338         //      << "' x: '" << cmd.x
339         //      << " y: '" << cmd.y
340         //      << "' button: " << cmd.button() << endl;
341
342 #if 0
343         // delete empty mathbox (LFUN_BACKSPACE and LFUN_DELETE)
344         bool remove_inset = false;
345
346         switch (cmd.action) {
347                 case LFUN_MOUSE_PRESS:
348                         //lyxerr << "Mouse single press" << endl;
349                         return lfunMousePress(cur, cmd);
350                 case LFUN_MOUSE_MOTION:
351                         //lyxerr << "Mouse motion" << endl;
352                         return lfunMouseMotion(cur, cmd);
353                 case LFUN_MOUSE_RELEASE:
354                         //lyxerr << "Mouse single release" << endl;
355                         return lfunMouseRelease(cur, cmd);
356                 case LFUN_MOUSE_DOUBLE:
357                         //lyxerr << "Mouse double" << endl;
358                         return dispatch(cur, FuncRequest(LFUN_WORDSEL));
359                 default:
360                         break;
361         }
362
363         DispatchResult result(true);
364         string argument    = cmd.argument;
365         bool sel           = false;
366         bool was_macro     = mathcursor::inMacroMode(cur);
367
368         mathcursor::normalize(cur);
369         mathcursor::touch();
370
371         switch (cmd.action) {
372
373         case LFUN_MATH_MUTATE:
374         case LFUN_MATH_DISPLAY:
375         case LFUN_MATH_NUMBER:
376         case LFUN_MATH_NONUMBER:
377         case LFUN_CELL_SPLIT:
378         case LFUN_BREAKLINE:
379         case LFUN_DELETE_LINE_FORWARD:
380         case LFUN_INSERT_LABEL:
381         case LFUN_MATH_EXTERN:
382         case LFUN_TABULAR_FEATURE:
383         case LFUN_PASTESELECTION:
384         case LFUN_MATH_LIMITS:
385                 recordUndo(cur, Undo::ATOMIC);
386                 mathcursor::dispatch(cur, cmd);
387                 break;
388
389         case LFUN_WORDSEL:
390                 mathcursor::home(cur, false);
391                 mathcursor::end(cur, true);
392                 break;
393
394         case LFUN_UP_PARAGRAPHSEL:
395         case LFUN_UP_PARAGRAPH:
396         case LFUN_DOWN_PARAGRAPHSEL:
397         case LFUN_DOWN_PARAGRAPH:
398                 result = DispatchResult(true, FINISHED);
399                 break;
400
401         case LFUN_HOMESEL:
402         case LFUN_WORDLEFTSEL:
403                 sel = true; // fall through
404         case LFUN_HOME:
405         case LFUN_WORDLEFT:
406                 result = mathcursor::home(cur, sel)
407                         ? DispatchResult(true, true) : DispatchResult(true, FINISHED);
408                 break;
409
410         case LFUN_ENDSEL:
411         case LFUN_WORDRIGHTSEL:
412                 sel = true; // fall through
413         case LFUN_END:
414         case LFUN_WORDRIGHT:
415                 result = mathcursor::end(cur, sel)
416                         ? DispatchResult(true, true) : DispatchResult(false, FINISHED_RIGHT);
417                 break;
418
419         case LFUN_PRIORSEL:
420         case LFUN_PRIOR:
421         case LFUN_BEGINNINGBUFSEL:
422         case LFUN_BEGINNINGBUF:
423                 result = DispatchResult(true, FINISHED);
424                 break;
425
426         case LFUN_NEXTSEL:
427         case LFUN_NEXT:
428         case LFUN_ENDBUFSEL:
429         case LFUN_ENDBUF:
430                 result = DispatchResult(false, FINISHED_RIGHT);
431                 break;
432
433         case LFUN_CELL_FORWARD:
434                 mathcursor::idxNext(cur);
435                 break;
436
437         case LFUN_CELL_BACKWARD:
438                 mathcursor::idxPrev(cur);
439                 break;
440
441         case LFUN_DELETE_WORD_BACKWARD:
442         case LFUN_BACKSPACE:
443                 recordUndo(cur, Undo::ATOMIC);
444                 if (!mathcursor::backspace(cur)) {
445                         result = DispatchResult(true, FINISHED);
446                         remove_inset = true;
447                 }
448                 break;
449
450         case LFUN_DELETE_WORD_FORWARD:
451         case LFUN_DELETE:
452                 recordUndo(cur, Undo::ATOMIC);
453                 if (!mathcursor::erase(cur)) {
454                         result = DispatchResult(true, FINISHED);
455                         remove_inset = true;
456                 }
457                 break;
458
459         //    case LFUN_GETXY:
460         //      sprintf(dispatch_buffer, "%d %d",);
461         //      DispatchResult= dispatch_buffer;
462         //      break;
463         case LFUN_SETXY: {
464                 lyxerr << "LFUN_SETXY broken!" << endl;
465                 int x = 0;
466                 int y = 0;
467                 istringstream is(cmd.argument.c_str());
468                 is >> x >> y;
469                 mathcursor::setScreenPos(cur, x, y);
470                 break;
471         }
472
473         case LFUN_PASTE: {
474                 size_t n = 0;
475                 istringstream is(cmd.argument.c_str());
476                 is >> n;
477                 if (was_macro)
478                         mathcursor::macroModeClose(cur);
479                 recordUndo(cur, Undo::ATOMIC);
480                 mathcursor::selPaste(cur, n);
481                 break;
482         }
483
484         case LFUN_CUT:
485                 recordUndo(cur, Undo::DELETE);
486                 mathcursor::selCut(cur);
487                 break;
488
489         case LFUN_COPY:
490                 mathcursor::selCopy(cur);
491                 break;
492
493
494         // Special casing for superscript in case of LyX handling
495         // dead-keys:
496         case LFUN_CIRCUMFLEX:
497                 if (cmd.argument.empty()) {
498                         // do superscript if LyX handles
499                         // deadkeys
500                         recordUndo(cur, Undo::ATOMIC);
501                         mathcursor::script(cur, true);
502                 }
503                 break;
504
505         case LFUN_UMLAUT:
506         case LFUN_ACUTE:
507         case LFUN_GRAVE:
508         case LFUN_BREVE:
509         case LFUN_DOT:
510         case LFUN_MACRON:
511         case LFUN_CARON:
512         case LFUN_TILDE:
513         case LFUN_CEDILLA:
514         case LFUN_CIRCLE:
515         case LFUN_UNDERDOT:
516         case LFUN_TIE:
517         case LFUN_OGONEK:
518         case LFUN_HUNG_UMLAUT:
519                 break;
520
521         //  Math fonts
522         case LFUN_FREEFONT_APPLY:
523         case LFUN_FREEFONT_UPDATE:
524                 handleFont2(cur, cmd.argument);
525                 break;
526
527         case LFUN_BOLD:         handleFont(cur, cmd.argument, "mathbf"); break;
528         case LFUN_SANS:         handleFont(cur, cmd.argument, "mathsf"); break;
529         case LFUN_EMPH:         handleFont(cur, cmd.argument, "mathcal"); break;
530         case LFUN_ROMAN:        handleFont(cur, cmd.argument, "mathrm"); break;
531         case LFUN_CODE:         handleFont(cur, cmd.argument, "texttt"); break;
532         case LFUN_FRAK:         handleFont(cur, cmd.argument, "mathfrak"); break;
533         case LFUN_ITAL:         handleFont(cur, cmd.argument, "mathit"); break;
534         case LFUN_NOUN:         handleFont(cur, cmd.argument, "mathbb"); break;
535         //case LFUN_FREEFONT_APPLY:  handleFont(cur, cmd.argument, "textrm"); break;
536         case LFUN_DEFAULT:      handleFont(cur, cmd.argument, "textnormal"); break;
537
538         case LFUN_MATH_MODE:
539                 if (mathcursor::currentMode(cur) == MathInset::TEXT_MODE)
540                         mathcursor::niceInsert(cur, MathAtom(new MathHullInset("simple")));
541                 else
542                         handleFont(cur, cmd.argument, "textrm");
543                 //cur.owner()->message(_("math text mode toggled"));
544                 break;
545
546         case LFUN_MATH_SIZE:
547 #if 0
548                 if (!arg.empty()) {
549                         recordUndo(cur, Undo::ATOMIC);
550                         mathcursor::setSize(arg);
551                 }
552 #endif
553                 break;
554
555         case LFUN_INSERT_MATRIX: {
556                 recordUndo(cur, Undo::ATOMIC);
557                 unsigned int m = 1;
558                 unsigned int n = 1;
559                 string v_align;
560                 string h_align;
561                 istringstream is(argument);
562                 is >> m >> n >> v_align >> h_align;
563                 m = max(1u, m);
564                 n = max(1u, n);
565                 v_align += 'c';
566                 mathcursor::niceInsert(cur,
567                         MathAtom(new MathArrayInset("array", m, n, v_align[0], h_align)));
568                 break;
569         }
570
571         case LFUN_MATH_DELIM: {
572                 //lyxerr << "formulabase::LFUN_MATH_DELIM, arg: '" << arg << "'" << endl;
573                 string ls;
574                 string rs = split(cmd.argument, ls, ' ');
575                 // Reasonable default values
576                 if (ls.empty())
577                         ls = '(';
578                 if (rs.empty())
579                         rs = ')';
580                 recordUndo(cur, Undo::ATOMIC);
581                 mathcursor::handleNest(cur, MathAtom(new MathDelimInset(ls, rs)));
582                 break;
583         }
584
585         case LFUN_SPACE_INSERT:
586         case LFUN_MATH_SPACE:
587                 recordUndo(cur, Undo::ATOMIC);
588                 mathcursor::insert(cur, MathAtom(new MathSpaceInset(",")));
589                 break;
590
591         case LFUN_UNDO:
592                 cur.bv().owner()->message(_("Invalid action in math mode!"));
593                 break;
594
595
596         case LFUN_EXEC_COMMAND:
597                 result = DispatchResult(false);
598                 break;
599
600         case LFUN_INSET_ERT:
601                 // interpret this as if a backslash was typed
602                 recordUndo(cur, Undo::ATOMIC);
603                 mathcursor::interpret(cur, '\\');
604                 break;
605
606         case LFUN_BREAKPARAGRAPH:
607         case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
608         case LFUN_BREAKPARAGRAPH_SKIP:
609                 argument = "\n";
610                 // fall through
611
612 // FIXME: We probably should swap parts of "math-insert" and "self-insert"
613 // handling such that "self-insert" works on "arbitrary stuff" too, and
614 // math-insert only handles special math things like "matrix".
615         case LFUN_INSERT_MATH:
616                 recordUndo(cur, Undo::ATOMIC);
617                 mathcursor::niceInsert(cur, argument);
618                 break;
619
620         case -1:
621         case LFUN_SELFINSERT:
622                 if (!argument.empty()) {
623                         recordUndo(cur, Undo::ATOMIC);
624                         if (argument.size() == 1)
625                                 result = mathcursor::interpret(cur, argument[0])
626                                         ? DispatchResult(true, true) : DispatchResult(false, FINISHED_RIGHT);
627                         else
628                                 mathcursor::insert(cur, argument);
629                 }
630                 break;
631
632         case LFUN_ESCAPE:
633                 if (cur.selection())
634                         mathcursor::selClear(cur);
635                 else
636                         result = DispatchResult(false);
637                 break;
638
639         case LFUN_INSET_TOGGLE:
640                 mathcursor::insetToggle(cur);
641                 break;
642
643         case LFUN_DIALOG_SHOW:
644                 result = DispatchResult(false);
645                 break;
646
647         case LFUN_DIALOG_SHOW_NEW_INSET: {
648                 string const & name = argument;
649                 string data;
650                 if (name == "ref") {
651                         RefInset tmp(name);
652                         data = tmp.createDialogStr(name);
653                 }
654
655                 if (data.empty())
656                         result = DispatchResult(false);
657                 else
658                         cur.bv().owner()->getDialogs().show(name, data, 0);
659                 break;
660         }
661
662         case LFUN_INSET_APPLY: {
663                 string const name = cmd.getArg(0);
664                 InsetBase * base = cur.bv().owner()->getDialogs().getOpenInset(name);
665
666                 if (base) {
667                         FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument);
668                         result = base->dispatch(cur, fr);
669                 } else {
670                         MathArray ar;
671                         if (createMathInset_fromDialogStr(cmd.argument, ar)) {
672                                 mathcursor::insert(cur, ar);
673                                 result = DispatchResult(true, true);
674                         } else {
675                                 result = DispatchResult(false);
676                         }
677                 }
678                 break;
679         }
680
681         case LFUN_WORD_REPLACE:
682         case LFUN_WORD_FIND: {
683                 result = 
684                         searchForward(&cur.bv(), cmd.getArg(0), false, false)
685                                 ? DispatchResult(true, true) : DispatchResult(false);
686                 break;
687         }
688
689         default:
690                 result = DispatchResult(false);
691         }
692
693         if (result == DispatchResult(true, true))
694                 cur.bv().update();
695
696         mathcursor::normalize(cur);
697         mathcursor::touch();
698
699         BOOST_ASSERT(inMathed());
700
701         if (result.dispatched()) {
702                 revealCodes(cur);
703                 cur.bv().stuffClipboard(mathcursor::grabSelection(cur));
704         } else {
705                 releaseMathCursor(cur);
706                 if (remove_inset)
707                         cur.bv().owner()->dispatch(FuncRequest(LFUN_DELETE));
708         }
709
710         return result;  // original version
711 #endif
712 }
713
714
715 void InsetFormulaBase::revealCodes(LCursor & cur) const
716 {
717         if (!inMathed())
718                 return;
719         ostringstream os;
720         cur.info(os);
721         cur.bv().owner()->message(os.str());
722 /*
723         // write something to the minibuffer
724         // translate to latex
725         mathcursor::markInsert(bv);
726         ostringstream os;
727         write(NULL, os);
728         string str = os.str();
729         mathcursor::markErase(bv);
730         string::size_type pos = 0;
731         string res;
732         for (string::iterator it = str.begin(); it != str.end(); ++it) {
733                 if (*it == '\n')
734                         res += ' ';
735                 else if (*it == '\0') {
736                         res += "  -X-  ";
737                         pos = it - str.begin();
738                 }
739                 else
740                         res += *it;
741         }
742         if (pos > 30)
743                 res = res.substr(pos - 30);
744         if (res.size() > 60)
745                 res = res.substr(0, 60);
746         bv.owner()->message(res);
747 */
748 }
749
750
751 InsetOld::Code InsetFormulaBase::lyxCode() const
752 {
753         return InsetOld::MATH_CODE;
754 }
755
756
757 int InsetFormulaBase::ylow() const
758 {
759         return yo_ - dim_.asc;
760 }
761
762
763 int InsetFormulaBase::yhigh() const
764 {
765         return yo_ + dim_.des;
766 }
767
768
769 int InsetFormulaBase::xlow() const
770 {
771         return xo_;
772 }
773
774
775 int InsetFormulaBase::xhigh() const
776 {
777         return xo_ + dim_.wid;
778 }
779
780
781 /////////////////////////////////////////////////////////////////////
782
783
784 bool InsetFormulaBase::searchForward(BufferView * bv, string const & str,
785                                      bool, bool)
786 {
787         return false;
788 #ifdef WITH_WARNINGS
789 #warning pretty ugly
790 #endif
791         static InsetFormulaBase * lastformula = 0;
792         static CursorBase current = CursorBase(ibegin(par().nucleus()));
793         static MathArray ar;
794         static string laststr;
795
796         if (lastformula != this || laststr != str) {
797                 //lyxerr << "reset lastformula to " << this << endl;
798                 lastformula = this;
799                 laststr = str;
800                 current = ibegin(par().nucleus());
801                 ar.clear();
802                 mathed_parse_cell(ar, str);
803         } else {
804                 increment(current);
805         }
806         //lyxerr << "searching '" << str << "' in " << this << ar << endl;
807
808         for (CursorBase it = current; it != iend(par().nucleus()); increment(it)) {
809                 CursorSlice & top = it.back();
810                 MathArray const & a = top.asMathInset()->cell(top.idx_);
811                 if (a.matchpart(ar, top.pos_)) {
812                         mathcursor::formula_ = this;
813                         mathcursor::setSelection(bv->cursor(), it, ar.size());
814                         current = it;
815                         top.pos_ += ar.size();
816                         bv->update();
817                         return true;
818                 }
819         }
820
821         //lyxerr << "not found!" << endl;
822         lastformula = 0;
823         return false;
824 }
825
826
827 bool InsetFormulaBase::searchBackward(BufferView * bv, string const & what,
828                                       bool a, bool b)
829 {
830         lyxerr[Debug::MATHED] << "searching backward not implemented in mathed" << endl;
831         return searchForward(bv, what, a, b);
832 }
833
834
835 bool InsetFormulaBase::display() const
836 {
837         return par()->asHullInset() && par()->asHullInset()->display();
838 }
839
840
841 string InsetFormulaBase::selectionAsString(BufferView & bv) const
842 {
843         return inMathed() ? mathcursor::grabSelection(bv.cursor()) : string();
844 }
845
846 /////////////////////////////////////////////////////////////////////
847
848
849 void mathDispatchCreation(LCursor & cur, FuncRequest const & cmd,
850         bool display)
851 {
852         // use selection if available..
853         //string sel;
854         //if (action == LFUN_MATH_IMPORT_SELECTION)
855         //      sel = "";
856         //else
857
858         string sel =
859                 cur.bv().getLyXText()->selectionAsString(*cur.bv().buffer(), false);
860
861         if (sel.empty()) {
862                 InsetFormula * f = new InsetFormula;
863                 if (openNewInset(cur, f)) {
864                         cur.inset()->dispatch(cur, FuncRequest(LFUN_MATH_MUTATE, "simple"));
865                         // don't do that also for LFUN_MATH_MODE unless you want end up with
866                         // always changing to mathrm when opening an inlined inset
867                         // -- I really hate "LyXfunc overloading"...
868                         if (display)
869                                 f->dispatch(cur, FuncRequest(LFUN_MATH_DISPLAY));
870                         f->dispatch(cur, FuncRequest(LFUN_INSERT_MATH, cmd.argument));
871                 }
872         } else {
873                 // create a macro if we see "\\newcommand" somewhere, and an ordinary
874                 // formula otherwise
875                 InsetFormulaBase * f;
876                 if (sel.find("\\newcommand") == string::npos &&
877                                 sel.find("\\def") == string::npos)
878                         f = new InsetFormula(sel);
879                 else
880                         f = new InsetFormulaMacro(sel);
881                 cur.bv().getLyXText()->cutSelection(true, false);
882                 openNewInset(cur, f);
883         }
884         cmd.message(N_("Math editor mode"));
885 }
886
887
888 void mathDispatch(LCursor & cur, FuncRequest const & cmd)
889 {
890         if (!cur.bv().available())
891                 return;
892
893         switch (cmd.action) {
894
895                 case LFUN_MATH_DISPLAY:
896                         mathDispatchCreation(cur, cmd, true);
897                         break;
898
899                 case LFUN_MATH_MODE:
900                         mathDispatchCreation(cur, cmd, false);
901                         break;
902
903                 case LFUN_MATH_IMPORT_SELECTION:
904                         mathDispatchCreation(cur, cmd, false);
905                         break;
906
907                 case LFUN_MATH_MACRO:
908                         if (cmd.argument.empty())
909                                 cmd.errorMessage(N_("Missing argument"));
910                         else {
911                                 string s = cmd.argument;
912                                 string const s1 = token(s, ' ', 1);
913                                 int const nargs = s1.empty() ? 0 : atoi(s1);
914                                 string const s2 = token(s, ' ', 2);
915                                 string const type = s2.empty() ? "newcommand" : s2;
916                                 openNewInset(cur, new InsetFormulaMacro(token(s, ' ', 0), nargs, s2));
917                         }
918                         break;
919
920                 case LFUN_INSERT_MATH:
921                 case LFUN_INSERT_MATRIX:
922                 case LFUN_MATH_DELIM: {
923                         InsetFormula * f = new InsetFormula;
924                         if (openNewInset(cur, f)) {
925                                 cur.inset()->dispatch(cur, FuncRequest(LFUN_MATH_MUTATE, "simple"));
926                                 cur.inset()->dispatch(cur, cmd);
927                         }
928                         break;
929                 }
930
931                 default:
932                         break;
933         }
934 }