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