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