]> git.lyx.org Git - lyx.git/blob - src/mathed/formula.C
5f2275f228f4484594cc456982529fb460123b1c
[lyx.git] / src / mathed / formula.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
18 #include "Lsstream.h"
19
20 #ifdef __GNUG__
21 #pragma implementation "formula.h"
22 #endif
23
24 #include "formula.h"
25 #include "commandtags.h"
26 #include "math_cursor.h"
27 #include "math_parser.h"
28 #include "lyx_main.h"
29 #include "minibuffer.h"
30 #include "BufferView.h"
31 #include "lyxtext.h"
32 #include "gettext.h"
33 #include "LaTeXFeatures.h"
34 #include "debug.h"
35 #include "lyx_gui_misc.h"
36 #include "support/LOstream.h"
37 #include "LyXView.h"
38 #include "Painter.h"
39 #include "font.h"
40 #include "support/lyxlib.h"
41 #include "lyxrc.h"
42 #include "math_inset.h"
43 #include "math_parinset.h"
44 #include "math_matrixinset.h"
45 #include "math_rowst.h"
46 #include "math_spaceinset.h"
47 #include "math_deliminset.h"
48 #include "mathed/support.h"
49
50 using std::ostream;
51 using std::istream;
52 using std::pair;
53 using std::endl;
54 using std::vector;
55 using std::max;
56
57 extern string mathed_label;
58
59 extern char const * latex_special_chars;
60
61 int greek_kb_flag = 0;
62
63 LyXFont * Math_Fonts = 0; // this is only used by Whichfont and mathed_init_fonts (Lgb)
64
65 static LyXFont::FONT_SIZE lfont_size = LyXFont::SIZE_NORMAL;
66
67 // local global
68 static int sel_x;
69 static int sel_y;
70 static bool sel_flag;
71
72 MathedCursor * InsetFormula::mathcursor = 0; 
73
74 void mathed_init_fonts();
75
76
77 static
78 void mathedValidate(LaTeXFeatures & features, MathParInset * par);
79
80
81 LyXFont WhichFont(short type, int size)
82 {
83         LyXFont f;
84     
85         if (!Math_Fonts)
86                 mathed_init_fonts();
87         
88         switch (type) {
89         case LM_TC_SYMB:             
90                 f = Math_Fonts[2];
91                 break;
92         case LM_TC_BSYM:             
93                 f = Math_Fonts[2];
94                 break;
95         case LM_TC_VAR:
96         case LM_TC_IT:
97                 f = Math_Fonts[0];
98                 break;
99         case LM_TC_BF:
100                 f = Math_Fonts[3];
101                 break;
102         case LM_TC_SF:
103                 f = Math_Fonts[7];
104                 break;
105         case LM_TC_CAL:
106                 f = Math_Fonts[4];
107                 break;
108         case LM_TC_TT:
109                 f = Math_Fonts[5];
110                 break;
111         case LM_TC_SPECIAL: //f = Math_Fonts[0]; break;
112         case LM_TC_TEXTRM:
113         case LM_TC_RM:    
114                 f = Math_Fonts[6];
115                 break;
116         default:
117                 f = Math_Fonts[1];
118                 break;   
119         }
120         
121         f.setSize(lfont_size);
122         
123         switch (size) {
124         case LM_ST_DISPLAY:     
125                 if (type == LM_TC_BSYM) {
126                         f.incSize();
127                         f.incSize();
128                 }
129         break;
130         case LM_ST_TEXT:
131                 break;
132         case LM_ST_SCRIPT:
133                 f.decSize();
134                 break;
135         case LM_ST_SCRIPTSCRIPT:
136                 f.decSize();
137                 f.decSize();
138         break;
139         default:
140                 lyxerr << "Mathed Error: wrong font size: " << size << endl;
141                 break;
142         }
143         
144         if (type != LM_TC_TEXTRM) 
145                 f.setColor(LColor::math);
146         return f;
147 }
148
149
150 void mathed_init_fonts() //removed 'static' because DEC cxx does not
151                          //like it (JMarc)
152         // Probably because this func is declared as a friend in math_defs.h
153         // Lgb
154 {
155
156     Math_Fonts = new LyXFont[8]; //DEC cxx cannot initialize all fonts
157                                  //at once (JMarc) rc
158     for (int i = 0 ; i < 8 ; ++i) { 
159         Math_Fonts[i] = LyXFont(LyXFont::ALL_SANE);
160     }
161     Math_Fonts[0].setShape(LyXFont::ITALIC_SHAPE);
162     
163     Math_Fonts[1].setFamily(LyXFont::SYMBOL_FAMILY);
164     
165     Math_Fonts[2].setFamily(LyXFont::SYMBOL_FAMILY);
166     Math_Fonts[2].setShape(LyXFont::ITALIC_SHAPE);
167
168     Math_Fonts[3].setSeries(LyXFont::BOLD_SERIES);
169       
170     Math_Fonts[4].setFamily(LyXFont::SANS_FAMILY);
171     Math_Fonts[4].setShape(LyXFont::ITALIC_SHAPE);
172       
173     Math_Fonts[5].setFamily(LyXFont::TYPEWRITER_FAMILY);
174
175     Math_Fonts[6].setFamily(LyXFont::ROMAN_FAMILY);
176
177     Math_Fonts[7].setFamily(LyXFont::SANS_FAMILY);
178     
179     LyXFont f = WhichFont(LM_TC_VAR, LM_ST_TEXT);
180     MathedInset::df_asc = lyxfont::maxAscent(f); 
181     MathedInset::df_des = lyxfont::maxDescent(f);
182     MathedInset::df_width = lyxfont::width('I', f);    
183 }
184
185
186
187
188
189
190
191
192
193
194
195
196 InsetFormula::InsetFormula(bool display)
197 {
198         par = new MathParInset; // this leaks
199         //   mathcursor = 0;
200         disp_flag = display;
201         //label = 0;
202         if (disp_flag) {
203                 par->SetType(LM_OT_PAR);
204                 par->SetStyle(LM_ST_DISPLAY);
205         }
206 }
207
208
209 InsetFormula::InsetFormula(MathParInset * p)
210 {
211    if (is_matrix_type(p->GetType()))
212            lyxerr << "InsetFormula::InsetFormula: This shouldn't happen" << endl; 
213    par = is_multiline(p->GetType()) ? 
214          new MathMatrixInset(static_cast<MathMatrixInset*>(p)): 
215          new MathParInset(p);
216 //   mathcursor = 0;
217    
218    disp_flag = (par->GetType()>0);
219    //label = 0;
220 }
221
222
223 InsetFormula::~InsetFormula()
224 {
225    delete par;
226 }
227
228
229 Inset * InsetFormula::Clone(Buffer const &) const
230 {
231     InsetFormula * f = new InsetFormula(par);
232     f->label = label;
233     return f;
234 }
235
236
237 void InsetFormula::Write(Buffer const * buf, ostream & os) const
238 {
239         os << "Formula ";
240         Latex(buf, os, false, false);
241 }
242
243
244 int InsetFormula::Latex(Buffer const *, ostream & os, bool fragile, bool) const
245 {
246     int ret = 0;      
247 //#warning Alejandro, the number of lines is not returned in this case
248 // This problem will disapear at 0.13.
249     mathed_write(par, os, &ret, fragile, label);
250     return ret;
251 }
252
253
254 int InsetFormula::Ascii(Buffer const *, ostream & os, int) const
255 {
256     par->Write(os, false);
257     return 0;
258 }
259
260
261 int InsetFormula::Linuxdoc(Buffer const * buf, ostream & os) const
262 {
263     return Ascii(buf, os, 0);
264 }
265
266
267 int InsetFormula::DocBook(Buffer const * buf, ostream & os) const
268 {
269     return Ascii(buf, os, 0);
270 }
271
272
273 // Check if uses AMS macros 
274 void InsetFormula::Validate(LaTeXFeatures & features) const
275 {
276         if (is_ams(par->GetType()))
277                 features.amsstyle = true;
278
279         // Validation is necessary only if not using AMS math.
280         // To be safe, we will always run mathedValidate.
281         //if (!features.amsstyle)
282         mathedValidate(features, par);
283 }
284
285
286 void InsetFormula::Read(Buffer const *, LyXLex & lex)
287 {
288         istream & is = lex.getStream();
289     
290         mathed_parser_file(is, lex.GetLineNo());   
291    
292         // Silly hack to read labels. 
293         //mathed_label = 0;
294         mathed_label.erase();
295         
296         mathed_parse(0, 0, &par);
297         par->Metrics();
298         disp_flag = (par->GetType() > 0);
299         
300         // Update line number
301         lex.setLineNo(mathed_parser_lineno());
302         
303         //if (mathed_label) {
304         if (!mathed_label.empty()) {
305                 label = mathed_label;
306                 //mathed_label = 0;
307                 mathed_label.erase();
308         }
309         
310         // reading of end_inset in the inset!!!
311         while (lex.IsOK()) {
312                 lex.nextToken();
313                 if (lex.GetString() == "\\end_inset")
314                         break;
315                 lyxerr << "InsetFormula::Read: Garbage before \\end_inset,"
316                         " or missing \\end_inset!" << endl;
317         }
318    
319 #ifdef DEBUG
320         Write(lyxerr);
321 #endif
322 }
323
324
325 int InsetFormula::ascent(BufferView *, LyXFont const &) const
326 {
327    return par->Ascent() + ((disp_flag) ? 8 : 1);
328 }
329
330
331 int InsetFormula::descent(BufferView *, LyXFont const &) const
332 {
333    return par->Descent() + ((disp_flag) ? 8 : 1);
334 }
335
336
337 int InsetFormula::width(BufferView * bv, LyXFont const & f) const
338 {
339     MathedInset::workWidth = bv->workWidth();
340     lfont_size = f.size();
341     par->Metrics();
342     return par->Width(); //+2;
343 }
344
345
346 void InsetFormula::draw(BufferView * bv, LyXFont const & f,
347                         int baseline, float & x, bool) const
348 {
349         MathedInset::workWidth = bv->workWidth();
350         Painter & pain = bv->painter();
351         // Seems commenting out solves a problem.
352         LyXFont font = mathed_get_font(LM_TC_TEXTRM, LM_ST_TEXT);
353         font.setSize(f.size());
354         lfont_size = font.size();
355         /// Let's try to wait a bit with this... (Lgb)
356         //UpdatableInset::draw(pain, font, baseline, x);
357         
358         // otherwise a segfault could occur
359         // in some XDrawRectangles (i.e. matrix) (Matthias)
360         if (mathcursor && mathcursor->GetPar() == par) { 
361                 if (mathcursor->Selection()) {
362                         int n;
363                         int * xp = 0;
364                         int * yp = 0;
365                         mathcursor->SelGetArea(&xp, &yp, n);
366                         pain.fillPolygon(xp, yp, n, LColor::selection);
367                 }
368                 mathcursor->draw(pain, int(x), baseline);
369         } else {
370                 par->draw(pain, int(x), baseline);
371         }
372         x += float(width(bv, font));
373
374         if (is_numbered(par->GetType())) {
375                 LyXFont wfont = WhichFont(LM_TC_BF, par->size);
376                 wfont.setLatex(LyXFont::OFF);
377                 
378                 if (is_singlely_numbered(par->GetType())) {
379                         string str;
380                         if (!label.empty())
381                                 str = string("(") + label + ")";
382                         else
383                                 str = string("(#)");
384                         pain.text(int(x + 20), baseline, str, wfont);
385                 } else {
386                         MathMatrixInset * mt =
387                                 static_cast<MathMatrixInset*>(par);
388                         int y;
389                         MathedRowSt const * crow = mt->getRowSt();
390                         while (crow) {
391                                 y = baseline + crow->getBaseline();
392                                 if (crow->isNumbered()) {
393                                         string str;
394                                         if (!crow->getLabel().empty())
395                                                 str = string("(") + crow->getLabel() + ")";
396                                         else
397                                                 str = "(#)";
398                                         pain.text(int(x + 20), y, str, wfont);
399                                 }
400                                 crow = crow->getNext();
401                         }
402                 }
403         }
404         cursor_visible = false;
405 }
406
407
408 string const InsetFormula::EditMessage() const 
409 {
410         return _("Math editor mode");
411 }
412
413
414 void InsetFormula::Edit(BufferView * bv, int x, int y, unsigned int)
415 {
416     mathcursor = new MathedCursor(par);
417     if (!bv->lockInset(this))
418         lyxerr[Debug::MATHED] << "Cannot lock inset!!!" << endl;
419     par->Metrics();
420     bv->updateInset(this, false);
421     x += par->xo; 
422     y += par->yo; 
423     mathcursor->SetPos(x, y);
424     sel_x = sel_y = 0;
425     sel_flag = false;
426 }
427
428
429 void InsetFormula::InsetUnlock(BufferView * bv)
430 {
431    if (mathcursor) {
432        if (mathcursor->InMacroMode()) {
433            mathcursor->MacroModeClose();
434            UpdateLocal(bv);
435        }                                         
436      delete mathcursor;
437    }
438    mathcursor = 0;
439    bv->updateInset(this, false);
440 }
441
442
443 // Now a symbol can be inserted only if the inset is locked
444 void InsetFormula::InsertSymbol(BufferView * bv, string const & s)
445
446    if (s.empty() || !mathcursor) return;   
447    mathcursor->Interpret(s);
448    UpdateLocal(bv);
449 }
450
451    
452 void InsetFormula::GetCursorPos(BufferView *, int & x, int & y) const
453 {
454     mathcursor->GetPos(x, y);
455     x -= par->xo; 
456     y -= par->yo;
457 }
458
459
460 void InsetFormula::ToggleInsetCursor(BufferView * bv)
461 {
462   if (!mathcursor)
463     return;
464
465   int x;
466   int y;
467   mathcursor->GetPos(x, y);
468 //  x -= par->xo; 
469   y -= par->yo; 
470     LyXFont font = WhichFont(LM_TC_TEXTRM, LM_ST_TEXT);
471   int asc = lyxfont::maxAscent(font);
472   int desc = lyxfont::maxDescent(font);
473   
474   if (cursor_visible)
475     bv->hideLockedInsetCursor();
476   else
477     bv->showLockedInsetCursor(x, y, asc, desc);
478   cursor_visible = !cursor_visible;
479 }
480
481
482 void InsetFormula::ShowInsetCursor(BufferView * bv, bool)
483 {
484   if (!cursor_visible) {
485     if (mathcursor) {
486       int x;
487       int y;
488       mathcursor->GetPos(x, y);
489       //  x -= par->xo; 
490       y -= par->yo;
491         LyXFont font = WhichFont(LM_TC_TEXTRM, LM_ST_TEXT);
492         int asc = lyxfont::maxAscent(font);
493         int desc = lyxfont::maxDescent(font);
494       bv->fitLockedInsetCursor(x, y, asc, desc);
495     }
496     ToggleInsetCursor(bv);
497   }
498 }
499
500
501 void InsetFormula::HideInsetCursor(BufferView * bv)
502 {
503   if (cursor_visible)
504     ToggleInsetCursor(bv);
505 }
506
507
508 void InsetFormula::ToggleInsetSelection(BufferView * bv)
509 {
510     if (!mathcursor)
511       return;
512     
513 //    int x, y, w, h;
514     //int n;
515     //XPoint * p = 
516     //mathcursor->SelGetArea(n);
517 //    XFillPolygon(fl_get_display(), pm, LyXGetSelectionGC(), p, n, Nonconvex, CoordModeOrigin);
518 //    x -= par->xo; 
519 //    y -= par->yo;
520
521     bv->updateInset(this, false);
522       
523 }
524
525
526 void InsetFormula::display(bool dspf)
527 {
528    if (dspf != disp_flag) {
529       if (dspf) {
530          par->SetType(LM_OT_PAR);
531          par->SetStyle(LM_ST_DISPLAY);
532       } else {
533          if (is_multiline(par->GetType())) { 
534             MathParInset * p = new MathParInset(par);
535             delete par;
536             par = p;
537             if (mathcursor) 
538                mathcursor->SetPar(par); 
539          }
540          par->SetType(LM_OT_MIN);
541          par->SetStyle(LM_ST_TEXT);
542          if (!label.empty()) {
543                  label.erase();
544          }
545       }
546       disp_flag = dspf;
547    }
548 }
549
550
551 vector<string> const InsetFormula::getLabelList() const
552 {
553 //#warning This is dirty, I know. Ill clean it at 0.11
554 // Correction, the only way to clean this is with a new kernel: 0.13.
555
556         vector<string> label_list;
557
558         if (is_multi_numbered(par->GetType())) {
559                 MathMatrixInset * mt = static_cast<MathMatrixInset*>(par);
560                 MathedRowSt const * crow = mt->getRowSt();
561                 while (crow) {
562                         if (!crow->getLabel().empty())
563                                 label_list.push_back(crow->getLabel());
564                         crow = crow->getNext();
565                 }
566         } else if (!label.empty())
567                 label_list.push_back(label);
568
569         return label_list;
570 }
571
572
573 void InsetFormula::UpdateLocal(BufferView * bv)
574 {
575    par->Metrics();  // To inform lyx kernel the exact size 
576                   // (there were problems with arrays).
577    bv->updateInset(this, true);
578 }
579
580
581 void InsetFormula::InsetButtonRelease(BufferView * bv,
582                                       int x, int y, int /*button*/)
583 {
584     if (mathcursor) {
585         HideInsetCursor(bv);
586         x += par->xo;
587         y += par->yo;
588         mathcursor->SetPos(x, y);
589         ShowInsetCursor(bv);
590         if (sel_flag) {
591             sel_flag = false; 
592             sel_x = sel_y = 0;
593             bv->updateInset(this, false); 
594         }
595     }
596 }
597
598
599 void InsetFormula::InsetButtonPress(BufferView * bv,
600                                     int x, int y, int /*button*/)
601 {
602     sel_flag = false;
603     sel_x = x;  sel_y = y;
604     if (mathcursor && mathcursor->Selection()) {
605         mathcursor->SelClear();
606         bv->updateInset(this, false); 
607     }
608 }
609
610
611 void InsetFormula::InsetMotionNotify(BufferView * bv,
612                                      int x, int y, int /*button*/)
613 {
614     if (sel_x && sel_y && abs(x-sel_x) > 4 && !sel_flag) {
615         sel_flag = true;
616         HideInsetCursor(bv);
617         mathcursor->SetPos(sel_x + par->xo, sel_y + par->yo);
618         mathcursor->SelStart();
619         ShowInsetCursor(bv); 
620         mathcursor->GetPos(sel_x, sel_y);
621     } else if (sel_flag) {
622           HideInsetCursor(bv);
623           x += par->xo;
624           y += par->yo;
625           mathcursor->SetPos(x, y);
626           ShowInsetCursor(bv);
627           mathcursor->GetPos(x, y);
628           if (sel_x!= x || sel_y!= y)
629             bv->updateInset(this, false); 
630           sel_x = x;  sel_y = y;
631       }
632 }
633
634
635 void InsetFormula::InsetKeyPress(XKeyEvent *)
636 {
637         lyxerr[Debug::MATHED] << "Used InsetFormula::InsetKeyPress." << endl;
638 }
639
640
641 // Special Mathed functions
642 bool InsetFormula::SetNumber(bool numbf)
643 {
644    if (disp_flag) {
645       short type = par->GetType();
646       bool oldf = is_numbered(type);
647       if (numbf && !oldf) ++type;
648       if (!numbf && oldf) --type;
649       par->SetType(type);
650       return oldf;
651    } else
652      return false;
653 }
654
655
656 UpdatableInset::RESULT
657 InsetFormula::LocalDispatch(BufferView * bv,
658                             int action, string const & arg)
659 {
660 //   extern char *dispatch_result;
661     MathedTextCodes varcode = LM_TC_MIN;       
662     bool was_macro = mathcursor->InMacroMode();
663     bool sel = false;
664     bool space_on = false;
665     bool was_selection = mathcursor->Selection();
666     RESULT result = DISPATCHED;
667     static MathSpaceInset * sp= 0;
668
669    HideInsetCursor(bv);
670
671     if (mathcursor->getLastCode() == LM_TC_TEX) { 
672         varcode = LM_TC_TEX;
673     }
674    switch (action) {
675        
676     // --- Cursor Movements ---------------------------------------------
677     case LFUN_RIGHTSEL: sel = true;
678     case LFUN_RIGHT:
679       {
680          result = DISPATCH_RESULT(mathcursor->Right(sel));
681          if (!sel && (result == DISPATCHED))
682              result = DISPATCHED_NOUPDATE;
683          break;
684       }
685     case LFUN_LEFTSEL: sel = true;     
686     case LFUN_LEFT:
687       {
688          result = DISPATCH_RESULT(mathcursor->Left(sel));
689          if (!sel && (result == DISPATCHED))
690              result = DISPATCHED_NOUPDATE;
691          break;
692       }
693     case LFUN_UPSEL: sel = true;  
694     case LFUN_UP:
695       result = DISPATCH_RESULT(mathcursor->Up(sel));
696       if (!sel && (result == DISPATCHED))
697           result = DISPATCHED_NOUPDATE;
698       break;
699        
700     case LFUN_DOWNSEL: sel = true;  
701     case LFUN_DOWN:
702       result = DISPATCH_RESULT(mathcursor->Down(sel));
703       if (!sel && (result == DISPATCHED))
704           result = DISPATCHED_NOUPDATE;
705       break;
706     case LFUN_HOME:
707       mathcursor->Home();
708       result = DISPATCHED_NOUPDATE;
709       break;
710     case LFUN_END:
711       mathcursor->End();
712       result = DISPATCHED_NOUPDATE;
713       break;
714     case LFUN_DELETE_LINE_FORWARD:
715       bv->lockedInsetStoreUndo(Undo::DELETE);
716       mathcursor->DelLine();
717       UpdateLocal(bv);
718       break;
719     case LFUN_BREAKLINE:
720     {
721       bv->lockedInsetStoreUndo(Undo::INSERT);
722       byte c = arg.empty() ? '1' : arg[0];
723       mathcursor->Insert(c, LM_TC_CR);
724       if (!label.empty()) {
725          mathcursor->setLabel(label);
726          label.erase();
727       }
728       par = mathcursor->GetPar();
729       UpdateLocal(bv);
730       break;
731     }
732     case LFUN_TAB:
733       bv->lockedInsetStoreUndo(Undo::INSERT);
734       mathcursor->Insert(0, LM_TC_TAB);
735       //UpdateInset(this);
736       break;     
737     case LFUN_TABINSERT:
738       bv->lockedInsetStoreUndo(Undo::INSERT);
739       mathcursor->Insert('T', LM_TC_TAB);
740       UpdateLocal(bv);
741       break;     
742     case LFUN_BACKSPACE:
743        if (!mathcursor->Left()) 
744          break;
745        
746        if (!mathcursor->InMacroMode() && mathcursor->pullArg()) {       
747            bv->updateInset(this, true);
748            break;
749        }
750       
751     case LFUN_DELETE:
752       bv->lockedInsetStoreUndo(Undo::DELETE);
753       mathcursor->Delete();       
754       bv->updateInset(this, true);
755       break;    
756 //    case LFUN_GETXY:
757 //      sprintf(dispatch_buffer, "%d %d",);
758 //      dispatch_result = dispatch_buffer;
759 //      break;
760     case LFUN_SETXY:
761       {
762          int x;
763          int y;
764          int x1;
765          int y1;
766          istringstream ist(arg.c_str());
767          ist >> x >> y;
768          par->GetXY(x1, y1);
769          mathcursor->SetPos(x1 + x, y1 + y);
770       }
771       break;
772
773       /* cursor selection ---------------------------- */
774
775     case LFUN_PASTE:
776             if (was_macro)
777                 mathcursor->MacroModeClose();
778             bv->lockedInsetStoreUndo(Undo::INSERT);
779             mathcursor->SelPaste(); UpdateLocal(bv); break;
780     case LFUN_CUT:
781             bv->lockedInsetStoreUndo(Undo::DELETE);
782             mathcursor->SelCut(); UpdateLocal(bv); break;
783     case LFUN_COPY: mathcursor->SelCopy(); break;      
784     case LFUN_HOMESEL:
785     case LFUN_ENDSEL:
786     case LFUN_WORDRIGHTSEL:
787     case LFUN_WORDLEFTSEL:
788       break;
789       
790     // --- accented characters ------------------------------
791
792     case LFUN_UMLAUT: mathcursor->setAccent(LM_ddot); break;
793     case LFUN_CIRCUMFLEX: mathcursor->setAccent(LM_hat); break;
794     case LFUN_GRAVE: mathcursor->setAccent(LM_grave); break;
795     case LFUN_ACUTE: mathcursor->setAccent(LM_acute); break;
796     case LFUN_TILDE: mathcursor->setAccent(LM_tilde); break;
797     case LFUN_MACRON: mathcursor->setAccent(LM_bar); break;
798     case LFUN_DOT: mathcursor->setAccent(LM_dot); break;
799     case LFUN_CARON: mathcursor->setAccent(LM_check); break;
800     case LFUN_BREVE: mathcursor->setAccent(LM_breve); break;
801     case LFUN_VECTOR: mathcursor->setAccent(LM_vec); break; 
802       
803     // Greek mode     
804     case LFUN_GREEK:
805     {
806        if (!greek_kb_flag) {
807           greek_kb_flag = 1;
808           bv->owner()->getMiniBuffer()->Set(_("Math greek mode on"));
809        } else
810          greek_kb_flag = 0;
811        break;
812     }  
813       
814     // Greek keyboard      
815     case LFUN_GREEK_TOGGLE:
816     {
817        greek_kb_flag = (greek_kb_flag) ? 0 : 2;
818        if (greek_kb_flag)
819          bv->owner()->getMiniBuffer()->Set(_("Math greek keyboard on"));
820        else
821          bv->owner()->getMiniBuffer()->Set(_("Math greek keyboard off"));
822        break;
823     }  
824    
825       //  Math fonts 
826     case LFUN_BOLD:  mathcursor->toggleLastCode(LM_TC_BF); break;
827     case LFUN_SANS:  mathcursor->toggleLastCode(LM_TC_SF); break;
828     case LFUN_EMPH:  mathcursor->toggleLastCode(LM_TC_CAL); break;
829     case LFUN_ROMAN: mathcursor->toggleLastCode(LM_TC_RM); break;
830     case LFUN_CODE:  mathcursor->toggleLastCode(LM_TC_TT); break;   
831     case LFUN_DEFAULT:  mathcursor->setLastCode(LM_TC_VAR); break;
832     case LFUN_TEX: 
833     {
834 //       varcode = LM_TC_TEX;
835         mathcursor->setLastCode(LM_TC_TEX);
836         bv->owner()->getMiniBuffer()->Set(_("TeX mode")); 
837        break;
838     }
839
840     case LFUN_MATH_NUMBER:
841     {
842       bv->lockedInsetStoreUndo(Undo::INSERT);
843        if (disp_flag) {
844           short type = par->GetType();
845           if (is_numbered(type)) {
846              --type;
847              if (!label.empty()) {
848                      label.erase();
849              }
850              bv->owner()->getMiniBuffer()->Set(_("No number"));  
851           } else {
852              ++type;
853              bv->owner()->getMiniBuffer()->Set(_("Number"));
854           }
855           par->SetType(type);
856           UpdateLocal(bv);
857        }
858        break;
859     }
860     
861     case LFUN_MATH_NONUMBER:
862     { 
863         if (is_multi_numbered(par->GetType())) {
864 //         MathMatrixInset *mt = (MathMatrixInset*)par;
865            //BUG 
866 //         mt->SetNumbered(!mt->IsNumbered());
867
868 #warning This is a terrible hack! We should find a better solution.
869        while (mathcursor->getLabel() == MathedXIter::error_label) {
870            if (LocalDispatch(bv, LFUN_LEFT, string()) == FINISHED)
871                return DISPATCHED;
872        }
873             mathcursor->setNumbered();
874             UpdateLocal(bv);
875         }
876         break;
877     }
878        
879     case LFUN_MATH_LIMITS:
880     {
881       bv->lockedInsetStoreUndo(Undo::INSERT);
882        if (mathcursor->Limits())
883          UpdateLocal(bv);
884     }
885  
886     case LFUN_MATH_SIZE:
887        if (!arg.empty()) {
888            latexkeys * l = in_word_set (arg);
889            int sz = (l) ? l->id: -1;
890            mathcursor->SetSize(sz);
891            UpdateLocal(bv);
892            break;
893        }
894        
895     case LFUN_INSERT_MATH:
896     {
897         bv->lockedInsetStoreUndo(Undo::INSERT);
898         InsertSymbol(bv, arg);
899         break;
900     }
901     
902     case LFUN_INSERT_MATRIX:
903     { 
904       bv->lockedInsetStoreUndo(Undo::INSERT);
905        int k, m, n;
906        char s[80], arg2[80];
907        // This is just so that too long args won't ooze out of s.
908        strncpy(arg2, arg.c_str(), 80); arg2[79]= '\0';
909        k = sscanf(arg2, "%d %d %s", &m, &n, s);
910        s[79] = '\0';
911         
912        if (k < 1) {
913            m = n = 1;
914        } else if (k == 1) {
915            n = 1;
916        }
917         
918        MathMatrixInset * p = new MathMatrixInset(m, n);      
919        if (mathcursor && p) {
920           if (k > 2 && int(strlen(s)) > m)
921             p->SetAlign(s[0], &s[1]);
922           mathcursor->Insert(p, LM_TC_ACTIVE_INSET);
923           UpdateLocal(bv);
924        }
925        break;
926     }
927       
928     case LFUN_MATH_DELIM:
929     {  
930       bv->lockedInsetStoreUndo(Undo::INSERT);
931        char lf[40], rg[40], arg2[40];
932        int ilf = '(', irg = '.';
933        latexkeys * l;
934        string vdelim("(){}[]./|");
935         
936        if (arg.empty())
937                break;
938        ::strncpy(arg2, arg.c_str(), 40); arg2[39]= '\0';
939        int n = sscanf(arg2, "%s %s", lf, rg);
940        lf[39] = '\0'; rg[39] = '\0';
941
942        if (n > 0) {
943            if (isdigit(lf[0])) 
944              ilf = lyx::atoi(lf);
945            else 
946              if (lf[1]) {
947                  l = in_word_set(lf, strlen(lf));
948                  // Long words will cause l == 0; so check.
949                  if (l) ilf = l->id;
950              } else
951              if (vdelim.find(lf[0]) != string::npos)
952                ilf = lf[0];
953            
954            if (n > 1) {
955                if (isdigit(rg[0]))
956                  irg = lyx::atoi(rg);
957                else 
958                  if (rg[1]) {
959                      l = in_word_set(rg, strlen(rg));
960                      if (l) irg = l->id;
961                  } else
962                  if (vdelim.find(rg[0]) != string::npos)
963                    irg = rg[0];
964            }
965        }
966        
967        MathDelimInset * p = new MathDelimInset(ilf, irg);
968        mathcursor->Insert(p, LM_TC_ACTIVE_INSET);
969        UpdateLocal(bv);
970        break;
971     }
972
973     case LFUN_PROTECTEDSPACE:
974     {
975       bv->lockedInsetStoreUndo(Undo::INSERT);
976        sp = new MathSpaceInset(1); 
977        mathcursor->Insert(sp);
978        space_on = true;
979        UpdateLocal(bv);
980        break;
981     }
982       
983     case LFUN_INSERT_LABEL:
984     {
985        bv->lockedInsetStoreUndo(Undo::INSERT);
986        if (par->GetType() < LM_OT_PAR)
987               break;
988
989        string old_label = is_multiline(par->GetType())
990                ?  mathcursor->getLabel() : label;
991
992 #warning This is a terrible hack! We should find a better solution.
993        /// This is needed becuase in some positions mathcursor->cursor->crow
994        /// is equal to 0, and therefore the label cannot be inserted.
995        /// So we move the cursor left until mathcursor->cursor->crow != 0.
996        while (old_label == MathedXIter::error_label) {
997            if (LocalDispatch(bv, LFUN_LEFT, string()) == FINISHED)
998                return DISPATCHED;
999            old_label = mathcursor->getLabel();
1000        }
1001
1002        string new_label = arg;
1003        if (new_label.empty()) {
1004           string default_label = (lyxrc.label_init_length >= 0) ? "eq:" : "";
1005           pair<bool, string> res = old_label.empty()
1006                   ? askForText(_("Enter new label to insert:"), default_label)
1007                   : askForText(_("Enter label:"), old_label);
1008           if (!res.first)
1009              break;
1010           new_label = frontStrip(strip(res.second));
1011        }
1012
1013        if (new_label == old_label)
1014                break;  // Nothing to do
1015
1016        if (!new_label.empty())
1017           SetNumber(true);
1018
1019        if (!new_label.empty() && bv->ChangeRefsIfUnique(old_label, new_label))
1020               bv->redraw();
1021
1022        if (is_multi_numbered(par->GetType()))
1023           mathcursor->setLabel(new_label);
1024 //        MathMatrixInset *mt = (MathMatrixInset*)par;
1025 //        mt->SetLabel(new_label);
1026        else
1027           label = new_label;
1028        UpdateLocal(bv);
1029        break;
1030     }
1031     
1032     case LFUN_MATH_DISPLAY:
1033       bv->lockedInsetStoreUndo(Undo::EDIT);
1034       display(!disp_flag);
1035       UpdateLocal(bv);
1036       break;
1037       
1038     // Invalid actions under math mode
1039     case LFUN_MATH_MODE:  
1040     {
1041         if (mathcursor->getLastCode()!= LM_TC_TEXTRM) {
1042             bv->owner()->getMiniBuffer()->Set(_("math text mode"));
1043             varcode = LM_TC_TEXTRM;
1044         } else {
1045             varcode = LM_TC_VAR;
1046         }
1047         mathcursor->setLastCode(varcode);
1048         break; 
1049     }
1050     case LFUN_UNDO:
1051       bv->owner()->getMiniBuffer()->Set(_("Invalid action in math mode!"));
1052       break;
1053
1054     //------- dummy actions
1055     case LFUN_EXEC_COMMAND:
1056        bv->owner()->getMiniBuffer()->PrepareForCommand(); 
1057        break;
1058        
1059     default:
1060       if ((action == -1  || action == LFUN_SELFINSERT) && !arg.empty())  {
1061          unsigned char c = arg[0];
1062          bv->lockedInsetStoreUndo(Undo::INSERT);
1063          
1064          if (c == ' ' && mathcursor->getAccent() == LM_hat) {
1065              c = '^';
1066              mathcursor->setAccent(0);
1067          }
1068          if (c == 0) {      // Dead key, do nothing 
1069              //lyxerr << "deadkey" << endl;
1070              break;
1071          } 
1072          if (isalpha(c)) {
1073              if (mathcursor->getLastCode() == LM_TC_TEX) { 
1074                mathcursor->MacroModeOpen();
1075                mathcursor->clearLastCode();
1076                varcode = LM_TC_MIN;
1077             } else          
1078             if (!varcode) {             
1079                 short f = (mathcursor->getLastCode()) ? 
1080                           mathcursor->getLastCode() :
1081                           static_cast<MathedTextCodes>(mathcursor->GetFCode());
1082                 varcode = MathIsAlphaFont(f) ?
1083                         static_cast<MathedTextCodes>(f) :
1084                         LM_TC_VAR;
1085             }
1086
1087 //           lyxerr << "Varcode << vardoce;
1088             MathedTextCodes char_code = varcode;
1089             if (greek_kb_flag) {
1090                     char greek[26] = 
1091                     {'A', 'B', 'X',  0 , 'E',  0 ,  0 , 'H', 'I',  0 ,
1092                      'K',  0 , 'M', 'N', 'O',  0 ,  0 , 'P',  0 , 'T',
1093                      'Y',  0,   0,   0,   0 , 'Z' };
1094                     if ('A' <= c && c <= 'Z' && greek[c - 'A']) {
1095                             char_code = LM_TC_RM;
1096                             c = greek[c - 'A'];
1097                     } else
1098                             char_code = LM_TC_SYMB;
1099             }
1100             mathcursor->Insert(c, char_code);
1101             if (greek_kb_flag && char_code == LM_TC_RM )
1102                     mathcursor->setLastCode(LM_TC_VAR);
1103             varcode = LM_TC_MIN;
1104             if (greek_kb_flag<2) greek_kb_flag = 0;
1105          } else 
1106            if (strchr("!,:;{}", c) && (varcode == LM_TC_TEX||was_macro)) {
1107                mathcursor->Insert(c, LM_TC_TEX);
1108                if (c == '{') {
1109                    mathcursor->Insert('}', LM_TC_TEX);
1110                    mathcursor->Left();
1111                }
1112                mathcursor->clearLastCode();
1113 //             varcode = LM_TC_MIN;
1114            } else
1115            if (c == '_' && varcode == LM_TC_TEX) {
1116                mathcursor->Insert(c, LM_TC_SPECIAL);
1117                mathcursor->clearLastCode();
1118 //             varcode = LM_TC_MIN;
1119            } else
1120             if (('0'<= c && c<= '9') && (varcode == LM_TC_TEX||was_macro)) {
1121                 mathcursor->MacroModeOpen();
1122                 mathcursor->clearLastCode();
1123                 mathcursor->Insert(c, LM_TC_MIN);
1124             }
1125          else
1126            if (('0'<= c && c<= '9') || strchr(";:!|[]().,?", c)) 
1127               mathcursor->Insert(c, LM_TC_CONST);
1128          else
1129            if (strchr("+/-*<>=", c))
1130               mathcursor->Insert(c, LM_TC_BOP);
1131          else
1132            if (strchr(latex_special_chars, c) && c!= '_')
1133               mathcursor->Insert(c, LM_TC_SPECIAL);
1134          else
1135            if (c == '_' || c == '^') {
1136                char s[2];
1137                s[0] = c;
1138                s[1] = 0;
1139               mathcursor->Interpret (s);
1140            } else
1141            if (c == ' ') {          
1142                if (!varcode) {  
1143                    short f = (mathcursor->getLastCode()) ? 
1144                               mathcursor->getLastCode() :
1145                               static_cast<MathedTextCodes>(mathcursor->GetFCode());
1146                    varcode = MathIsAlphaFont(f) ?
1147                            static_cast<MathedTextCodes>(f) :
1148                            LM_TC_VAR;
1149                }
1150               if (varcode == LM_TC_TEXTRM) {
1151                   mathcursor->Insert(c, LM_TC_TEXTRM);
1152               } else
1153               if (was_macro)
1154                 mathcursor->MacroModeClose();
1155               else 
1156               if (sp) {
1157                  int isp = (sp->GetSpace()<5) ? sp->GetSpace()+1: 0;
1158                  sp->SetSpace(isp);
1159                  space_on = true;
1160               } else {
1161                   if (!mathcursor->Pop() && mathcursor->IsEnd()) 
1162                     result = FINISHED;
1163               }
1164            } else
1165            if (c == '\'' || c == '@') {
1166               mathcursor->Insert (c, LM_TC_VAR);
1167            } else
1168            if (c == '\\') {
1169               if (was_macro)
1170                 mathcursor->MacroModeClose();
1171               bv->owner()->getMiniBuffer()->Set(_("TeX mode")); 
1172                mathcursor->setLastCode(LM_TC_TEX);
1173            } 
1174          UpdateLocal(bv);
1175       } else if (action == LFUN_MATH_PANEL) {
1176         result = UNDISPATCHED;
1177       } else {
1178         // lyxerr << "Closed by action " << action << endl;
1179         result =  FINISHED;
1180       }
1181    }
1182    if (was_macro != mathcursor->InMacroMode()
1183        && action >= 0
1184        && action != LFUN_BACKSPACE)
1185            UpdateLocal(bv);
1186    if (sp && !space_on) sp = 0;
1187    if (mathcursor->Selection() || was_selection)
1188        ToggleInsetSelection(bv);
1189     
1190    if ((result == DISPATCHED) || (result == DISPATCHED_NOUPDATE) ||
1191        (result == UNDISPATCHED))
1192       ShowInsetCursor(bv);
1193    else
1194       bv->unlockInset(this);
1195     
1196    return result;
1197 }
1198
1199
1200
1201 static
1202 void mathedValidate(LaTeXFeatures & features, MathParInset * par)
1203 {
1204     MathedIter it(par->GetData());
1205     
1206     while (it.OK() && !(features.binom && features.boldsymbol)) {
1207         if (it.IsInset()) {
1208             if (it.IsActive()) {
1209                 MathParInset * p = it.GetActiveInset();
1210                 if (!features.binom && p->GetType() == LM_OT_MACRO && 
1211                     p->GetName() == "binom") {
1212                     features.binom = true;
1213                 } else {
1214                     for (int i = 0; i <= p->getMaxArgumentIdx(); ++i) {
1215                         p->setArgumentIdx(i);
1216                         mathedValidate(features, p);
1217                     }
1218                 }
1219             } else {
1220                 MathedInset* p = it.GetInset();
1221                 if (!features.boldsymbol &&
1222                     p->GetName() == "boldsymbol") {
1223                     features.boldsymbol = true;
1224                 }
1225             }       
1226         }
1227         it.Next();
1228     }
1229 }