]> git.lyx.org Git - lyx.git/blob - src/mathed/formulabase.C
972a0296bf7d25dbca10501ee7dcbb23ee0214e0
[lyx.git] / src / mathed / formulabase.C
1  /*
2 *  File:        formula.C
3 *  Purpose:     Implementation of formula inset
4 *  Author:      Alejandro Aguilar Sierra <asierra@servidor.unam.mx>
5 *  Created:     January 1996
6 *  Description: Allows the edition of math paragraphs inside Lyx.
7 *
8 *  Copyright: 1996-1998 Alejandro Aguilar Sierra
9 *
10 *  Version: 0.4, Lyx project.
11 *
12 *   You are free to use and modify this code under the terms of
13 *   the GNU General Public Licence version 2 or later.
14 */
15
16 #include <config.h>
17 #include <fstream>
18
19 #include "Lsstream.h"
20
21 #ifdef __GNUG__
22 #pragma implementation
23 #endif
24
25 #include "formula.h"
26 #include "formulamacro.h"
27 #include "commandtags.h"
28 #include "math_cursor.h"
29 #include "math_parser.h"
30 #include "BufferView.h"
31 #include "lyxtext.h"
32 #include "lyxfunc.h"
33 #include "gettext.h"
34 #include "LaTeXFeatures.h"
35 #include "debug.h"
36 #include "support/lstrings.h"
37 #include "LyXView.h"
38 #include "Painter.h"
39 #include "font.h"
40 #include "math_arrayinset.h"
41 #include "math_spaceinset.h"
42 #include "math_macrotable.h"
43 #include "support/lyxlib.h"
44 #include "mathed/support.h"
45 #include "undo_funcs.h"
46
47 using std::endl;
48 using std::ostream;
49 using std::vector;
50
51 extern char const * latex_special_chars;
52
53 int greek_kb_flag = 0;
54 extern char const * latex_mathenv[];
55 MathCursor        * mathcursor = 0;
56
57
58 namespace {
59
60
61 // local global
62 int sel_x;
63 int sel_y;
64 bool sel_flag;
65
66 void mathed_init_fonts();
67
68 string nicelabel(string const & label)
69 {
70         return "(" + (label.empty() ? "#" : label) + ")";
71 }
72
73 void handleFont(BufferView * bv, MathTextCodes t) 
74 {
75         if (mathcursor->selection())
76                 bv->lockedInsetStoreUndo(Undo::EDIT);
77         mathcursor->handleFont(t);
78 }
79
80 void handleAccent(BufferView * bv, string const & name)
81 {
82         bv->lockedInsetStoreUndo(Undo::EDIT);
83         mathcursor->handleAccent(name);
84 }
85
86 void handleDelim(BufferView * bv, int l, int r)
87 {
88         bv->lockedInsetStoreUndo(Undo::EDIT);
89         mathcursor->handleDelim(l, r);
90 }
91
92 bool openNewInset(BufferView * bv, UpdatableInset * new_inset)
93 {
94         LyXText * lt = bv->getLyXText();
95         
96         bv->beforeChange(lt);
97         finishUndo();
98         if (!bv->insertInset(new_inset)) {
99                 delete new_inset;
100                 return false;
101         }
102         new_inset->edit(bv, 0, 0, 0);
103         return true;
104 }
105
106
107 // returns the nearest enclosing grid
108 MathArrayInset * matrixpar(int & idx)
109 {
110         idx = 0;
111         return (mathcursor ? mathcursor->enclosingArray(idx) : 0); 
112 }
113
114
115 } // namespace anon
116
117
118
119 InsetFormulaBase::InsetFormulaBase(MathInset * par)
120         : par_(par)
121 {
122 #ifdef WITH_WARNINGS
123 #warning This is needed as long the math parser is not re-entrant
124 #endif
125         MathMacroTable::builtinMacros();
126         //lyxerr << "sizeof MathInset: " << sizeof(MathInset) << "\n";
127 }
128
129
130 InsetFormulaBase::InsetFormulaBase(InsetFormulaBase const & f)
131         : UpdatableInset(f), par_(f.par_->clone())
132 {}
133
134
135 InsetFormulaBase::~InsetFormulaBase()
136 {
137         delete par_;
138 }
139
140
141 void InsetFormulaBase::read(Buffer const *, LyXLex & lex)
142 {
143         read(lex);
144 }
145
146 void InsetFormulaBase::write(Buffer const *, ostream & os) const
147 {
148         write(os);
149 }
150
151 int InsetFormulaBase::latex(Buffer const *, ostream & os,
152         bool fragile, bool spacing) const
153 {
154         return latex(os, fragile, spacing);
155 }
156
157 int InsetFormulaBase::ascii(Buffer const *, ostream & os, int spacing) const
158 {
159         return ascii(os, spacing);
160 }
161
162 int InsetFormulaBase::linuxdoc(Buffer const *, ostream & os) const
163 {
164         return linuxdoc(os);
165 }
166
167 int InsetFormulaBase::docBook(Buffer const *, ostream & os) const
168 {
169         return docBook(os);
170 }
171
172
173
174 // Check if uses AMS macros
175 void InsetFormulaBase::validate(LaTeXFeatures &) const
176 {}
177
178
179 string const InsetFormulaBase::editMessage() const
180 {
181         return _("Math editor mode");
182 }
183
184
185 void InsetFormulaBase::edit(BufferView * bv, int x, int /*y*/, unsigned int)
186 {
187         mathcursor = new MathCursor(this);
188
189         if (!bv->lockInset(this))
190                 lyxerr[Debug::MATHED] << "Cannot lock inset!!!" << endl;
191
192         metrics();
193         //bv->updateInset(this, false);
194         if (x == 0)
195                 mathcursor->first();
196         else
197                 mathcursor->last();
198         sel_x = 0;
199         sel_y = 0;
200         sel_flag = false;
201 }
202
203
204 void InsetFormulaBase::edit(BufferView * bv, bool front)
205 {
206 #warning Please have a look if this is right (Jug)
207         edit(bv, front ? 0 : 1, 0, 0);
208 }
209
210
211 void InsetFormulaBase::insetUnlock(BufferView * bv)
212 {
213         if (mathcursor) {
214                 if (mathcursor->inMacroMode()) {
215                         mathcursor->macroModeClose();
216                         updateLocal(bv, true);
217                 }
218                 delete mathcursor;
219                 mathcursor = 0;
220         }
221         bv->updateInset(this, false);
222 }
223
224
225 void InsetFormulaBase::getCursorPos(BufferView *, int & x, int & y) const
226 {
227         mathcursor->getPos(x, y);
228         x -= par_->xo();
229         y -= par_->yo();
230 }
231
232
233 void InsetFormulaBase::toggleInsetCursor(BufferView * bv)
234 {
235         if (!mathcursor)
236                 return;
237
238         if (isCursorVisible())
239                 bv->hideLockedInsetCursor();
240         else {
241                 int x;
242                 int y;
243                 mathcursor->getPos(x, y);
244                 //x -= par_->xo();
245                 y -= par_->yo();
246                 int asc;
247                 int desc;
248                 math_font_max_dim(LM_TC_TEXTRM, LM_ST_TEXT, asc, desc);
249                 bv->showLockedInsetCursor(x, y, asc, desc);
250         }
251
252         toggleCursorVisible();
253 }
254
255
256 void InsetFormulaBase::showInsetCursor(BufferView * bv, bool)
257 {
258         if (!isCursorVisible()) {
259                 if (mathcursor) {
260                         int x;
261                         int y;
262                         mathcursor->getPos(x, y);
263                         x -= par_->xo();
264                         y -= par_->yo();
265                         int asc;
266                         int desc;
267                         math_font_max_dim(LM_TC_TEXTRM, LM_ST_TEXT, asc, desc);
268                         bv->fitLockedInsetCursor(x, y, asc, desc);
269                 }
270                 toggleInsetCursor(bv);
271         }
272 }
273
274
275 void InsetFormulaBase::hideInsetCursor(BufferView * bv)
276 {
277         if (isCursorVisible())
278                 toggleInsetCursor(bv);
279 }
280
281
282 void InsetFormulaBase::toggleInsetSelection(BufferView * bv)
283 {
284         if (mathcursor)
285                 bv->updateInset(this, false);
286 }
287
288
289 vector<string> const InsetFormulaBase::getLabelList() const
290 {
291   return std::vector<string>();
292 }
293
294
295 void InsetFormulaBase::updateLocal(BufferView * bv, bool dirty)
296 {
297         metrics();
298         bv->updateInset(this, dirty);
299 }
300
301
302 void InsetFormulaBase::metrics() const
303 {
304         const_cast<MathInset *>(par_)->metrics(LM_ST_TEXT);
305 }
306
307
308 void InsetFormulaBase::insetButtonRelease(BufferView * bv,
309                                           int x, int y, int /*button*/)
310 {
311         if (mathcursor) {
312                 hideInsetCursor(bv);
313                 x += par_->xo();
314                 y += par_->yo();
315                 mathcursor->setPos(x, y);
316                 showInsetCursor(bv);
317                 if (sel_flag) {
318                         sel_flag = false;
319                         sel_x = 0;
320                         sel_y = 0;
321                 }
322                 bv->updateInset(this, false);
323         }
324 }
325
326
327 void InsetFormulaBase::insetButtonPress(BufferView * bv,
328                                         int x, int y, int /*button*/)
329 {
330         sel_flag = false;
331         sel_x = x;
332         sel_y = y;
333         if (mathcursor && mathcursor->selection()) {
334                 mathcursor->selClear();
335                 bv->updateInset(this, false);
336         }
337 }
338
339
340 void InsetFormulaBase::insetMotionNotify(BufferView * bv,
341                                          int x, int y, int /*button*/)
342 {
343         if (sel_x && sel_y && abs(x-sel_x) > 4 && !sel_flag) {
344                 sel_flag = true;
345                 hideInsetCursor(bv);
346                 mathcursor->setPos(sel_x + par_->xo(), sel_y + par_->yo());
347                 mathcursor->selStart();
348                 showInsetCursor(bv);
349                 mathcursor->getPos(sel_x, sel_y);
350         } else if (sel_flag) {
351                 hideInsetCursor(bv);
352                 x += par_->xo();
353                 y += par_->yo();
354                 mathcursor->setPos(x, y);
355                 showInsetCursor(bv);
356                 mathcursor->getPos(x, y);
357                 if (sel_x != x || sel_y != y)
358                         bv->updateInset(this, false);
359                 sel_x = x;
360                 sel_y = y;
361         }
362 }
363
364
365 void InsetFormulaBase::insetKeyPress(XKeyEvent *)
366 {
367         lyxerr[Debug::MATHED] << "Used InsetFormulaBase::InsetKeyPress." << endl;
368 }
369
370
371
372 UpdatableInset::RESULT
373 InsetFormulaBase::localDispatch(BufferView * bv, kb_action action,
374                             string const & arg)
375 {
376         //lyxerr << "InsetFormulaBase::LocalDispatch: act: " << action
377         //      << " arg: '" << arg << "' cursor: " << mathcursor << "\n";
378
379         if (!mathcursor) 
380                 return UNDISPATCHED;
381
382         MathTextCodes varcode = LM_TC_MIN;
383         bool was_macro = mathcursor->inMacroMode();
384         bool sel = false;
385         bool was_selection = mathcursor->selection();
386         RESULT result = DISPATCHED;
387
388         hideInsetCursor(bv);
389
390         if (mathcursor->getLastCode() == LM_TC_TEX)
391                 varcode = LM_TC_TEX;
392
393         mathcursor->normalize();
394
395         switch (action) {
396
397                 // --- Cursor Movements ---------------------------------------------
398
399         case LFUN_RIGHTSEL:
400                 sel = true; // fall through...
401
402         case LFUN_RIGHT:
403                 result = DISPATCH_RESULT(mathcursor->right(sel));
404                 updateLocal(bv, false);
405                 break;
406
407
408         case LFUN_LEFTSEL:
409                 sel = true; // fall through
410
411         case LFUN_LEFT:
412                 result = DISPATCH_RESULT(mathcursor->left(sel));
413                 updateLocal(bv, false);
414                 break;
415
416
417         case LFUN_UPSEL:
418                 sel = true;
419
420         case LFUN_UP:
421                 result = DISPATCH_RESULT(mathcursor->up(sel));
422                 updateLocal(bv, false);
423                 break;
424
425
426         case LFUN_DOWNSEL:
427                 sel = true;
428
429         case LFUN_DOWN:
430                 result = DISPATCH_RESULT(mathcursor->down(sel));
431                 updateLocal(bv, false);
432                 break;
433
434         case LFUN_HOME:
435                 mathcursor->home();
436                 updateLocal(bv, false);
437                 break;
438
439         case LFUN_END:
440                 mathcursor->end();
441                 updateLocal(bv, false);
442                 break;
443
444         case LFUN_DELETE_LINE_FORWARD:
445                 bv->lockedInsetStoreUndo(Undo::DELETE);
446                 mathcursor->delLine();
447                 updateLocal(bv, true);
448                 break;
449
450         case LFUN_TAB:
451                 mathcursor->idxNext();
452                 updateLocal(bv, false);
453                 break;
454
455         case LFUN_SHIFT_TAB:
456                 mathcursor->idxPrev();
457                 updateLocal(bv, false);
458                 break;
459
460         case LFUN_TABINSERT:
461                 bv->lockedInsetStoreUndo(Undo::EDIT);
462                 mathcursor->splitCell();
463                 updateLocal(bv, true);
464                 break;
465
466         case LFUN_BACKSPACE:
467                 // if (!mathcursor->inMacroMode() && mathcursor->pos() == 0)
468                 if (mathcursor->pos() == 0) {
469                         bv->lockedInsetStoreUndo(Undo::DELETE);
470                         mathcursor->pullArg(false);
471                         bv->updateInset(this, true);
472                         break;
473                 }
474                 if (mathcursor->inMacroMode())
475                         mathcursor->left();
476                 else
477                         mathcursor->plainLeft();
478                 // fall through...
479
480         case LFUN_DELETE:
481                 bv->lockedInsetStoreUndo(Undo::DELETE);
482                 if (mathcursor->pos() == mathcursor->array().size()) 
483                         mathcursor->pullArg(true);
484                 else
485                         mathcursor->erase();
486                 bv->updateInset(this, true);
487                 break;
488
489                 //    case LFUN_GETXY:
490                 //      sprintf(dispatch_buffer, "%d %d",);
491                 //      dispatch_result = dispatch_buffer;
492                 //      break;
493         case LFUN_SETXY:
494         {
495                 lyxerr << "LFUN_SETXY broken!\n";
496                 int x;
497                 int y;
498                 int x1;
499                 int y1;
500                 istringstream is(arg.c_str());
501                 is >> x >> y;
502                 par_->getXY(x1, y1);
503                 mathcursor->setPos(x1 + x, y1 + y);
504                 updateLocal(bv, false);
505         }
506         break;
507
508
509         case LFUN_PASTE:
510                 if (was_macro)
511                         mathcursor->macroModeClose();
512                 bv->lockedInsetStoreUndo(Undo::INSERT);
513                 mathcursor->selPaste();
514                 updateLocal(bv, true);
515                 break;
516
517         case LFUN_CUT:
518                 bv->lockedInsetStoreUndo(Undo::DELETE);
519                 mathcursor->selCut();
520                 updateLocal(bv, true);
521                 break;
522
523         case LFUN_COPY:
524                 mathcursor->selCopy();
525                 break;
526
527         case LFUN_HOMESEL:
528         case LFUN_ENDSEL:
529         case LFUN_WORDRIGHTSEL:
530         case LFUN_WORDLEFTSEL:
531                 break;
532
533                 // --- accented characters ------------------------------
534
535         case LFUN_UMLAUT:     handleAccent(bv, "ddot"); break;
536         case LFUN_CIRCUMFLEX: handleAccent(bv, "hat"); break;
537         case LFUN_GRAVE:      handleAccent(bv, "grave"); break;
538         case LFUN_ACUTE:      handleAccent(bv, "acute"); break;
539         case LFUN_TILDE:      handleAccent(bv, "tilde"); break;
540         case LFUN_MACRON:     handleAccent(bv, "bar"); break;
541         case LFUN_DOT:        handleAccent(bv, "dot"); break;
542         case LFUN_CARON:      handleAccent(bv, "check"); break;
543         case LFUN_BREVE:      handleAccent(bv, "breve"); break;
544         case LFUN_VECTOR:     handleAccent(bv, "vec"); break;
545
546                 // Greek mode
547         case LFUN_GREEK:
548                 if (!greek_kb_flag) {
549                         greek_kb_flag = 1;
550                         bv->owner()->message(_("Math greek mode on"));
551                 } else
552                         greek_kb_flag = 0;
553                 break;
554
555                 // Greek keyboard
556         case LFUN_GREEK_TOGGLE:
557                 greek_kb_flag = greek_kb_flag ? 0 : 2;
558                 if (greek_kb_flag)
559                         bv->owner()->message(_("Math greek keyboard on"));
560                 else
561                         bv->owner()->message(_("Math greek keyboard off"));
562                 break;
563
564                 //  Math fonts
565         case LFUN_BOLD:    handleFont(bv, LM_TC_BF); break;
566         case LFUN_SANS:    handleFont(bv, LM_TC_SF); break;
567         case LFUN_EMPH:    handleFont(bv, LM_TC_CAL); break;
568         case LFUN_ROMAN:   handleFont(bv, LM_TC_RM); break;
569         case LFUN_CODE:    handleFont(bv, LM_TC_TT); break;
570         case LFUN_DEFAULT: handleFont(bv, LM_TC_VAR); break;
571
572         case LFUN_MATH_MODE:
573                 handleFont(bv, LM_TC_TEXTRM);
574                 //bv->owner()->message(_("math text mode toggled"));
575                 break;
576
577 #ifndef NO_LATEX
578         case LFUN_TEX:
579                 if (!mathcursor->selection()) {
580                         mathcursor->handleFont(LM_TC_TEX);
581                         //bv->owner()->message(_("TeX mode toggled"));
582                 }
583                 break;
584 #endif
585
586         case LFUN_MATH_LIMITS:
587                 bv->lockedInsetStoreUndo(Undo::INSERT);
588                 if (mathcursor->toggleLimits())
589                         updateLocal(bv, true);
590                 break;
591
592         case LFUN_MATH_SIZE:
593                 if (!arg.empty()) {
594                         bv->lockedInsetStoreUndo(Undo::INSERT);
595                         latexkeys const * l = in_word_set(arg);
596                         mathcursor->setSize(MathStyles(l ? l->id : static_cast<unsigned int>(-1)));
597                         updateLocal(bv, true);
598                 }
599                 break;
600
601         case LFUN_INSERT_MATRIX:
602                 if (!arg.empty()) {
603                         bv->lockedInsetStoreUndo(Undo::INSERT);
604                         mathcursor->interpret("matrix " + arg);
605                         updateLocal(bv, true);
606                 }
607                 break;
608
609         case LFUN_INSERT_MATH:
610                 if (!arg.empty()) {
611                         bv->lockedInsetStoreUndo(Undo::INSERT);
612                         mathcursor->interpret(arg);
613                         updateLocal(bv, true);
614                 }
615                 break;
616
617         case LFUN_MATH_SPACE:
618         {
619                 bv->lockedInsetStoreUndo(Undo::EDIT);
620                 MathSpaceInset * p = mathcursor->prevSpaceInset();
621                 if (p) 
622                         p->incSpace();
623                 else
624                         mathcursor->insert(new MathSpaceInset(1));
625                 updateLocal(bv, true);
626                 break;
627         }
628
629         case LFUN_MATH_DELIM:
630         {
631                 bv->lockedInsetStoreUndo(Undo::INSERT);
632                 static const string vdelim("(){}[]./|");
633                 //lyxerr << "formulabase::LFUN_MATH_DELIM, arg: '" << arg << "'\n";
634
635                 if (arg.empty())
636                         break;
637
638                 // try to read integers first
639                 int ilt = '(';
640                 int irt = '.';
641                 istringstream is(arg.c_str());
642                 is >> ilt >> irt;
643
644                 if (!is) { // ok, the beasties are no integers... try something else
645                         ilt = '(';
646                         irt = '.';
647
648                         istringstream is(arg.c_str());
649                         string lt;
650                         string rt;
651                         is >> lt >> rt;
652                         //lyxerr << "formulabase::LFUN_MATH_DELIM, lt: '" << lt << "'\n";
653                         //lyxerr << "formulabase::LFUN_MATH_DELIM, rt: '" << rt << "'\n";
654
655                         if (lt.size() > 1) {
656                                 latexkeys const * l = in_word_set(lt);
657                                 if (l)
658                                         ilt = l->id;
659                         } else if (vdelim.find(lt[0]) != string::npos)
660                                         ilt = lt[0];
661
662                         if (rt.size() > 1) {
663                                 latexkeys const * l = in_word_set(rt);
664                                 if (l)
665                                         irt = l->id;
666                         } else if (vdelim.find(rt[0]) != string::npos)
667                                         irt = rt[0];
668                 }
669
670                 handleDelim(bv, ilt, irt);
671                 updateLocal(bv, true);
672                 break;
673         }
674
675         case LFUN_PROTECTEDSPACE:
676                 //lyxerr << " called LFUN_PROTECTEDSPACE\n";
677                 bv->lockedInsetStoreUndo(Undo::INSERT);
678                 mathcursor->insert(new MathSpaceInset(1));
679                 updateLocal(bv, true);
680                 break;
681
682         case LFUN_UNDO:
683                 bv->owner()->message(_("Invalid action in math mode!"));
684                 break;
685
686
687         case LFUN_MATH_HALIGN:
688         {
689                 bv->lockedInsetStoreUndo(Undo::INSERT);
690                 lyxerr << "handling halign '" << arg << "'\n";
691                 int idx;
692                 MathArrayInset * p = matrixpar(idx);
693                 if (!p)
694                         break; 
695                 p->halign(arg.size() ? arg[0] : 'c', p->col(idx));
696                 updateLocal(bv, true);
697                 break;
698         }
699
700         case LFUN_MATH_VALIGN:
701         {
702                 bv->lockedInsetStoreUndo(Undo::INSERT);
703                 lyxerr << "handling valign '" << arg << "'\n";
704                 int idx;
705                 MathArrayInset * p = matrixpar(idx);
706                 if (!p)
707                         break; 
708                 p->valign(arg.size() ? arg[0] : 'c');
709                 updateLocal(bv, true);
710                 break;
711         }
712
713         case LFUN_MATH_ROW_INSERT:
714         {
715                 bv->lockedInsetStoreUndo(Undo::INSERT);
716                 int idx;
717                 MathArrayInset * p = matrixpar(idx);
718                 lyxerr << " calling LFUN_MATH_ROW_INSERT on " << p << endl;
719                 if (!p)
720                         break; 
721                 p->addRow(p->row(idx));
722                 updateLocal(bv, true);
723                 break;
724         }
725
726         case LFUN_MATH_ROW_DELETE:
727         {
728                 bv->lockedInsetStoreUndo(Undo::INSERT);
729                 int idx;
730                 MathArrayInset * p = matrixpar(idx);
731                 lyxerr << " calling LFUN_MATH_ROW_DELETE on " << p << endl;
732                 if (!p)
733                         break; 
734                 p->delRow(p->row(idx));
735                 updateLocal(bv, true);
736                 break;
737         }
738
739         case LFUN_MATH_COLUMN_INSERT:
740         {
741                 bv->lockedInsetStoreUndo(Undo::INSERT);
742                 int idx;
743                 MathArrayInset * p = matrixpar(idx);
744                 if (!p)
745                         break; 
746                 p->addCol(p->col(idx));
747                 updateLocal(bv, true);
748                 break;
749         }
750
751         case LFUN_MATH_COLUMN_DELETE:
752         {
753                 bv->lockedInsetStoreUndo(Undo::INSERT);
754                 int idx;
755                 MathArrayInset * p = matrixpar(idx);
756                 if (!p)
757                         break; 
758                 p->delCol(p->col(idx));
759                 updateLocal(bv, true);
760                 break;
761         }
762
763         case LFUN_EXEC_COMMAND:
764                 result = UNDISPATCHED;
765                 break;
766
767         default:
768                 if ((action == -1 || action == LFUN_SELFINSERT) && !arg.empty()) {
769                         unsigned char c = arg[0];
770
771                         lyxerr << "Action: " << action << endl;
772                         
773                         lyxerr << "char: '" << c << "'  int: " << int(c) << endl;
774                         //owner_->getIntl()->getTrans().TranslateAndInsert(c, lt);      
775                         //lyxerr << "trans: '" << c << "'  int: " << int(c) << endl;
776                         bv->lockedInsetStoreUndo(Undo::INSERT);
777
778                         if (c == 0) {      // Dead key, do nothing
779                                 //lyxerr << "deadkey" << endl;
780                                 break;
781                         }
782
783                         if (isalpha(c)) {
784                                 if (mathcursor->getLastCode() == LM_TC_TEX) {
785                                         mathcursor->macroModeOpen();
786                                         mathcursor->clearLastCode();
787                                         varcode = LM_TC_MIN;
788                                 } else if (!varcode) {          
789                                         MathTextCodes f = mathcursor->getLastCode() ?
790                                                 mathcursor->getLastCode() :
791                                                 mathcursor->nextCode();
792                                         varcode = MathIsAlphaFont(f) ?
793                                                 static_cast<MathTextCodes>(f) :
794                                                 LM_TC_VAR;
795                                 }
796                                 
797                                 //           lyxerr << "Varcode << vardoce;
798                                 MathTextCodes char_code = varcode;
799                                 if (greek_kb_flag) {
800                                         char greek[26] =
801                                         {'A', 'B', 'X',  0 , 'E',  0 ,  0 , 'H', 'I',  0 ,
802                                          'K',  0 , 'M', 'N', 'O',  0 ,  0 , 'P',  0 , 'T',
803                                          'Y',  0,   0,   0,   0 , 'Z' };
804                                         
805                                         if ('A' <= c && c <= 'Z' && greek[c - 'A']) {
806                                                 char_code = LM_TC_RM;
807                                                 c = greek[c - 'A'];
808                                         } else
809                                                 char_code = LM_TC_SYMB;
810                                 }
811                                 
812                                 mathcursor->insert(c, char_code);
813                                 
814                                 if (greek_kb_flag && char_code == LM_TC_RM)
815                                         mathcursor->setLastCode(LM_TC_VAR);
816                                 
817                                 varcode = LM_TC_MIN;
818                                 
819                                 if (greek_kb_flag < 2)
820                                         greek_kb_flag = 0;
821                                 
822                         } else if (strchr("!,:;{}", c) && (varcode == LM_TC_TEX||was_macro)) {
823                                 mathcursor->insert(c, LM_TC_TEX);
824                                 if (c == '{') {
825                                         mathcursor->insert('}', LM_TC_TEX);
826                                         mathcursor->left();
827                                 }
828                                 mathcursor->clearLastCode();
829                                 //             varcode = LM_TC_MIN;
830                         } else if (c == '_' && varcode == LM_TC_TEX) {
831                                 mathcursor->insert(c, LM_TC_SPECIAL);
832                                 mathcursor->clearLastCode();
833                                 //             varcode = LM_TC_MIN;
834                         } else if ('0' <= c && c <= '9' && (varcode == LM_TC_TEX||was_macro)) {
835                                 mathcursor->macroModeOpen();
836                                 mathcursor->clearLastCode();
837                                 mathcursor->insert(c, LM_TC_MIN);
838                         } else if (('0' <= c && c <= '9') || strchr(";:!|[]().,?", c)) {
839                                 MathTextCodes code = mathcursor->getLastCode();
840                                 if (code != LM_TC_TEXTRM)
841                                         code = LM_TC_CONST;
842                                 mathcursor->insert(c, code);
843                         } else if (strchr("+/-*<>=", c)) {
844                                 MathTextCodes code = mathcursor->getLastCode();
845                                 if (code != LM_TC_TEXTRM)
846                                         code = LM_TC_BOP;
847                                 mathcursor->insert(c, code);
848                         } else if (strchr(latex_special_chars, c) && c != '_') {
849                                 MathTextCodes code = mathcursor->getLastCode();
850                                 if (code != LM_TC_TEXTRM)
851                                         code = LM_TC_SPECIAL;
852                                 mathcursor->insert(c, code);
853                         } else if (c == '_' || c == '^') {
854                                 char s[2];
855                                 s[0] = c;
856                                 s[1] = 0;
857                                 mathcursor->interpret(s);
858                         } else if (c == ' ') {
859                                 if (!varcode) { 
860                                         MathTextCodes f = (mathcursor->getLastCode()) ?
861                                                 mathcursor->getLastCode() :
862                                                 mathcursor->nextCode();
863                                         varcode = MathIsAlphaFont(f) ? f : LM_TC_VAR;
864                                 }
865                                 
866                                 if (varcode == LM_TC_TEXTRM)
867                                         mathcursor->insert(c, LM_TC_TEXTRM);
868                                 else if (was_macro)
869                                         mathcursor->macroModeClose();
870                                 else if (mathcursor->pop())
871                                         mathcursor->plainRight();
872                                 else {
873                                         // this would not work if the inset is in an table!
874                                         //bv->text->cursorRight(bv, true);
875                                         result = FINISHED;
876                                 }
877                         } else if (c == '\'' || c == '@') {
878                                 mathcursor->insert(c, LM_TC_VAR);
879                         } else if (c == '\\') {
880                                 if (was_macro)
881                                         mathcursor->macroModeClose();
882                                 bv->owner()->message(_("TeX mode"));
883                                 mathcursor->setLastCode(LM_TC_TEX);
884                         }
885                         updateLocal(bv, true);
886                 } else if (action == LFUN_MATH_PANEL) {
887                         result = UNDISPATCHED;
888                 } else {
889                         lyxerr << "Closed by action " << action << endl;
890                         result =  FINISHED;
891                 }
892         }
893
894         mathcursor->normalize();
895
896         if (was_macro != mathcursor->inMacroMode()
897                                 && action >= 0 && action != LFUN_BACKSPACE) 
898                 updateLocal(bv, true);
899         
900         if (mathcursor->selection() || was_selection)
901                 toggleInsetSelection(bv);
902
903         if (result == DISPATCHED || result == DISPATCHED_NOUPDATE ||
904             result == UNDISPATCHED)
905                 showInsetCursor(bv);
906         else
907                 bv->unlockInset(this);
908
909         return result;  // original version
910 }
911
912
913 Inset::Code InsetFormulaBase::lyxCode() const
914 {
915         return Inset::MATH_CODE;
916 }
917
918
919 LyXFont const InsetFormulaBase::convertFont(LyXFont const & f) const
920 {
921         // We have already discussed what was here
922         LyXFont font(f);
923 #ifndef NO_LATEX
924         font.setLatex(LyXFont::OFF);
925 #endif
926         return font;
927 }
928
929 MathInset * InsetFormulaBase::par() const
930 {
931         return par_;
932 }
933
934
935 void mathDispatchCreation(BufferView * bv, string const & arg, bool display)
936 {
937         if (bv->available()) {
938 // Feature "Read math inset from selection" disabled.
939 //              // use selection if available..
940 //              string sel;
941 //              if (action == LFUN_MATH_IMPORT_SELECTION)
942 //                      sel = "";
943 //              else
944 //                      sel = bv->getLyXText()->selectionAsString(bv->buffer());
945
946                         InsetFormula * f;
947 //              if (sel.empty()) {
948                                 f = new InsetFormula;
949                                 if (openNewInset(bv, f)) {
950                                         // don't do that also for LFUN_MATH_MODE unless you want end up with
951                                         // always changing to mathrm when opening an inlined inset
952                                         // -- I really hate "LyXfunc overloading"...
953                                         if (display)
954                                                 f->localDispatch(bv, LFUN_MATH_DISPLAY, string());
955                                         f->localDispatch(bv, LFUN_INSERT_MATH, arg);
956                                 }
957 //              } else {
958 //                      f = new InsetFormula(sel);
959 //                      bv->getLyXText()->cutSelection(bv);
960 //                      openNewInset(bv, f);
961 //              }
962         }
963         bv->owner()->getLyXFunc()->setMessage(N_("Math editor mode"));
964 }
965
966 void mathDispatchMathDisplay(BufferView * bv, string const & arg)
967 {
968         mathDispatchCreation(bv, arg, true);
969 }
970         
971 void mathDispatchMathMode(BufferView * bv, string const & arg)
972 {
973         mathDispatchCreation(bv, arg, false);
974 }
975
976 void mathDispatchMathImportSelection(BufferView * bv, string const & arg)
977 {
978         mathDispatchCreation(bv, arg, true);
979 }
980
981 void mathDispatchMathMacro(BufferView * bv, string const & arg)
982 {
983         if (bv->available()) {
984                 if (arg.empty())
985                         bv->owner()->getLyXFunc()->setErrorMessage(N_("Missing argument"));
986                 else {
987                         string s(arg);
988                         string const s1 = token(s, ' ', 1);
989                         int const na = s1.empty() ? 0 : lyx::atoi(s1);
990                         openNewInset(bv, new InsetFormulaMacro(token(s, ' ', 0), na));
991                 }
992         }
993 }
994
995 void mathDispatchMathDelim(BufferView * bv, string const & arg)
996 {          
997         if (bv->available()) { 
998                 if (openNewInset(bv, new InsetFormula))
999                         bv->theLockingInset()->localDispatch(bv, LFUN_MATH_DELIM, arg);
1000         }
1001 }          
1002
1003
1004 void mathDispatchInsertMatrix(BufferView * bv, string const & arg)
1005 {          
1006         if (bv->available()) { 
1007                 if (openNewInset(bv, new InsetFormula))
1008                         bv->theLockingInset()->localDispatch(bv, LFUN_INSERT_MATRIX, arg);
1009         }
1010 }          
1011
1012 void mathDispatchInsertMath(BufferView * bv, string const & arg)
1013 {
1014         if (bv->available()) {
1015                 if (arg.size() && arg[0] == '\\')
1016                         openNewInset(bv, new InsetFormula(arg));
1017                 else
1018                         mathDispatchMathMode(bv, arg);
1019         }
1020 }
1021