]> git.lyx.org Git - lyx.git/blobdiff - src/text.C
John's Layout Tabular UI improvements and Martins fixes to clearing the
[lyx.git] / src / text.C
index 33aa39f811651ecf1aff3cedabb092d6e0c8ae6d..e546e323162056e38d1ab286eb4f915d08c041e9 100644 (file)
@@ -12,7 +12,7 @@
 
 #include "lyxtext.h"
 #include "lyxrow.h"
-#include "layout.h"
+#include "lyxtextclasslist.h"
 #include "paragraph.h"
 #include "lyx_gui_misc.h"
 #include "gettext.h"
@@ -69,17 +69,26 @@ int LyXText::workWidth(BufferView * bview) const
 int LyXText::workWidth(BufferView * bview, Inset * inset) const
 {
        Paragraph * par = 0;
-       pos_type pos = 0;
-
-       Buffer::inset_iterator it = bview->buffer()->inset_iterator_begin();
-
-       for (; it != bview->buffer()->inset_iterator_end(); ++it) {
-               if (*it == inset) {
-                       par = it.getPar();
-                       pos = it.getPos();
-                       break;
+       pos_type pos = -1;
+
+       par = inset->parOwner();
+       if (par)
+               pos = par->getPositionOfInset(inset);
+
+       if (!par || pos == -1) {
+               lyxerr << "LyXText::workWidth: something is wrong,"
+                       " fall back to the brute force method" << endl;
+               Buffer::inset_iterator it = bview->buffer()->inset_iterator_begin();
+               Buffer::inset_iterator end = bview->buffer()->inset_iterator_end();
+               for ( ; it != end; ++it) {
+                       if (*it == inset) {
+                               par = it.getPar();
+                               pos = it.getPos();
+                               break;
+                       }
                }
        }
+       
        if (!par) {
                return workWidth(bview);
        }
@@ -100,10 +109,10 @@ int LyXText::workWidth(BufferView * bview, Inset * inset) const
                int dummy_y;
                Row * row = getRow(par, pos, dummy_y);
                Row * frow = row;
-               while(frow->previous() && frow->par() == frow->previous()->par())
+               while (frow->previous() && frow->par() == frow->previous()->par())
                        frow = frow->previous();
                unsigned int maxw = 0;
-               while(frow->next() && frow->par() == frow->next()->par()) {
+               while (frow->next() && frow->par() == frow->next()->par()) {
                        if ((frow != row) && (maxw < frow->width()))
                                maxw = frow->width();
                        frow = frow->next();
@@ -128,7 +137,7 @@ unsigned char LyXText::transformChar(unsigned char c, Paragraph * par,
                        pos_type pos) const
 {
        if (!Encodings::is_arabic(c))
-               if (lyxrc.font_norm_type == LyXRC::ISO_8859_6_8 && isdigit(c))
+               if (lyxrc.font_norm_type == LyXRC::ISO_8859_6_8 && IsDigit(c))
                        return c + (0xb0 - '0');
                else
                        return c;
@@ -236,10 +245,11 @@ int LyXText::singleWidth(BufferView * bview, Paragraph * par,
 // Returns the paragraph position of the last character in the specified row
 pos_type LyXText::rowLast(Row const * row) const
 {
-       if (!row->next() || row->next()->par() != row->par())
+       if (!row->next() || row->next()->par() != row->par()) {
                return row->par()->size() - 1;
-       else 
+       } else {
                return row->next()->pos() - 1;
+       }
 }
 
 
@@ -921,7 +931,7 @@ LyXText::nextBreakPoint(BufferView * bview, Row const * row, int width) const
                textclasslist.Style(bview->buffer()->params.textclass,
                                    par->getLayout());
        pos_type i = pos;
-
+       
        if (layout.margintype == MARGIN_RIGHT_ADDRESS_BOX) {
                /* special code for right address boxes, only newlines count */
                while (i < par->size()) {
@@ -949,7 +959,7 @@ LyXText::nextBreakPoint(BufferView * bview, Row const * row, int width) const
                                last_separator = i;
                                x = width; // this means break
                        } else if (c == Paragraph::META_INSET &&
-                                  par->getInset(i)) {
+                                  par->getInset(i)) {
                                
                                // check wether a Display() inset is
                                // valid here. if not, change it to
@@ -957,12 +967,14 @@ LyXText::nextBreakPoint(BufferView * bview, Row const * row, int width) const
                                if (par->getInset(i)->display() &&
                                    (layout.isCommand() ||
                                     (layout.labeltype == LABEL_MANUAL
-                                     && i < beginningOfMainBody(bview->buffer(), par)))) {
+                                     && i < beginningOfMainBody(bview->buffer(), par))))
+                               {
                                        // display istn't allowd
                                        par->getInset(i)->display(false);
                                        x += singleWidth(bview, par, i, c);
                                } else if (par->getInset(i)->display() ||
-                                        par->getInset(i)->needFullRow()) {
+                                          par->getInset(i)->needFullRow())
+                               {
                                        // So break the line here
                                        if (i == pos) {
                                                if (pos < last-1) {
@@ -976,6 +988,16 @@ LyXText::nextBreakPoint(BufferView * bview, Row const * row, int width) const
                                        x = width;  // this means break
                                } else {
                                        x += singleWidth(bview, par, i, c);
+                                       // we have to check this separately as we could have a
+                                       // lineseparator and then the algorithm below would prefer
+                                       // that which IS wrong! We should always break on an inset
+                                       // if it's too long and not on the last separator.
+                                       // Maybe the only exeption is insets used as chars but
+                                       // then we would have to have a special function inside
+                                       // the inset to tell us this. Till then we leave it as
+                                       // it is now. (Jug 20020106)
+                                       if (pos < i && x >= width && last_separator >= 0)
+                                               last_separator = i - 1;
                                }
                        } else  {
                                if (IsLineSeparatorChar(c))
@@ -993,8 +1015,12 @@ LyXText::nextBreakPoint(BufferView * bview, Row const * row, int width) const
                                        x = left_margin;
                        }
                }
+               if ((pos+1 < i) && (last_separator < 0) && (x >= width))
+                       last_separator = i - 2;
+               else if ((pos < i) && (last_separator < 0) && (x >= width))
+                       last_separator = i - 1;
                // end of paragraph is always a suitable separator
-               if (i == last && x < width)
+               else if (i == last && x < width)
                        last_separator = i;
        }
        
@@ -1125,16 +1151,19 @@ int LyXText::numberOfHfills(Buffer const * buf, Row const * row) const
 {
        pos_type const last = rowLast(row);
        pos_type first = row->pos();
+       
        if (first) { /* hfill *DO* count at the beginning 
                      * of paragraphs! */
-               while(first <= last && row->par()->isHfill(first))
+               while (first <= last && row->par()->isHfill(first)) {
                        ++first;
+               }
        }
 
        first = max(first, beginningOfMainBody(buf, row->par()));
        int n = 0;
        for (pos_type p = first; p <= last; ++p) {
                // last, because the end is ignored!
+               
                if (row->par()->isHfill(p)) {
                        ++n;
                }
@@ -1150,7 +1179,7 @@ int LyXText::numberOfLabelHfills(Buffer const * buf, Row const * row) const
        pos_type first = row->pos();
        if (first) { /* hfill *DO* count at the beginning 
                      * of paragraphs! */
-               while(first < last && row->par()->isHfill(first))
+               while (first < last && row->par()->isHfill(first))
                        ++first;
        }
 
@@ -1342,9 +1371,8 @@ void LyXText::setHeightOfRow(BufferView * bview, Row * row_ptr) const
                        maxasc += LYX_PAPER_MARGIN;
       
                // add the vertical spaces, that the user added
-               if (firstpar->params().spaceTop().kind() != VSpace::NONE)
-                       maxasc += int(firstpar->params().spaceTop().inPixels(bview));
-      
+               maxasc += getLengthMarkerHeight(bview, firstpar->params().spaceTop());
                // do not forget the DTP-lines!
                // there height depends on the font of the nearest character
                if (firstpar->params().lineTop())
@@ -1456,8 +1484,7 @@ void LyXText::setHeightOfRow(BufferView * bview, Row * row_ptr) const
                        maxdesc += LYX_PAPER_MARGIN;
          
                // add the vertical spaces, that the user added
-               if (firstpar->params().spaceBottom().kind() != VSpace::NONE)
-                       maxdesc += int(firstpar->params().spaceBottom().inPixels(bview));
+               maxdesc += getLengthMarkerHeight(bview, firstpar->params().spaceBottom());
          
                // do not forget the DTP-lines!
                // there height depends on the font of the nearest character
@@ -1474,7 +1501,8 @@ void LyXText::setHeightOfRow(BufferView * bview, Row * row_ptr) const
                // and now the layout spaces, for example before and after
                // a section, or between the items of a itemize or enumerate
                // environment
-               if (!firstpar->params().pagebreakBottom() && row_ptr->par()->next()) {
+               if (!firstpar->params().pagebreakBottom()
+                   && row_ptr->par()->next()) {
                        Paragraph * nextpar = row_ptr->par()->next();
                        Paragraph * comparepar = row_ptr->par();
                        float usual = 0;
@@ -1526,7 +1554,7 @@ void LyXText::setHeightOfRow(BufferView * bview, Row * row_ptr) const
        if (inset_owner) {
                Row * r = firstrow;
                width = max(0,workWidth(bview));
-               while(r) {
+               while (r) {
                        if (r->width() > width)
                                width = r->width();
                        r = r->next();
@@ -1777,7 +1805,7 @@ void LyXText::insertChar(BufferView * bview, char c)
                static string const number_seperators = ".,:";
 
                if (current_font.number() == LyXFont::ON) {
-                       if (!isdigit(c) && !contains(number_operators, c) &&
+                       if (!IsDigit(c) && !contains(number_operators, c) &&
                            !(contains(number_seperators, c) &&
                              cursor.pos() >= 1 &&
                              cursor.pos() < cursor.par()->size() &&
@@ -1789,7 +1817,7 @@ void LyXText::insertChar(BufferView * bview, char c)
                                      cursor.pos() - 1).number() == LyXFont::ON)
                            )
                                number(bview); // Set current_font.number to OFF
-               } else if (isdigit(c) &&
+               } else if (IsDigit(c) &&
                           real_current_font.isVisibleRightToLeft()) {
                        number(bview); // Set current_font.number to ON
 
@@ -1908,6 +1936,8 @@ void LyXText::insertChar(BufferView * bview, char c)
        // Is there a break one row above
        if ((cursor.par()->isLineSeparator(cursor.pos())
             || cursor.par()->isNewline(cursor.pos())
+                || ((cursor.pos() < cursor.par()->size()) &&
+                        cursor.par()->isInset(cursor.pos()+1))
             || cursor.row()->fill() == -1)
            && row->previous() && row->previous()->par() == row->par()) {
                pos_type z = nextBreakPoint(bview,
@@ -3158,6 +3188,97 @@ void LyXText::paintRowDepthBar(DrawRowParams & p)
        }
 }
 
+
+int LyXText::getLengthMarkerHeight(BufferView * bv, VSpace const & vsp) const
+{
+       int const arrow_size = 4;
+       int const space_size = int(vsp.inPixels(bv));
+
+       if (vsp.kind() != VSpace::LENGTH) {
+               return space_size;
+       }
+       LyXFont font;
+       font.decSize();
+       int const min_size = std::max(3 * arrow_size,
+                                     lyxfont::maxAscent(font)
+                                     + lyxfont::maxDescent(font));
+
+       if (vsp.length().len().value() < 0.0)
+               return min_size;
+       else 
+               return std::max(min_size, space_size);
+}
+
+int LyXText::drawLengthMarker(DrawRowParams & p, string const & prefix,
+                             VSpace const & vsp, int start)
+{
+       int const arrow_size = 4;
+       int const size = getLengthMarkerHeight(p.bv, vsp);
+       int const end = start + size;
+
+       // the label to display (if any)
+       string str;
+       // y-values for top arrow
+       int ty1, ty2;
+       // y-values for bottom arrow
+       int by1, by2;
+       switch (vsp.kind()) {
+       case VSpace::LENGTH:
+       {
+               str = prefix + " (" + vsp.asLyXCommand() + ")";
+               // adding or removing space
+               bool const added = !(vsp.length().len().value() < 0.0);
+               ty1 = added ? (start + arrow_size) : start;
+               ty2 = added ? start : (start + arrow_size);
+               by1 = added ? (end - arrow_size) : end;
+               by2 = added ? end : (end - arrow_size);
+               break;
+       }
+       case VSpace:: VFILL:
+               str = prefix + " (vertical fill)";
+               ty1 = ty2 = start;
+               by1 = by2 = end;
+               break;
+       default:
+               // nothing to draw here
+               return size;
+       }
+       int const leftx = p.xo + leftMargin(p.bv, p.row);
+       int const midx = leftx + arrow_size;
+       int const rightx = midx + arrow_size;
+       // first the string
+       int w = 0;
+       int a = 0;
+       int d = 0;
+       LyXFont font;
+       font.setColor(LColor::added_space).decSize();
+       lyxfont::rectText(str, font, w, a, d);
+       p.pain->rectText(leftx + 2 * arrow_size + 5, 
+                        start + ((end - start) / 2) + d,
+                        str, font,
+                        backgroundColor(),
+                        backgroundColor());
+       
+       // top arrow
+       p.pain->line(leftx, ty1, midx, ty2, LColor::added_space);
+       p.pain->line(midx, ty2, rightx, ty1, LColor::added_space);
+
+       // bottom arrow
+       p.pain->line(leftx, by1, midx, by2, LColor::added_space);
+       p.pain->line(midx, by2, rightx, by1, LColor::added_space);
+
+       // joining line
+       p.pain->line(midx, ty2, midx, by2, LColor::added_space);
+
+       return size;
+}
  
 void LyXText::paintFirstRow(DrawRowParams & p)
 {
@@ -3170,7 +3291,7 @@ void LyXText::paintFirstRow(DrawRowParams & p)
        }
        
        int y_top = 0;
-               
+
        // think about the margins
        if (!p.row->previous() && bv_owner)
                y_top += LYX_PAPER_MARGIN;
@@ -3195,49 +3316,9 @@ void LyXText::paintFirstRow(DrawRowParams & p)
                y_top += 3 * defaultHeight();
        }
        
-       // draw a vfill top
-       if (parparams.spaceTop().kind() == VSpace::VFILL) {
-               int const y1 = p.yo + y_top + 3 * defaultHeight();
-               int const y2 = p.yo + 2 + y_top;
-               p.pain->line(0, y1, LYX_PAPER_MARGIN, y1, LColor::added_space);
-               
-               p.pain->line(0, y2, LYX_PAPER_MARGIN, y2, LColor::added_space);
-
-               int const x = LYX_PAPER_MARGIN / 2;
-               p.pain->line(x, y2, x, y1, LColor::added_space);
-               
-               y_top += 3 * defaultHeight();
-       } else if (parparams.spaceTop().kind() == VSpace::LENGTH) {
-               string str = string(_("Space above")) + " ("
-                       + parparams.spaceTop().asLyXCommand()
-                       + ")";
-               int const space = int(parparams.spaceTop().inPixels(p.bv));
-               int const y = p.yo + y_top + space / 2;
-               p.pain->line(p.xo, y, p.xo + p.width, y, 
-                       LColor::added_space, Painter::line_onoffdash);
-               int w = 0;
-               int a = 0;
-               int d = 0;
-               LyXFont pb_font;
-               pb_font.setColor(LColor::added_space).decSize();
-               lyxfont::rectText(str, pb_font, w, a, d);
-
-               // don't draw if it won't fit 
-               if (a + d + 4 < space) { 
-                       p.pain->rectText(p.xo + (p.width - w)/2, y + d,
-                                     str, pb_font,
-                                     backgroundColor(),
-                                     backgroundColor());
-               }
-       }
-       
-       y_top += int(parparams.spaceTop().inPixels(p.bv));
+       // draw the additional space if needed:
+       y_top += drawLengthMarker(p, _("Space above"),
+                                 parparams.spaceTop(), p.yo + y_top);
        
        Buffer const * buffer = p.bv->buffer();
  
@@ -3274,8 +3355,8 @@ void LyXText::paintFirstRow(DrawRowParams & p)
                y_top += asc;
  
                int const w = (inset_owner ?  inset_owner->width(p.bv, font) : ww);
-               int const xp = static_cast<int>(inset_owner ? p.x : 0);
-               p.pain->line(xp, p.yo + y_top, w, p.yo + y_top,
+               int const xp = static_cast<int>(inset_owner ? p.xo : 0);
+               p.pain->line(xp, p.yo + y_top, xp + w, p.yo + y_top,
                        LColor::topline, Painter::line_solid,
                        Painter::line_thick);
                
@@ -3316,7 +3397,7 @@ void LyXText::paintFirstRow(DrawRowParams & p)
                                                        lyxfont::width(str, font);
                                        }
  
-                                       p.pain->text(int(x), p.yo +
+                                       p.pain->text(int(x),
                                                p.yo + p.row->baseline() - 
                                                p.row->ascent_of_text() - maxdesc,
                                                str, font);
@@ -3325,9 +3406,10 @@ void LyXText::paintFirstRow(DrawRowParams & p)
                                if (is_rtl) {
                                        x = ww - leftMargin(p.bv, p.row)
                                                + lyxfont::width(layout.labelsep, font);
-                               } else
+                               } else {
                                        x = p.x - lyxfont::width(layout.labelsep, font)
                                                - lyxfont::width(str, font);
+                               }
 
                                p.pain->text(int(x), p.yo + p.row->baseline(), str, font);
                        }
@@ -3386,7 +3468,7 @@ void LyXText::paintLastRow(DrawRowParams & p)
 {
        Paragraph * par = p.row->par();
        ParagraphParameters const & parparams = par->params();
-       int y_bottom = p.row->height();
+       int y_bottom = p.row->height() - 1;
        
        // think about the margins
        if (!p.row->next() && bv_owner)
@@ -3400,7 +3482,8 @@ void LyXText::paintLastRow(DrawRowParams & p)
                pb_font.setColor(LColor::pagebreak).decSize();
                int const y = p.yo + y_bottom - 2 * defaultHeight();
  
-               p.pain->line(p.xo, y, p.xo + p.width, y, LColor::pagebreak, Painter::line_onoffdash);
+               p.pain->line(p.xo, y, p.xo + p.width, y, LColor::pagebreak,
+                            Painter::line_onoffdash);
  
                int w = 0;
                int a = 0;
@@ -3413,49 +3496,12 @@ void LyXText::paintLastRow(DrawRowParams & p)
                y_bottom -= 3 * defaultHeight();
        }
        
-       // draw a vfill bottom
-       if (parparams.spaceBottom().kind() == VSpace::VFILL) {
-               int const x = LYX_PAPER_MARGIN / 2; 
-               int const x2 = LYX_PAPER_MARGIN;
-               int const y = p.yo + y_bottom - 3 * defaultHeight();
-               int const y2 = p.yo + y_bottom - 2;
-               
-               p.pain->line(0, y, x2, y, LColor::added_space);
-               p.pain->line(0, y2, x2, y2, LColor::added_space);
-               p.pain->line(x, y, x, y2, LColor::added_space);
-               y_bottom -= 3 * defaultHeight();
-       } else if (parparams.spaceBottom().kind() == VSpace::LENGTH) {
-               string str = string(_("Space below"))
-                       + " ("
-                       + parparams.spaceBottom().asLyXCommand()
-                       + ")";
-               int const space = int(parparams.spaceBottom().inPixels(p.bv));
-               int const y = p.yo + y_bottom - space / 2;
-               p.pain->line(p.xo, y, p.xo + p.width, y,
-                       LColor::added_space, Painter::line_onoffdash);
-               int w = 0;
-               int a = 0;
-               int d = 0;
-               LyXFont pb_font;
-               pb_font.setColor(LColor::added_space).decSize();
-               lyxfont::rectText(str, pb_font, w, a, d);
-
-               // don't draw if it won't fit 
-               if (a + d + 4 < space) { 
-                       p.pain->rectText(p.xo + (p.width - w) / 2, y + d,
-                                     str, pb_font,
-                                     backgroundColor(),
-                                     backgroundColor());
-               } 
-       }
-       
-       // think about user added space
-       y_bottom -= int(parparams.spaceBottom().inPixels(p.bv));
+       // draw the additional space if needed:
+       int const height =  getLengthMarkerHeight(p.bv,
+                                                 parparams.spaceBottom());
+       y_bottom -= drawLengthMarker(p, _("Space below"),
+                                    parparams.spaceBottom(),
+                                    p.yo + y_bottom - height);
        
        Buffer const * buffer = p.bv->buffer();
  
@@ -3469,15 +3515,14 @@ void LyXText::paintLastRow(DrawRowParams & p)
                y_bottom -= asc;
  
                int const w = (inset_owner ?  inset_owner->width(p.bv, font) : ww);
-               int const xp = static_cast<int>(inset_owner ? p.x : 0);
+               int const xp = static_cast<int>(inset_owner ? p.xo : 0);
                int const y = p.yo + y_bottom; 
-               p.pain->line(xp, y, w, y, LColor::topline, Painter::line_solid,
+               p.pain->line(xp, y, xp + w, y, LColor::topline, Painter::line_solid,
                          Painter::line_thick);
  
                y_bottom -= asc;
        }
 
-       pos_type const last = rowLastPrintable(p.row);
        bool const is_rtl = p.row->par()->isRightToLeftPar(p.bv->buffer()->params);
        int const endlabel = par->getEndLabel(buffer->params);
  
@@ -3486,7 +3531,7 @@ void LyXText::paintLastRow(DrawRowParams & p)
        case END_LABEL_BOX:
        case END_LABEL_FILLED_BOX:
        {
-               LyXFont const font = getFont(buffer, par, last);
+               LyXFont const font = getLabelFont(buffer, par);
                int const size = int(0.75 * lyxfont::maxAscent(font));
                int const y = (p.yo + p.row->baseline()) - size;
                int x = is_rtl ? LYX_PAPER_MARGIN : ww - LYX_PAPER_MARGIN - size;
@@ -3495,12 +3540,10 @@ void LyXText::paintLastRow(DrawRowParams & p)
                        x += (size - p.row->fill() + 1) * (is_rtl ? -1 : 1);
  
                if (endlabel == END_LABEL_BOX) {
-                       p.pain->line(x, y, x, y + size, LColor::eolmarker);
-                       p.pain->line(x + size, y, x + size , y + size, LColor::eolmarker);
-                       p.pain->line(x, y, x + size, y, LColor::eolmarker);
-                       p.pain->line(x, y + size, x + size, y + size, LColor::eolmarker);
+                       p.pain->rectangle(x, y, size, size, LColor::eolmarker);
                } else {
-                       p.pain->fillRectangle(x, y, size, size, LColor::eolmarker);
+                       p.pain->fillRectangle(x, y, size, size,
+                                             LColor::eolmarker);
                }
                break;
        }