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