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