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