]> git.lyx.org Git - lyx.git/blob - src/mathed/formulabase.C
fix reading of labels with underscore and probably break a few other things
[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 "lyxfunc.h"
32 #include "gettext.h"
33 #include "LaTeXFeatures.h"
34 #include "debug.h"
35 #include "math_support.h"
36 #include "math_metricsinfo.h"
37 #include "support/lstrings.h"
38 #include "frontends/LyXView.h"
39 #include "frontends/font_metrics.h"
40 #include "frontends/mouse_state.h"
41 #include "Lsstream.h"
42 #include "math_arrayinset.h"
43 #include "math_charinset.h"
44 #include "math_deliminset.h"
45 #include "math_cursor.h"
46 #include "math_factory.h"
47 #include "math_fontinset.h"
48 #include "math_hullinset.h"
49 #include "math_iterator.h"
50 #include "math_macrotable.h"
51 #include "math_parser.h"
52 #include "math_pos.h"
53 #include "math_spaceinset.h"
54 #include "undo_funcs.h"
55 #include "textpainter.h"
56 #include "frontends/Dialogs.h"
57 #include "intl.h"
58 #include "insets/insetcommandparams.h"
59 #include "ref_inset.h"
60
61 using std::endl;
62 using std::ostream;
63 using std::vector;
64 using std::abs;
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()->getLyXFunc()->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, y);
178         //lyxerr << "setting pos to " << x << "," << y << "\n";
179
180         // if that is removed, we won't get the magenta box when entering an
181         // inset for the first time
182         bv->updateInset(this, false);
183 }
184
185
186 void InsetFormulaBase::edit(BufferView * bv, bool front)
187 {
188         if (!bv->lockInset(this))
189                 lyxerr << "Cannot lock math inset in edit call!\n";
190         releaseMathCursor(bv);
191         mathcursor = new MathCursor(this, front);
192         metrics(bv);
193         bv->updateInset(this, false);
194 }
195
196
197 void InsetFormulaBase::insetUnlock(BufferView * bv)
198 {
199         if (mathcursor) {
200                 if (mathcursor->inMacroMode()) {
201                         mathcursor->macroModeClose();
202                         updateLocal(bv, true);
203                 }
204                 releaseMathCursor(bv);
205         }
206         generatePreview();
207         bv->updateInset(this, false);
208 }
209
210
211 void InsetFormulaBase::getCursorPos(BufferView *, int & x, int & y) const
212 {
213         // calling metrics here destroys the cached xo,yo positions e.g. in
214         // MathParboxinset. And it would be too expensive anyway...
215         //metrics(bv);
216         mathcursor->getPos(x, y);
217         //x -= xo_;
218         y -= yo_;
219         //lyxerr << "getCursorPos: " << x << " " << y << "\n";
220 }
221
222
223 void InsetFormulaBase::toggleInsetCursor(BufferView * bv)
224 {
225         //lyxerr << "toggleInsetCursor: " << isCursorVisible() << "\n";
226         if (isCursorVisible())
227                 hideInsetCursor(bv);
228         else
229                 showInsetCursor(bv);
230 }
231
232
233 void InsetFormulaBase::showInsetCursor(BufferView * bv, bool)
234 {
235         if (isCursorVisible())
236                 return;
237         fitInsetCursor(bv);
238         int x, y, asc, des;
239         getCursorPos(bv, x, y);
240         math_font_max_dim(font_, asc, des);
241         bv->showLockedInsetCursor(x, y, asc, des);
242         setCursorVisible(true);
243         //lyxerr << "showInsetCursor: " << x << " " << y << "\n";
244 }
245
246
247 void InsetFormulaBase::hideInsetCursor(BufferView * bv)
248 {
249         if (!isCursorVisible())
250                 return;
251         bv->hideLockedInsetCursor();
252         setCursorVisible(false);
253         //lyxerr << "hideInsetCursor: \n";
254 }
255
256
257 void InsetFormulaBase::fitInsetCursor(BufferView * bv) const
258 {
259         if (!mathcursor)
260                 return;
261         int x, y, asc, des;
262         math_font_max_dim(font_, asc, des);
263         getCursorPos(bv, x, y);
264         //y += yo_;
265         //lyxerr << "fitInsetCursor: x: " << x << " y: " << y << " yo: " << yo_ << "\n";
266         bv->fitLockedInsetCursor(x, y, asc, des);
267 }
268
269
270 void InsetFormulaBase::toggleInsetSelection(BufferView * bv)
271 {
272         if (mathcursor)
273                 bv->updateInset(this, false);
274 }
275
276
277 vector<string> const InsetFormulaBase::getLabelList() const
278 {
279   return vector<string>();
280 }
281
282
283 void InsetFormulaBase::updateLocal(BufferView * bv, bool dirty)
284 {
285         metrics(bv);
286         if (mathcursor)
287                 bv->fitCursor();
288         bv->updateInset(this, dirty);
289 }
290
291
292 bool InsetFormulaBase::insetButtonRelease(BufferView * bv,
293         int /*x*/, int /*y*/, mouse_button::state button)
294 {
295         if (!mathcursor)
296                 return false;
297
298         //lyxerr << "insetButtonRelease: " << x << " " << y << "\n";
299         hideInsetCursor(bv);
300         showInsetCursor(bv);
301         bv->updateInset(this, false);
302
303         if (button == mouse_button::button3) {
304                 // try to dispatch to enclosed insets first
305                 if (mathcursor->dispatch("mouse-3-release"))
306                         return true;
307
308                 // launch math panel for right mouse button
309                 bv->owner()->getDialogs()->showMathPanel();
310                 return true;
311         }
312
313         if (button == mouse_button::button1) {
314                 // try to dispatch to enclosed insets first
315                 if (mathcursor->dispatch("mouse-1-release"))
316                         return true;
317
318                 // try to set the cursor
319                 //delete mathcursor;
320                 //mathcursor = new MathCursor(this, x == 0);
321                 //metrics(bv);
322                 //mathcursor->setPos(x + xo_, y + yo_);
323                 return true;
324         }
325         return false;
326 }
327
328
329 void InsetFormulaBase::insetButtonPress(BufferView * bv,
330                                         int x, int y, mouse_button::state button)
331 {
332         //lyxerr << "insetButtonPress: "
333         //      << x << " " << y << " but: " << button << "\n";
334         //lyxerr << "formula: ";
335         par()->dump();
336
337         releaseMathCursor(bv);
338         mathcursor = new MathCursor(this, x == 0);
339
340         if (button == mouse_button::button1) {
341                 // just set the cursor here
342                 //lyxerr << "setting cursor\n";
343                 metrics(bv);
344                 first_x = x;
345                 first_y = y;
346                 mathcursor->selClear();
347                 mathcursor->setPos(x + xo_, y + yo_);
348
349                 if (mathcursor->dispatch("mouse-1-press")) {
350                         //delete mathcursor;
351                         return;
352                 }
353
354         }
355         if (button == mouse_button::button3) {
356                 if (mathcursor->dispatch("mouse-3-press")) {
357                         //delete mathcursor;
358                         return;
359                 }
360         }
361         bv->updateInset(this, false);
362 }
363
364
365 void InsetFormulaBase::insetMotionNotify(BufferView * bv,
366         int x, int y, mouse_button::state button)
367 {
368         if (!mathcursor)
369                 return;
370
371         if (button == mouse_button::button1)
372                 if (mathcursor->dispatch("mouse-1-motion"))
373                         return;
374
375         if (button == mouse_button::button3)
376                 if (mathcursor->dispatch("mouse-3-motion"))
377                         return;
378
379         if (abs(x - first_x) < 2 && abs(y - first_y) < 2) {
380                 //lyxerr << "insetMotionNotify: ignored\n";
381                 return;
382         }
383         first_x = x;
384         first_y = y;
385
386         if (!mathcursor->selection())
387                 mathcursor->selStart();
388
389         //lyxerr << "insetMotionNotify: " << x + xo_ << ' ' << y + yo_
390         //      << ' ' << button << "\n";
391         hideInsetCursor(bv);
392         mathcursor->setPos(x + xo_, y + yo_);
393         showInsetCursor(bv);
394         bv->updateInset(this, false);
395 }
396
397
398 UpdatableInset::RESULT
399 InsetFormulaBase::localDispatch(BufferView * bv, FuncRequest const & ev)
400 {
401         //lyxerr << "InsetFormulaBase::localDispatch: act: " << action
402         //      << " arg: '" << arg
403         //      << "' cursor: " << mathcursor << "\n";
404
405         if (!mathcursor)
406                 return UNDISPATCHED;
407
408         string argument    = ev.argument;
409         RESULT result      = DISPATCHED;
410         bool sel           = false;
411         bool was_macro     = mathcursor->inMacroMode();
412         bool was_selection = mathcursor->selection();
413
414         hideInsetCursor(bv);
415
416         mathcursor->normalize();
417         mathcursor->touch();
418
419         switch (ev.action) {
420
421         case LFUN_WORDRIGHTSEL:
422         case LFUN_RIGHTSEL:
423                 sel = true; // fall through...
424         case LFUN_RIGHT:
425                 result = mathcursor->right(sel) ? DISPATCHED : FINISHED_RIGHT;
426                 //lyxerr << "calling scroll 20\n";
427                 //scroll(bv, 20);
428                 updateLocal(bv, false);
429                 // write something to the minibuffer
430                 //bv->owner()->message(mathcursor->info());
431                 break;
432
433         case LFUN_WORDLEFTSEL:
434         case LFUN_LEFTSEL:
435                 sel = true; // fall through
436         case LFUN_LEFT:
437                 result = mathcursor->left(sel) ? DISPATCHED : FINISHED;
438                 updateLocal(bv, false);
439                 break;
440
441         case LFUN_UPSEL:
442                 sel = true; // fall through
443         case LFUN_UP:
444                 result = mathcursor->up(sel) ? DISPATCHED : FINISHED_UP;
445                 updateLocal(bv, false);
446                 break;
447
448         case LFUN_DOWNSEL:
449                 sel = true; // fall through
450         case LFUN_DOWN:
451                 result = mathcursor->down(sel) ? DISPATCHED : FINISHED_DOWN;
452                 updateLocal(bv, false);
453                 break;
454
455         case LFUN_HOMESEL:
456                 sel = true; // fall through
457         case LFUN_HOME:
458                 result = mathcursor->home(sel) ? DISPATCHED : FINISHED;
459                 updateLocal(bv, false);
460                 break;
461
462         case LFUN_ENDSEL:
463                 sel = true; // fall through
464         case LFUN_END:
465                 result = mathcursor->end(sel) ? DISPATCHED : FINISHED_RIGHT;
466                 updateLocal(bv, false);
467                 break;
468
469         case LFUN_PRIORSEL:
470         case LFUN_PRIOR:
471                 result = FINISHED_UP;
472                 updateLocal(bv, false);
473                 break;
474
475         case LFUN_NEXTSEL:
476         case LFUN_NEXT:
477                 result = FINISHED_DOWN;
478                 updateLocal(bv, false);
479                 break;
480
481         case LFUN_DELETE_LINE_FORWARD:
482                 bv->lockedInsetStoreUndo(Undo::DELETE);
483                 mathcursor->delLine();
484                 updateLocal(bv, true);
485                 break;
486
487         case LFUN_TAB:
488                 mathcursor->idxNext();
489                 updateLocal(bv, false);
490                 break;
491
492         case LFUN_SHIFT_TAB:
493                 mathcursor->idxPrev();
494                 updateLocal(bv, false);
495                 break;
496
497         case LFUN_TABINSERT:
498                 bv->lockedInsetStoreUndo(Undo::EDIT);
499                 mathcursor->splitCell();
500                 updateLocal(bv, true);
501                 break;
502
503         case LFUN_DELETE_WORD_BACKWARD:
504         case LFUN_BACKSPACE:
505                 bv->lockedInsetStoreUndo(Undo::DELETE);
506                 mathcursor->backspace();
507                 updateLocal(bv, true);
508                 break;
509
510         case LFUN_DELETE_WORD_FORWARD:
511         case LFUN_DELETE:
512                 bv->lockedInsetStoreUndo(Undo::DELETE);
513                 mathcursor->erase();
514                 bv->updateInset(this, true);
515                 break;
516
517         //    case LFUN_GETXY:
518         //      sprintf(dispatch_buffer, "%d %d",);
519         //      dispatch_result = dispatch_buffer;
520         //      break;
521         case LFUN_SETXY: {
522                 lyxerr << "LFUN_SETXY broken!\n";
523                 int x = 0;
524                 int y = 0;
525                 istringstream is(ev.argument.c_str());
526                 is >> x >> y;
527                 mathcursor->setPos(x, y);
528                 updateLocal(bv, false);
529                 break;
530         }
531
532         case LFUN_PASTE:
533                 if (was_macro)
534                         mathcursor->macroModeClose();
535                 bv->lockedInsetStoreUndo(Undo::EDIT);
536                 mathcursor->selPaste();
537                 updateLocal(bv, true);
538                 break;
539
540         case LFUN_CUT:
541                 bv->lockedInsetStoreUndo(Undo::DELETE);
542                 mathcursor->selCut();
543                 updateLocal(bv, true);
544                 break;
545
546         case LFUN_COPY:
547                 mathcursor->selCopy();
548                 break;
549
550
551         // Special casing for superscript in case of LyX handling
552         // dead-keys:
553         case LFUN_CIRCUMFLEX:
554                 if (ev.argument.empty()) {
555                         // do superscript if LyX handles
556                         // deadkeys
557                         bv->lockedInsetStoreUndo(Undo::EDIT);
558                         mathcursor->script(true);
559                         updateLocal(bv, true);
560                 }
561                 break;
562
563         case LFUN_UMLAUT:
564         case LFUN_ACUTE:
565         case LFUN_GRAVE:
566         case LFUN_BREVE:
567         case LFUN_DOT:
568         case LFUN_MACRON:
569         case LFUN_CARON:
570         case LFUN_TILDE:
571         case LFUN_CEDILLA:
572         case LFUN_CIRCLE:
573         case LFUN_UNDERDOT:
574         case LFUN_TIE:
575         case LFUN_OGONEK:
576         case LFUN_HUNG_UMLAUT:
577                 break;
578
579         //  Math fonts
580         case LFUN_GREEK_TOGGLE: handleFont(bv, ev.argument, "lyxgreek"); break;
581         case LFUN_BOLD:         handleFont(bv, ev.argument, "textbf"); break;
582         case LFUN_SANS:         handleFont(bv, ev.argument, "textsf"); break;
583         case LFUN_EMPH:         handleFont(bv, ev.argument, "mathcal"); break;
584         case LFUN_ROMAN:        handleFont(bv, ev.argument, "mathrm"); break;
585         case LFUN_CODE:         handleFont(bv, ev.argument, "texttt"); break;
586         case LFUN_FRAK:         handleFont(bv, ev.argument, "mathfrak"); break;
587         case LFUN_ITAL:         handleFont(bv, ev.argument, "mathit"); break;
588         case LFUN_NOUN:         handleFont(bv, ev.argument, "mathbb"); break;
589         case LFUN_DEFAULT:      handleFont(bv, ev.argument, "textnormal"); break;
590         case LFUN_FREE:         handleFont(bv, ev.argument, "textrm"); break;
591
592         case LFUN_GREEK:
593                 handleFont(bv, ev.argument, "lyxgreek1");
594                 if (ev.argument.size())
595                         mathcursor->interpret(ev.argument);
596                 break;
597
598         case LFUN_MATH_MODE:
599                 if (mathcursor->currentMode()) {
600                         handleFont(bv, ev.argument, "textrm");
601                 } else {
602                         mathcursor->niceInsert(MathAtom(new MathHullInset("simple")));
603                         updateLocal(bv, true);
604                 }
605                 //bv->owner()->message(_("math text mode toggled"));
606                 break;
607
608         case LFUN_MATH_LIMITS:
609                 bv->lockedInsetStoreUndo(Undo::EDIT);
610                 if (mathcursor->toggleLimits())
611                         updateLocal(bv, true);
612                 break;
613
614         case LFUN_MATH_SIZE:
615 #if 0
616                 if (!arg.empty()) {
617                         bv->lockedInsetStoreUndo(Undo::EDIT);
618                         mathcursor->setSize(arg);
619                         updateLocal(bv, true);
620                 }
621 #endif
622                 break;
623
624         case LFUN_INSERT_MATRIX:
625                 if (!ev.argument.empty()) {
626                         bv->lockedInsetStoreUndo(Undo::EDIT);
627                         mathcursor->interpret("matrix " + ev.argument);
628                         updateLocal(bv, true);
629                 }
630                 break;
631
632         case LFUN_SUPERSCRIPT:
633         case LFUN_SUBSCRIPT:
634         {
635                 bv->lockedInsetStoreUndo(Undo::EDIT);
636                 mathcursor->script(ev.action == LFUN_SUPERSCRIPT);
637                 updateLocal(bv, true);
638                 break;
639         }
640
641         case LFUN_MATH_DELIM:
642         {
643                 //lyxerr << "formulabase::LFUN_MATH_DELIM, arg: '" << arg << "'\n";
644                 string ls;
645                 string rs = split(ev.argument, ls, ' ');
646                 // Reasonable default values
647                 if (ls.empty())
648                         ls = '(';
649                 if (rs.empty())
650                         rs = ')';
651
652                 bv->lockedInsetStoreUndo(Undo::EDIT);
653                 mathcursor->handleNest(MathAtom(new MathDelimInset(ls, rs)));
654                 updateLocal(bv, true);
655                 break;
656         }
657
658         case LFUN_PROTECTEDSPACE:
659         case LFUN_MATH_SPACE:
660                 bv->lockedInsetStoreUndo(Undo::EDIT);
661                 mathcursor->insert(MathAtom(new MathSpaceInset(",")));
662                 updateLocal(bv, true);
663                 break;
664
665         case LFUN_UNDO:
666                 bv->owner()->message(_("Invalid action in math mode!"));
667                 break;
668
669
670         case LFUN_MATH_HALIGN:
671         case LFUN_MATH_VALIGN:
672         case LFUN_MATH_ROW_INSERT:
673         case LFUN_MATH_ROW_DELETE:
674         case LFUN_MATH_COLUMN_INSERT:
675         case LFUN_MATH_COLUMN_DELETE:
676         {
677                 MathInset::idx_type idx = 0;
678                 MathGridInset * p = mathcursor ? mathcursor->enclosingGrid(idx) : 0;
679                 if (p) {
680                         mathcursor->popToEnclosingGrid();
681                         bv->lockedInsetStoreUndo(Undo::EDIT);
682                         char align = ev.argument.size() ? ev.argument[0] : 'c';
683                         switch (ev.action) {
684                                 case LFUN_MATH_HALIGN: p->halign(align, p->col(idx)); break;
685                                 case LFUN_MATH_VALIGN: p->valign(align); break;
686                                 case LFUN_MATH_ROW_INSERT: p->addRow(p->row(idx)); break;
687                                 case LFUN_MATH_ROW_DELETE: p->delRow(p->row(idx)); break;
688                                 case LFUN_MATH_COLUMN_INSERT: p->addFancyCol(p->col(idx)); break;
689                                 case LFUN_MATH_COLUMN_DELETE: p->delFancyCol(p->col(idx)); break;
690                                 default: ;
691                         }
692                         updateLocal(bv, true);
693                 }
694                 break;
695         }
696
697         case LFUN_EXEC_COMMAND:
698                 result = UNDISPATCHED;
699                 break;
700
701         case LFUN_INSET_ERT:
702                 // interpret this as if a backslash was typed
703                 bv->lockedInsetStoreUndo(Undo::EDIT);
704                 mathcursor->interpret('\\');
705                 updateLocal(bv, true);
706                 break;
707
708         case LFUN_BREAKPARAGRAPH:
709         case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
710         case LFUN_BREAKPARAGRAPH_SKIP:
711                 argument = "\n";
712                 // fall through
713
714         case -1:
715         case LFUN_INSERT_MATH:
716         case LFUN_SELFINSERT:
717                 if (!argument.empty()) {
718                         bv->lockedInsetStoreUndo(Undo::EDIT);
719                         if (argument.size() == 1)
720                                 result = mathcursor->interpret(argument[0]) ? DISPATCHED : FINISHED_RIGHT;
721                         else
722                                 result = mathcursor->interpret(argument) ? DISPATCHED : FINISHED_RIGHT;
723                         updateLocal(bv, true);
724                 }
725                 break;
726
727         case LFUN_MATH_PANEL:
728                 result = UNDISPATCHED;
729                 break;
730
731         case LFUN_ESCAPE:
732                 if (mathcursor->selection())
733                         mathcursor->selClear();
734                 else
735                         result = UNDISPATCHED;
736                 break;
737
738         case LFUN_INSET_TOGGLE:
739                 mathcursor->insetToggle();
740                 updateLocal(bv, true);
741                 break;
742
743         case LFUN_REF_INSERT:
744                 //if (argument.empty()) {
745                 //      InsetCommandParams p("ref");
746                 //      owner_->getDialogs()->createRef(p.getAsString());
747                 //} else {
748                 //      InsetCommandParams p;
749                 //      p.setFromString(argument);
750
751                 //      InsetRef * inset = new InsetRef(p, *buffer_);
752                 //      if (!insertInset(inset))
753                 //              delete inset;
754                 //      else
755                 //              updateInset(inset, true);
756                 //}
757                 //
758                 if (ev.argument.empty()) {
759                         InsetCommandParams p("ref");
760                         bv->owner()->getDialogs()->createRef(p.getAsString());
761                 } else {
762                         //mathcursor->handleNest(new InsetRef2);
763                         //mathcursor->insert(arg);
764                         mathcursor->insert(MathAtom(new RefInset(ev.argument)));
765                 }
766                 updateLocal(bv, true);
767                 break;
768
769         default:
770                 result = UNDISPATCHED;
771         }
772
773         mathcursor->normalize();
774         mathcursor->touch();
775
776         lyx::Assert(mathcursor);
777
778         if (mathcursor->selection() || was_selection)
779                 toggleInsetSelection(bv);
780
781         if (result == DISPATCHED || result == DISPATCHED_NOUPDATE ||
782             result == UNDISPATCHED) {
783                 fitInsetCursor(bv);
784                 showInsetCursor(bv);
785                 revealCodes(bv);
786         } else {
787                 releaseMathCursor(bv);
788                 bv->unlockInset(this);
789         }
790
791         return result;  // original version
792 }
793
794
795 void InsetFormulaBase::revealCodes(BufferView * bv) const
796 {
797         if (!mathcursor)
798                 return;
799         bv->owner()->message(mathcursor->info());
800
801 #if 0
802         // write something to the minibuffer
803         // translate to latex
804         mathcursor->markInsert();
805         ostringstream os;
806         write(NULL, os);
807         string str = os.str();
808         mathcursor->markErase();
809         string::size_type pos = 0;
810         string res;
811         for (string::iterator it = str.begin(); it != str.end(); ++it) {
812                 if (*it == '\n')
813                         res += ' ';
814                 else if (*it == '\0') {
815                         res += "  -X-  ";
816                         pos = it - str.begin();
817                 }
818                 else
819                         res += *it;
820         }
821         if (pos > 30)
822                 res = res.substr(pos - 30);
823         if (res.size() > 60)
824                 res = res.substr(0, 60);
825         bv->owner()->message(res);
826 #endif
827 }
828
829
830 Inset::Code InsetFormulaBase::lyxCode() const
831 {
832         return Inset::MATH_CODE;
833 }
834
835
836 int InsetFormulaBase::ylow() const
837 {
838         return yo_ - ascent(view(), font_);
839 }
840
841
842 int InsetFormulaBase::yhigh() const
843 {
844         return yo_ + descent(view(), font_);
845 }
846
847
848 int InsetFormulaBase::xlow() const
849 {
850         return xo_;
851 }
852
853
854 int InsetFormulaBase::xhigh() const
855 {
856         return xo_ + width(view(), font_);
857 }
858
859
860 /////////////////////////////////////////////////////////////////////
861
862
863 bool InsetFormulaBase::searchForward(BufferView * bv, string const & str,
864                                      bool, bool)
865 {
866 #ifdef WITH_WARNINGS
867 #warning pretty ugly
868 #endif
869         static InsetFormulaBase * lastformula = 0;
870         static MathIterator current = MathIterator(ibegin(par().nucleus()));
871         static MathArray ar;
872         static string laststr;
873
874         if (lastformula != this || laststr != str) {
875                 //lyxerr << "reset lastformula to " << this << "\n";
876                 lastformula = this;
877                 laststr = str;
878                 current = ibegin(par().nucleus());
879                 ar.clear();
880                 mathed_parse_cell(ar, str);
881         } else {
882                 ++current;
883         }
884         //lyxerr << "searching '" << str << "' in " << this << ar << endl;
885
886         for (MathIterator it = current; it != iend(par().nucleus()); ++it) {
887                 if (it.cell().matchpart(ar, it.back().pos_)) {
888                         bv->unlockInset(bv->theLockingInset());
889                         if (!bv->lockInset(this)) {
890                                 lyxerr << "Cannot lock inset" << endl;
891                                 return false;
892                         }
893                         delete mathcursor;
894                         mathcursor = new MathCursor(this, true);
895                         metrics(bv);
896                         mathcursor->setSelection(it, ar.size());
897                         current = it;
898                         it.jump(ar.size());
899                         updateLocal(bv, false);
900                         return true;
901                 }
902         }
903
904         //lyxerr << "not found!\n";
905         lastformula = 0;
906         return false;
907 }
908
909
910 bool InsetFormulaBase::searchBackward(BufferView * bv, string const & what,
911                                       bool a, bool b)
912 {
913         lyxerr[Debug::MATHED] << "searching backward not implemented in mathed\n";
914         return searchForward(bv, what, a, b);
915 }
916
917
918 /////////////////////////////////////////////////////////////////////
919
920
921 void mathDispatchCreation(BufferView * bv, string const & arg, bool display)
922 {
923         if (!bv->available())
924                 return;
925
926         // use selection if available..
927         //string sel;
928         //if (action == LFUN_MATH_IMPORT_SELECTION)
929         //      sel = "";
930         //else
931
932         string sel = bv->getLyXText()->selectionAsString(bv->buffer(), false);
933
934         if (sel.empty()) {
935                 InsetFormula * f = new InsetFormula(bv);
936                 if (openNewInset(bv, f)) {
937                         f->mutate("simple");
938                         // don't do that also for LFUN_MATH_MODE unless you want end up with
939                         // always changing to mathrm when opening an inlined inset
940                         // -- I really hate "LyXfunc overloading"...
941                         if (display)
942                                 f->localDispatch(bv, FuncRequest(LFUN_MATH_DISPLAY));
943                         f->localDispatch(bv, FuncRequest(LFUN_INSERT_MATH, arg));
944                 }
945         } else {
946                 // create a macro if we see "\\newcommand" somewhere, and an ordinary
947                 // formula otherwise
948                 InsetFormulaBase * f;
949                 if (sel.find("\\newcommand") == string::npos &&
950                                 sel.find("\\def") == string::npos)
951                         f = new InsetFormula(sel);
952                 else
953                         f = new InsetFormulaMacro(sel);
954                 bv->getLyXText()->cutSelection(bv);
955                 openNewInset(bv, f);
956         }
957         bv->owner()->getLyXFunc()->setMessage(N_("Math editor mode"));
958 }
959
960
961 void mathDispatchMathDisplay(BufferView * bv, string const & arg)
962 {
963         mathDispatchCreation(bv, arg, true);
964 }
965
966
967 void mathDispatchMathMode(BufferView * bv, string const & arg)
968 {
969         mathDispatchCreation(bv, arg, false);
970 }
971
972
973 void mathDispatchMathImportSelection(BufferView * bv, string const & arg)
974 {
975         mathDispatchCreation(bv, arg, true);
976 }
977
978
979 void mathDispatchMathMacro(BufferView * bv, string const & arg)
980 {
981         if (!bv->available())
982                 return;
983         if (arg.empty())
984                 bv->owner()->getLyXFunc()->setErrorMessage(N_("Missing argument"));
985         else {
986                 string s = arg;
987                 string const s1 = token(s, ' ', 1);
988                 int const na = s1.empty() ? 0 : lyx::atoi(s1);
989                 openNewInset(bv, new InsetFormulaMacro(token(s, ' ', 0), na));
990         }
991 }
992
993
994 void mathDispatchMathDelim(BufferView * bv, string const & arg)
995 {
996         if (!bv->available())
997                 return;
998         InsetFormula * f = new InsetFormula(bv);
999         if (openNewInset(bv, f)) {
1000                 f->mutate("simple");
1001                 bv->theLockingInset()->localDispatch(bv, FuncRequest(LFUN_MATH_DELIM, arg));
1002         }
1003 }
1004
1005
1006 void mathDispatchInsertMatrix(BufferView * bv, string const & arg)
1007 {
1008         if (!bv->available())
1009                 return;
1010         InsetFormula * f = new InsetFormula(bv);
1011         if (openNewInset(bv, f)) {
1012                 f->mutate("simple");
1013                 bv->theLockingInset()->localDispatch(bv, FuncRequest(LFUN_INSERT_MATRIX, arg));
1014         }
1015 }
1016
1017
1018 void mathDispatchInsertMath(BufferView * bv, string const & arg)
1019 {
1020         if (!bv->available())
1021                 return;
1022         InsetFormula * f = new InsetFormula(bv);
1023         if (openNewInset(bv, f)) {
1024                 f->mutate("simple");
1025     bv->theLockingInset()->localDispatch(bv, FuncRequest(LFUN_INSERT_MATH, arg));
1026         }
1027 }
1028
1029
1030 void mathDispatchGreek(BufferView * bv, string const & arg)
1031 {
1032         if (!bv->available())
1033                 return;
1034         InsetFormula * f = new InsetFormula(bv);
1035         if (openNewInset(bv, f)) {
1036                 f->mutate("simple");
1037                 bv->theLockingInset()->localDispatch(bv, FuncRequest(LFUN_GREEK, arg));
1038                 bv->unlockInset(f);
1039         }
1040 }
1041
1042
1043 void mathDispatch(BufferView *, kb_action, string const &)
1044 {}
1045
1046
1047 void mathDispatch(BufferView *, string const &)
1048 {}