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