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 / math_cursor.C < prev    next >
C/C++ Source or Header  |  1998-04-23  |  21KB  |  942 lines

  1. /*
  2.  *  File:        math_cursor.C
  3.  *  Purpose:     Interaction for mathed
  4.  *  Author:      Alejandro Aguilar Sierra <asierra@servidor.unam.mx> 
  5.  *  Created:     January 1996
  6.  *  Description: Math interaction for a WYSIWYG math editor.
  7.  *
  8.  *  Dependencies: Xlib, XForms
  9.  *
  10.  *  Copyright: (c) 1996, Alejandro Aguilar Sierra
  11.  *
  12.  *   Version: 0.8beta, Mathed & Lyx project.
  13.  *
  14.  *   You are free to use and modify this code under the terms of
  15.  *   the GNU General Public Licence version 2 or later.
  16.  */
  17.  
  18. #ifdef __GNUG__
  19. #pragma implementation
  20. #endif
  21.  
  22. #include <config.h>
  23. #include FORMS_H_LOCATION
  24. #include "math_inset.h"
  25. #include "math_parser.h"
  26. #include "math_cursor.h"
  27. #include "math_macro.h"
  28. #include "error.h"
  29.  
  30. extern void mathed_set_font(short type, int style);
  31.  
  32. extern GC canvasGC, mathGC, latexGC, cursorGC, mathFrameGC;
  33.  
  34. static LyxArrayBase *selarray=0;
  35.  
  36. inline bool IsAlpha(char c)
  37. {
  38.    return ('A' <= c  && c<='Z' || 'a' <= c  && c<='z');
  39. }
  40.  
  41. // This was very smaller, I'll change it later 
  42. inline bool IsMacro(short token, int id)
  43. {
  44.    return (token!=LM_TK_STACK && token!=LM_TK_FRAC && token!=LM_TK_SQRT && token!=LM_TK_WIDE &&
  45.        token!=LM_TK_SPACE && token!=LM_TK_DOTS &&  token!=LM_TK_FUNCLIM &&
  46.        token!=LM_TK_BIGSYM && token!=LM_TK_ACCENT && 
  47.        !(token==LM_TK_SYM && id<255));
  48. }
  49.  
  50. // Yes, mathed isn't using LString yet.
  51. inline char *strnew(char const* s)
  52. {
  53.     char *s1 = new char[strlen(s)+1];
  54.     strcpy(s1, s);
  55.     return s1;
  56. }
  57.  
  58.  
  59.  
  60. #define MAX_STACK_ITEMS 32
  61.  
  62. struct MathStackXIter {
  63.     
  64.     int i, imax;
  65.     MathedXIter *item;
  66.     
  67.     MathStackXIter(int n=MAX_STACK_ITEMS): imax(n) {
  68.     item = new MathedXIter[imax];
  69.     i = 0;
  70.     }
  71.     
  72.     MathStackXIter(MathStackXIter &stk);
  73.     
  74.     ~MathStackXIter() {
  75.     delete[] item;
  76.     }
  77.    
  78.     void push(MathedXIter** a) {
  79.     *a = &item[i++];
  80.     }
  81.       
  82.     MathedXIter* pop() {
  83.     i--;
  84.     return &item[i-1];
  85.     }
  86.       
  87.     MathedXIter* Item(int idx) {
  88.        return (idx+1 <= i) ? &item[i-idx-1]: (MathedXIter*)NULL;
  89.     }
  90.  
  91.     void Reset() {
  92.     i = 0;
  93.     }
  94.    
  95.     int Full() {
  96.     return (i>=MAX_STACK_ITEMS);
  97.     }
  98.    
  99.     int Empty() {
  100.     return (i<=1);
  101.     }
  102.  
  103.     int Level() { return i; } 
  104.     
  105. } mathstk, *selstk=0;
  106.  
  107.  
  108. MathStackXIter::MathStackXIter(MathStackXIter &stk) {
  109.     imax = stk.imax;
  110.     item = new MathedXIter[imax];
  111.     i = stk.i;
  112.     for (int k=0; k<i; k++) {
  113.         item[k].SetData(stk.item[k].getPar());
  114.         item[k].GoBegin();
  115.         item[k].goPosAbs(stk.item[k].getPos());
  116.     }
  117. }
  118.  
  119.  
  120. /***----------------  Mathed Cursor  ---------------------------***/
  121.   
  122. MathedCursor::MathedCursor(MathParInset *p) // : par(p)
  123. {
  124.     accent = 0;
  125.     anchor = 0;
  126.     lastcode = LM_TC_MIN;
  127.     SetPar(p);
  128. //    selarray = NULL;     
  129.     if (!MathMacroTable::built)
  130.     MathMacroTable::mathMTable.builtinMacros();
  131. }
  132.  
  133.  
  134. void MathedCursor::SetPar(MathParInset *p)
  135. {
  136.    win = 0;
  137.    is_visible = False;
  138.    macro_mode = false;
  139.    selection = false; // not SelClear() ?
  140.    mathstk.Reset();
  141.    mathstk.push(&cursor);
  142.    par = p;
  143.    cursor->SetData(par);
  144. }
  145.  
  146. void MathedCursor::Draw(long unsigned pm, int x, int y)
  147. {
  148. //    fprintf(stderr, "Cursor[%d %d] ", x, y);
  149.     win = pm;    // win = (mathedCanvas) ? mathedCanvas: pm;
  150.     par->Metrics();
  151.     int w = par->Width()+2, a = par->Ascent()+1, h = par->Height()+1;
  152.     if (par->GetType()>LM_OT_PAR) { a += 4;  h += 8; }
  153.     
  154.    if (!canvasGC) mathed_set_font(LM_TC_VAR, 1);
  155.     //   XFillRectangle(fl_display,pm, canvasGC, x, y-a, w, h);
  156.     XDrawRectangle(fl_display,pm, mathFrameGC, x-1, y-a, w, h);
  157.     XFlush(fl_display);
  158.     MathParInset::pm = pm;
  159.     par->Draw(x, y);
  160.     cursor->Adjust();
  161. }
  162.  
  163.  
  164. void MathedCursor::Redraw()
  165. {  
  166.    lyxerr.debug("Mathed: Redrawing!", Error::MATHED);
  167.    par->Metrics();
  168.    int w = par->Width(), h = par->Height();
  169.    int x, y;
  170.    par->GetXY(x, y);
  171.    mathed_set_font(LM_TC_VAR, 1);
  172.    XFillRectangle(fl_display, win,canvasGC,x, y-par->Ascent(), w, h);
  173.    XFlush(fl_display);
  174.     MathParInset::pm = win;
  175.    par->Draw(x, y);
  176. }
  177.  
  178. bool MathedCursor::Left(bool sel)
  179. {
  180.    if (macro_mode) {
  181.       MacroModeBack();
  182.       return true;
  183.    }
  184.     clearLastCode();
  185.    if (sel && !selection) SelStart();
  186.    if (!sel && selection) SelClear();
  187.    bool result = cursor->Prev();
  188.    if (!result && !mathstk.Empty()) {
  189.       cursor = mathstk.pop();
  190.       cursor->Adjust();
  191.       result = true;
  192.       if (selection) SelClear();
  193.    } else  
  194.      if (result && cursor->IsActive()) {
  195.     if (cursor->IsScript()) {
  196.        cursor->Prev();
  197.        if (!cursor->IsScript())
  198.          cursor->Next();
  199.        cursor->Adjust(); 
  200.        return true;
  201.     }
  202.     if (!selection) {
  203.         MathParInset *p = cursor->GetActiveInset();
  204.         if (!p)
  205.           return result;
  206.         
  207.         p->setArgumentIdx(p->getMaxArgumentIdx());
  208.         mathstk.push(&cursor);
  209.         cursor->SetData(p);
  210.         cursor->GoLast();
  211.     }
  212.      } 
  213.    return result;  
  214. }
  215.  
  216. // Leave the inset
  217. bool MathedCursor::Pop()
  218. {
  219.    if (!mathstk.Empty()) {
  220.       cursor = mathstk.pop();
  221.       cursor->Next(); 
  222.       return true;
  223.    }
  224.    return false;
  225. }
  226.  
  227. // Go to the inset 
  228. bool MathedCursor::Push()
  229.    if (cursor->IsActive()) {
  230.       MathParInset *p = cursor->GetActiveInset();
  231.        if (!p) return false;
  232.       mathstk.push(&cursor);
  233.       cursor->SetData(p);
  234.       return true;
  235.    }
  236.    return false;
  237. }  
  238.  
  239. bool MathedCursor::Right(bool sel)
  240. {  
  241.    if (macro_mode) {
  242.       MacroModeClose();
  243.       return true;
  244.    } 
  245.     clearLastCode();
  246.    if (sel && !selection) SelStart();
  247.    if (!sel && selection) SelClear();
  248.    bool result = false;
  249.  
  250.    if (cursor->IsActive()) {
  251.       if (cursor->IsScript()) {
  252.      cursor->Next();
  253.      // A script may be followed by another script
  254.      if (cursor->IsScript()) 
  255.        cursor->Next();
  256.      return true;
  257.       }
  258.       if (!selection) { 
  259.       MathParInset *p = cursor->GetActiveInset();
  260.       if (!p) {
  261.           fprintf(stderr, "Math error: Inset expected.\n");
  262.           return cursor->Next();
  263.       }
  264.       p->setArgumentIdx(0);
  265.       mathstk.push(&cursor);
  266.       cursor->SetData(p);
  267.       result = true;
  268.       } else
  269.      result = cursor->Next();
  270.    } else {
  271.        if (cursor->GetChar()!=LM_TC_CR)
  272.      result = cursor->Next();
  273.      if (!result && !mathstk.Empty()) {
  274.     cursor = mathstk.pop();
  275.     cursor->Next();
  276.      cursor->Adjust();
  277.     result = true;
  278.     if (selection) SelClear();
  279.      }
  280.    }
  281.    return result;
  282. }
  283.  
  284.  
  285. void MathedCursor::SetPos(int x, int y)
  286. {
  287.     int xp = 0;
  288.     
  289.     if (macro_mode) MacroModeClose();
  290.     lastcode = LM_TC_MIN;
  291.     mathstk.Reset();
  292.     mathstk.push(&cursor);
  293.     cursor->SetData(par);
  294.     cursor->fitCoord(x, y);
  295.     while (cursor->GetX()<x && cursor->OK()) {
  296.     if (cursor->IsActive()) {
  297.         MathParInset *p = cursor->GetActiveInset();
  298.         if (p->Inside(x, y)) {
  299.         p->SetFocus(x, y);
  300.         mathstk.push(&cursor);
  301.         cursor->SetData(p);
  302.         cursor->fitCoord(x, y);
  303.         continue;
  304.         }
  305.     }
  306.     xp = cursor->GetX();
  307.     cursor->ipush();
  308.     if (!cursor->Next() && !Pop()) 
  309.       break;
  310.     }
  311.     if (x-xp < cursor->GetX()-x) cursor->ipop();
  312.     cursor->Adjust();
  313. }
  314.    
  315.  
  316. void MathedCursor::Home()
  317. {
  318.    if (macro_mode) MacroModeClose();
  319.     clearLastCode();
  320.    mathstk.Reset();
  321.    mathstk.push(&cursor);
  322.    cursor->GoBegin();
  323. }
  324.  
  325. void MathedCursor::End()
  326. {
  327.    if (macro_mode) MacroModeClose();
  328.     clearLastCode();
  329.    mathstk.Reset();
  330.    mathstk.push(&cursor);
  331.    cursor->GoLast();
  332. }
  333.  
  334. void MathedCursor::Insert(byte c, MathedTextCodes t)
  335. {  
  336.    if (selection) SelDel();
  337.    
  338.    if (t==LM_TC_MIN)
  339.       t = lastcode;
  340.     
  341.    if (t==LM_TC_CR) {
  342.       MathParInset *p= cursor->p;
  343.       if (p==par && p->GetType()<LM_OT_MPAR && p->GetType()>LM_OT_MIN) {
  344.      MathMatrixInset* mt = new MathMatrixInset(3, 0);
  345.      mt->SetAlign(' ', "rcl");
  346.      mt->SetStyle(LM_ST_DISPLAY);
  347.      mt->SetType((p->GetType()==LM_OT_PARN) ? LM_OT_MPARN: LM_OT_MPAR);
  348.      mt->SetData(p->GetData());
  349.      p->SetData(0);//BUG duda
  350.      delete p;
  351.      par = mt;
  352.      p = mt;
  353.      p->Metrics();
  354.      int pos = cursor->getPos();
  355.      cursor->SetData(par);
  356.      cursor->goPosAbs(pos);
  357.       }      
  358.       if (p &&  p->Permit(LMPF_ALLOW_CR)) {
  359.       cursor->addRow();
  360.       }
  361.    } else
  362.    if (t==LM_TC_TAB) {
  363.       MathParInset *p = cursor->p;
  364.       if (p &&  p->Permit(LMPF_ALLOW_TAB)) {
  365.       if (c) {
  366.           cursor->Insert(c, t);
  367.           cursor->checkTabs();
  368.       } else
  369.         cursor->goNextColumn();
  370.       } else // Navigate between arguments
  371.      if (p && p->GetType()==LM_OT_MACRO) {
  372.          if (p->getArgumentIdx() < p->getMaxArgumentIdx()) {
  373.          p->setArgumentIdx(p->getArgumentIdx()+1);
  374.          cursor->SetData(p);
  375.          return;
  376.          }
  377.  
  378.      }
  379.        
  380.    } else {
  381.        if (macro_mode) {
  382.        if (MathIsAlphaFont(t) || t==LM_TC_MIN) {
  383.            MacroModeInsert(c);
  384.            return;
  385.        } else {
  386.            MacroModeClose();
  387.        }
  388.        } 
  389.        if (accent) {
  390.        cursor->Insert(new MathAccentInset(c, t, accent));
  391.        accent = 0;  // accent consumed
  392.        } else 
  393.      cursor->Insert(c, t);
  394.        lastcode = t;
  395.        
  396.        return;
  397.    }
  398.     clearLastCode();
  399. }
  400.  
  401. void MathedCursor::Insert(MathedInset* p, int t)
  402. {
  403.    if (macro_mode) MacroModeClose();
  404.    if (selection) {
  405.       if (MathIsActive(t)) {
  406.      SelCut();
  407.      ((MathParInset*)p)->SetData(selarray);
  408.       } else
  409.     SelDel();
  410.    }
  411.          
  412.    if (mathstk.i<MAX_STACK_ITEMS-1) {
  413.        
  414.        if (accent && !MathIsActive(t)) {
  415.        cursor->Insert(new MathAccentInset(p, accent));
  416.        accent = 0;  // accent consumed
  417.        } else {
  418.        cursor->Insert(p, t);
  419.        
  420.        if (MathIsActive(t)) {
  421.            cursor->Prev();
  422.            Push();
  423.        }
  424.        }
  425.      
  426.    } else
  427.      fprintf(stderr, "Math error: Full stack.\n");
  428. }
  429.  
  430. void MathedCursor::Delete() 
  431. {   
  432.    if (macro_mode) return;
  433.    if (selection) {
  434.       SelDel();
  435.       return;
  436.    }
  437.    if (cursor->Empty() && !mathstk.Empty()) {
  438.       cursor = mathstk.pop();
  439.    } 
  440. //   if (cursor->GetChar()!=LM_TC_TAB)
  441.     cursor->Delete();
  442.     cursor->checkTabs();
  443. }
  444.  
  445. void MathedCursor::DelLine()
  446. {  
  447.     if (macro_mode) MacroModeClose();
  448.     if (selection) {
  449.     SelDel();
  450.     return;
  451.     }
  452.     MathParInset *p= cursor->p;
  453.     if (p &&  (p->GetType()<=LM_OT_MATRIX && p->GetType()>=LM_OT_MPAR)) {
  454.     cursor->delRow();
  455.     }
  456. }
  457.  
  458.  
  459. bool MathedCursor::Up(bool sel)
  460. {
  461.     bool result = false;
  462.    
  463.     if (macro_mode) MacroModeClose();
  464.     
  465.     if (sel && !selection) SelStart();
  466.     if (!sel && selection) SelClear();
  467.     
  468.     MathParInset *p;
  469.  
  470.     if (cursor->IsScript()) {
  471.     char cd = cursor->GetChar();
  472.     if (MathIsUp(cd)) {
  473.         Push();
  474.         return true;
  475.     } else {
  476.         // A subscript may be followed by a superscript
  477.         cursor->ipush();
  478.         cursor->Next();
  479.         if (MathIsUp(cursor->GetChar())) {
  480.         Push();
  481.         return true;
  482.         } else  // return to the previous state
  483.           cursor->ipop();
  484.       }
  485.    }    
  486.      
  487.     result = cursor->Up();
  488.     if (!result && cursor->p) {
  489.     p = cursor->p;   
  490.    
  491.     if (p->GetType()==LM_OT_SCRIPT) {
  492.         MathedXIter *cx = mathstk.Item(1);
  493.         bool is_down = (cx->GetChar()==LM_TC_DOWN);
  494.         cursor = mathstk.pop();
  495.         cursor->Next();
  496.         result =  (is_down) ? true: Up();
  497.     } else {
  498.         result = (p->getArgumentIdx() > 0);
  499.         if (result) {
  500.         p->setArgumentIdx(p->getArgumentIdx()-1);
  501.         cursor->SetData(p);
  502.         }
  503.     }
  504.     if (!result && !mathstk.Empty()) {
  505.         cursor = mathstk.pop();
  506.         return Up();
  507.     }     
  508.     }
  509.     return result;
  510. }
  511.  
  512.  
  513. bool MathedCursor::Down(bool sel)
  514. {
  515.     bool result = false;
  516.    
  517.     if (macro_mode) MacroModeClose();
  518.     
  519.     if (sel && !selection) SelStart();
  520.     if (!sel && selection) SelClear();
  521. //    if (selection) SelClear();
  522.  
  523.     MathParInset *p;
  524.  
  525.     if (cursor->IsScript()) {
  526.     char cd = cursor->GetChar(); 
  527.     if (MathIsDown(cd)) {
  528.         Push();
  529.         return true;
  530.     } else {
  531.         // A superscript may be followed by a subscript
  532.         cursor->ipush();
  533.         cursor->Next();
  534.         if (MathIsDown(cursor->GetChar())) {
  535.         Push();
  536.         return true;
  537.         } else
  538.           cursor->ipop();
  539.       }
  540.    }
  541.      
  542.     result = cursor->Down();
  543.     if (!result && cursor->p) {
  544.        p= cursor->p;   
  545.     if (p->GetType()==LM_OT_SCRIPT) {
  546.         MathedXIter *cx = mathstk.Item(1);
  547.         bool is_up = (cx->GetChar()==LM_TC_UP);
  548.         cursor = mathstk.pop();
  549.         cursor->Next();
  550.         result = (is_up) ? true: Down();
  551.     } else {
  552.         result = (p->getArgumentIdx() < p->getMaxArgumentIdx());
  553.         if (result) {
  554.         p->setArgumentIdx(p->getArgumentIdx()+1);
  555.         cursor->SetData(p);
  556.         }
  557.     }
  558.     if (!result && !mathstk.Empty()) {
  559.         cursor = mathstk.pop();
  560.         return Down(sel);
  561.     }    
  562.     }
  563.     return result;
  564. }
  565.  
  566. bool MathedCursor::Limits()
  567. {
  568.    if (cursor->IsInset()) {
  569.       MathedInset *p = cursor->GetInset();
  570.       bool ol = p->GetLimits();
  571.       p->SetLimits(!ol);
  572.       return (ol!=p->GetLimits());
  573.    }
  574.    return false;
  575. }
  576.  
  577. void MathedCursor::SetSize(short size)
  578. {
  579.     MathParInset *p = cursor->p;
  580.     p->UserSetSize(size);
  581.     cursor->SetData(p);
  582. }
  583.  
  584.  
  585. void MathedCursor::setLabel(char const* label)
  586. {  // ugly hack and possible bug
  587.     if (!cursor->setLabel(strnew(label)))
  588.       fprintf(stderr, "MathErr: Bad place to set labels.");
  589. }
  590.  
  591.  
  592. void MathedCursor::setNumbered()
  593. {  // another ugly hack
  594.     MathedRowSt *crow = cursor->crow;
  595.     if (!crow) return;    
  596.     crow->setNumbered(!crow->isNumbered());
  597. }
  598.  
  599.  
  600. void MathedCursor::Interpret(char const *s)
  601. {
  602.     MathedInset *p = 0;
  603.     latexkeys *l = 0;   
  604.     MathedTextCodes tcode = LM_TC_INSET;
  605.     
  606.     if (s[0]=='^' || s[0]=='_') {
  607.     char c = cursor->GetChar();
  608.     if (MathIsUp(c) && s[0]=='^' || MathIsDown(c) && s[0]=='_') {
  609.         Push();
  610.         return;
  611.     } else // A script may be followed by a script
  612.       if (MathIsUp(c)  || MathIsDown(c)) { 
  613.         cursor->ipush();
  614.         cursor->Next();
  615.         c = cursor->GetChar();
  616.         if (MathIsUp(c) && s[0]=='^' || MathIsDown(c) && s[0]=='_') {
  617.         Push();
  618.         return;
  619.         } else
  620.           cursor->ipop();
  621.     }
  622.     p = new MathParInset(LM_ST_SCRIPT, "", LM_OT_SCRIPT);
  623.     Insert (p, (s[0]=='_') ? LM_TC_DOWN: LM_TC_UP); 
  624.     return;
  625.     } else   
  626.       if (s[0]=='!' || s[0]==','  || s[0]==':' || s[0]==';') {
  627.       int sp = ((s[0]==',') ? 1:((s[0]==':') ? 2:((s[0]==';') ? 3: 0))); 
  628.       p = new MathSpaceInset(sp);
  629.       Insert(p);
  630.       return;
  631.       } else  
  632.       l = in_word_set (s, strlen(s));
  633.     
  634.     if (!l) {       
  635.     p = MathMacroTable::mathMTable.getMacro(s);
  636.     if (!p) {
  637.         lyxerr.debug(LString("Macro2 ") + s + ' ' + tcode, Error::MATHED);
  638.         p = new MathFuncInset(s, LM_OT_UNDEF);
  639.     } else {
  640.         tcode = ((MathMacro*)p)->getTCode();
  641.         fprintf(stderr, "Macro2 %s %d  ", s, tcode);
  642.     }
  643.     } else {
  644.     MathedInsetTypes fractype = LM_OT_FRAC;
  645.     switch (l->token) {
  646.      case LM_TK_BIGSYM:
  647.      {
  648.          p = new MathBigopInset(l->name, l->id);
  649.          break;
  650.      }
  651.      case LM_TK_SYM:
  652.      {              
  653.          if (l->id<255) {
  654.          Insert((byte)l->id, MathIsBOPS(l->id) ? 
  655.             LM_TC_BOPS: LM_TC_SYMB);         
  656.          } else {
  657.          p = new MathFuncInset(l->name);
  658.          }
  659.          break;
  660.      }  
  661.      case LM_TK_STACK:
  662.         fractype = LM_OT_STACKREL;
  663.         lyxerr.debug(" i:stackrel ", Error::MATHED);
  664.      case LM_TK_FRAC: 
  665.      {     
  666.          p = new MathFracInset(fractype);
  667.          tcode = LM_TC_ACTIVE_INSET;
  668.          break;
  669.      }
  670.      case LM_TK_SQRT: 
  671.      {     
  672.          p = new MathSqrtInset; 
  673.          tcode = LM_TC_ACTIVE_INSET;
  674.          break;
  675.      }
  676.      case LM_TK_WIDE: 
  677.      {     
  678.          p = new MathDecorationInset(l->id); 
  679.          tcode = LM_TC_ACTIVE_INSET;
  680.          break;
  681.      } 
  682.      case  LM_TK_FUNCLIM:
  683.      {
  684.          p = new MathFuncInset(l->name, LM_OT_FUNCLIM);
  685.          break;
  686.      }
  687.      case LM_TK_SPACE:
  688.      {
  689.          p = new MathSpaceInset(l->id);
  690.          break;
  691.      }       
  692.      case LM_TK_DOTS: 
  693.      {
  694.          p = new MathDotsInset(l->name, l->id);
  695.          break;
  696.      }       
  697.      case LM_TK_ACCENT:
  698.         setAccent(l->id);
  699.         break;
  700.      case LM_TK_MACRO:
  701.         p = MathMacroTable::mathMTable.getMacro(s);
  702.         tcode = ((MathMacro*)p)->getTCode();
  703.         lyxerr.debug(LString("Macro ") + s + ' ' + tcode, Error::MATHED);
  704.         break;
  705.      default:
  706.      {
  707.          p = new MathFuncInset(l->name);
  708.          break;
  709.      }
  710.     }
  711.     }
  712.     if (p) {
  713.     Insert(p, tcode);
  714.     par->Metrics();
  715.     }
  716. }
  717.  
  718.  
  719. void MathedCursor::MacroModeOpen()
  720. {
  721.    if (!macro_mode)  {
  722.       macroln = 0;
  723.       macrobf[0] = '\0';
  724.       imacro = new MathFuncInset(¯obf[0]);
  725.       Insert (imacro);
  726.       macro_mode = true;
  727.    } else
  728.      fprintf(stderr, "Mathed Warning: Already in macro mode\n");
  729. }
  730.  
  731. void MathedCursor::MacroModeClose()
  732. {
  733.    if (macro_mode)  {
  734. //       fprintf(stderr, "Pos[%d] ", cursor->getPos());
  735.       macro_mode = false;
  736.       latexkeys *l = in_word_set(macrobf, macroln);
  737.       if (macroln>0 && (!l || (l && IsMacro(l->token, l->id))) && 
  738.       !MathMacroTable::mathMTable.getMacro(macrobf)) {
  739.       if (!l) {
  740.         imacro->SetName(strnew(macrobf));
  741.           // This guarantees that the string will be removed by destructor
  742.         imacro->SetType(LM_OT_UNDEF);
  743.       } else 
  744.         imacro->SetName(l->name);
  745.       } else {
  746.          Left();
  747.      imacro->SetName(NULL);
  748.      if (cursor->GetInset()->GetType()==LM_OT_ACCENT) {
  749.          accent = ((MathAccentInset*)cursor->GetInset())->getAccentCode();
  750.      }
  751.      cursor->Delete();
  752.      if (l || MathMacroTable::mathMTable.getMacro(macrobf)) {
  753.         Interpret(macrobf);
  754.      }
  755.       }
  756.       imacro = NULL;
  757.    } else
  758.      fprintf(stderr, "Mathed Warning: we are not in macro mode\n");
  759. }
  760.  
  761. void MathedCursor::MacroModeBack()
  762. {
  763.    if (macro_mode) {
  764.      if (macroln>0) {
  765.     macrobf[--macroln] = '\0';
  766.     imacro->Metrics();
  767.      } else 
  768.     MacroModeClose();
  769.    } else
  770.      fprintf(stderr, "Mathed Warning: we are not in macro mode\n");
  771. }
  772.  
  773. void MathedCursor::MacroModeInsert(char c)
  774. {
  775.    if (macro_mode) {
  776.       macrobf[macroln+1] = macrobf[macroln];
  777.       macrobf[macroln++] = c;
  778.       imacro->Metrics();
  779.    } else
  780.      fprintf(stderr, "Mathed Warning: we are not in macro mode\n");
  781. }
  782.  
  783. void MathedCursor::SelCopy()
  784. {
  785.     if (selection) {
  786.     int p1, p2;
  787.     p1 = (cursor->pos < selpos) ? cursor->pos: selpos;
  788.     p2 = (cursor->pos > selpos) ? cursor->pos: selpos;
  789.     selarray = cursor->Copy(p1, p2);
  790.     cursor->Adjust();
  791.     SelClear();
  792.     }
  793. }
  794.  
  795. void MathedCursor::SelCut()
  796. {   
  797.     if (selection) {
  798.     if (cursor->pos==selpos) return;
  799.     
  800.     int p1, p2;
  801.     p1 = (cursor->pos < selpos) ? cursor->pos: selpos;
  802.     p2 = (cursor->pos > selpos) ? cursor->pos: selpos;
  803.     selarray = cursor->Copy(p1, p2);
  804.     cursor->Clean(selpos);
  805.     cursor->Adjust();
  806.     SelClear();
  807.     }
  808. }
  809.  
  810. void MathedCursor::SelDel()
  811. {
  812. //    fprintf(stderr, "Deleting sel ");
  813.     if (selection) {    
  814.     if (cursor->pos==selpos) return;
  815.          cursor->Clean(selpos);
  816.     cursor->Adjust();
  817.     SelClear();
  818.     }
  819. }
  820.  
  821. void MathedCursor::SelPaste()
  822. {
  823. //    fprintf(stderr, "paste %p %d ", selarray, cursor->pos);
  824.     if (selection) SelDel();
  825.     if (selarray) {
  826.     cursor->Merge(selarray);
  827.     cursor->Adjust();
  828.     }
  829. }
  830.  
  831. void MathedCursor::SelStart()
  832. {
  833.    lyxerr.debug("Starting sel ",Error::MATHED);
  834.     if (!anchor) {
  835.     selpos = cursor->pos;   
  836.     selstk = new MathStackXIter(mathstk); 
  837.     anchor = selstk->Item(-1); 
  838.     anchor->SetData(cursor->p);
  839.     anchor->GoBegin();
  840.     anchor->goPosAbs(selpos);
  841.     selection = true;
  842.     
  843.     }
  844. }
  845.  
  846. void MathedCursor::SelClear()
  847. {   
  848.    lyxerr.debug("Clearing sel ", Error::MATHED);
  849.     selection = false;
  850.     delete selstk;
  851.     selstk = 0;
  852.     anchor = 0;
  853. }
  854.  
  855.  
  856.  
  857. // Anchor position must be at the same level that stack.
  858. void MathedCursor::SelBalance()
  859. {
  860.     int d = mathstk.Level() - selstk->Level();
  861.  
  862.     // If unbalanced, balance them
  863.     while (d != 0) {
  864.         if (d<0) {
  865. //            fprintf(stderr, "b[%d %d %d %d]", mathstk.Level(), selstk->Level(), anchor->GetX(), cursor->GetX());
  866.             anchor = selstk->pop();
  867.             if (anchor->GetX() >= cursor->GetX()) 
  868.           anchor->Next();
  869.         } else {
  870. //            fprintf(stderr, "a[%d %d]", mathstk.Level(), selstk->Level());
  871.             Pop();
  872.         }
  873.         d = mathstk.Level() - selstk->Level();
  874.     }
  875.  
  876.     // Once balanced the levels, check that they are at the same paragraph
  877.     selpos = anchor->pos;
  878.  
  879.  
  880. XPoint *MathedCursor::SelGetArea(int& np)
  881. {   
  882.     if (!selection) {
  883.     np = 0;
  884.     return 0;
  885.     }
  886.     
  887.     static XPoint point[10];
  888.     
  889.     // single row selection
  890.     int i = 0, x, y, a, d, w, xo, yo, x1, y1, a1, d1; //, p1, p2;
  891.  
  892.     // Balance anchor and cursor
  893.     SelBalance();
  894.  
  895.     cursor->p->GetXY(xo, yo);
  896.     w = cursor->p->Width();
  897.     cursor->GetPos(x1, y1);
  898.     cursor->getAD(a1, d1);
  899.     anchor->GetPos(x, y);
  900.     anchor->getAD(a, d);
  901.  
  902.     point[i].x = x;
  903.     point[i++].y = y+d;
  904.     point[i].x = x;
  905.     point[i++].y = y-a;
  906.     
  907.     if (y!=y1) {
  908.     point[i].x = xo + w;
  909.     point[i++].y = y-a;
  910.     if (x1<xo+w) {
  911.         point[i].x = xo + w;
  912.         point[i++].y = y1-a;
  913.     }
  914.     }
  915.     
  916.     point[i].x = x1;
  917.     point[i++].y = y1-a;
  918.     point[i].x = x1;
  919.     point[i++].y = y1+d;
  920.     
  921.     if (y!=y1) {
  922.     point[i].x = xo;
  923.     point[i++].y = y1+d;
  924.     if (x>xo) {
  925.         point[i].x = xo;
  926.         point[i++].y = y+d;
  927.     }
  928.     }
  929.     point[i].x = point[0].x;
  930.     point[i++].y = point[0].y;
  931.     np = i;
  932. //    fprintf(stderr, "AN[%d %d %d %d] ", x, y, x1, y1); 
  933. //    fprintf(stderr, "MT[%d %d %d %d] ", a, d, a1, d1);
  934. //    for (i=0; i<np; i++)
  935. //      fprintf(stderr, "XY[%d %d] ", point[i].x, point[i].y);
  936.     
  937.     return &point[0];
  938. }
  939.  
  940.