]> git.lyx.org Git - lyx.git/blobdiff - src/Row.cpp
GuiAbout: enforce a reasonable width (show all tabs)
[lyx.git] / src / Row.cpp
index aeede91d85e7d0e61371eec64cc2edffc56bab5d..57f02e2987867729d1643f70b976202944a9bec6 100644 (file)
 
 #include "support/debug.h"
 #include "support/lassert.h"
+#include "support/lyxalgo.h"
 
-#include <algorithm>
 #include <ostream>
 
-#include <boost/next_prior.hpp>
-
 using namespace std;
 
 namespace lyx {
@@ -47,10 +45,11 @@ double Row::Element::pos2x(pos_type const i) const
 
        double w = 0;
        //handle first the two bounds of the element
-       if (i == endpos && !(inset && inset->lyxCode() == SEPARATOR_CODE))
-               w = rtl ? 0 : width();
+       if (i == endpos && type != VIRTUAL
+               && !(inset && inset->lyxCode() == SEPARATOR_CODE))
+               w = rtl ? 0 : full_width();
        else if (i == pos || type != STRING)
-               w = rtl ? width() : 0;
+               w = rtl ? full_width() : 0;
        else {
                FontMetrics const & fm = theFontMetrics(font);
                w = fm.pos2x(str, i - pos, font.isVisibleRightToLeft());
@@ -60,7 +59,7 @@ double Row::Element::pos2x(pos_type const i) const
 }
 
 
-pos_type Row::Element::x2pos(double &x) const
+pos_type Row::Element::x2pos(int &x) const
 {
        //lyxerr << "x2pos: x=" << x << " w=" << width() << " " << *this;
        bool const rtl = font.isVisibleRightToLeft();
@@ -69,24 +68,21 @@ pos_type Row::Element::x2pos(double &x) const
        switch (type) {
        case STRING: {
                FontMetrics const & fm = theFontMetrics(font);
-               // FIXME: is it really necessary for x to be a double?
-               int xx = int(x);
-               i = fm.x2pos(str, xx, rtl);
-               x = xx;
+               i = fm.x2pos(str, x, rtl);
                break;
        }
        case VIRTUAL:
                // those elements are actually empty (but they have a width)
                i = 0;
-               x = rtl ? width() : 0;
+               x = rtl ? int(full_width()) : 0;
                break;
        case SEPARATOR:
        case INSET:
        case SPACE:
                // those elements contain only one position. Round to
                // the closest side.
-               if (x > width()) {
-                       x = width();
+               if (x > full_width()) {
+                       x = int(full_width());
                        i = !rtl;
                } else {
                        x = 0;
@@ -100,22 +96,22 @@ pos_type Row::Element::x2pos(double &x) const
 }
 
 
-bool Row::Element::breakAt(double w)
+bool Row::Element::breakAt(int w)
 {
-       if (type != STRING || width() <= w)
+       if (type != STRING || dim.wid <= w)
                return false;
 
        bool const rtl = font.isVisibleRightToLeft();
        if (rtl)
-               w = width() - w;
+               w = dim.wid - w;
        pos_type new_pos = x2pos(w);
        if (new_pos == pos)
                return false;
        str = str.substr(0, new_pos - pos);
        if (rtl)
-               dim.wid -= int(w);
+               dim.wid -= w;
        else
-               dim.wid = int(w);
+               dim.wid = w;
        endpos = new_pos;
        return true;
 }
@@ -134,7 +130,7 @@ pos_type Row::Element::right_pos() const
 
 
 Row::Row()
-       : separator(0), label_hfill(0), x(0), right_margin(0),
+       : separator(0), label_hfill(0), left_margin(0), right_margin(0),
          sel_beg(-1), sel_end(-1),
          begin_margin_sel(false), end_margin_sel(false),
          changed_(false), crc_(0), pos_(0), end_(0), right_boundary_(false)
@@ -236,7 +232,7 @@ ostream & operator<<(ostream & os, Row::Element const & e)
                os << "SPACE: ";
                break;
        }
-       os << "width=" << e.width();
+       os << "width=" << e.full_width();
        return os;
 }
 
@@ -244,7 +240,7 @@ ostream & operator<<(ostream & os, Row::Element const & e)
 ostream & operator<<(ostream & os, Row const & row)
 {
        os << " pos: " << row.pos_ << " end: " << row.end_
-          << " x: " << row.x
+          << " left_margin: " << row.left_margin
           << " width: " << row.dim_.wid
           << " right_margin: " << row.right_margin
           << " ascent: " << row.dim_.asc
@@ -252,11 +248,11 @@ ostream & operator<<(ostream & os, Row const & row)
           << " separator: " << row.separator
           << " label_hfill: " << row.label_hfill 
           << " row_boundary: " << row.right_boundary() << "\n";
-       double x = row.x;
+       double x = row.left_margin;
        Row::Elements::const_iterator it = row.elements_.begin();
        for ( ; it != row.elements_.end() ; ++it) {
                os << "x=" << x << " => " << *it << endl;
-               x += it->width();
+               x += it->full_width();
        }
        return os;
 }
@@ -362,37 +358,50 @@ void Row::shortenIfNeeded(pos_type const keep, int const w)
        if (empty() || width() <= w)
                return;
 
-       /** First, we try to remove elements one by one from the end
-        * until a separator is found. cit points to the first element
-        * we want to remove from the row.
-        */
        Elements::iterator const beg = elements_.begin();
        Elements::iterator const end = elements_.end();
-       Elements::iterator cit = end;
-       Elements::iterator first_below = end;
-       int new_end = end_;
-       int new_wid = dim_.wid;
-       // if the row ends with a separator, skip it.
-       if (cit != beg && boost::prior(cit)->type == SEPARATOR && new_end > keep) {
-               --cit;
-               new_end = cit->pos;
-               new_wid -= cit->dim.wid;
+       Elements::iterator last_sep = elements_.end();
+       int last_width = 0;
+       int wid = left_margin;
+
+       Elements::iterator cit = beg;
+       for ( ; cit != end ; ++cit) {
+               if (cit->type == SEPARATOR && cit->pos >= keep) {
+                       last_sep = cit;
+                       last_width = wid;
+               }
+               if (wid + cit->dim.wid > w)
+                       break;
+               wid += cit->dim.wid;
+       }
+
+       if (last_sep != end) {
+               // We have found a suitable separator. This is the
+               // common case.
+               end_ = last_sep->endpos;
+               dim_.wid = last_width;
+               elements_.erase(last_sep, end);
+               return;
        }
 
-       // Search for a separator where the row can be broken.
-       while (cit != beg && boost::prior(cit)->type != SEPARATOR && new_end > keep) {
+       if (cit == end) {
+               // This should not happen since the row is too long.
+               LYXERR0("Something is wrong cannot shorten row: " << *this);
+               return;
+       }
+
+       if (cit != beg && cit->type == VIRTUAL) {
+               // It is not possible to separate a virtual element from the
+               // previous one.
                --cit;
-               new_end = cit->pos;
-               new_wid -= cit->dim.wid;
-               if (new_wid < w && first_below == end)
-                       first_below = cit;
+               wid -= cit->dim.wid;
        }
 
        if (cit != beg) {
-               // We have found a suitable separator. This is the
-               // common case.
-               end_ = new_end;
-               dim_.wid = new_wid;
+               // There is no separator, but several elements (probably
+               // insets) have been added. We can cut at this place.
+               end_ = cit->pos;
+               dim_.wid = wid;
                elements_.erase(cit, end);
                return;
        }
@@ -402,17 +411,11 @@ void Row::shortenIfNeeded(pos_type const keep, int const w)
         * something: when we have one big string, maybe with some
         * other things after it.
         */
-       double max_w = w - x;
-       if (first_below->breakAt(max_w)) {
-               end_ = first_below->endpos;
-               dim_.wid = int(x + first_below->width());
+       if (cit->breakAt(w - left_margin)) {
+               end_ = cit->endpos;
+               dim_.wid = left_margin + cit->dim.wid;
                // If there are other elements, they should be removed.
-               elements_.erase(boost::next(first_below), end);
-       } else if (first_below->pos > pos_) {
-               end_ = first_below->pos;
-               dim_.wid = new_wid;
-               // Remove all elements from first_below.
-               elements_.erase(first_below, end);
+               elements_.erase(next(cit, 1), end);
        }
 }