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