home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / lyx-0.13.2.tar.gz / lyx-0.13.2.tar / lyx-0.13.2 / src / formula.C < prev    next >
C/C++ Source or Header  |  1998-04-23  |  29KB  |  1,205 lines

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