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 / text.C < prev    next >
C/C++ Source or Header  |  1998-04-23  |  120KB  |  4,059 lines

  1. /* This file is part of
  2. * ======================================================
  3. *           LyX, The Document Processor
  4. *      
  5. *        Copyright (C) 1995 Matthias Ettrich
  6. *           Copyright (C) 1995-1998 The LyX Team.
  7. *
  8. *======================================================*/
  9.  
  10. #include <config.h>
  11. #include <stdlib.h>
  12. #include <ctype.h>
  13.  
  14. #ifdef __GNUG__
  15. #pragma implementation "table.h"
  16. #endif
  17.  
  18. #include "layout.h"
  19. #include "lyxparagraph.h"
  20. #include "lyxtext.h"
  21. #include "textutils.h"
  22. #include "lyx_gui_misc.h"
  23. #include "lyxdraw.h"
  24. #include "gettext.h"
  25. #include "bufferparams.h"
  26. #include "lyxscreen.h"
  27.  
  28. //     $Id: text.C,v 1.1.1.1 1998/04/23 16:02:57 larsbj Exp $    
  29.  
  30. #if !defined(lint) && !defined(WITH_WARNINGS)
  31. static char vcid[] = "$Id: text.C,v 1.1.1.1 1998/04/23 16:02:57 larsbj Exp $";
  32. #endif /* lint */
  33.  
  34.  
  35. static const int LYX_PAPER_MARGIN = 20;
  36.  
  37. extern int reverse_video;
  38.  
  39. // ale070405
  40. extern int bibitemMaxWidth(const class LyXFont &);
  41.  
  42.  
  43. int LyXText::SingleWidth(LyXParagraph *par, int pos)
  44. {
  45.     char c = par->GetChar(pos);
  46.     return SingleWidth(par, pos, c);
  47. }
  48.  
  49.  
  50. int LyXText::SingleWidth(LyXParagraph *par, int pos, char c)
  51. {
  52.     LyXFont font = GetFont(par, pos);
  53.  
  54.     // The most common case is handled first (Asger)
  55.     if (IsPrintable(c)) {
  56.         return font.width(c);
  57.  
  58.     } else if (IsHfillChar(c)) {
  59.         return 3;    /* because of the representation
  60.                  * as vertical lines */
  61.  
  62.     } else if (c == LYX_META_FOOTNOTE ||
  63.            c == LYX_META_MARGIN ||
  64.            c == LYX_META_FIG ||
  65.            c == LYX_META_TAB ||
  66.            c == LYX_META_WIDE_FIG ||
  67.            c == LYX_META_WIDE_TAB ||
  68.            c == LYX_META_ALGORITHM) 
  69.     {
  70.         LString fs;
  71.         switch (c) {
  72.         case LYX_META_MARGIN:
  73.             fs = "margin";
  74.             break;
  75.         case LYX_META_FIG:
  76.             fs = "fig";
  77.             break;
  78.         case LYX_META_TAB:
  79.             fs = "tab";
  80.             break;
  81.         case LYX_META_ALGORITHM:
  82.             fs = "alg";
  83.             break;
  84.         case LYX_META_WIDE_FIG:
  85.             fs = "wide-fig";
  86.             break;
  87.         case LYX_META_WIDE_TAB:
  88.             fs = "wide-tab";
  89.             break;
  90.         case LYX_META_FOOTNOTE:
  91.             fs = "foot";
  92.             break;
  93.         }
  94.         font.decSize();
  95.         font.decSize();
  96.         return font.stringWidth(fs);
  97.     } 
  98.    
  99.     else if (c == LYX_META_INSET) {
  100.         Inset *tmpinset=par->GetInset(pos);
  101.         if (tmpinset)
  102.             return par->GetInset(pos)->Width(font);
  103.         else
  104.             return 0;
  105.  
  106.     } else if (IsSeparatorChar(c))
  107.         c = ' ';
  108.     else if (IsNewlineChar(c))
  109.         c = 'n';
  110.     return font.width(c);
  111. }
  112.  
  113.  
  114. /* returns the paragraph position of the last character in the 
  115.  * specified row */
  116. int LyXText::RowLast(Row *row)
  117. {
  118.     if (row->next == NULL)
  119.         return row->par->Last()-1;
  120.     else if (row->next->par != row->par) 
  121.         return row->par->Last()-1;
  122.     else 
  123.         return row->next->pos - 1;
  124. }
  125.  
  126.  
  127. void LyXText::Draw(Row *row, int &pos, LyXScreen &scr, int offset, float &x)
  128. {
  129.     char c = row->par->GetChar(pos);
  130.  
  131.     if (IsNewlineChar(c)) {
  132.         pos++;
  133.         // Draw end-of-line marker
  134.  
  135.         LyXFont font = GetFont(row->par, pos);
  136.         int asc = font.maxAscent();
  137.         int wid = font.width('n');
  138.         int y = (offset + row->baseline);
  139.         XPoint p[3];
  140.         p[0].x = int(x + wid*0.375); p[0].y = int(y - 0.875*asc*0.75);
  141.         p[1].x = int(x);         p[1].y = int(y - 0.500*asc*0.75);
  142.         p[2].x = int(x + wid*0.375); p[2].y = int(y - 0.125*asc*0.75);
  143.         scr.drawLines(GetColorGC(LyXFont::RED),p, 3);
  144.         
  145.         p[0].x = int(x);         p[0].y = int(y - 0.500*asc*0.75);
  146.         p[1].x = int(x + wid);         p[1].y = int(y - 0.500*asc*0.75);
  147.         p[2].x = int(x + wid);         p[2].y = int(y - asc*0.75);
  148.         scr.drawLines(GetColorGC(LyXFont::RED),p, 3);
  149.         return;
  150.     }
  151.  
  152.     LyXFont font = GetFont(row->par, pos);
  153.     LyXFont font2 = font;
  154.  
  155.     if (c == LYX_META_FOOTNOTE ||
  156.         c == LYX_META_MARGIN ||
  157.         c == LYX_META_FIG ||
  158.         c == LYX_META_TAB ||
  159.         c == LYX_META_WIDE_FIG ||
  160.         c == LYX_META_WIDE_TAB ||
  161.         c == LYX_META_ALGORITHM) {
  162.         LString fs;
  163.         switch (c) {
  164.         case LYX_META_MARGIN:
  165.             fs = "margin";
  166.             /* draw a sign at the left margin! */ 
  167.             scr.drawText(font, "!", 1, offset + row->baseline,
  168.                      (LYX_PAPER_MARGIN - font.width('!'))/2);
  169.             break;
  170.         case LYX_META_FIG:
  171.             fs = "fig";
  172.             break;
  173.         case LYX_META_TAB:
  174.             fs = "tab";
  175.             break;
  176.         case LYX_META_ALGORITHM:
  177.             fs = "alg";
  178.             break;
  179.         case LYX_META_WIDE_FIG:
  180.             fs = "wide-fig";
  181.             break;
  182.         case LYX_META_WIDE_TAB:
  183.             fs = "wide-tab";
  184.             break;
  185.         case LYX_META_FOOTNOTE:
  186.             fs = "foot";
  187.             break;
  188.         }
  189.         font.decSize();
  190.         font.decSize();
  191.       
  192.         /* calculate the position of the footnotemark */
  193.         int y = (row->baseline - font2.maxAscent() 
  194.              + font.maxAscent());
  195.       
  196.         font.setColor(LyXFont::INSET);
  197.  
  198.         /* draw it and set new x position */
  199.         x += scr.drawString(font, fs, offset + y, int(x));
  200.       
  201.         pos++;
  202.         return;
  203.     } else if (c == LYX_META_INSET) {
  204.         Inset *tmpinset = row->par->GetInset(pos);
  205.         if (tmpinset) 
  206.             tmpinset->Draw(font, scr, offset + row->baseline, x);
  207.         pos++;
  208.         return;
  209.     }
  210.  
  211.     /* usual characters, no insets */
  212.  
  213.     // Collect character that we can draw in one command
  214.  
  215.     // This is dirty, but fast. Notice that it will never be too small.
  216.     // For the record, I'll note that Microsoft Word has a limit
  217.     // of 768 here. We have none :-) (Asger)
  218.     static char textstring[1024];
  219.  
  220.     int last = RowLast(row);
  221.     // Prevent crash in the extremely unlikely event
  222.     // that our array is too small
  223.     if (last > pos+1020) last = pos + 1020;
  224.  
  225.     textstring[0] = c;
  226.     pos++;
  227.  
  228.     int i = 1;
  229.  
  230.     while (pos <= last &&
  231.            (unsigned char) (c = row->par->GetChar(pos)) > ' ' &&
  232.            font2 == GetFont(row->par, pos)) {
  233.         textstring[i++] = c;
  234.         pos++;
  235.     }
  236.     textstring[i] = 0; 
  237.  
  238.     float tmpx = x;
  239.  
  240.     /* Draw text and set the new x position */ 
  241.     x += scr.drawText(font, textstring, i, offset + row->baseline, 
  242.               int(x));
  243.     /* what about underbars? */
  244.     if (font.underbar() == LyXFont::ON && font.latex() != LyXFont::ON) {
  245.         scr.drawLine(gc_copy, offset + row->baseline + 2,
  246.                  int(tmpx), int(x - tmpx));
  247.     }
  248.  
  249.     // If we want ulem.sty support, drawing
  250.     // routines should go here. (Asger)
  251.     // Why shouldn't LyXFont::drawText handle it internally?
  252. }
  253.  
  254.  
  255. /* Returns the left beginning of the text. 
  256. * This information cannot be taken from the layouts-objekt, because in 
  257. * LaTeX the beginning of the text fits in some cases (for example sections)
  258. * exactly the label-width. */
  259. int LyXText::LeftMargin(Row* row)
  260. {
  261.    int x;
  262.    LyXLayout *layout;
  263.    LyXFont labelfont;
  264.    LyXParagraph *newpar;
  265.    Row dummyrow;
  266.    layout = lyxstyle.Style(parameters->textclass, row->par->GetLayout());
  267.    
  268.    LString parindent = layout->parindent; 
  269.  
  270.    /* table stuff -- begin*/ 
  271.    if (row->par->table)
  272.       parindent.erase();
  273.    /* table stuff -- end*/       
  274.  
  275.    x = LYX_PAPER_MARGIN;
  276.  
  277.    x += lyxstyle.TextClass(parameters->textclass)->
  278.      defaultfont.signedStringWidth(lyxstyle.TextClass(parameters->textclass)->leftmargin);
  279.  
  280.    if (row->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)  {
  281.     LyXFont font(LyXFont::ALL_SANE);
  282.     font.setSize(LyXFont::SIZE_SMALL);
  283.     x += font.textWidth("Mwide-figM", 10) + LYX_PAPER_MARGIN/2;
  284.    }
  285.  
  286.    /* this is the way, LyX handles the LaTeX-Environments.
  287.     * I have had this idea very late, so it seems to be a
  288.     * later added hack and this is true */ 
  289.    if (!row->par->GetDepth()) {
  290.       if (!row->par->GetLayout()) {
  291.      /* find the previous same level paragraph */
  292.      if (row->par->FirstPhysicalPar()->Previous()) {
  293.         newpar = row->par->DepthHook(row->par->GetDepth());
  294.         if (newpar && lyxstyle.Style(parameters->textclass, newpar->GetLayout())->nextnoindent)
  295.            parindent.erase();
  296.      }
  297.       }
  298.    }
  299.    else {
  300.       /* find the next level paragraph */ 
  301.       
  302.       newpar = row->par->DepthHook(row->par->GetDepth()-1);
  303.  
  304.       /* make a corresponding row. Needed to call LeftMargin() */
  305.       
  306.       /* check wether it is a sufficent paragraph */ 
  307.       if (newpar && newpar->footnoteflag == row->par->footnoteflag
  308.       && lyxstyle.Style(parameters->textclass, 
  309.                 newpar->GetLayout())->isEnvironment()) {
  310.          dummyrow.par = newpar;
  311.          dummyrow.pos = newpar->Last();
  312.          x = LeftMargin(&dummyrow);
  313.       }
  314.       else {
  315.      /* this is no longer an error, because this function is used
  316.       * to clear impossible depths after changing a layout. Since there
  317.       * is always a redo, LeftMargin() is always called */ 
  318.      
  319.      /* printf("LYX_ERROR (text, LeftMargin()) impossible depth \n");*/ 
  320.      row->par->FirstPhysicalPar()->depth = 0;
  321.       }
  322.       
  323.       if (newpar && !row->par->GetLayout()) {
  324.      if (newpar->FirstPhysicalPar()->noindent)
  325.         parindent.erase();
  326.      else
  327.         parindent = lyxstyle.Style(parameters->textclass, 
  328.                        newpar->GetLayout())->parindent;
  329.       }
  330.       
  331.    }
  332.    
  333.    labelfont = GetFont(row->par, -2);
  334.    switch (layout->margintype) {
  335.     case MARGIN_DYNAMIC:
  336.       if (!layout->leftmargin.empty()) {
  337.     x += lyxstyle.TextClass(parameters->textclass)->defaultfont.signedStringWidth(layout->leftmargin);
  338.       }
  339.       if (!row->par->GetLabelString().empty()) {
  340.         x += labelfont.signedStringWidth(layout->labelindent);
  341.         x += labelfont.stringWidth(row->par->GetLabelString());
  342.         x += labelfont.stringWidth(layout->labelsep);
  343.       }
  344.       break;
  345.     case MARGIN_MANUAL:
  346.       x += labelfont.signedStringWidth(layout->labelindent);
  347.       if (row->pos >= BeginningOfMainBody(row->par)) {
  348.      if (!row->par->GetLabelWidthString().empty()) {
  349.         x += labelfont.stringWidth(row->par->GetLabelWidthString());
  350.         x += labelfont.stringWidth(layout->labelsep);
  351.      }
  352.       }
  353.       break;
  354.     case MARGIN_STATIC:
  355.       x += ( lyxstyle.TextClass(parameters->textclass)->defaultfont.signedStringWidth(layout->leftmargin) * 4
  356.          / (row->par->GetDepth() + 4));
  357.       break;
  358.     case MARGIN_FIRST_DYNAMIC:
  359.       if (layout->labeltype == LABEL_MANUAL) {
  360.      if (row->pos >= BeginningOfMainBody(row->par)) {
  361.         x += labelfont.signedStringWidth(layout->leftmargin);
  362.      }
  363.      else {
  364.         x += labelfont.signedStringWidth(layout->labelindent);
  365.      }
  366.       }
  367.       else {
  368.      if (row->pos
  369.          // Special case to fix problems with theorems (JMarc)
  370.          || (layout->labeltype == LABEL_STATIC
  371.          && layout->latextype == LATEX_ENVIRONMENT
  372.          && ! row->par->IsFirstInSequence())){
  373.          x += labelfont.signedStringWidth(layout->leftmargin);
  374.      }
  375.      else if (layout->labeltype != LABEL_TOP_ENVIRONMENT
  376.           && layout->labeltype != LABEL_BIBLIO
  377.           && layout->labeltype != LABEL_CENTERED_TOP_ENVIRONMENT) {
  378.          x += labelfont.signedStringWidth(layout->labelindent);
  379.          x += labelfont.stringWidth(layout->labelsep);
  380.          x += labelfont.stringWidth(row->par->GetLabelString());
  381.      } 
  382.       }
  383.       break;
  384.       
  385.     case MARGIN_RIGHT_ADDRESS_BOX:
  386.     {
  387.       /* ok, a terrible hack. The left margin depends on the widest row
  388.        * in this paragraph. Do not care about footnotes, they are *NOT*
  389.        * allowed in the LaTeX realisation of this layout. */ 
  390.       
  391.       /* find the first row of this paragraph */ 
  392.       Row *tmprow = row;
  393.       while (tmprow->previous && tmprow->previous->par == row->par)
  394.           tmprow = tmprow->previous;
  395.       
  396.       int minfill = tmprow->fill;
  397.       while (tmprow-> next && tmprow->next->par == row->par) {
  398.      tmprow = tmprow->next;
  399.      if (tmprow->fill < minfill)
  400.        minfill = tmprow->fill;
  401.       }
  402.       
  403.       x += lyxstyle.TextClass(parameters->textclass)->defaultfont.signedStringWidth(layout->leftmargin);
  404.       x += minfill;
  405.     }
  406.       break;
  407.    }
  408.    if (row->par->pextra_type == PEXTRA_INDENT) {
  409.        if (!row->par->pextra_widthp.empty()) {
  410.            x += paperwidth * atoi(row->par->pextra_widthp.c_str()) / 100;
  411.        } else if (!row->par->pextra_width.empty()) {
  412.            int xx = VSpace(row->par->pextra_width).inPixels();
  413.  
  414.            if (xx > paperwidth)
  415.                xx = paperwidth * 80 / 100;
  416.            x += xx;
  417.        } else { // should not happen
  418.            LyXFont font(LyXFont::ALL_SANE);
  419.            x += font.stringWidth("XXXXXX");
  420.        }
  421.    }
  422.    
  423.    int align;
  424.    if (row->par->FirstPhysicalPar()->align == LYX_ALIGN_LAYOUT)
  425.      align = layout->align;
  426.    else
  427.      align = row->par->FirstPhysicalPar()->align;
  428.    
  429.    /* set the correct parindent */
  430.    if (row->pos == 0) {
  431.        if ((layout->labeltype == LABEL_NO_LABEL 
  432.         || layout->labeltype == LABEL_TOP_ENVIRONMENT 
  433.         || layout->labeltype == LABEL_CENTERED_TOP_ENVIRONMENT
  434.         || (layout->labeltype == LABEL_STATIC
  435.         && layout->latextype == LATEX_ENVIRONMENT
  436.         && ! row->par->IsFirstInSequence()))
  437.        && row->par == row->par->FirstPhysicalPar()
  438.        && align == LYX_ALIGN_BLOCK
  439.        && !row->par->noindent
  440.        && (row->par->layout ||
  441.            parameters->paragraph_separation == LYX_PARSEP_INDENT))
  442.      x += lyxstyle.TextClass(parameters->textclass)->defaultfont.stringWidth(parindent);
  443.        else 
  444.      if (layout->labeltype==LABEL_BIBLIO) { // ale970405 Right width for bibitems
  445.          x += bibitemMaxWidth(lyxstyle.TextClass(parameters->textclass)->defaultfont);
  446.      }
  447.    }
  448.  
  449.    return x;
  450. }
  451.     
  452.    
  453. int LyXText::RightMargin(Row *row)
  454. {
  455.    int  x;
  456.    LyXLayout* layout;
  457.    
  458.    LyXParagraph *newpar;
  459.    Row dummyrow;
  460.    layout = lyxstyle.Style(parameters->textclass, row->par->GetLayout());
  461.  
  462.    x = LYX_PAPER_MARGIN;
  463.  
  464.    x += lyxstyle.TextClass(parameters->textclass)->
  465.      defaultfont.signedStringWidth(lyxstyle.TextClass(parameters->textclass)->rightmargin);
  466.    if (row->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)  {
  467.      x += LYX_PAPER_MARGIN/2;
  468.    }
  469.  
  470.     /* this is the way, LyX handles the LaTeX-Environments.
  471.     * I have had this idea very late, so it seems to be a
  472.     * later added hack and this is true */ 
  473.    if (row->par->GetDepth()) {
  474.       /* find the next level paragraph */ 
  475.       
  476.       newpar = row->par;
  477.       
  478.       do {
  479.         newpar = newpar->FirstPhysicalPar()->Previous();
  480.         if (newpar) 
  481.             newpar = newpar->FirstPhysicalPar();
  482.       } while (newpar && newpar->GetDepth() >= row->par->GetDepth()
  483.            && newpar->footnoteflag == row->par->footnoteflag);
  484.       
  485.       /* make a corresponding row. Needed to call LeftMargin() */
  486.  
  487.       /* check wether it is a sufficent paragraph */ 
  488.       if (newpar && newpar->footnoteflag == row->par->footnoteflag
  489.       && lyxstyle.Style(parameters->textclass,
  490.                 newpar->GetLayout())->isEnvironment()) {
  491.          dummyrow.par = newpar;
  492.          dummyrow.pos = 0;
  493.          x = RightMargin(&dummyrow);
  494.       }
  495.       else {
  496.      /* this is no longer an error, because this function is used
  497.       * to clear impossible depths after changing a layout. Since there
  498.       * is always a redo, LeftMargin() is always called */ 
  499.      
  500.      /* printf("LYX_ERROR (text, LeftMargin()) impossible depth \n");*/ 
  501.      row->par->FirstPhysicalPar()->depth = 0;
  502.       }
  503.    }
  504.  
  505.    //fprintf(stderr,"rightmargin: %s\n", layout->rightmargin.c_str());
  506.    //fflush(stderr);
  507.    x += (lyxstyle.TextClass(parameters->textclass)->defaultfont.signedStringWidth(layout->rightmargin) * 4
  508.      / (row->par->GetDepth() + 4));
  509.    return x;
  510.    
  511. }
  512.  
  513.  
  514. int LyXText::LabelEnd (Row *row)
  515. {
  516.    if (lyxstyle.Style(parameters->textclass, row->par->GetLayout())->margintype == MARGIN_MANUAL) {
  517.       Row tmprow;
  518.       tmprow = *row;
  519.       tmprow.pos = row->par->Last();
  520.       return LeftMargin(&tmprow);      /* just the beginning 
  521.                     * of the main body */
  522.    }
  523.    else
  524.      return 0;                   /* LabelEnd is only needed, if the  
  525.                     * layout fills a flushleft
  526.                     * label. */
  527. }
  528.  
  529.  
  530. /* table stuff -- begin*/ 
  531. int LyXText::NumberOfCell(LyXParagraph *par, int pos)
  532. {
  533.    int cell = 0;
  534.    int tmp_pos = 0;
  535.    while (tmp_pos < pos) {
  536.       if (par->IsNewline(tmp_pos))
  537.            cell++;
  538.       tmp_pos++;
  539.    }
  540.    return cell;
  541. }
  542.  
  543.  
  544. int LyXText::WidthOfCell(LyXParagraph *par, int &pos)
  545. {
  546.    int w = 0;
  547.    while (pos < par->Last() && !par->IsNewline(pos)) {
  548.       w += SingleWidth(par, pos);
  549.       pos++;
  550.    }
  551.    if (par->IsNewline(pos))
  552.       pos++;
  553.    return w;
  554. }
  555.  
  556.  
  557. char LyXText::HitInTable(Row* row, int x)
  558. {
  559.   float tmpx;
  560.   float fill_separator, fill_hfill, fill_label_hfill;
  561.   if (!row->par->table)
  562.     return 0;
  563.   PrepareToPrint(row, tmpx, fill_separator, fill_hfill, fill_label_hfill);
  564.   return (x > tmpx && x < tmpx + row->par->table->WidthOfTable());
  565. }
  566.  
  567.  
  568. bool LyXText::MouseHitInTable(int x, long y)
  569. {
  570.     Row *row = GetRowNearY(y);
  571.         return HitInTable(row, x);
  572. }
  573.  
  574.  
  575. /* table stuff -- end*/
  576.  
  577.  
  578. /* get the next breakpoint in a given paragraph */
  579. int LyXText::NextBreakPoint(Row* row, int width)
  580. {
  581.     int x = 0;
  582.     int last_separator = -1; /* position of the last possible breakpoint 
  583.                   * -1 isn't a suitable value, but a flag */
  584.     int i = 0;
  585.     int left_margin;
  586.     
  587.     LyXParagraph *par = row->par;
  588.     int pos = row->pos;
  589.     
  590.     /* table stuff -- begin*/ 
  591.     if (par->table) {
  592.         while (pos<par->last 
  593.                && (!par->IsNewline(pos) 
  594.                || !par->table->IsFirstCell(NumberOfCell(par, pos+1)))) {
  595.             if (par->GetChar(pos) == LYX_META_INSET &&
  596.                 par->GetInset(pos) && par->GetInset(pos)->Display()){
  597.                 par->GetInset(pos)->SetDisplay(false);
  598.             }
  599.             pos++;
  600.         }
  601.         return pos;
  602.     }
  603.     /* table stuff -- end*/ 
  604.     
  605.     left_margin = LabelEnd(row);
  606.     width -= RightMargin(row);
  607.     int main_body = BeginningOfMainBody(par);
  608.     LyXLayout* layout = lyxstyle.Style(parameters->textclass, par->GetLayout());
  609.     i = pos;
  610.     char c;
  611.     
  612.     if (layout->margintype == MARGIN_RIGHT_ADDRESS_BOX) {
  613.         /* special code for right address boxes, only newlines count */
  614.         while (i < par->Last()) {
  615.             if (par->IsNewline(i)) {
  616.                 last_separator = i;
  617.                 i = par->Last() - 1;/* this means break  */
  618.                 x = width;
  619.             } else if (par->GetChar(i) == LYX_META_INSET &&
  620.                    par->GetInset(i) && par->GetInset(i)->Display()){
  621.                 par->GetInset(i)->SetDisplay(false);
  622.             }
  623.             i++;
  624.         }
  625.     } else {
  626.         // Last position is an invariant
  627.         int const last = par->Last();
  628.         /* this is the usual handling */ 
  629.         x = LeftMargin(row);
  630.         while (x < width && i < last) {
  631.             c = par->GetChar(i);
  632.             if (IsNewlineChar(c)) {
  633.                 last_separator = i;
  634.                 x = width;               /* this means break  */
  635.             } else if (c == LYX_META_INSET &&
  636.                    par->GetInset(i) && par->GetInset(i)->Display()){
  637.                 /* check wether a Display() inset is valid here .
  638.                    if not, change it to non-display*/ 
  639.                 if (layout->isCommand()
  640.                     || (layout->labeltype == LABEL_MANUAL
  641.                     && i < BeginningOfMainBody(par))){
  642.                     /* display istn't allowd */ 
  643.                     par->GetInset(i)->SetDisplay(false);
  644.                     x += SingleWidth(par, i, c);
  645.                 } else {
  646.                     /* inset is display. So break the line here */ 
  647.                     if (i==pos){
  648.                         if (pos < last-1) {
  649.                             last_separator = i;
  650.                             if (IsLineSeparatorChar(par->GetChar(i+1)))
  651.                                 last_separator++;
  652.                         } else
  653.                             last_separator = last; // to avoid extra rows
  654.                     } else
  655.                         last_separator = i - 1;
  656.                     x = width;               /* this means break  */
  657.                 }
  658.             } else  {
  659.                 if (IsLineSeparatorChar(c))
  660.                     last_separator = i;
  661.                 x += SingleWidth(par, i, c);
  662.             }
  663.             i++;
  664.             if (i == main_body) {
  665.                 x += GetFont(par, -2).stringWidth(layout->labelsep);
  666.                 if (par->IsLineSeparator(i - 1))
  667.                     x-= SingleWidth(par, i - 1);
  668.                 if (x < left_margin)
  669.                     x = left_margin;
  670.             }
  671.         }
  672.         /* end of paragraph is always a suitable separator */
  673.         if (i == last && x < width)
  674.             last_separator = i;
  675.     }
  676.     
  677.     /* well, if last_separator is still 0, the line isn't breakable. 
  678.      * don't care and cut simply at the end */
  679.     if (last_separator < 0) {
  680.         last_separator = i;
  681.     }
  682.     
  683.     /* manual labels cannot be broken in LaTeX, do not care  */
  684.     if (main_body && last_separator < main_body)
  685.         last_separator = main_body - 1;
  686.     
  687.     return last_separator;
  688. }
  689.  
  690.  
  691. /* returns the minimum space a row needs on the screen in pixel */
  692. int LyXText::Fill(Row *row, int paperwidth)
  693. {
  694.    int w,i, last, fill, left_margin;
  695.    /* get the pure distance */
  696.    last = RowLast(row);
  697.    
  698.    /* table stuff -- begin*/
  699.    if (row->par->table) {
  700.       /* for tables FILL does calculate the widthes of each cell in 
  701.        * the row */ 
  702.       int pos = row->pos;
  703.       int cell = NumberOfCell(row->par, pos);
  704.       w = 0;
  705.       do {
  706.      row->par->table->SetWidthOfCell(cell, WidthOfCell(row->par, pos));
  707.      cell++;
  708.       } while (pos <= last && !row->par->table->IsFirstCell(cell));
  709.       /* don't forget the very last table cell without characters */
  710.       if (cell == row->par->table->GetNumberOfCells()-1)
  711.           row->par->table->SetWidthOfCell(cell, WidthOfCell(row->par, pos));
  712.       
  713.       return 0; /* width of table cannot be returned since
  714.          * we cannot guarantee its correct value at
  715.          * this point. */ 
  716.    }
  717.    /* table stuff -- end*/ 
  718.  
  719.    left_margin = LabelEnd(row);
  720.  
  721.      /* if the row ends with newline, this newline will not be relevant */ 
  722.      if (last >= 0 && row->par->IsNewline(last))
  723.        last--;
  724.      
  725.      /* if the row ends with a space, this space will not be relevant */ 
  726.      if (last >= 0 && row->par->IsLineSeparator(last))
  727.        last--;
  728.  
  729.    /* special handling of the right address boxes */ 
  730.    if (lyxstyle.Style(parameters->textclass, row->par->GetLayout())->margintype == MARGIN_RIGHT_ADDRESS_BOX) {
  731.       int tmpfill = row->fill;
  732.       row->fill = 0;                /* the minfill in MarginLeft()  */
  733.       w = LeftMargin(row);
  734.       row->fill = tmpfill;
  735.       
  736.       /* the old way, impossible when using environments: */ 
  737.       /*  w = LyXStringWidth(lyxstyle.Style(parameters->textclass, row->par->GetLayout())->font, */ 
  738.       /*              lyxstyle.Style(parameters->textclass, row->par->GetLayout())->leftmargin); */
  739.    }
  740.    else
  741.      w = LeftMargin(row);
  742.    
  743.    int main_body = BeginningOfMainBody(row->par);
  744.    LyXLayout *layout = lyxstyle.Style(parameters->textclass,
  745.                       row->par->GetLayout());
  746.    i = row->pos;
  747.    while (i<= last) {
  748.       w += SingleWidth(row->par, i);
  749.       i++;
  750.       if (i == main_body) {
  751.      w += GetFont(row->par, -2).stringWidth(layout->labelsep);
  752.      if (row->par->IsLineSeparator(i - 1))
  753.        w-= SingleWidth(row->par, i - 1);
  754.      if (w < left_margin)
  755.        w = left_margin;
  756.       }
  757.    }
  758.    
  759.    fill = paperwidth - w - RightMargin(row);
  760.    return fill;
  761. }
  762.  
  763.  
  764. /* returns the minimum space a manual label needs on the screen in pixel */ 
  765. int LyXText::LabelFill(Row *row)
  766. {
  767.    int w,i, last;
  768.    int fill=0;
  769.    
  770.    last = BeginningOfMainBody(row->par) - 1;
  771.    /* -1 because a label ends either with a space that is in the label, 
  772.     * or with the beginning of a footnote that is outside the label. */ 
  773.  
  774.    // I don't understand this code in depth, but sometimes "last" is less than
  775.    // 0 and this causes a crash. This fix seems to work correctly, but I
  776.    // bet the real error is elsewhere.  The bug is triggered when you have an 
  777.    // open footnote in a paragraph environment with a manual label. (Asger)
  778.    if (last<0) last = 0;
  779.  
  780.    if (row->par->IsLineSeparator(last))    /* a sepearator at this end 
  781.                     * does not count */
  782.      last--;
  783.    
  784.    w = 0;
  785.    i = row->pos;
  786.    while (i<= last) {
  787.       w += SingleWidth(row->par, i);
  788.       i++;
  789.    }
  790.    
  791.    if (!row->par->labelwidthstring.empty()) {
  792.       fill = GetFont(row->par, -2).stringWidth(row->par->labelwidthstring) - w;
  793.    }
  794.    
  795.    if (fill < 0)
  796.      fill = 0;
  797.    
  798.    return fill;
  799. }
  800.  
  801.  
  802. /* returns the number of separators in the specified row. The separator 
  803. * on the very last column doesnt count */ 
  804. int LyXText::NumberOfSeparators(Row *row)
  805. {
  806.    int n,p,last;
  807.    
  808.    last = RowLast(row);
  809.    n = 0;
  810.    p = row->pos;
  811.    int main_body = BeginningOfMainBody(row->par);
  812.    if (p < main_body)
  813.      p = main_body;
  814.    for (; p < last; p++) {
  815.       if (row->par->IsSeparator(p)) {
  816.      n++;
  817.       }
  818.    }
  819.    return n;
  820. }
  821.  
  822.  
  823. /* returns the number of hfills in the specified row. The LyX-Hfill is
  824. * a LaTeX \hfill so that the hfills at the beginning and at the end were 
  825. * ignored. This is *MUCH* more usefull than not to ignore!  */
  826. int LyXText::NumberOfHfills(Row *row)
  827. {
  828.    int n,p,last, first;
  829.    
  830.    last = RowLast(row);
  831.    first = row->pos;
  832.    if (first) {                   /* hfill *DO* count at the beginning 
  833.                     * of paragraphs! */
  834.      while(first <= last && row->par->IsHfill(first))
  835.        first++;
  836.    }
  837.  
  838.    n = 0;
  839.    int main_body = BeginningOfMainBody(row->par);
  840.    if (first < main_body)
  841.      first = main_body;
  842.    for (p = first; p <= last; p++) {    /* last, because the end is ignored!  */
  843.       if (row->par->IsHfill(p)) {
  844.      n++;
  845.       }
  846.    }
  847.    return n;
  848. }
  849.  
  850.  
  851. /* like NumberOfHfills, but only those in the manual label! */ 
  852. int LyXText::NumberOfLabelHfills(Row *row)
  853. {
  854.    int n,p,last, first;
  855.    
  856.    last = RowLast(row);
  857.    first = row->pos;
  858.    if (first) {                   /* hfill *DO* count at the beginning 
  859.                     * of paragraphs! */
  860.       while(first < last && row->par->IsHfill(first))
  861.           first++;
  862.    }
  863.  
  864.    n = 0;
  865.    int main_body = BeginningOfMainBody(row->par);
  866.    
  867.    if (last > main_body)
  868.      last = main_body;
  869.    
  870.    for (p = first; p < last; p++) {    /* last, because the end is ignored!  */
  871.       if (row->par->IsHfill(p)) {
  872.      n++;
  873.       }
  874.    }
  875.    return n;
  876. }
  877.  
  878.  
  879. /* returns true, if a expansion is needed.
  880.  * Rules are given by LaTeX */ 
  881. bool LyXText::HfillExpansion(Row *row_ptr, int pos)
  882. {
  883.    /* by the way, is it a hfill? */ 
  884.    if (!row_ptr->par->IsHfill(pos))
  885.      return false;
  886.    
  887.    /* at the end of a row it does not count */ 
  888.    if (pos >= RowLast(row_ptr))
  889.      return false;
  890.    
  891.    /* at the beginning of a row it does not count, if it is not 
  892.     * the first row of a paragaph */ 
  893.    if (!row_ptr->pos)
  894.      return true;
  895.    
  896.    /* in some labels  it does not count */ 
  897.    if ( lyxstyle.Style(parameters->textclass, row_ptr->par->GetLayout())->margintype != MARGIN_MANUAL &&
  898.        pos < BeginningOfMainBody(row_ptr->par))
  899.      return false; 
  900.    
  901.    /* if there is anything between the first char of the row and
  902.     * the sepcified position that is not a newline and not a hfill,
  903.     * the hfill will count, otherwise not */ 
  904.    
  905.    int i = row_ptr->pos;
  906.    while (i < pos && (row_ptr->par->IsNewline(i)
  907.               || row_ptr->par->IsHfill(i)))
  908.      i++;
  909.    
  910.    return (i != pos);
  911. }
  912.  
  913.  
  914. void LyXText::SetHeightOfRow(Row *row_ptr)
  915. {
  916.     /* get the maximum ascent and the maximum descent */
  917.    int asc, maxasc, desc, maxdesc, pos_end, pos, labeladdon;
  918.    float layoutasc = 0;
  919.    float layoutdesc = 0;
  920.    float tmptop = 0;
  921.    LyXParagraph *par, *firstpar;
  922.    LyXFont tmpfont;
  923.    Inset *tmpinset;
  924.  
  925.    /* this must not happen before the currentrow for clear reasons.
  926.       so the trick is just to set the current row onto this row */
  927.    long unused_y;
  928.    GetRow(row_ptr->par, row_ptr->pos, unused_y);
  929.  
  930.    /* ok , let us initialize the maxasc and maxdesc value. 
  931.     * This depends in LaTeX of the font of the last character
  932.     * in the paragraph. The hack below is necessary because
  933.     * of the possibility of open footnotes */
  934.  
  935.    /* Correction: only the fontsize count. The other properties
  936.       are taken from the layoutfont. Nicer on the screen :) */
  937.    
  938.    par = row_ptr->par->LastPhysicalPar();
  939.    firstpar = row_ptr->par->FirstPhysicalPar();
  940.    
  941.    LyXLayout *layout = lyxstyle.Style(parameters->textclass, firstpar->GetLayout());
  942.    
  943.    LyXFont font = GetFont(par, par->Last()-1);
  944.    LyXFont::FONT_SIZE size = font.size();
  945.    font = GetFont(par, -1);
  946.    font.setSize(size);
  947.  
  948.    LyXFont labelfont = GetFont(par, -2);
  949.  
  950.    maxasc = int(font.maxAscent() *
  951.            layout->spacing.getValue() *
  952.            parameters->spacing.getValue());
  953.    maxdesc = int(font.maxDescent() *
  954.             layout->spacing.getValue() *
  955.             parameters->spacing.getValue());
  956.  
  957.    pos_end = RowLast(row_ptr);
  958.    
  959.    labeladdon = 0;
  960.  
  961.    // Check if any insets are larger
  962.    for (pos = row_ptr->pos; pos <= pos_end; pos++) {
  963.       if (row_ptr->par->GetChar(pos) == LYX_META_INSET) {
  964.      tmpfont = GetFont(row_ptr->par, pos);
  965.          tmpinset = row_ptr->par->GetInset(pos);
  966.          if (tmpinset) {
  967.             asc = tmpinset->Ascent(tmpfont);
  968.             desc = tmpinset->Descent(tmpfont);
  969.         if (asc > maxasc) 
  970.           maxasc = asc;
  971.         if (desc > maxdesc)
  972.           maxdesc = desc;
  973.      }
  974.       }
  975.    }
  976.  
  977.    // Check if any custom fonts are larger (Asger)
  978.    // This is not completely correct, but we can live with the small,
  979.    // cosmetic error for now.
  980.    LyXFont::FONT_SIZE maxsize = row_ptr->par->HighestFontInRange(row_ptr->pos, pos_end);
  981.    if (maxsize > font.size()) {
  982.     font.setSize(maxsize);
  983.  
  984.     asc = font.maxAscent();
  985.     desc = font.maxDescent();
  986.     if (asc > maxasc) 
  987.         maxasc = asc;
  988.     if (desc > maxdesc)
  989.         maxdesc = desc;
  990.    }
  991.  
  992.    /* table stuff -- begin*/
  993.    if (row_ptr->par->table){
  994.      // stretch the rows a bit
  995.       maxasc += 1;
  996.       maxdesc +=1;
  997.    }
  998.    /* table stuff -- end*/
  999.  
  1000.    // This is nicer with box insets:
  1001.    maxasc++;
  1002.    maxdesc++;
  1003.  
  1004.    row_ptr->ascent_of_text = maxasc;
  1005.    
  1006.    /* is it a top line? */ 
  1007.    if (row_ptr->pos == 0
  1008.        && row_ptr->par == firstpar) {
  1009.       
  1010.       /* some parksips VERY EASY IMPLEMENTATION */ 
  1011.       if (parameters->paragraph_separation == LYX_PARSEP_SKIP) {
  1012.      if (layout->isParagraph()
  1013.          && firstpar->GetDepth() == 0
  1014.          && firstpar->Previous())
  1015.         maxasc += parameters->getDefSkip().inPixels();
  1016.      else if (firstpar->Previous()
  1017.           && lyxstyle.Style(parameters->textclass,
  1018.                firstpar->Previous()->GetLayout())->isParagraph()
  1019.           && firstpar->Previous()->GetDepth() == 0)
  1020.        // is it right to use defskip here too? (AS)
  1021.        maxasc += parameters->getDefSkip().inPixels();
  1022.       }
  1023.       
  1024.       /* the paper margins */ 
  1025.       if (!row_ptr->par->previous)
  1026.            maxasc += LYX_PAPER_MARGIN;
  1027.       
  1028.       /* add the vertical spaces, that the user added */
  1029.       if (firstpar->added_space_top.kind() != VSpace::NONE)
  1030.            maxasc += int(firstpar->added_space_top.inPixels());
  1031.       
  1032.       /* do not forget the DTP-lines! 
  1033.        * there height depends on the font of the nearest character */
  1034.       if (firstpar->line_top)
  1035.            maxasc += 2 * GetFont(firstpar, 0).ascent('x');
  1036.       
  1037.       /* and now the pagebreaks */ 
  1038.       if (firstpar->pagebreak_top)
  1039.            maxasc += 3 * DefaultHeight();
  1040.       
  1041.       /*  this is special code for the chapter, since the label of this
  1042.        * layout is printed in an extra row */ 
  1043.       if (layout->labeltype == LABEL_COUNTER_CHAPTER
  1044.       && parameters->secnumdepth>=0) {
  1045.           labeladdon = int(labelfont.maxDescent() *
  1046.                   layout->spacing.getValue() *
  1047.                   parameters->spacing.getValue())
  1048.               + int(labelfont.maxAscent() *
  1049.                    layout->spacing.getValue() *
  1050.                    parameters->spacing.getValue());
  1051.       }
  1052.       
  1053.       /* sepcial code for the top label */ 
  1054.       if ((layout->labeltype == LABEL_TOP_ENVIRONMENT
  1055.        || layout->labeltype == LABEL_BIBLIO
  1056.        || layout->labeltype == LABEL_CENTERED_TOP_ENVIRONMENT)
  1057.       && row_ptr->par->IsFirstInSequence()) {
  1058.      labeladdon = int(
  1059.          (labelfont.maxAscent() *
  1060.           layout->spacing.getValue() *
  1061.           parameters->spacing.getValue())
  1062.          +(labelfont.maxDescent() *
  1063.            layout->spacing.getValue() *
  1064.            parameters->spacing.getValue())
  1065.          + layout->topsep * DefaultHeight()
  1066.          + layout->labelbottomsep *  DefaultHeight());
  1067.       }
  1068.    
  1069.       /* and now the layout spaces, for example before and after a section, 
  1070.        * or between the items of a itemize or enumerate environment */ 
  1071.       
  1072.       if (!firstpar->pagebreak_top) {
  1073.      LyXParagraph *prev = row_ptr->par->Previous();
  1074.      if (prev)
  1075.         prev = row_ptr->par->DepthHook(row_ptr->par->GetDepth());
  1076.      if (prev && prev->GetLayout() == firstpar->GetLayout()
  1077.          && prev->GetDepth() == firstpar->GetDepth()
  1078.          && prev->GetLabelWidthString() == firstpar->GetLabelWidthString())
  1079.        {
  1080.           layoutasc = (layout->itemsep * DefaultHeight());
  1081.        }
  1082.      else if (row_ptr->previous) {
  1083.         tmptop = layout->topsep;
  1084.         
  1085.         if (row_ptr->previous->par->GetDepth() >= row_ptr->par->GetDepth())
  1086.            tmptop-=lyxstyle.Style(parameters->textclass, row_ptr->previous->par->GetLayout())->bottomsep;
  1087.         
  1088.         if (tmptop > 0)
  1089.            layoutasc = (tmptop * DefaultHeight());
  1090.      }
  1091.      else if (row_ptr->par->line_top){
  1092.         tmptop = layout->topsep;
  1093.         
  1094.         if (tmptop > 0)
  1095.            layoutasc = (tmptop * DefaultHeight());
  1096.      }
  1097.      
  1098.      prev = row_ptr->par->DepthHook(row_ptr->par->GetDepth()-1);
  1099.      if (prev)  {
  1100.         maxasc += int(lyxstyle.Style(parameters->textclass,
  1101.                      prev->GetLayout())->parsep * DefaultHeight());
  1102.      }
  1103.      else {
  1104.         if (firstpar->Previous()
  1105.             && firstpar->Previous()->GetDepth() == 0
  1106.             && firstpar->Previous()->GetLayout() != firstpar->GetLayout()) {
  1107.            /* avoid parsep */ 
  1108.         }
  1109.         else if (firstpar->Previous()){
  1110.            maxasc += int(layout->parsep * DefaultHeight());
  1111.         }
  1112.      }
  1113.       }
  1114.    }
  1115.    
  1116.    /* is it a bottom line? */ 
  1117.    if (row_ptr->par->ParFromPos(RowLast(row_ptr) + 1) == par
  1118.        && (!row_ptr->next || row_ptr->next->par != row_ptr->par)) {     
  1119.       
  1120.       /* the paper margins */ 
  1121.       if (!par->next)
  1122.         maxdesc += LYX_PAPER_MARGIN;
  1123.     
  1124.       /* add the vertical spaces, that the user added */
  1125.       if (firstpar->added_space_bottom.kind() != VSpace::NONE)
  1126.         maxdesc += int(firstpar->added_space_bottom.inPixels());
  1127.       
  1128.       /* do not forget the DTP-lines! 
  1129.        * there height depends on the font of the nearest character */
  1130.       if (firstpar->line_bottom)
  1131.         maxdesc += 2 * (GetFont(par, par->Last()-1).ascent('x'));
  1132.       
  1133.       /* and now the pagebreaks */
  1134.       if (firstpar->pagebreak_bottom)
  1135.         maxdesc += 3 * DefaultHeight();
  1136.       
  1137.       /* and now the layout spaces, for example before and after a section, 
  1138.        * or between the items of a itemize or enumerate environment */
  1139.       if (!firstpar->pagebreak_bottom && row_ptr->par->Next()) {
  1140.          LyXParagraph *nextpar = row_ptr->par->Next();
  1141.          LyXParagraph *comparepar = row_ptr->par;
  1142.          float usual = 0;
  1143.          float  unusual = 0;
  1144.          
  1145.          if (comparepar->GetDepth() > nextpar->GetDepth()) {
  1146.         usual = (lyxstyle.Style(parameters->textclass, comparepar->GetLayout())->bottomsep * DefaultHeight());
  1147.         comparepar = comparepar->DepthHook(nextpar->GetDepth());
  1148.         if (comparepar->GetLayout()!=nextpar->GetLayout()
  1149.             || nextpar->GetLabelWidthString() != 
  1150.                 comparepar->GetLabelWidthString())
  1151.           unusual = (lyxstyle.Style(parameters->textclass, comparepar->GetLayout())->bottomsep * DefaultHeight());
  1152.         
  1153.         if (unusual > usual)
  1154.           layoutdesc = unusual;
  1155.         else
  1156.           layoutdesc = usual;
  1157.          }
  1158.          else if (comparepar->GetDepth() ==  nextpar->GetDepth()) {
  1159.         
  1160.         if (comparepar->GetLayout()!= nextpar->GetLayout()
  1161.             || nextpar->GetLabelWidthString() !=
  1162.             comparepar->GetLabelWidthString())
  1163.           layoutdesc = int(lyxstyle.Style(parameters->textclass, comparepar->GetLayout())->bottomsep * DefaultHeight());
  1164.          }
  1165.       }
  1166.        }
  1167.    
  1168.    /* incalculate the layout spaces */ 
  1169.    maxasc += int(layoutasc * 2 / (2 + firstpar->GetDepth()));
  1170.    maxdesc += int(layoutdesc * 2 / (2 + firstpar->GetDepth()));
  1171.  
  1172.    /* table stuff -- begin*/
  1173.    if (row_ptr->par->table){
  1174.       maxasc += row_ptr->par->table->
  1175.     AdditionalHeight(NumberOfCell(row_ptr->par, row_ptr->pos));
  1176.    }
  1177.    /* table stuff -- end*/
  1178.    
  1179.    /* calculate the new height of the text */ 
  1180.    height -= row_ptr->height;
  1181.    
  1182.    row_ptr->height=maxasc+maxdesc+labeladdon;
  1183.    row_ptr->baseline=maxasc+labeladdon;
  1184.    
  1185.    height += row_ptr->height;
  1186. }
  1187.  
  1188.  
  1189. /* Appends the implicit specified paragraph behind the specified row,
  1190.  * start at the implicit given position */
  1191. void LyXText::AppendParagraph(Row *row)
  1192. {
  1193.    int z;
  1194.    Row *tmprow;
  1195.    bool not_ready = true;
  1196.    
  1197.    // Get the width of the row
  1198.    z = row->pos;
  1199.  
  1200.    // The last character position of a paragraph is an invariant so we can 
  1201.    // safely get it here. (Asger)
  1202.    int lastposition = row->par->Last();
  1203.  
  1204.    do {
  1205.       // Get the next breakpoint
  1206.       z = NextBreakPoint(row, paperwidth);
  1207.       
  1208.       tmprow = row;
  1209.  
  1210.       // Insert the new row
  1211.       if (z < lastposition) {
  1212.      z++;
  1213.      InsertRow(row, row->par, z);
  1214.      row = row->next;
  1215.  
  1216.      row->height = 0;
  1217.       } else
  1218.      not_ready = false;
  1219.       
  1220.       // Set the dimensions of the row
  1221.       tmprow->fill = Fill(tmprow, paperwidth);
  1222.       SetHeightOfRow(tmprow);
  1223.  
  1224.    } while (not_ready);
  1225. }
  1226.  
  1227.  
  1228. void LyXText::BreakAgain(Row *row)
  1229. {
  1230.    int z;
  1231.    char not_ready;
  1232.    z = row->pos;
  1233.    Row *tmprow, *tmprow2;
  1234.    
  1235.    not_ready = 1;
  1236.    
  1237.    do  {
  1238.       /* get the next breakpoint */
  1239.       z = NextBreakPoint(row, paperwidth);
  1240.       
  1241.       tmprow = row;
  1242.       
  1243.       if (z < row->par->Last() ) {
  1244.      if (!row->next || (row->next && row->next->par != row->par)) {
  1245.         /* insert a new row */ 
  1246.         z++;
  1247.         InsertRow(row, row->par, z);
  1248.         row = row->next;
  1249.         row->height = 0;
  1250.      }
  1251.      else  {
  1252.         row=row->next;
  1253.         z++;
  1254.         if (row->pos == z)
  1255.           not_ready = 0;           /* the rest will not change  */
  1256.         else {
  1257.            row->pos = z;
  1258.         }
  1259.      }
  1260.       }
  1261.       else {
  1262.      /* if there are some rows too much, delete them */
  1263.      /* only if you broke the whole paragraph! */ 
  1264.      tmprow2 = row;
  1265.      while (tmprow2->next && tmprow2->next->par == row->par) {
  1266.         tmprow2 = tmprow2->next;
  1267.      }
  1268.      while (tmprow2 != row) {
  1269.         tmprow2 = tmprow2->previous;
  1270.         RemoveRow(tmprow2->next);
  1271.      }
  1272.      not_ready = 0;
  1273.       }
  1274.        
  1275.       /* set the dimensions of the row */ 
  1276.       tmprow->fill = Fill(tmprow, paperwidth);
  1277.       SetHeightOfRow(tmprow);
  1278.    } while (not_ready);
  1279. }
  1280.  
  1281.  
  1282. /* this is just a little changed version of break again */ 
  1283. void LyXText::BreakAgainOneRow(Row *row)
  1284. {
  1285.    int z;
  1286.    char not_ready;
  1287.    z = row->pos;
  1288.    Row *tmprow, *tmprow2;
  1289.    
  1290.    not_ready = 1;
  1291.    
  1292.    /* get the next breakpoint */
  1293.    z = NextBreakPoint(row, paperwidth);
  1294.    
  1295.    tmprow = row;
  1296.    
  1297.    if (z < row->par->Last() ) {
  1298.       if (!row->next || (row->next && row->next->par != row->par)) {
  1299.      /* insert a new row */ 
  1300.      z++;
  1301.      InsertRow(row, row->par, z);
  1302.      row = row->next;
  1303.      row->height = 0;
  1304.       }
  1305.       else  {
  1306.      row=row->next;
  1307.      z++;
  1308.      if (row->pos == z)
  1309.        not_ready = 0;           /* the rest will not change  */
  1310.      else {
  1311.         row->pos = z;
  1312.      }
  1313.       }
  1314.    }
  1315.    else {
  1316.       /* if there are some rows too much, delete them */
  1317.       /* only if you broke the whole paragraph! */ 
  1318.       tmprow2 = row;
  1319.       while (tmprow2->next && tmprow2->next->par == row->par) {
  1320.      tmprow2 = tmprow2->next;
  1321.       }
  1322.       while (tmprow2 != row) {
  1323.      tmprow2 = tmprow2->previous;
  1324.      RemoveRow(tmprow2->next);
  1325.       }
  1326.       not_ready = 0;
  1327.    }
  1328.    
  1329.    /* set the dimensions of the row */ 
  1330.    tmprow->fill = Fill(tmprow, paperwidth);
  1331.    SetHeightOfRow(tmprow);
  1332. }
  1333.  
  1334.  
  1335. void LyXText::BreakParagraph(char keep_layout)
  1336. {
  1337.    LyXLayout *layout = lyxstyle.Style(parameters->textclass,
  1338.                       cursor.par->GetLayout());
  1339.    
  1340.    /* table stuff -- begin*/
  1341.    if (cursor.par->table) {
  1342.        // breaking of tables is only allowed at the beginning or the end */
  1343.        if (cursor.pos && cursor.pos < cursor.par->last &&
  1344.            !cursor.par->table->ShouldBeVeryLastCell(NumberOfCell(cursor.par, cursor.pos)))
  1345.            return; /* no breaking of tables allowed */ 
  1346.    }
  1347.    /* table stuff -- end*/
  1348.  
  1349.    /* this is only allowed, if the current paragraph is not empty or caption*/ 
  1350.    if ((cursor.par->Last() <= 0 && !cursor.par->IsDummy())
  1351.        && 
  1352.        layout->labeltype!=LABEL_SENSITIVE)
  1353.      return;
  1354.  
  1355.    SetUndo(Undo::INSERT, 
  1356.        cursor.par->ParFromPos(cursor.pos)->previous, 
  1357.        cursor.par->ParFromPos(cursor.pos)->next); 
  1358.  
  1359.    /* table stuff -- begin*/
  1360.    if (cursor.par->table) {
  1361.        int cell = NumberOfCell(cursor.par, cursor.pos);
  1362.        if (cursor.par->table->ShouldBeVeryLastCell(cell))
  1363.            SetCursor(cursor.par,cursor.par->last);
  1364.    }
  1365.    /* table stuff -- end*/
  1366.    /* please break alway behind a space */ 
  1367.    if (cursor.pos < cursor.par->Last()
  1368.        && cursor.par->IsLineSeparator(cursor.pos))
  1369.      cursor.pos++;
  1370.    
  1371.    /* break the paragraph */
  1372.    if (keep_layout)
  1373.      keep_layout = 2;
  1374.    else    
  1375.      keep_layout = layout->isEnvironment();
  1376.    cursor.par->BreakParagraph(cursor.pos, keep_layout);
  1377.  
  1378.    /* table stuff -- begin*/
  1379.    if (cursor.par->table){
  1380.      // the table should stay with the contents
  1381.      if (!cursor.pos){
  1382.        cursor.par->Next()->table = cursor.par->table;
  1383.        cursor.par->table = NULL;
  1384.      }
  1385.    }
  1386.    /* table stuff -- end*/
  1387.  
  1388.    /* well this is the caption hack since one caption is really enough */
  1389.    if (layout->labeltype == LABEL_SENSITIVE){
  1390.      if (!cursor.pos)
  1391.        cursor.par->SetLayout(0); /* set the new paragraph to standard-layout */
  1392.      else
  1393.        cursor.par->Next()->SetLayout(0); /* set the new paragraph to standard-layout */
  1394.      
  1395.    }
  1396.    
  1397.    /* if the cursor is at the beginning of a row without prior newline, 
  1398.     *  move one row up! 
  1399.     * This touches only the screen-update. Otherwise we would may have
  1400.     * an empty row on the screen */
  1401.    if (cursor.pos && !cursor.row->par->IsNewline(cursor.row->pos -1) &&
  1402.        cursor.row->pos == cursor.pos) {
  1403.      CursorLeft();
  1404.    } 
  1405.    
  1406.    status = LyXText::NEED_MORE_REFRESH;
  1407.    refresh_row = cursor.row;
  1408.    refresh_y = cursor.y - cursor.row->baseline;
  1409.    
  1410.    /* Do not forget the special right address boxes */
  1411.    if (layout->margintype == MARGIN_RIGHT_ADDRESS_BOX) {
  1412.       while (refresh_row->previous &&
  1413.          refresh_row->previous->par == refresh_row->par) {
  1414.         refresh_row = refresh_row->previous;
  1415.         refresh_y -= refresh_row->height;
  1416.          }
  1417.    }
  1418.    RemoveParagraph(cursor.row);
  1419.    
  1420.    /* set the dimensions of the cursor row */
  1421.    cursor.row->fill = Fill(cursor.row, paperwidth);
  1422.  
  1423.    SetHeightOfRow(cursor.row);
  1424.    
  1425.    while (!cursor.par->Next()->table && cursor.par->Next()->Last()
  1426.       && cursor.par->Next()->IsNewline(0))
  1427.      cursor.par->Next()->Erase(0);
  1428.    
  1429.    InsertParagraph(cursor.par->Next(), cursor.row);
  1430.  
  1431.    UpdateCounters(cursor.row->previous);
  1432.    
  1433.    /* this check is necessary. Otherwise the new empty paragraph will
  1434.     * be deleted automatically. And it is more friendly for the user! */ 
  1435.    if (cursor.pos)
  1436.      SetCursor(cursor.par->Next(), 0);
  1437.    else
  1438.      SetCursor(cursor.par, 0);
  1439.    
  1440.    if (cursor.row->next)
  1441.      BreakAgain(cursor.row->next);
  1442.  
  1443.    need_break_row = NULL;
  1444. }
  1445.  
  1446.  
  1447. void LyXText::OpenFootnote()
  1448. {
  1449.    LyXParagraph *par, *endpar,*tmppar;
  1450.    Row *row;
  1451.    
  1452.    par = cursor.par->ParFromPos(cursor.pos);
  1453.    
  1454.    /* if there is no footnote in this paragraph, just return. */ 
  1455.    if (!par->next
  1456.        || par->next->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
  1457.      return;
  1458.    
  1459.    /* ok, move the cursor right before the footnote */ 
  1460.    
  1461.    /* just a little faster than using CursorRight() */
  1462.    for (cursor.pos=0; cursor.par->ParFromPos(cursor.pos)!=par; cursor.pos++);
  1463.    /* now the cursor is at the beginning of the physical par */
  1464.    SetCursor(cursor.par, cursor.pos + cursor.par->ParFromPos(cursor.pos)->last);
  1465.    
  1466.    /* the cursor must be exactly before the footnote */ 
  1467.    par = cursor.par->ParFromPos(cursor.pos);
  1468.    
  1469.    status = LyXText::NEED_MORE_REFRESH;
  1470.    refresh_row = cursor.row;
  1471.    refresh_y = cursor.y - cursor.row->baseline;
  1472.    
  1473.    tmppar = cursor.par;
  1474.    endpar = cursor.par->Next();
  1475.    row = cursor.row;
  1476.    
  1477.    tmppar->OpenFootnote(cursor.pos);
  1478.    RemoveParagraph(row);
  1479.    /* set the dimensions of the cursor row */
  1480.    row->fill = Fill(row, paperwidth);
  1481.    SetHeightOfRow(row);
  1482.    tmppar = tmppar->Next();
  1483.    
  1484.    while (tmppar != endpar) {
  1485.       if (tmppar) {
  1486.      InsertParagraph(tmppar, row);
  1487.      while (row->next && row->next->par == tmppar)
  1488.        row = row->next;
  1489.      tmppar = tmppar->Next();
  1490.       }
  1491.    }
  1492.    SetCursor(par->next, 0);
  1493.    sel_cursor = cursor;
  1494. }
  1495.    
  1496.  
  1497. /* table stuff -- begin*/
  1498.  
  1499. void LyXText::TableFeatures(int feature, LString val)
  1500. {
  1501.     int
  1502.         actCell;
  1503.     
  1504.     if (!cursor.par->table)
  1505.         return; /* this should never happen */
  1506.   
  1507.     actCell = NumberOfCell(cursor.par, cursor.pos);
  1508.     SetUndo(Undo::FINISH, 
  1509.             cursor.par->ParFromPos(cursor.pos)->previous, 
  1510.             cursor.par->ParFromPos(cursor.pos)->next); 
  1511.  
  1512.     switch (feature){
  1513.       case LyXTable::SET_PWIDTH:
  1514.           cursor.par->table->SetPWidth(actCell,val);
  1515.           break;
  1516.       default:
  1517.           break;
  1518.     }
  1519.     RedoParagraph();
  1520. }
  1521.  
  1522.  
  1523. void LyXText::TableFeatures(int feature)
  1524. {
  1525.     int
  1526.         setLines = 0,
  1527.         setAlign = LYX_ALIGN_LEFT,
  1528.         lineSet,
  1529.         actCell;
  1530.     bool
  1531.         what;
  1532.     
  1533.     if (!cursor.par->table)
  1534.         return; /* this should never happen */
  1535.   
  1536.     actCell = NumberOfCell(cursor.par, cursor.pos);
  1537.     SetUndo(Undo::FINISH, 
  1538.             cursor.par->ParFromPos(cursor.pos)->previous, 
  1539.             cursor.par->ParFromPos(cursor.pos)->next); 
  1540.  
  1541.     switch (feature){
  1542.       case LyXTable::ALIGN_LEFT:
  1543.           setAlign=LYX_ALIGN_LEFT;
  1544.           break;
  1545.       case LyXTable::ALIGN_RIGHT:
  1546.           setAlign=LYX_ALIGN_RIGHT;
  1547.           break;
  1548.       case LyXTable::ALIGN_CENTER:
  1549.           setAlign=LYX_ALIGN_CENTER;
  1550.           break;
  1551.       default:
  1552.           break;
  1553.     }
  1554.     switch (feature){
  1555.       case LyXTable::APPEND_ROW: {
  1556.       int pos = cursor.pos;
  1557.           /* move to the next row */
  1558.           int cell_org = actCell;
  1559.           int cell = cell_org;
  1560.  
  1561.           // if there is a ContRow following this row I have to add
  1562.           // the row after the ContRow's
  1563.           if ((pos < cursor.par->Last()) &&
  1564.               cursor.par->table->RowHasContRow(cell_org)) {
  1565.               while((pos < cursor.par->Last()) &&
  1566.                     !cursor.par->table->IsContRow(cell)) {
  1567.                   while (pos < cursor.par->Last() &&
  1568.                          !cursor.par->IsNewline(pos))
  1569.                       pos++;
  1570.                   if (pos < cursor.par->Last())
  1571.                       pos++;
  1572.                   cell++;
  1573.               }
  1574.               while((pos < cursor.par->Last()) &&
  1575.                     cursor.par->table->IsContRow(cell)) {
  1576.                   while (pos < cursor.par->Last() &&
  1577.                          !cursor.par->IsNewline(pos))
  1578.                       pos++;
  1579.                   if (pos < cursor.par->Last())
  1580.                       pos++;
  1581.                   cell++;
  1582.               }
  1583.               cell_org = --cell;
  1584.               if (pos < cursor.par->Last())
  1585.                   pos--;
  1586.           }
  1587.           while (pos < cursor.par->Last() && 
  1588.                  (cell == cell_org || !cursor.par->table->IsFirstCell(cell))){
  1589.               while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
  1590.                   pos++;
  1591.               if (pos < cursor.par->Last())
  1592.                   pos++;
  1593.               cell++;
  1594.           }
  1595.         
  1596.           /* insert the new cells */ 
  1597.           int number = cursor.par->table->NumberOfCellsInRow(cell_org);
  1598.           int i;
  1599.           for (i=0; i<number; i++)
  1600.               cursor.par->InsertChar(pos, LYX_META_NEWLINE);
  1601.         
  1602.           /* append the row into the table */
  1603.           cursor.par->table->AppendRow(cell_org);
  1604.           RedoParagraph();
  1605.           return;
  1606.       }
  1607.       case LyXTable::APPEND_CONT_ROW: {
  1608.           int pos = cursor.pos;
  1609.           /* move to the next row */
  1610.           int cell_org = actCell;
  1611.           int cell = cell_org;
  1612.  
  1613.           // if there is already a controw but not for this cell
  1614.           // the AppendContRow sets only the right values but does
  1615.           // not actually add a row
  1616.           if (cursor.par->table->RowHasContRow(cell_org) &&
  1617.               (cursor.par->table->CellHasContRow(cell_org)<0)) {
  1618.               cursor.par->table->AppendContRow(cell_org);
  1619.               RedoParagraph();
  1620.               return;
  1621.           }
  1622.           while (pos < cursor.par->Last() && 
  1623.                  (cell == cell_org
  1624.                   || !cursor.par->table->IsFirstCell(cell))){
  1625.               while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
  1626.                   pos++;
  1627.               if (pos < cursor.par->Last())
  1628.                   pos++;
  1629.               cell++;
  1630.           }
  1631.         
  1632.           /* insert the new cells */ 
  1633.           int number = cursor.par->table->NumberOfCellsInRow(cell_org);
  1634.           int i;
  1635.           for (i=0; i<number; i++)
  1636.               cursor.par->InsertChar(pos, LYX_META_NEWLINE);
  1637.         
  1638.           /* append the row into the table */
  1639.           cursor.par->table->AppendContRow(cell_org);
  1640.           RedoParagraph();
  1641.           return;
  1642.       }
  1643.       case LyXTable::APPEND_COLUMN: { 
  1644.           int pos = 0;
  1645.           int cell_org = actCell;
  1646.           int cell = 0;
  1647.           do{
  1648.               if (pos && (cursor.par->IsNewline(pos-1))){
  1649.                   if (cursor.par->table->AppendCellAfterCell(cell_org, cell)){
  1650.                       cursor.par->InsertChar(pos, LYX_META_NEWLINE);
  1651.                       if (pos<=cursor.pos)
  1652.                           cursor.pos++;
  1653.                       pos++;
  1654.                   }
  1655.                   cell++;
  1656.               }
  1657.               pos++;
  1658.           } while (pos<= cursor.par->Last());
  1659.           /* remember that the very last cell doesn't end with a newline.
  1660.              This saves one byte memory per table ;-) */ 
  1661.           if (cursor.par->table->AppendCellAfterCell(cell_org, cell))
  1662.               cursor.par->InsertChar(cursor.par->Last(), LYX_META_NEWLINE);
  1663.         
  1664.           /* append the column into the table */ 
  1665.           cursor.par->table->AppendColumn(cell_org);
  1666.         
  1667.           RedoParagraph();
  1668.           return;
  1669.       }
  1670.       case LyXTable::DELETE_ROW:
  1671.           RemoveTableRow(&cursor);
  1672.           RedoParagraph();
  1673.           return;
  1674.     
  1675.       case LyXTable::DELETE_COLUMN: {
  1676.           int pos = 0;
  1677.           int cell_org = actCell;
  1678.           int cell = 0;
  1679.           do{
  1680.               if (!pos || (cursor.par->IsNewline(pos-1))){
  1681.                   if (cursor.par->table->DeleteCellIfColumnIsDeleted(cell, cell_org)){
  1682.                       // delete one cell
  1683.                       while (pos < cursor.par->Last() && !cursor.par->IsNewline(pos))
  1684.                           cursor.par->Erase(pos);
  1685.                       if (pos < cursor.par->Last())
  1686.                           cursor.par->Erase(pos);
  1687.                       else 
  1688.                           cursor.par->Erase(pos - 1); // the missing newline at the end of a table
  1689.                       pos--; // because of pos++ below
  1690.                   }   
  1691.                   cell++;
  1692.               }
  1693.               pos++;
  1694.           } while (pos<= cursor.par->Last());
  1695.         
  1696.           /* delete the column from the table */ 
  1697.           cursor.par->table->DeleteColumn(cell_org);
  1698.         
  1699.           /* set the cursor to the beginning of the table, where else? */ 
  1700.           cursor.pos = 0;
  1701.           RedoParagraph();
  1702.           return;
  1703.       }
  1704.       case LyXTable::TOGGLE_LINE_TOP:
  1705.           lineSet = !cursor.par->table->TopLine(actCell);
  1706.           if (!selection){
  1707.               cursor.par->table->SetTopLine(actCell,lineSet);
  1708.           } else {
  1709.               int i,n=-1,m=-2;
  1710.               for (i=sel_start_cursor.pos; i<=sel_end_cursor.pos; i++){
  1711.                   if ((n=NumberOfCell(sel_start_cursor.par,i)) != m) {
  1712.                       cursor.par->table->SetTopLine(n,lineSet);
  1713.                       m = n;
  1714.                   }
  1715.               }
  1716.           }
  1717.           RedoParagraph();
  1718.           return;
  1719.     
  1720.       case LyXTable::TOGGLE_LINE_BOTTOM:
  1721.           lineSet = !cursor.par->table->BottomLine(actCell);
  1722.           if (!selection){
  1723.               cursor.par->table->SetBottomLine(actCell,lineSet);
  1724.           } else {
  1725.               int i,n=-1,m=-2;
  1726.               for (i=sel_start_cursor.pos; i<=sel_end_cursor.pos; i++){
  1727.                   if ((n=NumberOfCell(sel_start_cursor.par,i)) != m) {
  1728.                       cursor.par->table->SetBottomLine(n,lineSet);
  1729.                       m = n;
  1730.                   }
  1731.               }
  1732.           }
  1733.           RedoParagraph();
  1734.           return;
  1735.         
  1736.       case LyXTable::TOGGLE_LINE_LEFT:
  1737.           lineSet = !cursor.par->table->LeftLine(actCell);
  1738.           if (!selection){
  1739.               cursor.par->table->SetLeftLine(actCell,lineSet);
  1740.           } else {
  1741.               int i,n=-1,m=-2;
  1742.               for (i=sel_start_cursor.pos; i<=sel_end_cursor.pos; i++){
  1743.                   if ((n=NumberOfCell(sel_start_cursor.par,i)) != m) {
  1744.                       cursor.par->table->SetLeftLine(n,lineSet);
  1745.                       m = n;
  1746.                   }
  1747.               }
  1748.           }
  1749.           RedoParagraph();
  1750.           return;
  1751.  
  1752.       case LyXTable::TOGGLE_LINE_RIGHT:
  1753.           lineSet = !cursor.par->table->RightLine(actCell);
  1754.           if (!selection){
  1755.               cursor.par->table->SetRightLine(actCell,lineSet);
  1756.           } else {
  1757.               int i,n=-1,m=-2;
  1758.               for (i=sel_start_cursor.pos; i<=sel_end_cursor.pos; i++){
  1759.                   if ((n=NumberOfCell(sel_start_cursor.par,i)) != m) {
  1760.                       cursor.par->table->SetRightLine(n,lineSet);
  1761.                       m = n;
  1762.                   }
  1763.               }
  1764.           }
  1765.           RedoParagraph();
  1766.           return;
  1767.     
  1768.       case LyXTable::ALIGN_LEFT:
  1769.       case LyXTable::ALIGN_RIGHT:
  1770.       case LyXTable::ALIGN_CENTER:
  1771.           if (!selection){
  1772.               cursor.par->table->SetAlignment(actCell,setAlign);
  1773.           } else {
  1774.               int i,n=-1,m=-2;
  1775.               for (i=sel_start_cursor.pos; i<=sel_end_cursor.pos; i++){
  1776.                   if ((n=NumberOfCell(sel_start_cursor.par,i)) != m) {
  1777.                       cursor.par->table->SetAlignment(n,setAlign);
  1778.                       m = n;
  1779.                   }
  1780.               }
  1781.           }
  1782.           RedoParagraph();
  1783.           return;
  1784.         
  1785.       case LyXTable::DELETE_TABLE:
  1786.           SetCursorIntern(cursor.par, 0);
  1787.           delete cursor.par->table;
  1788.           cursor.par->table = NULL;
  1789.           // temporary: Should put table in simple_cut_buffer (with before and after
  1790.           // dummy-paragraph !! 
  1791.           // not necessar anymore with UNDO :)
  1792.           int i;
  1793.           for (i = cursor.par->last-1; i>=0; i--)
  1794.           cursor.par->Erase(i);
  1795.           RedoParagraph();
  1796.           return;
  1797.         
  1798.       case LyXTable::MULTICOLUMN: {
  1799.           int number = 0;
  1800.           // check wether we are completly in a multicol
  1801.           int multicol = cursor.par->table->IsMultiColumn(actCell);
  1802.           if (multicol && selection && sel_start_cursor.row == sel_end_cursor.row){
  1803.           multicol = NumberOfCell(sel_start_cursor.par, sel_start_cursor.pos)
  1804.                   == NumberOfCell(sel_end_cursor.par, sel_end_cursor.pos);
  1805.           }
  1806.  
  1807.           if (multicol){
  1808.           int newlines = cursor.par->table->UnsetMultiColumn(actCell);
  1809.           int pos = cursor.pos;
  1810.           while (pos<cursor.par->Last() && !cursor.par->IsNewline(pos))
  1811.                   pos++;
  1812.           for (;newlines;newlines--)
  1813.                   cursor.par->InsertChar(pos, LYX_META_NEWLINE);
  1814.           RedoParagraph();
  1815.           return;
  1816.           }
  1817.           else {
  1818.           // selection must be in one row (or no selection)
  1819.           if (!selection){
  1820.                   cursor.par->table->SetMultiColumn(NumberOfCell(cursor.par,
  1821.                                                                  cursor.pos),
  1822.                                                     1);
  1823.                   RedoParagraph();
  1824.                   return;
  1825.           }
  1826.           else {
  1827.                   if (sel_start_cursor.row == sel_end_cursor.row){
  1828.                       int i;
  1829.                       number = 1;
  1830.                       for (i=sel_start_cursor.pos; i<sel_end_cursor.pos; i++){
  1831.                           if (sel_start_cursor.par->IsNewline(i)){
  1832.                               sel_start_cursor.par->Erase(i);
  1833.                               // check for double-blanks
  1834.                               if ((i && !sel_start_cursor.par->IsLineSeparator(i-1))
  1835.                                   &&
  1836.                                   (i<sel_start_cursor.par->Last() 
  1837.                                    && !sel_start_cursor.par->IsLineSeparator(i)))
  1838.                                   sel_start_cursor.par->InsertChar(i, ' ');
  1839.                               else {
  1840.                                   sel_end_cursor.pos--;
  1841.                                   i--;
  1842.                               }
  1843.                               number++;
  1844.                           }
  1845.                       }
  1846.                       cursor.par->table->
  1847.               SetMultiColumn(NumberOfCell(sel_start_cursor.par,
  1848.                               sel_start_cursor.pos),
  1849.                      number);
  1850.                       cursor.pos = sel_start_cursor.pos;
  1851.                       RedoParagraph();
  1852.                       return;
  1853.                   }
  1854.                   else {
  1855.                       WriteAlert(_("Impossible Operation!"), 
  1856.                                  _("Multicolumns can only be horizontally."), 
  1857.                                  _("Sorry."));
  1858.                   }
  1859.           }
  1860.           }
  1861.       break;
  1862.       }
  1863.       case LyXTable::SET_ALL_LINES:
  1864.           setLines = 1;
  1865.       case LyXTable::UNSET_ALL_LINES:
  1866.           if (!selection){
  1867.               cursor.par->table->SetAllLines(NumberOfCell(cursor.par,
  1868.                                                           cursor.pos),
  1869.                                              setLines);
  1870.           } else {
  1871.               int i,n=-1,m=-2;
  1872.               for (i=sel_start_cursor.pos; i<=sel_end_cursor.pos; i++){
  1873.                   if ((n=NumberOfCell(sel_start_cursor.par,i)) != m) {
  1874.                       cursor.par->table->SetAllLines(n,setLines);
  1875.                       m = n;
  1876.                   }
  1877.               }
  1878.           }
  1879.           RedoParagraph();
  1880.           return;
  1881.       case LyXTable::SET_LONGTABLE:
  1882.           cursor.par->table->SetLongTable(true);
  1883.           return;
  1884.       case LyXTable::UNSET_LONGTABLE:
  1885.           cursor.par->table->SetLongTable(false);
  1886.           return;
  1887.       case LyXTable::SET_ROTATE_TABLE:
  1888.           cursor.par->table->SetRotateTable(true);
  1889.           return;
  1890.       case LyXTable::UNSET_ROTATE_TABLE:
  1891.           cursor.par->table->SetRotateTable(false);
  1892.           return;
  1893.       case LyXTable::SET_ROTATE_CELL:
  1894.           if (!selection){
  1895.               cursor.par->table->SetRotateCell(actCell,true);
  1896.           } else {
  1897.               int i,n=-1,m=-2;
  1898.               for (i=sel_start_cursor.pos; i<=sel_end_cursor.pos; i++){
  1899.                   if ((n=NumberOfCell(sel_start_cursor.par,i)) != m) {
  1900.                       cursor.par->table->SetRotateCell(n,true);
  1901.                       m = n;
  1902.                   }
  1903.               }
  1904.           }
  1905.           return;
  1906.       case LyXTable::UNSET_ROTATE_CELL:
  1907.           if (!selection){
  1908.               cursor.par->table->SetRotateCell(actCell,false);
  1909.           } else {
  1910.               int i,n=-1,m=-2;
  1911.               for (i=sel_start_cursor.pos; i<=sel_end_cursor.pos; i++){
  1912.                   if ((n=NumberOfCell(sel_start_cursor.par,i)) != m) {
  1913.                       cursor.par->table->SetRotateCell(n,false);
  1914.                       m = n;
  1915.                   }
  1916.               }
  1917.           }
  1918.           return;
  1919.       case LyXTable::SET_LINEBREAKS:
  1920.           what = !cursor.par->table->Linebreaks(cursor.par->table->FirstVirtualCell(actCell));
  1921.           if (!selection){
  1922.               cursor.par->table->SetLinebreaks(actCell,what);
  1923.           } else {
  1924.               int i,n=-1,m=-2;
  1925.               for (i=sel_start_cursor.pos; i<=sel_end_cursor.pos; i++){
  1926.                   if ((n=NumberOfCell(sel_start_cursor.par,i)) != m) {
  1927.                       cursor.par->table->SetLinebreaks(n,what);
  1928.                       m = n;
  1929.                   }
  1930.               }
  1931.           }
  1932.           return;
  1933.       case LyXTable::SET_LTFIRSTHEAD:
  1934.           cursor.par->table->SetLTHead(actCell,true);
  1935.           return;
  1936.       case LyXTable::SET_LTHEAD:
  1937.           cursor.par->table->SetLTHead(actCell,false);
  1938.           return;
  1939.       case LyXTable::SET_LTFOOT:
  1940.           cursor.par->table->SetLTFoot(actCell,false);
  1941.           return;
  1942.       case LyXTable::SET_LTLASTFOOT:
  1943.           cursor.par->table->SetLTFoot(actCell,true);
  1944.           return;
  1945.       case LyXTable::SET_LTNEWPAGE:
  1946.           what = !cursor.par->table->LTNewPage(actCell);
  1947.           cursor.par->table->SetLTNewPage(actCell,what);
  1948.           return;
  1949.     }
  1950. }
  1951.     
  1952.  
  1953. void LyXText::InsertCharInTable(char c)
  1954. {
  1955.     Row *row;
  1956.     Row *tmprow;
  1957.     long y;
  1958.     bool jumped_over_space;
  1959.     
  1960.     /* first check, if there will be two blanks together or a blank at 
  1961.      * the beginning of a paragraph. 
  1962.      * I decided to handle blanks like normal characters, the main 
  1963.      * difference are the special checks when calculating the row.fill
  1964.      * (blank does not count at the end of a row) and the check here */ 
  1965.     
  1966.     LyXFont realtmpfont = real_current_font;
  1967.     LyXFont rawtmpfont = current_font; /* store the current font.
  1968.                         * This is because of the use
  1969.                         * of cursor movements. The moving
  1970.                         * cursor would refresh the 
  1971.                         * current font */
  1972.  
  1973.     // Get the font that is used to calculate the baselineskip
  1974.     int const lastpos = cursor.par->Last();
  1975.     LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
  1976.  
  1977.     jumped_over_space = false;
  1978.     if (IsLineSeparatorChar(c)) {
  1979.         
  1980.         /* avoid double blanks but insert the new blank because
  1981.          * of a possible font change */
  1982.         if (cursor.pos < lastpos &&
  1983.             cursor.par->IsLineSeparator(cursor.pos))
  1984.         {
  1985.             cursor.par->Erase(cursor.pos);
  1986.             jumped_over_space = true;
  1987.         }
  1988.         else if ((cursor.pos > 0 && 
  1989.               cursor.par->IsLineSeparator(cursor.pos - 1))
  1990.              || (cursor.pos > 0 && cursor.par->IsNewline(cursor.pos - 1))
  1991.               || (cursor.pos == 0 &&
  1992.                   !(cursor.par->Previous()
  1993.                   && cursor.par->Previous()->footnoteflag
  1994.                   == LyXParagraph::OPEN_FOOTNOTE)))
  1995.             return;
  1996.     }
  1997.     else if (IsNewlineChar(c)) {
  1998.             if (!IsEmptyTableCell()) {
  1999.                 TableFeatures(LyXTable::APPEND_CONT_ROW);
  2000.                 CursorDown();
  2001.             }
  2002.       /* the newline character is the separator of the cells */
  2003.       // cursor.par->InsertChar(cursor.pos, c);
  2004.       // SetCharFont(cursor.par, cursor.pos, rawtmpfont);
  2005.       // RedoParagraphs(cursor, cursor.par->Next());
  2006.       // SetCursor(cursor.par, cursor.pos+1);
  2007.       return;
  2008.     }
  2009.    
  2010.     row = cursor.row;
  2011.     y = cursor.y - row->baseline;
  2012.     if (c != LYX_META_INSET)    /* in this case LyXText::InsertInset 
  2013.                      * already inserted the character */
  2014.         cursor.par->InsertChar(cursor.pos, c);
  2015.     SetCharFont(cursor.par, cursor.pos, rawtmpfont);
  2016.  
  2017.     if (!jumped_over_space) {
  2018.         /* refresh the positions */
  2019.         tmprow = row;
  2020.         while (tmprow->next && tmprow->next->par == row->par) {
  2021.             tmprow = tmprow->next;
  2022.             tmprow->pos++;
  2023.         }
  2024.     }
  2025.  
  2026.     cursor.pos++;
  2027.  
  2028.     CheckParagraphInTable(cursor.par, cursor.pos);
  2029.     
  2030.     current_font = rawtmpfont;
  2031.     real_current_font = realtmpfont;
  2032.     
  2033.     /* check, whether the last character's font has changed. */
  2034.     if (cursor.pos && cursor.pos == cursor.par->Last()
  2035.         && rawparfont != rawtmpfont)
  2036.         RedoHeightOfParagraph(cursor);
  2037. }
  2038.  
  2039.  
  2040. void LyXText::CheckParagraphInTable(LyXParagraph* par, int pos)
  2041. {
  2042.     Row *row;
  2043.     long y;
  2044.     
  2045.     if (par->GetChar(pos) == LYX_META_INSET &&
  2046.         par->GetInset(pos) && par->GetInset(pos)->Display()){
  2047.       par->GetInset(pos)->SetDisplay(false);
  2048.     }
  2049.  
  2050.     row = GetRow(par, pos, y);
  2051.     
  2052.     int tmpheight = row->height;
  2053.     SetHeightOfRow(row);
  2054.     
  2055.     int tmp_pos = pos;
  2056.     /* update the table information */
  2057.     while (tmp_pos && !par->IsNewline(tmp_pos - 1))
  2058.         tmp_pos--;
  2059.     if (par->table->SetWidthOfCell(NumberOfCell(par, pos),
  2060.                        WidthOfCell(par, tmp_pos))) {
  2061.         LyXCursor tmpcursor = cursor;
  2062.         SetCursorIntern(par, pos);
  2063.         /* make a complete redraw */
  2064.         RedoDrawingOfParagraph(cursor);
  2065.         cursor = tmpcursor;
  2066.     }
  2067.     else {
  2068.         /* redraw only the row */
  2069.         LyXCursor tmpcursor = cursor;
  2070.         SetCursorIntern(par, pos);
  2071.         refresh_y = y;
  2072.         refresh_x = cursor.x;
  2073.         refresh_row = row;
  2074.         refresh_pos = cursor.pos;
  2075.         cursor = tmpcursor;
  2076.         
  2077.         if (tmpheight == row->height)
  2078.             status = LyXText::NEED_VERY_LITTLE_REFRESH;
  2079.         else
  2080.             status = LyXText::NEED_MORE_REFRESH;
  2081.     }
  2082.         SetCursorIntern(cursor.par, cursor.pos);
  2083. }
  2084.  
  2085.  
  2086. void LyXText::BackspaceInTable()
  2087. {
  2088.     Row *tmprow, *row;
  2089.     long y;
  2090.     
  2091.     LyXFont rawtmpfont = current_font;
  2092.     LyXFont realtmpfont = real_current_font;
  2093.  
  2094.     // Get the font that is used to calculate the baselineskip
  2095.     int const lastpos = cursor.par->Last();
  2096.     LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
  2097.     
  2098.     if (cursor.pos == 0) {
  2099.         /* no pasting of table paragraphs */
  2100.         
  2101.         CursorLeft();
  2102.     }
  2103.     else {
  2104.         /* this is the code for a normal backspace, not pasting
  2105.          * any paragraphs */ 
  2106.       SetUndo(Undo::DELETE, 
  2107.           cursor.par->ParFromPos(cursor.pos)->previous, 
  2108.           cursor.par->ParFromPos(cursor.pos)->next); 
  2109.       
  2110.         CursorLeftIntern();
  2111.         
  2112.         /* some insets are undeletable here */
  2113.         if (cursor.par->GetChar(cursor.pos)==LYX_META_INSET) {
  2114.             if (!cursor.par->GetInset(cursor.pos)->Deletable())
  2115.                 return;
  2116.         }
  2117.         
  2118.         row = cursor.row;
  2119.         y = cursor.y - row->baseline;
  2120.         
  2121.         /* some special code when deleting a newline. */
  2122.         if (cursor.par->IsNewline(cursor.pos)) {
  2123.             /* nothing :-) */
  2124.             return;
  2125.         }
  2126.         else {
  2127.             cursor.par->Erase(cursor.pos);
  2128.             
  2129.             /* refresh the positions */
  2130.             tmprow = row;
  2131.             while (tmprow->next && tmprow->next->par == row->par) {
  2132.                 tmprow = tmprow->next;
  2133.                 tmprow->pos--;
  2134.             }
  2135.             
  2136.             /* delete superfluous blanks */ 
  2137.             if (cursor.pos < cursor.par->Last() - 1 &&
  2138.             (cursor.par->IsLineSeparator(cursor.pos))) {
  2139.                 
  2140.                 if (cursor.pos == BeginningOfMainBody(cursor.par)
  2141.                 || !cursor.pos 
  2142.                 || cursor.par->IsLineSeparator(cursor.pos - 1)) {
  2143.                     cursor.par->Erase(cursor.pos);
  2144.                     /* refresh the positions */
  2145.                     tmprow = row;
  2146.                     while (tmprow->next && 
  2147.                            tmprow->next->par == row->par) {
  2148.                         tmprow = tmprow->next;
  2149.                         tmprow->pos--;
  2150.                     }
  2151.                     if (cursor.pos)   /* move one character left */
  2152.                         cursor.pos--;
  2153.                 }
  2154.             }
  2155.         }
  2156.       
  2157.         CheckParagraphInTable(cursor.par, cursor.pos);
  2158.       
  2159.         /* check, wether the last characters font has changed. */ 
  2160.         if (cursor.pos && cursor.pos == cursor.par->Last()
  2161.             && rawparfont != rawtmpfont)
  2162.             RedoHeightOfParagraph(cursor);
  2163.  
  2164.         /* restore the current font 
  2165.          * That is what a user expects! */
  2166.         current_font = rawtmpfont;
  2167.         real_current_font = realtmpfont;
  2168.     }
  2169.     SetCursorIntern(cursor.par, cursor.pos);
  2170. }
  2171.  
  2172. /* table stuff -- end*/
  2173.  
  2174.  
  2175. /* just a macro to make some thing easier. */ 
  2176. void LyXText::RedoParagraph()
  2177. {
  2178.   LyXCursor tmpcursor = cursor;
  2179.   ClearSelection();
  2180.   RedoParagraphs(cursor, cursor.par->Next());;
  2181.   SetCursorIntern(tmpcursor.par, tmpcursor.pos);
  2182. }
  2183.  
  2184.  
  2185. /* insert a character, moves all the following breaks in the 
  2186.  * same Paragraph one to the right and make a rebreak */
  2187. void  LyXText::InsertChar(char c)
  2188. {
  2189.     Row *row;
  2190.     Row *tmprow;
  2191.     int z;
  2192.     long y;
  2193.     bool jumped_over_space;
  2194.     LyXFont realtmpfont;
  2195.     LyXFont rawtmpfont;
  2196.     int lastpos;
  2197.     LyXFont rawparfont;
  2198.    
  2199.     SetUndo(Undo::INSERT, 
  2200.         cursor.par->ParFromPos(cursor.pos)->previous, 
  2201.         cursor.par->ParFromPos(cursor.pos)->next);
  2202.  
  2203.     /* When the free-spacing option is set for the current layout,
  2204.      * all spaces are converted to protected spaces. */
  2205.     bool freeSpacingBo =
  2206.         lyxstyle.Style(parameters->textclass,
  2207.                    cursor.row->par->GetLayout())->free_spacing;
  2208.     //
  2209.     // Is this wanted? There cannot be a line break between protected
  2210.     // separators. Therefore I suggest the way implemented below
  2211.     // (Matthias)
  2212.     //
  2213.     //   if ( freeSpacingBo && IsLineSeparatorChar(c) )
  2214.     //       c = LYX_META_PROTECTED_SEPARATOR;
  2215.    
  2216.     if (freeSpacingBo && IsLineSeparatorChar(c) 
  2217.         && (!cursor.pos || cursor.par->IsLineSeparator(cursor.pos-1))) 
  2218.         c = LYX_META_PROTECTED_SEPARATOR;
  2219.    
  2220.     /* table stuff -- begin*/
  2221.       if (cursor.par->table) {
  2222.         InsertCharInTable(c);
  2223.         goto out;
  2224.     }
  2225.     /* table stuff -- end*/
  2226.    
  2227.     /* first check, if there will be two blanks together or a blank at 
  2228.      * the beginning of a paragraph. 
  2229.      * I decided to handle blanks like normal characters, the main 
  2230.      * difference are the special checks when calculating the row.fill
  2231.      * (blank does not count at the end of a row) and the check here */ 
  2232.  
  2233.     realtmpfont = real_current_font;
  2234.     rawtmpfont = current_font;  /* store the current font.
  2235.                      * This is because of the use
  2236.                      * of cursor movements. The moving
  2237.                      * cursor would refresh the 
  2238.                      * current font */
  2239.  
  2240.     // Get the font that is used to calculate the baselineskip
  2241.     lastpos = cursor.par->Last();
  2242.     rawparfont = cursor.par->GetFontSettings(lastpos - 1);
  2243.  
  2244.     jumped_over_space = false;
  2245.    
  2246.     if (IsLineSeparatorChar(c)) {
  2247.        
  2248.         if (cursor.pos < lastpos
  2249.             && cursor.par->IsLineSeparator(cursor.pos)) {
  2250.             /* the user inserted a space before a space. So we
  2251.              * will just make a CursorRight. BUT: The font of this
  2252.              * space should be set to current font. That is why
  2253.              * we need to rebreak perhaps. If there is a protected
  2254.              * blank at the end of a row we have to force
  2255.              * a rebreak.*/ 
  2256.        
  2257.             if (cursor.pos == RowLast(cursor.row)
  2258.                 && !IsLineSeparatorChar(c))
  2259.                 cursor.row->fill = -1;    /* force rebreak  */
  2260.        
  2261.             cursor.par->Erase(cursor.pos);
  2262.             jumped_over_space = true;
  2263.        
  2264.         } else if ((cursor.pos > 0 
  2265.                 && cursor.par->IsLineSeparator(cursor.pos - 1))
  2266.                || (cursor.pos > 0
  2267.                    && cursor.par->IsNewline(cursor.pos - 1))
  2268.                || (cursor.pos == 0
  2269.                    && !(cursor.par->Previous()
  2270.                     && cursor.par->Previous()->footnoteflag
  2271.                     == LyXParagraph::OPEN_FOOTNOTE)))
  2272.             goto out;
  2273.     } else if (IsNewlineChar(c)) {
  2274.         if (cursor.par->FirstPhysicalPar() == cursor.par
  2275.             && cursor.pos <= BeginningOfMainBody(cursor.par))
  2276.             goto out;
  2277.         /* no newline at first position 
  2278.          * of a paragraph or behind labels. 
  2279.          * TeX does not allow that. */
  2280.         
  2281.         if (cursor.pos < cursor.par->Last() &&
  2282.             cursor.par->IsLineSeparator(cursor.pos))
  2283.             CursorRightIntern(); // newline always after a blank!
  2284.         cursor.row->fill = -1;           // to force a new break
  2285.     }
  2286.    
  2287.     /* the display inset stuff */ 
  2288.     if (cursor.row->par->GetChar(cursor.row->pos) == LYX_META_INSET
  2289.         && cursor.row->par->GetInset(cursor.row->pos)
  2290.         && cursor.row->par->GetInset(cursor.row->pos)->Display())
  2291.         cursor.row->fill = -1; // to force a new break  
  2292.  
  2293.     /* get the cursor row fist */
  2294.     /* this is a dumb solution, i will try to hold the cursor.row
  2295.        in future */ 
  2296.     /* row = GetRow(cursor.par, cursor.pos, y);*/
  2297.     /* ok, heres a better way: */ 
  2298.     row = cursor.row;
  2299.     y = cursor.y - row->baseline;
  2300.     if (c != LYX_META_INSET)  /* in this case LyXText::InsertInset 
  2301.                    * already insertet the character */
  2302.         cursor.par->InsertChar(cursor.pos, c);
  2303.     SetCharFont(cursor.par, cursor.pos, rawtmpfont);
  2304.  
  2305.     if (!jumped_over_space) {
  2306.         /* refresh the positions */
  2307.         tmprow = row;
  2308.         while (tmprow->next && tmprow->next->par == row->par) {
  2309.             tmprow = tmprow->next;
  2310.             tmprow->pos++;
  2311.         }
  2312.     }
  2313.    
  2314.     /* Is there a break one row above */ 
  2315.     if ((cursor.par->IsLineSeparator(cursor.pos)
  2316.          || cursor.par->IsNewline(cursor.pos)
  2317.          || cursor.row->fill == -1)
  2318.         && row->previous && row->previous->par == row->par) {
  2319.         z = NextBreakPoint(row->previous, paperwidth);
  2320.         if ( z >= row->pos) {
  2321.             row->pos = z + 1;
  2322.             
  2323.             /* set the dimensions of the row above  */ 
  2324.             row->previous->fill = Fill(row->previous, paperwidth);
  2325.  
  2326.             SetHeightOfRow(row->previous);
  2327.          
  2328.             y -= row->previous->height;
  2329.             refresh_y = y;
  2330.             refresh_row = row->previous;
  2331.             status = LyXText::NEED_MORE_REFRESH;
  2332.          
  2333.             BreakAgainOneRow(row);
  2334.             SetCursor(cursor.par, cursor.pos + 1);
  2335.             /* cursor MUST be in row now */
  2336.          
  2337.             if (row->next && row->next->par == row->par)
  2338.                 need_break_row = row->next;
  2339.             else
  2340.                 need_break_row = NULL;
  2341.  
  2342.             current_font = rawtmpfont;
  2343.             real_current_font = realtmpfont;
  2344.          
  2345.             // check, wether the last characters font has changed. 
  2346.             if (cursor.pos && cursor.pos == cursor.par->Last()
  2347.                 && rawparfont != rawtmpfont)
  2348.                 RedoHeightOfParagraph(cursor);
  2349.             
  2350.             goto out;
  2351.         }
  2352.     }
  2353.    
  2354.     /* recalculate the fill of the row */ 
  2355.     if (row->fill >= 0)  /* needed because a newline
  2356.                   * will set fill to -1. Otherwise
  2357.                   * we would not get a rebreak! */
  2358.         row->fill = Fill(row, paperwidth);
  2359.     if (row->fill < 0 ) {
  2360.         refresh_y = y;
  2361.         refresh_row = row; 
  2362.         refresh_x = cursor.x;
  2363.         refresh_pos = cursor.pos;
  2364.         status = LyXText::NEED_MORE_REFRESH;
  2365.         BreakAgainOneRow(row); 
  2366.         /* will the cursor be in another row now? */ 
  2367.         if (RowLast(row) <= cursor.pos + 1 && row->next) {
  2368.             if (row->next && row->next->par == row->par)
  2369.                 /* this should
  2370.                  * always be true */
  2371.                 row = row->next;
  2372.             BreakAgainOneRow(row);
  2373.         }
  2374.         SetCursor(cursor.par, cursor.pos + 1);
  2375.         if (row->next && row->next->par == row->par)
  2376.             need_break_row = row->next;
  2377.         else
  2378.             need_break_row = NULL;
  2379.         
  2380.         current_font = rawtmpfont;
  2381.         real_current_font = realtmpfont;
  2382.     } else {
  2383.         refresh_y = y;
  2384.         refresh_x = cursor.x;
  2385.         refresh_row = row;
  2386.         refresh_pos = cursor.pos;
  2387.         
  2388.         int tmpheight = row->height;
  2389.         SetHeightOfRow(row);
  2390.         if (tmpheight == row->height)
  2391.             status = LyXText::NEED_VERY_LITTLE_REFRESH;
  2392.         else
  2393.             status = LyXText::NEED_MORE_REFRESH;
  2394.             
  2395.         SetCursor(cursor.par, cursor.pos + 1);
  2396.         current_font = rawtmpfont;
  2397.         real_current_font = realtmpfont;
  2398.     }
  2399.  
  2400.     /* check, wether the last characters font has changed. */ 
  2401.     if (cursor.pos && cursor.pos == cursor.par->Last()
  2402.         && rawparfont != rawtmpfont) {
  2403.         RedoHeightOfParagraph(cursor);
  2404.     } else {
  2405.         /* now the special right address boxes */
  2406.         if (lyxstyle.Style(parameters->textclass,
  2407.                    cursor.par->GetLayout())->margintype
  2408.             == MARGIN_RIGHT_ADDRESS_BOX) {
  2409.             RedoDrawingOfParagraph(cursor); 
  2410.         }
  2411.     }
  2412.   out:
  2413.     // Here we could call FinishUndo for every 20 characters inserted.
  2414.     // This is from my experience how emacs does it.
  2415.     static unsigned short counter = 0;
  2416.     if (counter < 20) {
  2417.         ++counter;
  2418.     } else {
  2419.         FinishUndo();
  2420.         counter = 0;
  2421.     }
  2422.     return;
  2423. }
  2424.    
  2425.    
  2426. void LyXText::PrepareToPrint(Row *row, float &x, float &fill_separator, 
  2427.                  float &fill_hfill, float &fill_label_hfill)
  2428. {
  2429.     float w, nh, nlh, ns;
  2430.     
  2431.     w = row->fill;
  2432.     fill_hfill = 0;
  2433.     fill_label_hfill = 0;
  2434.     fill_separator = 0;
  2435.     fill_label_hfill = 0;
  2436.     
  2437.     x = LeftMargin(row);
  2438.     
  2439.     /* is there a manual margin with a manual label */ 
  2440.     if (lyxstyle.Style(parameters->textclass,
  2441.                row->par->GetLayout())->margintype == MARGIN_MANUAL
  2442.         && lyxstyle.Style(parameters->textclass,
  2443.                   row->par->GetLayout())->labeltype == LABEL_MANUAL) {
  2444.            
  2445.         nlh = NumberOfLabelHfills(row) + 1; /* one more since labels 
  2446.                             * are left aligned*/ 
  2447.         if (nlh && !row->par->GetLabelWidthString().empty()) {
  2448.             fill_label_hfill = LabelFill(row) / nlh;
  2449.         }
  2450.     }
  2451.         
  2452.     /* are there any hfills in the row? */ 
  2453.     nh = NumberOfHfills(row);
  2454.     
  2455. /* table stuff -- begin*/
  2456.     if (row->par->table) {
  2457.        w = paperwidth - row->par->table->WidthOfTable()
  2458.        - x - RightMargin(row);
  2459.        nh = 0; /* ignore hfills in tables */ 
  2460.     }
  2461. /* table stuff -- end*/
  2462.  
  2463.     if (nh)
  2464.       fill_hfill = w /nh;
  2465.     else  {
  2466.        /* is it block, flushleft or flushright? 
  2467.         * set x how you need it */
  2468.        int align;
  2469.        if (row->par->FirstPhysicalPar()->align == LYX_ALIGN_LAYOUT)
  2470.          align = lyxstyle.Style(parameters->textclass, row->par->GetLayout())->align;
  2471.        else
  2472.          align = row->par->FirstPhysicalPar()->align;
  2473.        
  2474.        /* center displayed insets */ 
  2475.        if (row->par->GetChar(row->pos) == LYX_META_INSET
  2476.            && row->par->GetInset(row->pos)
  2477.            && row->par->GetInset(row->pos)->Display())
  2478.          align = LYX_ALIGN_CENTER;
  2479.  
  2480.        switch (align) {
  2481.         case LYX_ALIGN_BLOCK:
  2482.           ns = NumberOfSeparators(row);
  2483.           if (ns && row->next && row->next->par == row->par &&
  2484.           !(row->next->par->IsNewline(row->next->pos-1))
  2485.           && !(row->next->par->GetChar(row->next->pos) == LYX_META_INSET
  2486.                && row->next->par->GetInset(row->next->pos)
  2487.                && row->next->par->GetInset(row->next->pos)->Display())
  2488.           )
  2489.               fill_separator = w / ns;
  2490.           break;
  2491.         case LYX_ALIGN_RIGHT:
  2492.           x += w;
  2493.           break;
  2494.         case LYX_ALIGN_CENTER:
  2495.           x += w / 2;
  2496.           break;
  2497.        }
  2498.     }
  2499.      }
  2500.  
  2501.       
  2502. /* important for the screen */
  2503.  
  2504.  
  2505. /* the cursor set functions have a special mechanism. When they
  2506. * realize, that you left an empty paragraph, they will delete it.
  2507. * They also delet the corresponding row */
  2508.  
  2509.  
  2510. void LyXText::CursorRightOneWord()
  2511. {
  2512.     // treat floats, HFills and Insets as words
  2513.     LyXCursor tmpcursor = cursor;
  2514.  
  2515.     if (tmpcursor.pos == tmpcursor.par->Last()
  2516.         && tmpcursor.par->Next())
  2517.     {
  2518.             tmpcursor.par = tmpcursor.par->Next();
  2519.             tmpcursor.pos = 0;
  2520.     } else {
  2521.         int steps = 0;
  2522.         while (tmpcursor.pos < tmpcursor.par->Last()
  2523.                && !tmpcursor.par->IsSeparator(tmpcursor.pos)
  2524.                && !tmpcursor.par->IsKomma(tmpcursor.pos)
  2525.                && !tmpcursor.par->IsHfill(tmpcursor.pos)
  2526.                && !tmpcursor.par->IsFloat(tmpcursor.pos)
  2527.                && !tmpcursor.par->IsInset(tmpcursor.pos))
  2528.         {
  2529.             tmpcursor.pos++;
  2530.             steps++;
  2531.         }
  2532.         while (tmpcursor.pos < tmpcursor.par->Last()
  2533.                && (tmpcursor.par->IsSeparator(tmpcursor.pos)
  2534.                || tmpcursor.par->IsKomma(tmpcursor.pos)
  2535.                || tmpcursor.par->IsHfill(tmpcursor.pos)
  2536.                || tmpcursor.par->IsFloat(tmpcursor.pos)
  2537.                || tmpcursor.par->IsInset(tmpcursor.pos)))
  2538.         {
  2539.             if ((tmpcursor.par->IsInset(tmpcursor.pos)
  2540.                  || tmpcursor.par->IsFloat(tmpcursor.pos)
  2541.                  || tmpcursor.par->IsHfill(tmpcursor.pos))
  2542.                 && steps)
  2543.                 break;
  2544.             tmpcursor.pos++;
  2545.         }
  2546.     }
  2547.     SetCursor(tmpcursor.par, tmpcursor.pos);
  2548. }
  2549.  
  2550.  
  2551. void LyXText::CursorTab()
  2552. {
  2553.     if (cursor.par->table) {
  2554.         int cell = NumberOfCell(cursor.par, cursor.pos);
  2555.         while(cursor.par->table->IsContRow(cell)) {
  2556.             CursorUp();
  2557.             cell = NumberOfCell(cursor.par, cursor.pos);
  2558.         }
  2559.         if (cursor.par->table->ShouldBeVeryLastCell(cell))
  2560.             TableFeatures(LyXTable::APPEND_ROW);
  2561.     }
  2562.     LyXCursor tmpcursor = cursor;
  2563.     while (tmpcursor.pos < tmpcursor.par->Last()
  2564.            && !tmpcursor.par->IsNewline(tmpcursor.pos))
  2565.         tmpcursor.pos++;
  2566.    
  2567.     if (tmpcursor.pos == tmpcursor.par->Last()){
  2568.         if (tmpcursor.par->Next()) {
  2569.             tmpcursor.par = tmpcursor.par->Next();
  2570.             tmpcursor.pos = 0;
  2571.         }
  2572.     }
  2573.     else
  2574.         tmpcursor.pos++;
  2575.     SetCursor(tmpcursor.par, tmpcursor.pos);
  2576.     if (cursor.par->table) {
  2577.         int cell = NumberOfCell(cursor.par, cursor.pos);
  2578.         while (cursor.par->table->IsContRow(cell) &&
  2579.                !cursor.par->table->ShouldBeVeryLastCell(cell)) {
  2580.             tmpcursor = cursor;
  2581.             while (tmpcursor.pos < tmpcursor.par->Last()
  2582.                    && !tmpcursor.par->IsNewline(tmpcursor.pos))
  2583.                 tmpcursor.pos++;
  2584.    
  2585.             if (tmpcursor.pos == tmpcursor.par->Last()){
  2586.                 if (tmpcursor.par->Next()) {
  2587.                     tmpcursor.par = tmpcursor.par->Next();
  2588.                     tmpcursor.pos = 0;
  2589.                 }
  2590.             }
  2591.             else
  2592.                 tmpcursor.pos++;
  2593.             SetCursor(tmpcursor.par, tmpcursor.pos);
  2594.             cell = NumberOfCell(cursor.par, cursor.pos);
  2595.         }
  2596.     }
  2597. }
  2598.  
  2599.  
  2600. /* -------> Skip initial whitespace at end of word and move cursor to *start*
  2601.             of prior word, not to end of next prior word. */
  2602.  
  2603. void LyXText::CursorLeftOneWord() 
  2604. {
  2605.     // treat HFills, floats and Insets as words
  2606.     LyXCursor tmpcursor = cursor;
  2607.     while (tmpcursor.pos 
  2608.            && (tmpcursor.par->IsSeparator(tmpcursor.pos - 1) 
  2609.            || tmpcursor.par->IsKomma(tmpcursor.pos - 1))
  2610.            && !(tmpcursor.par->IsHfill(tmpcursor.pos - 1)
  2611.                 || tmpcursor.par->IsFloat(tmpcursor.pos - 1)
  2612.             || tmpcursor.par->IsInset(tmpcursor.pos - 1)))
  2613.         tmpcursor.pos--;
  2614.  
  2615.     if (tmpcursor.pos
  2616.         && (tmpcursor.par->IsInset(tmpcursor.pos - 1)
  2617.             || tmpcursor.par->IsFloat(tmpcursor.pos - 1)
  2618.         || tmpcursor.par->IsHfill(tmpcursor.pos - 1))) {
  2619.         tmpcursor.pos--;
  2620.     } else if (!tmpcursor.pos) {
  2621.         if (tmpcursor.par->Previous()){
  2622.             tmpcursor.par = tmpcursor.par->Previous();
  2623.             tmpcursor.pos = tmpcursor.par->Last();
  2624.         }
  2625.     } else {
  2626.         while (tmpcursor.pos > 0 
  2627.                && !tmpcursor.par->IsSeparator(tmpcursor.pos-1)
  2628.                && !tmpcursor.par->IsKomma(tmpcursor.pos-1)
  2629.                && !tmpcursor.par->IsHfill(tmpcursor.pos-1)
  2630.                && !tmpcursor.par->IsFloat(tmpcursor.pos-1)
  2631.                && !tmpcursor.par->IsInset(tmpcursor.pos-1))
  2632.             tmpcursor.pos--;
  2633.     }
  2634.     SetCursor(tmpcursor.par, tmpcursor.pos);
  2635. }
  2636.  
  2637. /* -------> Select current word. This depeds on behaviour of CursorLeftOneWord(), so it is
  2638.             patched as well. */
  2639.  
  2640. void LyXText::SelectWord() 
  2641. {
  2642.     /* Move cursor to the beginning, when not already there. */
  2643.     if ( cursor.pos
  2644.          && !cursor.par->IsSeparator(cursor.pos-1)
  2645.          && !cursor.par->IsKomma(cursor.pos-1) )
  2646.         CursorLeftOneWord();
  2647.  
  2648.     /* set the sel cursor */
  2649.     sel_cursor = cursor;
  2650.  
  2651.     while ( cursor.pos < cursor.par->Last()
  2652.             && !cursor.par->IsSeparator(cursor.pos)
  2653.             && !cursor.par->IsKomma(cursor.pos) )
  2654.         cursor.pos++;
  2655.     SetCursor( cursor.par, cursor.pos );
  2656.     
  2657.     /* finally set the selection */ 
  2658.     SetSelection();
  2659. }
  2660.  
  2661.  
  2662. /* -------> Select the word currently under the cursor when:
  2663.             1: no selection is currently set,
  2664.             2: the cursor is not at the borders of the word. */
  2665.  
  2666. int LyXText::SelectWordWhenUnderCursor() 
  2667. {
  2668.     if ( selection ) return 0;
  2669.     if ( cursor.pos < cursor.par->Last()
  2670.          && !cursor.par->IsSeparator(cursor.pos)
  2671.          && !cursor.par->IsKomma(cursor.pos)
  2672.          && cursor.pos 
  2673.          && !cursor.par->IsSeparator(cursor.pos -1)
  2674.          && !cursor.par->IsKomma(cursor.pos -1) ) {
  2675.         SelectWord();
  2676.         return 1;
  2677.     }
  2678.     return 0;
  2679. }
  2680.  
  2681.  
  2682. // This function is only used by the spellchecker for NextWord().
  2683. // It doesn't handle LYX_ACCENTs and probably never will.
  2684. char* LyXText::SelectNextWord(float &value)
  2685. {
  2686.     LyXParagraph* tmppar = cursor.par;
  2687.     
  2688.     // If this is not the very first word, skip rest of
  2689.     // current word because we are probably in the middle
  2690.     // of a word if there is text here.
  2691.     if (cursor.pos || cursor.par->previous) {
  2692.         while (cursor.pos < cursor.par->Last()
  2693.                && cursor.par->IsLetter(cursor.pos))
  2694.             cursor.pos++;
  2695.     }
  2696.     // Now, skip until we have real text (will jump paragraphs)
  2697.     while ((cursor.par->Last() > cursor.pos
  2698.         && !cursor.par->IsLetter(cursor.pos))
  2699.            || (cursor.par->Last() == cursor.pos
  2700.            && cursor.par->Next())){
  2701.         if (cursor.pos == cursor.par->Last()) {
  2702.             cursor.par = cursor.par->Next();
  2703.             cursor.pos = 0;
  2704.         }
  2705.         else
  2706.             cursor.pos++;
  2707.     }
  2708.   
  2709.     // Update the value if we changed paragraphs
  2710.     if (cursor.par != tmppar){
  2711.         SetCursor(cursor.par, cursor.pos);
  2712.         value = float(cursor.y)/float(height);
  2713.     }
  2714.  
  2715.     /* Start the selection from here */
  2716.     sel_cursor = cursor;
  2717.    
  2718.     /* and find the end of the word */
  2719.     while (cursor.pos < cursor.par->Last()
  2720.            && cursor.par->IsLetter(cursor.pos))
  2721.         cursor.pos++;
  2722.  
  2723.     // Finally, we copy the word to a string and return it
  2724.     char* string = NULL;
  2725.  
  2726.     if (sel_cursor.pos < cursor.pos) {
  2727.         string = new char [cursor.pos - sel_cursor.pos + 2];
  2728.         int i,j;
  2729.         
  2730.         for (i=sel_cursor.pos, j=0; i<cursor.pos; i++)
  2731.             string[j++] = cursor.par->GetChar(i);
  2732.         string[j] = '\0';
  2733.     }
  2734.     return string;
  2735. }
  2736.  
  2737.  
  2738. // This one is also only for the spellchecker
  2739. void LyXText::SelectSelectedWord()
  2740. {
  2741.     /* move cursor to the beginning */
  2742.     SetCursor(sel_cursor.par, sel_cursor.pos);
  2743.     
  2744.     /* set the sel cursor */
  2745.     sel_cursor = cursor;
  2746.     
  2747.     /* now find the end of the word */
  2748.     while (cursor.pos < cursor.par->Last()
  2749.            && cursor.par->IsLetter(cursor.pos))
  2750.         cursor.pos++;
  2751.     
  2752.     SetCursor(cursor.par, cursor.pos);
  2753.     
  2754.     /* finally set the selection */ 
  2755.     SetSelection();
  2756. }
  2757.  
  2758.  
  2759. /* -------> Delete from cursor up to the end of the current or next word. */
  2760. void LyXText::DeleteWordForward()
  2761. {
  2762.     LyXCursor tmpcursor = cursor;
  2763.         
  2764.     if (!cursor.par->Last())
  2765.         CursorRight();
  2766.     else {
  2767.         /* -------> Skip initial non-word stuff. */
  2768.         while ( cursor.pos < cursor.par->Last() 
  2769.             && (cursor.par->IsSeparator(cursor.pos)
  2770.                 || cursor.par->IsKomma(cursor.pos)) )
  2771.             cursor.pos++;
  2772.         
  2773.         SetCursorIntern(cursor.par, cursor.pos);
  2774.         selection = True; // to avoid deletion 
  2775.         CursorRightOneWord();
  2776.         sel_cursor = cursor;
  2777.         cursor = tmpcursor;
  2778.         SetSelection(); 
  2779.         
  2780.         /* -----> Great, CutSelection() gets rid of multiple spaces. */
  2781.         CutSelection();
  2782.     }
  2783. }
  2784.  
  2785.  
  2786. /* -------> Delete from cursor to start of current or prior word. */
  2787. void LyXText::DeleteWordBackward()
  2788. {
  2789.        LyXCursor tmpcursor = cursor;
  2790.        if (!cursor.par->Last())
  2791.          CursorLeft();
  2792.        else{
  2793.          selection = True; // to avoid deletion 
  2794.          CursorLeftOneWord();
  2795.          sel_cursor = cursor;
  2796.          cursor = tmpcursor;
  2797.          SetSelection();
  2798.          CutSelection();
  2799.        }
  2800. }
  2801.  
  2802.  
  2803. /* -------> Kill to end of line. */
  2804. void LyXText::DeleteLineForward()
  2805. {
  2806.     LyXCursor tmpcursor = cursor;
  2807.     if (!cursor.par->Last())
  2808.         CursorRight();
  2809.     else {
  2810.         CursorEnd();
  2811.         sel_cursor = cursor;
  2812.         cursor = tmpcursor;
  2813.         SetSelection();
  2814.         if (selection == false) {
  2815.             DeleteWordForward();
  2816.         } else {
  2817.             CutSelection();
  2818.         }
  2819.     }
  2820. }
  2821.  
  2822.  
  2823. /* -------> Upcase characters from cursor to end of word. */
  2824. void LyXText::UpcaseWord() 
  2825. {
  2826.   SetUndo(Undo::FINISH, 
  2827.       cursor.par->ParFromPos(cursor.pos)->previous,
  2828.       cursor.par->ParFromPos(cursor.pos)->next); 
  2829.  
  2830.     while (cursor.pos < cursor.par->Last()
  2831.     && !cursor.par->IsSeparator(cursor.pos) 
  2832.     && !cursor.par->IsKomma(cursor.pos) ) {
  2833.          if (cursor.par->GetChar(cursor.pos) != LYX_META_INSET)
  2834.             cursor.par->text[cursor.pos] =
  2835.                 toupper((unsigned char) cursor.par->text[cursor.pos]);
  2836.         CursorRight();
  2837.     }
  2838.     CheckParagraph(cursor.par, cursor.pos);
  2839.     CursorRightOneWord();
  2840. }
  2841.  
  2842.  
  2843. /* -------> Lowcase characters from cursor to end of word. */
  2844. void LyXText::LowcaseWord() 
  2845. {
  2846.   SetUndo(Undo::FINISH, 
  2847.       cursor.par->ParFromPos(cursor.pos)->previous,
  2848.       cursor.par->ParFromPos(cursor.pos)->next); 
  2849.  
  2850.     while ( cursor.pos < cursor.par->Last()
  2851.     && !cursor.par->IsSeparator(cursor.pos) 
  2852.     && !cursor.par->IsKomma(cursor.pos) ) {
  2853.          if (cursor.par->GetChar(cursor.pos) != LYX_META_INSET)
  2854.            cursor.par->text[cursor.pos] =
  2855.                tolower((unsigned char) cursor.par->text[cursor.pos]);
  2856.         CursorRight();
  2857.     }
  2858.     CheckParagraph(cursor.par, cursor.pos);
  2859.     CursorRightOneWord();
  2860. }
  2861.  
  2862.  
  2863. /* -------> Capitalize characters from cursor to end of word. */
  2864. void LyXText::CapitalizeWord() 
  2865. {
  2866.   SetUndo(Undo::FINISH, 
  2867.       cursor.par->ParFromPos(cursor.pos)->previous,
  2868.       cursor.par->ParFromPos(cursor.pos)->next); 
  2869.  
  2870.     bool firstBo = true;
  2871.     while ( cursor.pos < cursor.par->Last()
  2872.     && !cursor.par->IsSeparator(cursor.pos) 
  2873.     && !cursor.par->IsKomma(cursor.pos) ) {
  2874.         if ( firstBo ){
  2875.               if (cursor.par->GetChar(cursor.pos) != LYX_META_INSET)
  2876.                 cursor.par->text[cursor.pos]
  2877.                     = toupper((unsigned char) cursor.par->text[cursor.pos]);
  2878.         }
  2879.         else{
  2880.               if (cursor.par->GetChar(cursor.pos) != LYX_META_INSET)
  2881.                 cursor.par->text[cursor.pos]
  2882.                   = tolower((unsigned char) cursor.par->text[cursor.pos]);
  2883.          }
  2884.         firstBo = false;
  2885.         CursorRight();
  2886.     }
  2887.     CheckParagraph(cursor.par, cursor.pos);
  2888.     CursorRightOneWord();
  2889. }
  2890.  
  2891.  
  2892. void  LyXText::Delete()
  2893. {
  2894.    LyXCursor old_cursor = cursor;
  2895.    LyXCursor tmpcursor;
  2896.    /* this is a very easy implementation*/ 
  2897.    
  2898.    /* just move to the right */ 
  2899.    CursorRightIntern();
  2900.    
  2901.    if (cursor.par->previous == old_cursor.par->previous
  2902.        && cursor.par != old_cursor.par)
  2903.      return; // delete-emty-paragraph-mechanism has done it
  2904.    
  2905.    /* if you had success make a backspace */ 
  2906.    if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) {
  2907.      tmpcursor = cursor;
  2908.      cursor = old_cursor; // to make sure undo gets the right cursor position
  2909.      SetUndo(Undo::DELETE, 
  2910.          cursor.par->ParFromPos(cursor.pos)->previous, 
  2911.          cursor.par->ParFromPos(cursor.pos)->next); 
  2912.      cursor = tmpcursor;
  2913.      Backspace();
  2914.    }
  2915. }
  2916.  
  2917.  
  2918. void  LyXText::Backspace()
  2919. {
  2920.     LyXParagraph *tmppar;
  2921.     Row *tmprow, *row;
  2922.     long y;
  2923.     int tmpheight;
  2924.  
  2925.     /* table stuff -- begin*/
  2926.    
  2927.     if (cursor.par->table) {
  2928.         BackspaceInTable();
  2929.         return;
  2930.     }
  2931.     /* table stuff -- end*/
  2932.     
  2933.     LyXFont rawtmpfont = current_font;
  2934.     LyXFont realtmpfont = real_current_font;
  2935.    
  2936.     // Get the font that is used to calculate the baselineskip
  2937.     int const lastpos = cursor.par->Last();
  2938.     LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
  2939.  
  2940.     if (cursor.pos == 0) {
  2941.         /* we may paste some paragraphs */
  2942.       
  2943.         /* is it an empty paragraph? */
  2944.       
  2945.         if ((lastpos == 0
  2946.              || (lastpos == 1 && cursor.par->IsSeparator(0)))
  2947.             && !(cursor.par->Next() 
  2948.              && cursor.par->footnoteflag ==
  2949.              LyXParagraph::NO_FOOTNOTE
  2950.              && cursor.par->Next()->footnoteflag ==
  2951.              LyXParagraph::OPEN_FOOTNOTE)) {
  2952.             
  2953.             if (cursor.par->previous) {
  2954.                 tmppar = cursor.par->previous->FirstPhysicalPar();
  2955.                 if (cursor.par->GetLayout() == tmppar->GetLayout()
  2956.                     && cursor.par->footnoteflag == tmppar->footnoteflag
  2957.                     && cursor.par->GetAlign() == tmppar->GetAlign()) {
  2958.                     
  2959.                     tmppar->line_bottom = cursor.par->line_bottom;
  2960.                     tmppar->added_space_bottom = cursor.par->added_space_bottom;
  2961.                     tmppar->pagebreak_bottom = cursor.par->pagebreak_bottom;
  2962.                 }
  2963.                 
  2964.                 CursorLeftIntern();
  2965.              
  2966.                 /* the layout things can change the height of a row ! */ 
  2967.                 tmpheight = cursor.row->height;
  2968.                 SetHeightOfRow(cursor.row);
  2969.                 if (cursor.row->height != tmpheight) {
  2970.                     refresh_y = cursor.y - cursor.row->baseline;
  2971.                     refresh_row = cursor.row;
  2972.                     status = LyXText::NEED_MORE_REFRESH;
  2973.                 }
  2974.                 return;
  2975.             }
  2976.         }
  2977.         if (cursor.par->ParFromPos(cursor.pos)->previous){
  2978.             SetUndo(Undo::DELETE, 
  2979.                 cursor.par->ParFromPos(cursor.pos)->previous->previous, 
  2980.                 cursor.par->ParFromPos(cursor.pos)->next); 
  2981.         }
  2982.         tmppar = cursor.par;
  2983.         tmprow = cursor.row;
  2984.         CursorLeftIntern();
  2985.         /* Pasting is not allowed, if the paragraphs have different layout.
  2986.          * I think it is a real bug of all other word processors to allow
  2987.          * it. It confuses the user. Even so with a footnote paragraph and
  2988.          * a non-footnote paragraph. I will not allow pasting in this case, 
  2989.          * because the user would be confused if the footnote behaves 
  2990.          * different wether it is open or closed.
  2991.          * 
  2992.          * Correction: Pasting is always allowed with standard-layout */
  2993.         if (cursor.par != tmppar
  2994.             && (cursor.par->GetLayout() == tmppar->GetLayout()
  2995.             || !tmppar->GetLayout())
  2996.             && cursor.par->footnoteflag == tmppar->footnoteflag
  2997.             /* table stuff -- begin*/
  2998.             && !cursor.par->table /* no pasting of tables */ 
  2999.             /* table stuff -- end*/
  3000.             && cursor.par->GetAlign() == tmppar->GetAlign()) {
  3001.             
  3002.             cursor.par->PasteParagraph();
  3003.             
  3004.             if (!(cursor.pos &&
  3005.                   cursor.par->IsSeparator(cursor.pos - 1)))
  3006.                 cursor.par->InsertChar(cursor.pos, ' ');
  3007.             else
  3008.                 if (cursor.pos)
  3009.                     cursor.pos--;
  3010.             
  3011.             status = LyXText::NEED_MORE_REFRESH;
  3012.             refresh_row = cursor.row;
  3013.             refresh_y = cursor.y - cursor.row->baseline;
  3014.             
  3015.             /* remove the lost paragraph */
  3016.             RemoveParagraph(tmprow);
  3017.             RemoveRow(tmprow);  
  3018.             
  3019.             /* break the paragraph again */ 
  3020.             /* BreakAgain(cursor.row); */ 
  3021.             
  3022.             AppendParagraph(cursor.row);
  3023.             UpdateCounters(cursor.row);
  3024.             
  3025.             /* the row may have changed, block, hfills etc. */ 
  3026.             SetCursor(cursor.par, cursor.pos);
  3027.         }
  3028.     } else  {
  3029.         /* this is the code for a normal backspace, not pasting
  3030.          * any paragraphs */ 
  3031.         SetUndo(Undo::DELETE, 
  3032.             cursor.par->ParFromPos(cursor.pos)->previous, 
  3033.             cursor.par->ParFromPos(cursor.pos)->next); 
  3034.         CursorLeftIntern();
  3035.         
  3036.         /* some insets are undeletable here */
  3037.         if (cursor.par->GetChar(cursor.pos)==LYX_META_INSET) {
  3038.             if (!cursor.par->GetInset(cursor.pos)->Deletable())
  3039.                 return; 
  3040.             /* force complete redo when erasing display insets */ 
  3041.             /* this is a cruel mathod but save..... Matthias */ 
  3042.             if (cursor.par->GetInset(cursor.pos)->Display()){
  3043.                 cursor.par->Erase(cursor.pos);
  3044.                 RedoParagraph();
  3045.                 return;
  3046.             }
  3047.         }
  3048.         
  3049.         row = cursor.row;
  3050.         y = cursor.y - row->baseline;
  3051.         int z;
  3052.         
  3053.         /* remember that a space at the end of a row doesnt count
  3054.          * when calculating the fill */ 
  3055.         if (cursor.pos < RowLast(row) ||
  3056.             !cursor.par->IsLineSeparator(cursor.pos)) {
  3057.             row->fill += SingleWidth(cursor.par, cursor.pos);
  3058.         }
  3059.         
  3060.         /* some special code when deleting a newline. This is similar
  3061.          * to the behavior when pasting paragraphs */ 
  3062.         if (cursor.pos && cursor.par->IsNewline(cursor.pos)) {
  3063.             cursor.par->Erase(cursor.pos);
  3064.             /* refresh the positions */
  3065.             tmprow = row;
  3066.             while (tmprow->next && tmprow->next->par == row->par) {
  3067.                 tmprow = tmprow->next;
  3068.                 tmprow->pos--;
  3069.             }
  3070.             if (cursor.par->IsLineSeparator(cursor.pos - 1))
  3071.                 cursor.pos--;
  3072.             
  3073.             if (cursor.pos < cursor.par->Last() && !cursor.par->IsSeparator(cursor.pos)) {
  3074.                 cursor.par->InsertChar(cursor.pos, ' ');
  3075.                 /* refresh the positions */
  3076.                 tmprow = row;
  3077.                 while (tmprow->next && tmprow->next->par == row->par) {
  3078.                     tmprow = tmprow->next;
  3079.                     tmprow->pos++;
  3080.                 }
  3081.             }
  3082.         } else {
  3083.             cursor.par->Erase(cursor.pos);
  3084.             
  3085.             /* refresh the positions */
  3086.             tmprow = row;
  3087.             while (tmprow->next && tmprow->next->par == row->par) {
  3088.                 tmprow = tmprow->next;
  3089.                 tmprow->pos--;
  3090.             }
  3091.             
  3092.             /* delete superfluous blanks */ 
  3093.             if (cursor.pos < cursor.par->Last() - 1 &&
  3094.                 (cursor.par->IsLineSeparator(cursor.pos))) {
  3095.                 
  3096.                 if (cursor.pos == BeginningOfMainBody(cursor.par)
  3097.                     || !cursor.pos 
  3098.                     || cursor.par->IsLineSeparator(cursor.pos - 1)) {
  3099.                     cursor.par->Erase(cursor.pos);
  3100.                     /* refresh the positions */
  3101.                     tmprow = row;
  3102.                     while (tmprow->next && 
  3103.                            tmprow->next->par == row->par) {
  3104.                         tmprow = tmprow->next;
  3105.                         tmprow->pos--;
  3106.                     }
  3107.                     if (cursor.pos)   /* move one character left */
  3108.                         cursor.pos--;
  3109.                 }
  3110.             }
  3111.             
  3112.             /* delete newlines at the beginning of paragraphs */ 
  3113.             while (cursor.par->Last() &&
  3114.                    cursor.par->IsNewline(cursor.pos) &&
  3115.                    cursor.pos == BeginningOfMainBody(cursor.par)
  3116.                 ) {
  3117.                 cursor.par->Erase(cursor.pos);
  3118.                 /* refresh the positions */
  3119.                 tmprow = row;
  3120.                 while (tmprow->next && 
  3121.                        tmprow->next->par == row->par) {
  3122.                     tmprow = tmprow->next;
  3123.                     tmprow->pos--;
  3124.                 }
  3125.             }
  3126.         }
  3127.         
  3128.         /* is there a break one row above */ 
  3129.         if (row->previous && row->previous->par == row->par) {
  3130.             z = NextBreakPoint(row->previous, paperwidth);
  3131.             if ( z >= row->pos) {
  3132.                 row->pos = z + 1;
  3133.                 
  3134.                 tmprow = row->previous;
  3135.                 
  3136.                 /* maybe the current row is now empty */ 
  3137.                 if (row->pos >= row->par->Last()) {
  3138.                     /* remove it */ 
  3139.                     RemoveRow(row);
  3140.                     need_break_row = NULL;
  3141.                 }
  3142.                 else  {
  3143.                     BreakAgainOneRow(row);
  3144.                     if (row->next && row->next->par == row->par)
  3145.                         need_break_row = row->next;
  3146.                     else
  3147.                         need_break_row = NULL;
  3148.                 }
  3149.                 
  3150.                 /* set the dimensions of the row above  */ 
  3151.                 y -= tmprow->height;
  3152.                 tmprow->fill = Fill(tmprow, paperwidth);
  3153.                 SetHeightOfRow(tmprow);
  3154.                 
  3155.                 refresh_y = y;
  3156.                 refresh_row = tmprow;
  3157.                 status = LyXText::NEED_MORE_REFRESH;
  3158.                 SetCursor(cursor.par, cursor.pos);
  3159.                 current_font = rawtmpfont;
  3160.                 real_current_font = realtmpfont;
  3161.                 /* check, whether the last character's font has changed. */
  3162.                 rawtmpfont = cursor.par->GetFontSettings(cursor.par->Last() - 1);
  3163.                 if (rawparfont != rawtmpfont)
  3164.                     RedoHeightOfParagraph(cursor);
  3165.                 return;
  3166.             }
  3167.         }
  3168.         
  3169.         /* break the cursor row again */ 
  3170.         z = NextBreakPoint(row, paperwidth);
  3171.         
  3172.         if ( z != RowLast(row) || 
  3173.              (row->next && row->next->par == row->par &&
  3174.               RowLast(row) == row->par->Last() - 1)){
  3175.             
  3176.             /* it can happen that a paragraph loses one row
  3177.              * without a real breakup. This is when a word
  3178.              * is to long to be broken. Well, I don t care this 
  3179.              * hack ;-) */ 
  3180.             if (row->next && row->next->par == row->par &&
  3181.                 RowLast(row) == row->par->Last() - 1)
  3182.                 RemoveRow(row->next);
  3183.             
  3184.             refresh_y = y;
  3185.             refresh_row = row;
  3186.             status = LyXText::NEED_MORE_REFRESH;
  3187.             
  3188.             BreakAgainOneRow(row);
  3189.             
  3190.             SetCursor(cursor.par, cursor.pos);
  3191.             /* cursor MUST be in row now */
  3192.             
  3193.             if (row->next && row->next->par == row->par)
  3194.                 need_break_row = row->next;
  3195.             else
  3196.                 need_break_row = NULL;
  3197.         } else  {
  3198.             /* set the dimensions of the row */ 
  3199.             row->fill = Fill(row, paperwidth);
  3200.             int tmpheight = row->height;
  3201.             SetHeightOfRow(row);
  3202.             if (tmpheight == row->height)
  3203.                 status = LyXText::NEED_VERY_LITTLE_REFRESH;
  3204.             else
  3205.                 status = LyXText::NEED_MORE_REFRESH;
  3206.             refresh_y = y;
  3207.             refresh_row = row;
  3208.             SetCursor(cursor.par, cursor.pos);
  3209.         }
  3210.     }
  3211.    
  3212.     /* restore the current font 
  3213.      * That is what a user expects! */
  3214.     current_font = rawtmpfont; 
  3215.     real_current_font = realtmpfont;
  3216.     
  3217.     /* check, wether the last characters font has changed. */
  3218.     rawtmpfont = cursor.par->GetFontSettings(cursor.par->Last() - 1);
  3219.     if (rawparfont != rawtmpfont) {
  3220.         RedoHeightOfParagraph(cursor);
  3221.     } else {
  3222.         /* now the special right address boxes */
  3223.         if (lyxstyle.Style(parameters->textclass,
  3224.                    cursor.par->GetLayout())->margintype == MARGIN_RIGHT_ADDRESS_BOX) {
  3225.             RedoDrawingOfParagraph(cursor); 
  3226.         }
  3227.     }
  3228. }
  3229.  
  3230.  
  3231. void LyXText::GetVisibleRow(LyXScreen &scr, int offset, 
  3232.                 Row *row_ptr, long y)
  3233. {
  3234.     /* returns a printed row */
  3235.     
  3236.     int pos, pos_end;
  3237.     float x, tmpx;
  3238.     int y_top, y_bottom;
  3239.     float fill_separator, fill_hfill, fill_label_hfill;
  3240.     LyXParagraph *par, *firstpar;
  3241.     int left_margin;
  3242.     LyXFont font;
  3243.     int maxdesc;
  3244.     if (row_ptr->height <= 0) {
  3245.         fprintf(stderr, "LYX_ERROR: row.height: %d \n",
  3246.             row_ptr->height);
  3247.         return;
  3248.     }
  3249.     left_margin = LabelEnd(row_ptr);
  3250.     PrepareToPrint(row_ptr, x, fill_separator,
  3251.                fill_hfill, fill_label_hfill);
  3252.     
  3253.     int main_body = BeginningOfMainBody(row_ptr->par);
  3254.     
  3255.     /* initialize the pixmap */
  3256.     
  3257.     scr.fillRectangle(gc_clear,
  3258.               0, offset, paperwidth, row_ptr->height);
  3259.     // check for NOT FAST SELECTION
  3260.     if (selection) {
  3261.         /* selection code */ 
  3262.         if (sel_start_cursor.row == row_ptr &&
  3263.             sel_end_cursor.row == row_ptr) {
  3264.             scr.fillRectangle(gc_selection, sel_start_cursor.x,
  3265.                       offset,
  3266.                       sel_end_cursor.x -
  3267.                       sel_start_cursor.x,
  3268.                       row_ptr->height);
  3269.         }
  3270.         else if (sel_start_cursor.row == row_ptr) {
  3271.             scr.fillRectangle(gc_selection, sel_start_cursor.x,
  3272.                       offset,
  3273.                       paperwidth - sel_start_cursor.x,
  3274.                       row_ptr->height);
  3275.         } else if (sel_end_cursor.row == row_ptr) {
  3276.             scr.fillRectangle(gc_selection,0, offset,
  3277.                       sel_end_cursor.x, row_ptr->height);
  3278.         } else if (y > sel_start_cursor.y && y < sel_end_cursor.y) {
  3279.             scr.fillRectangle(gc_selection, 0, offset,
  3280.                       paperwidth, row_ptr->height);
  3281.             
  3282.         }
  3283.     } // end of NOT FAST SELECTION code
  3284.     
  3285.     if (row_ptr->par->pextra_type == PEXTRA_MINIPAGE) {
  3286.         /* draw a marker at the left margin! */ 
  3287.         LyXFont font = GetFont(row_ptr->par, 0);
  3288.         int asc = font.maxAscent();
  3289.         int x = (LYX_PAPER_MARGIN - font.width('|')) / 2;
  3290.         int y1 = (offset + row_ptr->baseline);
  3291.         int y2 = (offset + row_ptr->baseline) - asc;
  3292.  
  3293.         scr.drawVerticalLine(gc_minipage, x, y1, y2);
  3294.     }       
  3295.     if (row_ptr->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
  3296.         LyXFont font(LyXFont::ALL_SANE);
  3297.         font.setSize(LyXFont::SIZE_FOOTNOTE);
  3298.         font.setColor(LyXFont::RED);
  3299.         
  3300.         int box_x = LYX_PAPER_MARGIN;
  3301.         box_x += font.textWidth(" wide-tab ", 10);
  3302.         if (row_ptr->previous && 
  3303.             row_ptr->previous->par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE){
  3304.             LString fs;
  3305.             switch (row_ptr->par->footnotekind) {
  3306.             case LyXParagraph::MARGIN:
  3307.                 fs = " margin";
  3308.                 break;
  3309.             case LyXParagraph::FIG:
  3310.                 fs = " fig";
  3311.                 break;
  3312.             case LyXParagraph::TAB:
  3313.                 fs = " tab";
  3314.                 break;
  3315.             case LyXParagraph::WIDE_FIG:
  3316.                 fs = " wide-fig";
  3317.                 break;
  3318.             case LyXParagraph::WIDE_TAB:
  3319.                 fs = " wide-tab";
  3320.                 break;
  3321.             case LyXParagraph::ALGORITHM:
  3322.                 fs = " alg";
  3323.                 break;
  3324.             case LyXParagraph::FOOTNOTE:
  3325.                 fs = " foot";
  3326.                 break;
  3327.             }
  3328.             
  3329.             // Determine background color.
  3330.             gc_type back = gc_lighted;
  3331.             scr.fillRectangle(back,LYX_PAPER_MARGIN, offset+1,
  3332.                       box_x - LYX_PAPER_MARGIN, 
  3333.                       int(font.maxAscent())+
  3334.                       int(font.maxDescent()));
  3335.             
  3336.             scr.drawLine(gc_foot,
  3337.                      offset,
  3338.                      LYX_PAPER_MARGIN,
  3339.                      paperwidth - 2*LYX_PAPER_MARGIN);
  3340.             
  3341.             scr.drawString(font, fs,
  3342.                        offset + int(font.maxAscent())+1,
  3343.                        LYX_PAPER_MARGIN);
  3344.             scr.drawVerticalLine(gc_foot,
  3345.                          LYX_PAPER_MARGIN,
  3346.                          offset,
  3347.                          offset
  3348.                          + int(font.maxAscent())+
  3349.                          int(font.maxDescent()));
  3350.             
  3351.             scr.drawLine(gc_foot,
  3352.                      offset
  3353.                      + int(font.maxAscent())
  3354.                      + int(font.maxDescent()) + 1,
  3355.                      LYX_PAPER_MARGIN, box_x - LYX_PAPER_MARGIN); 
  3356.         }
  3357.         
  3358.         /* draw the open floats in a red box */
  3359.         scr.drawVerticalLine(gc_foot,
  3360.                      box_x,
  3361.                      offset,  offset + row_ptr->height);
  3362.         
  3363.         scr.drawVerticalLine(gc_foot,
  3364.                      paperwidth - LYX_PAPER_MARGIN,
  3365.                      offset,
  3366.                      offset + row_ptr->height);
  3367.             
  3368.         
  3369.     } else  {
  3370.         if (row_ptr->previous &&
  3371.             row_ptr->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
  3372.             LyXFont font(LyXFont::ALL_SANE);
  3373.             font.setSize(LyXFont::SIZE_FOOTNOTE);
  3374.             
  3375.             int box_x = LYX_PAPER_MARGIN;
  3376.             box_x += font.textWidth(" wide-tab ", 10);
  3377.             
  3378.             scr.drawLine(gc_foot,
  3379.                      offset,
  3380.                      box_x,
  3381.                      paperwidth - LYX_PAPER_MARGIN - box_x);
  3382.         }
  3383.     }
  3384.     
  3385.     LyXLayout* layout = lyxstyle.Style(parameters->textclass,
  3386.                        row_ptr->par->GetLayout());
  3387.     firstpar = row_ptr->par->FirstPhysicalPar();
  3388.     
  3389.     y_top = 0;
  3390.     y_bottom = row_ptr->height;
  3391.     
  3392.     /* is it a first row? */ 
  3393.     if (row_ptr->pos == 0
  3394.         && row_ptr->par == firstpar) {
  3395.         
  3396.         /* think about the margins */ 
  3397.         if (!row_ptr->previous)
  3398.             y_top += LYX_PAPER_MARGIN;
  3399.         
  3400.         if (row_ptr->par->pagebreak_top){ /* draw a top pagebreak  */
  3401.             scr.drawOnOffLine(offset + y_top + 2 * DefaultHeight(),
  3402.                       0, paperwidth);
  3403.             y_top += 3 * DefaultHeight();
  3404.         }
  3405.         
  3406.         if (row_ptr->par->added_space_top.kind() == VSpace::VFILL) {
  3407.             /* draw a vfill top  */
  3408.             scr.drawLine(gc_fill, 
  3409.                      offset + 2 + y_top,
  3410.                      0, LYX_PAPER_MARGIN);
  3411.             scr.drawLine(gc_fill,
  3412.                      offset + y_top + 3 * DefaultHeight(),
  3413.                      0, LYX_PAPER_MARGIN);
  3414.             scr.drawVerticalOnOffLine(LYX_PAPER_MARGIN / 2, 
  3415.                           offset + 2 + y_top,
  3416.                           offset + y_top + 3 *
  3417.                           DefaultHeight());
  3418.             
  3419.             y_top += 3 * DefaultHeight();
  3420.         }
  3421.         
  3422.         /* think about user added space */ 
  3423.         y_top += int(row_ptr->par->added_space_top.inPixels());
  3424.         
  3425.         /* think about the parskip */ 
  3426.         /* some parskips VERY EASY IMPLEMENTATION */ 
  3427.         if (parameters->paragraph_separation == LYX_PARSEP_SKIP) {
  3428.             if (layout->latextype == LATEX_PARAGRAPH
  3429.                 && firstpar->GetDepth() == 0
  3430.                 && firstpar->Previous())
  3431.                 y_top += parameters->getDefSkip().inPixels();
  3432.             else if (firstpar->Previous()
  3433.                  && lyxstyle.Style(parameters->textclass,
  3434.                            firstpar->Previous()->GetLayout())->latextype == LATEX_PARAGRAPH
  3435.                  && firstpar->Previous()->GetDepth() == 0)
  3436.                 // is it right to use defskip here, too? (AS) 
  3437.                 y_top += parameters->getDefSkip().inPixels();
  3438.         }
  3439.         
  3440.         if (row_ptr->par->line_top) {      /* draw a top line  */
  3441.             y_top +=  GetFont(row_ptr->par, 0).ascent('x');
  3442.  
  3443.             scr.drawThickLine(offset + y_top,
  3444.                       0, paperwidth);
  3445.             y_top +=  GetFont(row_ptr->par, 0).ascent('x');
  3446.         }
  3447.         
  3448.         /* should we print a label? */ 
  3449.         if (layout->labeltype >= LABEL_STATIC
  3450.             && (layout->labeltype != LABEL_STATIC
  3451.             || layout->latextype != LATEX_ENVIRONMENT
  3452.             || row_ptr->par->IsFirstInSequence())) {
  3453.             font = GetFont(row_ptr->par, -2);
  3454.             if (!row_ptr->par->GetLabelString().empty()) {
  3455.                 tmpx = x;
  3456.                 LString tmpstring = row_ptr->par->GetLabelString();
  3457.                 
  3458.                 if (layout->labeltype == LABEL_COUNTER_CHAPTER) {
  3459.                     if (parameters->secnumdepth >=0){
  3460.                         /* this is special code for the chapter layout. This is printed in
  3461.                          * an extra row and has a pagebreak at the top. */
  3462.                         maxdesc = int(font.maxDescent() * layout->spacing.getValue() * parameters->spacing.getValue())
  3463.                             + int(layout->parsep) * DefaultHeight();
  3464.                         scr.drawString(font, tmpstring,
  3465.                                    offset + row_ptr->baseline
  3466.                                    - row_ptr->ascent_of_text - maxdesc,
  3467.                                    int(x));
  3468.                     }
  3469.                 } else {
  3470.                     x -= font.stringWidth( layout->labelsep);
  3471.                     x -= font.stringWidth( tmpstring);
  3472.                     /* draw it! */
  3473.                     scr.drawString(font, tmpstring,
  3474.                                offset + row_ptr->baseline, int(x));
  3475.                 }
  3476.                 x = tmpx;
  3477.             }
  3478.             /* the labels at the top of an environment. More or less for bibliography */ 
  3479.         } else if (layout->labeltype == LABEL_TOP_ENVIRONMENT ||
  3480.                layout->labeltype == LABEL_BIBLIO ||
  3481.                layout->labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) {
  3482.             if (row_ptr->par->IsFirstInSequence()) {
  3483.                 font = GetFont(row_ptr->par, -2);
  3484.                 if (!row_ptr->par->GetLabelString().empty()) {
  3485.                     LString tmpstring = row_ptr->par->GetLabelString();
  3486.                     
  3487.                     maxdesc = int(font.maxDescent() * layout->spacing.getValue() * parameters->spacing.getValue()
  3488.                              + (layout->labelbottomsep * DefaultHeight()));
  3489.                     
  3490.                     int top_label_x = int(x);
  3491.                     if (layout->labeltype == LABEL_CENTERED_TOP_ENVIRONMENT){
  3492.                         top_label_x = int(x + (paperwidth - RightMargin(row_ptr) - x) / 2); 
  3493.                         top_label_x -= (font.stringWidth( tmpstring)/2);
  3494.                     }
  3495.                     
  3496.                     scr.drawString(font, tmpstring,
  3497.                                offset + row_ptr->baseline
  3498.                                - row_ptr->ascent_of_text - maxdesc,  
  3499.                                top_label_x);            
  3500.                 }
  3501.             }
  3502.         }
  3503.         if (layout->labeltype==LABEL_BIBLIO) { // ale970302
  3504.             if (row_ptr->par->bibkey) {
  3505.                 tmpx = x;
  3506.                 x -= font.stringWidth(layout->labelsep);
  3507.                 font = GetFont(row_ptr->par, -1);
  3508.                 x -= row_ptr->par->bibkey->Width(font);
  3509.                 row_ptr->par->bibkey->Draw(font, scr,
  3510.                                offset + row_ptr->baseline, 
  3511.                                x);
  3512.                 x = tmpx;
  3513.             }
  3514.         } 
  3515.     }
  3516.     
  3517.     /* is it a last row? */
  3518.     par = row_ptr->par->LastPhysicalPar();
  3519.     if (row_ptr->par->ParFromPos(RowLast(row_ptr) + 1) == par
  3520.         && (!row_ptr->next || row_ptr->next->par != row_ptr->par)) {     
  3521.         
  3522.         /* think about the margins */ 
  3523.         if (!row_ptr->next)
  3524.             y_bottom -= LYX_PAPER_MARGIN;
  3525.         
  3526.         /* draw a bottom pagebreak */ 
  3527.         if (firstpar->pagebreak_bottom) {
  3528.             scr.drawOnOffLine(offset + y_bottom - 2 *
  3529.                       DefaultHeight(),
  3530.                       0, paperwidth);
  3531.             y_bottom -= 3 * DefaultHeight();
  3532.         }
  3533.         
  3534.         if (firstpar->added_space_bottom.kind() == VSpace::VFILL) {
  3535.             /* draw a vfill bottom  */
  3536.             scr.drawLine(gc_fill,
  3537.                      offset + y_bottom - 3 * DefaultHeight(),
  3538.                      0, LYX_PAPER_MARGIN);
  3539.             scr.drawLine(gc_fill, offset + y_bottom - 2,
  3540.                      0, LYX_PAPER_MARGIN);
  3541.             scr.drawVerticalOnOffLine(LYX_PAPER_MARGIN / 2, 
  3542.                           offset + y_bottom - 3 * DefaultHeight(),
  3543.                           offset + y_bottom - 2
  3544.                 );        
  3545.             y_bottom -= 3* DefaultHeight();
  3546.         }
  3547.         
  3548.         /* think about user added space */ 
  3549.         y_bottom -= int(firstpar->added_space_bottom.inPixels());
  3550.         
  3551.         if (firstpar->line_bottom) {
  3552.             /* draw a bottom line */
  3553.             y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
  3554.  
  3555.             scr.drawThickLine(offset + y_bottom,
  3556.                       0, paperwidth);        
  3557.             y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
  3558.         }
  3559.     }
  3560.     
  3561.     /* draw the text in the pixmap */  
  3562.     pos_end = RowLast(row_ptr);
  3563.     
  3564.     pos = row_ptr->pos;
  3565.     /* table stuff -- begin*/
  3566.     if (row_ptr->par->table) {
  3567.         bool on_off;
  3568.         int cell = NumberOfCell(row_ptr->par, row_ptr->pos);
  3569.         float x_old = x;
  3570.         x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
  3571.         
  3572.         while (pos <= pos_end)  {
  3573.             if (row_ptr->par->IsNewline(pos)) {
  3574.                 
  3575.                 x = x_old + row_ptr->par->table->WidthOfColumn(cell);
  3576.                 /* draw the table lines, still very simple */
  3577.                 on_off = !row_ptr->par->table->TopLine(cell);
  3578.                 if ((!on_off ||
  3579.                      !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
  3580.                     !row_ptr->par->table->IsContRow(cell))
  3581.                     scr.drawTableLine(offset + row_ptr->baseline -
  3582.                               row_ptr->ascent_of_text,
  3583.                               int(x_old), int(x - x_old), on_off);
  3584.                 on_off = !row_ptr->par->table->BottomLine(cell);
  3585.                 if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
  3586.                     row_ptr->par->table->VeryLastRow(cell))
  3587.                     scr.drawTableLine(offset + y_bottom - 1,
  3588.                               int(x_old), int(x - x_old), on_off);
  3589.                 on_off = !row_ptr->par->table->LeftLine(cell);
  3590.                 
  3591.                 scr.drawVerticalTableLine(int(x_old), 
  3592.                               offset + row_ptr->baseline -
  3593.                               row_ptr->ascent_of_text,
  3594.                               offset + y_bottom - 1,
  3595.                               on_off);
  3596.                 on_off = !row_ptr->par->table->RightLine(cell);
  3597.                 
  3598.                 scr.drawVerticalTableLine(int(x) -
  3599.                               row_ptr->par->table->AdditionalWidth(cell),
  3600.                               offset + row_ptr->baseline -
  3601.                               row_ptr->ascent_of_text,
  3602.                               offset + y_bottom - 1,
  3603.                               on_off);
  3604.                 x_old = x;
  3605.                 /* take care about the alignment and other spaces */
  3606.                 cell++;
  3607.                 x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
  3608.                 if (row_ptr->par->table->IsFirstCell(cell))
  3609.                     cell--; // little hack, sorry
  3610.                 pos++;
  3611.             } else if (row_ptr->par->IsHfill(pos)) {
  3612.                 x += 1;
  3613.                 
  3614.                 scr.drawVerticalLine(gc_fill, int(x),  
  3615.                              offset + row_ptr->baseline - DefaultHeight()/2, 
  3616.                              offset + row_ptr->baseline);        
  3617.                 x += 2;
  3618.                 pos++;
  3619.             } else {
  3620.                 if (row_ptr->par->IsSeparator(pos)) {
  3621.                     tmpx = x;
  3622.                     x+=SingleWidth(row_ptr->par, pos);
  3623.                     /* -------> Only draw protected spaces when not in
  3624.                      * free-spacing mode. */
  3625.                     if (row_ptr->par->GetChar(pos)==LYX_META_PROTECTED_SEPARATOR && !layout->free_spacing) {
  3626.                         scr.drawVerticalLine(gc_fill, int(tmpx),
  3627.                                      offset + row_ptr->baseline - 3,
  3628.                                      offset + row_ptr->baseline - 1);
  3629.                         scr.drawLine(gc_fill,
  3630.                                  offset + row_ptr->baseline - 1,
  3631.                                  int(tmpx),
  3632.                                  int(x-tmpx-2));
  3633.                         scr.drawVerticalLine(gc_fill, int(x-2),
  3634.                                      offset + row_ptr->baseline - 3,
  3635.                                      offset + row_ptr->baseline - 1);            
  3636.                         /* what about underbars? */
  3637.                         font = GetFont(row_ptr->par, pos); 
  3638.                         if (font.underbar() == LyXFont::ON
  3639.                             && font.latex() != LyXFont::ON) {
  3640.                             scr.drawLine(gc_copy,
  3641.                                      offset +
  3642.                                      row_ptr->baseline + 2,
  3643.                                      int(tmpx),
  3644.                                      int(x - tmpx));                
  3645.                         }
  3646.                     }
  3647.                     pos++;
  3648.                 } else
  3649.                     Draw(row_ptr, pos, scr, offset, x);
  3650.             }
  3651.         }
  3652.         
  3653.         /* do not forget the very last cell. This has no NEWLINE so 
  3654.          * ignored by the code above*/ 
  3655.         if (cell == row_ptr->par->table->GetNumberOfCells()-1){
  3656.             x = x_old + row_ptr->par->table->WidthOfColumn(cell);
  3657.             on_off = !row_ptr->par->table->TopLine(cell);
  3658.             if ((!on_off ||
  3659.                  !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
  3660.                 !row_ptr->par->table->IsContRow(cell))
  3661.                 
  3662.                 scr.drawTableLine(offset + row_ptr->baseline -
  3663.                           row_ptr->ascent_of_text,
  3664.                           int(x_old), int(x - x_old), on_off);        
  3665.             on_off = !row_ptr->par->table->BottomLine(cell);
  3666.             if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
  3667.                 row_ptr->par->table->VeryLastRow(cell))
  3668.                 
  3669.                 scr.drawTableLine(offset + y_bottom - 1,
  3670.                           int(x_old), int(x - x_old), on_off);        
  3671.             on_off = !row_ptr->par->table->LeftLine(cell);
  3672.             
  3673.             scr.drawVerticalTableLine(int(x_old), 
  3674.                           offset + row_ptr->baseline -
  3675.                           row_ptr->ascent_of_text,
  3676.                           offset + y_bottom - 1,
  3677.                           on_off);        
  3678.             on_off = !row_ptr->par->table->RightLine(cell);
  3679.             
  3680.             scr.drawVerticalTableLine(int(x) -
  3681.                           row_ptr->par->table->AdditionalWidth(cell),
  3682.                           offset + row_ptr->baseline -
  3683.                           row_ptr->ascent_of_text,
  3684.                           offset + y_bottom - 1,
  3685.                           on_off);        
  3686.         }
  3687.     } else {
  3688.         /* table stuff -- end*/
  3689.         
  3690.         while (pos <= pos_end)  {
  3691.             
  3692.             if (row_ptr->par->IsHfill(pos)) {
  3693.                 x += 1;
  3694.                 scr.drawVerticalLine(gc_fill, int(x),  
  3695.                              offset + row_ptr->baseline - DefaultHeight()/2, 
  3696.                              offset + row_ptr->baseline);        
  3697.                 if (HfillExpansion(row_ptr,pos)) {
  3698.                     if (pos >= main_body) {
  3699.                         scr.drawOnOffLine(offset + row_ptr->baseline -
  3700.                                   DefaultHeight()/4,
  3701.                                   int(x),
  3702.                                   int(fill_hfill));            
  3703.                         x += fill_hfill;
  3704.                     } else {
  3705.                         scr.drawOnOffLine(offset + row_ptr->baseline -
  3706.                                   DefaultHeight()/4,
  3707.                                   int(x),
  3708.                                   int(fill_label_hfill));
  3709.                         x += fill_label_hfill;
  3710.                     }
  3711.                     scr.drawVerticalLine(gc_fill, int(x),
  3712.                                  offset + row_ptr->baseline -
  3713.                                  DefaultHeight()/2, 
  3714.                                  offset + row_ptr->baseline);
  3715.                 }
  3716.                 x += 2;
  3717.                 pos++;
  3718.             } else {
  3719.                 if (row_ptr->par->IsSeparator(pos)) {
  3720.                     tmpx = x;
  3721.                     x+=SingleWidth(row_ptr->par, pos);
  3722.                     if (pos >= main_body)
  3723.                         x+= fill_separator;
  3724.                     /* -------> Only draw protected spaces when not in
  3725.                      * free-spacing mode. */
  3726.                     if (row_ptr->par->GetChar(pos)==LYX_META_PROTECTED_SEPARATOR && !layout->free_spacing) {
  3727.                         
  3728.                         scr.drawVerticalLine(gc_fill, int(tmpx),
  3729.                                      offset + row_ptr->baseline - 3,
  3730.                                      offset + row_ptr->baseline - 1);
  3731.                         scr.drawLine(gc_fill,
  3732.                                  offset + row_ptr->baseline - 1,
  3733.                                  int(tmpx),
  3734.                                  int(x-tmpx-2));
  3735.                         scr.drawVerticalLine(gc_fill, int(x-2),
  3736.                                      offset + row_ptr->baseline - 3,
  3737.                                      offset + row_ptr->baseline - 1);            
  3738.                         /* what about underbars? */
  3739.                         font = GetFont(row_ptr->par, pos); 
  3740.                         if (font.underbar() == LyXFont::ON
  3741.                             && font.latex() != LyXFont::ON) {
  3742.                             scr.drawLine(gc_copy,
  3743.                          offset + row_ptr->baseline + 2,
  3744.                                      int(tmpx),
  3745.                                      int(x - tmpx));
  3746.                         }
  3747.                     }
  3748.                     pos++;
  3749.                 } else
  3750.                     Draw(row_ptr, pos, scr, offset, x);
  3751.             }
  3752.             if (pos == main_body) {
  3753.                 x += GetFont(row_ptr->par, -2).stringWidth(
  3754.                     layout->labelsep);
  3755.                 if (row_ptr->par->IsLineSeparator(pos - 1))
  3756.                     x-= SingleWidth(row_ptr->par, pos - 1);
  3757.                 if (x < left_margin)
  3758.                     x = left_margin;
  3759.             }
  3760.         }
  3761.     }
  3762. }
  3763.  
  3764.  
  3765. int LyXText::DefaultHeight()
  3766. {
  3767.     LyXFont font(LyXFont::ALL_SANE);
  3768.     return int(font.maxAscent() + font.maxDescent() * 1.5);
  3769. }
  3770.  
  3771.    
  3772. /* returns the column near the specified x-coordinate of the row 
  3773. * x is set to the real beginning of this column  */ 
  3774. int  LyXText::GetColumnNearX(Row *row, int& x)
  3775. {
  3776.     int c; 
  3777.     float tmpx;
  3778.     float fill_separator, fill_hfill, fill_label_hfill;
  3779.     int left_margin;
  3780.    
  3781.     left_margin = LabelEnd(row);
  3782.     PrepareToPrint(row, tmpx, fill_separator,
  3783.                fill_hfill, fill_label_hfill);
  3784.     int main_body = BeginningOfMainBody(row->par);
  3785.    
  3786.     c = row->pos;
  3787.  
  3788.     int last = RowLast(row);
  3789.     if (row->par->IsNewline(last))
  3790.         last--;
  3791.    
  3792.     LyXLayout *layout = lyxstyle.Style(parameters->textclass,
  3793.                        row->par->GetLayout());
  3794.     /* table stuff -- begin*/
  3795.     if (row->par->table) {
  3796.         if (!row->next || row->next->par != row->par)
  3797.        last = RowLast(row); /* the last row doesn't need a newline at the end*/
  3798.         int cell = NumberOfCell(row->par, row->pos);
  3799.         float x_old = tmpx;
  3800.         bool ready = false;
  3801.         tmpx += row->par->table->GetBeginningOfTextInCell(cell);
  3802.         while (c <= last
  3803.                && tmpx + SingleWidth(row->par, c)  <= x
  3804.                && !ready){
  3805.             if (row->par->IsNewline(c)) {
  3806.                 if (x_old + row->par->table->WidthOfColumn(cell) <= x){
  3807.                     tmpx = x_old + row->par->table->WidthOfColumn(cell);
  3808.                     x_old = tmpx;
  3809.                     cell++;
  3810.                     tmpx += row->par->table->GetBeginningOfTextInCell(cell);
  3811.                     c++;
  3812.                 } else
  3813.                     ready = true;
  3814.             } else {
  3815.                 tmpx += SingleWidth(row->par, c);
  3816.                 c++;
  3817.             }
  3818.         }
  3819.     } else
  3820.         /* table stuff -- end*/
  3821.  
  3822.         while (c <= last
  3823.                && tmpx + SingleWidth(row->par, c)  <= x) {
  3824.             
  3825.             if (c && c == main_body
  3826.                 && !row->par->IsLineSeparator(c - 1)) {
  3827.                 tmpx += GetFont(row->par, -2)
  3828.                     .stringWidth(layout->labelsep);
  3829.                 if (tmpx < left_margin)
  3830.                     tmpx = left_margin;
  3831.             }
  3832.          
  3833.             tmpx += SingleWidth(row->par, c);
  3834.             if (HfillExpansion(row, c)) {
  3835.                 if (c >= main_body)
  3836.                     tmpx += fill_hfill;
  3837.                 else
  3838.                     tmpx += fill_label_hfill;
  3839.             }
  3840.             else if (c >= main_body
  3841.                  && row->par->IsSeparator(c)) {
  3842.                 tmpx+= fill_separator;  
  3843.             }
  3844.             c++;
  3845.             if (c == main_body
  3846.                 && row->par->IsLineSeparator(c - 1)) {
  3847.                 tmpx += GetFont(row->par, -2)
  3848.                     .stringWidth(layout->labelsep);
  3849.                 tmpx-= SingleWidth(row->par, c - 1);
  3850.                 if (tmpx < left_margin)
  3851.                     tmpx = left_margin;
  3852.             }
  3853.         }
  3854.     /* make shure that a last space in a row doesnt count */
  3855.     if (c > 0 && c >= last
  3856.         && row->par->IsLineSeparator(c - 1)
  3857.         && !(!row->next || row->next->par != row->par)) {
  3858.         tmpx -= SingleWidth(row->par, c - 1);
  3859.         tmpx -= fill_separator;
  3860.     }
  3861.     c-=row->pos;
  3862.     
  3863.     x = int(tmpx);
  3864.     return c;
  3865. }
  3866.  
  3867.    
  3868. /* turn the selection into a new environment. If there is no selection,
  3869. * create an empty environment */ 
  3870. void LyXText::InsertFootnoteEnvironment(LyXParagraph::footnote_kind kind)
  3871. {
  3872.    /* no footnoteenvironment in a footnoteenvironment */ 
  3873.    if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
  3874.       WriteAlert(_("Impossible operation"), 
  3875.          _("You can't insert a float in a float!"), 
  3876.          _("Sorry."));
  3877.      return;
  3878.    }
  3879.    /* no marginpars in minipages */
  3880.    if (kind == LyXParagraph::MARGIN 
  3881.       && cursor.par->pextra_type == PEXTRA_MINIPAGE) {
  3882.       WriteAlert(_("Impossible operation"), 
  3883.          _("You can't insert a marginpar in a minipage!"), 
  3884.          _("Sorry."));
  3885.       return;
  3886.    }
  3887.    
  3888.    /* this doesnt make sense, if there is no selection */ 
  3889.    bool dummy_selection = false;
  3890.    if (!selection) {
  3891.       sel_start_cursor = cursor;       /* dummy selection  */
  3892.       sel_end_cursor = cursor;
  3893.       dummy_selection = true;
  3894.    }
  3895.    
  3896.    LyXParagraph *tmppar;
  3897.  
  3898.    if (sel_start_cursor.par->table || sel_end_cursor.par->table){
  3899.       WriteAlert(_("Impossible operation"), _("Cannot cut table."), _("Sorry."));
  3900.       return;
  3901.    }
  3902.      
  3903.    /* a test to make sure there is not already a footnote
  3904.     * in the selection. */
  3905.    
  3906.    tmppar = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
  3907.    
  3908.    while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos) && 
  3909.       tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
  3910.      tmppar = tmppar->next;
  3911.    
  3912.    if (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
  3913.        || tmppar->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
  3914.       WriteAlert(_("Impossible operation"), 
  3915.          _("Float would include float!"), 
  3916.          _("Sorry."));
  3917.       return;
  3918.    }
  3919.    
  3920.    /* ok we have a selection. This is always between sel_start_cursor
  3921.     * and sel_end cursor */
  3922.  
  3923.    SetUndo(Undo::FINISH, 
  3924.        sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous, 
  3925.        sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next); 
  3926.    
  3927.    if (sel_end_cursor.pos > 0 
  3928.        && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1))
  3929.      sel_end_cursor.pos--;           /* please break before a space at
  3930.                     * the end */
  3931.    if (sel_start_cursor.par == sel_end_cursor.par
  3932.        && sel_start_cursor.pos > sel_end_cursor.pos)
  3933.      sel_start_cursor.pos--;
  3934.  
  3935.    sel_end_cursor.par->BreakParagraphConservative(sel_end_cursor.pos);
  3936.    
  3937.    sel_end_cursor.par = sel_end_cursor.par->Next();
  3938.    sel_end_cursor.pos = 0;
  3939.    
  3940.    // don't forget to insert a dummy layout paragraph if necessary
  3941.    if (sel_start_cursor.par->GetLayout() != sel_end_cursor.par->layout){
  3942.      sel_end_cursor.par->BreakParagraphConservative(0);
  3943.      sel_end_cursor.par->layout = LYX_DUMMY_LAYOUT;
  3944.      sel_end_cursor.par = sel_end_cursor.par->next;
  3945.    }
  3946.    else
  3947.      sel_end_cursor.par->layout = LYX_DUMMY_LAYOUT;
  3948.  
  3949.    cursor = sel_end_cursor;
  3950.  
  3951.    /* please break behind a space, if there is one. The space should
  3952.     * be erased too */ 
  3953.    if (sel_start_cursor.pos > 0 
  3954.        && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1))
  3955.      sel_start_cursor.pos--;
  3956.    if (sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)) {
  3957.       sel_start_cursor.par->Erase(sel_start_cursor.pos);
  3958.    }
  3959.    
  3960.    sel_start_cursor.par->BreakParagraphConservative(sel_start_cursor.pos);
  3961.    tmppar = sel_start_cursor.par->Next();
  3962.    
  3963.    if (dummy_selection) {
  3964.        tmppar->Clear();
  3965.        if (kind == LyXParagraph::TAB
  3966.            || kind == LyXParagraph::FIG 
  3967.                || kind == LyXParagraph::WIDE_TAB
  3968.            || kind == LyXParagraph::WIDE_FIG 
  3969.                || kind == LyXParagraph::ALGORITHM) {
  3970.            int lay = lyxstyle.NumberOfLayout(parameters->textclass,
  3971.                              "Caption");
  3972.            if (lay == -1) // layout not found
  3973.                // use default layout "Standard" (0)
  3974.                lay = 0;
  3975.            tmppar->SetLayout(lay);
  3976.        }
  3977.    }
  3978.    else {
  3979.      if (sel_start_cursor.pos > 0) {
  3980.        /* the footnote-environment should begin with a standard layout.
  3981.     * Imagine you insert a footnote within an enumeration, you 
  3982.     * certainly do not want an enumerated footnote! */ 
  3983.        tmppar->Clear();
  3984.      }
  3985.      else {
  3986.        /* this is a exception the user would sometimes expect, I hope */
  3987.        sel_start_cursor.par->Clear();
  3988.      }
  3989.    }
  3990.    
  3991.    while (tmppar != sel_end_cursor.par) {
  3992.       tmppar->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
  3993.       tmppar->footnotekind = kind;
  3994.       tmppar = tmppar->Next();
  3995.    } 
  3996.  
  3997.    RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
  3998.    
  3999.    SetCursor(sel_start_cursor.par->Next(), 0);
  4000.  
  4001.    ClearSelection();
  4002. }
  4003.    
  4004.  
  4005. /* returns pointer to a specified row */
  4006. Row* LyXText::GetRow(LyXParagraph *par, int pos, long &y)
  4007. {
  4008.    Row* tmprow;
  4009.  
  4010.    if (currentrow){
  4011.      if (par == currentrow->par || par == currentrow->par->Previous()){
  4012.        while (currentrow->previous &&
  4013.           currentrow->previous->par != par->previous){
  4014.      currentrow = currentrow->previous;
  4015.      currentrow_y -= currentrow->height;
  4016.        }
  4017.      }
  4018.      tmprow = currentrow;
  4019.      y = currentrow_y;
  4020.      /* find the first row of the specified paragraph */ 
  4021.      while (tmprow->next && (tmprow->par != par)) {
  4022.        y += tmprow->height;
  4023.        tmprow = tmprow->next;
  4024.      }
  4025.  
  4026.      if (tmprow->par == par){
  4027.        /* now find the wanted row */ 
  4028.        while (tmprow->pos < pos && tmprow->next && tmprow->next->par == par && 
  4029.           tmprow->next->pos <= pos) {
  4030.      y += tmprow->height;
  4031.        tmprow = tmprow->next;
  4032.        }
  4033.        currentrow = tmprow;
  4034.        currentrow_y = y;
  4035.        return tmprow;
  4036.      }
  4037.    }
  4038.    tmprow = firstrow;
  4039.    y = 0;
  4040.    /* find the first row of the specified paragraph */ 
  4041.    while (tmprow->next && (tmprow->par != par)) {
  4042.       y += tmprow->height;
  4043.       tmprow = tmprow->next;
  4044.    }
  4045.  
  4046.    /* now find the wanted row */ 
  4047.    while (tmprow->pos < pos && tmprow->next && tmprow->next->par == par && 
  4048.       tmprow->next->pos <= pos) {
  4049.          y += tmprow->height;
  4050.          tmprow = tmprow->next;
  4051.    }
  4052.    
  4053.    currentrow = tmprow;
  4054.    currentrow_y = y;
  4055.  
  4056.    return tmprow;
  4057. }
  4058.