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