X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2FRow.cpp;h=57f02e2987867729d1643f70b976202944a9bec6;hb=0933df00113ee2735699c13559ad3b6e7e9fd115;hp=a0c0dc4ef8aa200c6982bf1e98c4e74177e1539e;hpb=2ff639a0e6d051c6411fe6655cefc36a4e902211;p=lyx.git diff --git a/src/Row.cpp b/src/Row.cpp index a0c0dc4ef8..57f02e2987 100644 --- a/src/Row.cpp +++ b/src/Row.cpp @@ -24,8 +24,8 @@ #include "support/debug.h" #include "support/lassert.h" +#include "support/lyxalgo.h" -#include #include using namespace std; @@ -43,12 +43,13 @@ double Row::Element::pos2x(pos_type const i) const bool const rtl = font.isVisibleRightToLeft(); - int w = 0; + double w = 0; //handle first the two bounds of the element - if (i == pos || type != STRING) - w = rtl ? width() : 0; - else if (i == endpos) - 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 ? full_width() : 0; else { FontMetrics const & fm = theFontMetrics(font); w = fm.pos2x(str, i - pos, font.isVisibleRightToLeft()); @@ -58,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(); @@ -67,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 = 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; @@ -98,6 +96,27 @@ pos_type Row::Element::x2pos(double &x) const } +bool Row::Element::breakAt(int w) +{ + if (type != STRING || dim.wid <= w) + return false; + + bool const rtl = font.isVisibleRightToLeft(); + if (rtl) + 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 -= w; + else + dim.wid = w; + endpos = new_pos; + return true; +} + + pos_type Row::Element::left_pos() const { return font.isVisibleRightToLeft() ? endpos : pos; @@ -110,9 +129,8 @@ 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) @@ -214,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; } @@ -222,18 +240,19 @@ 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 << " descent: " << row.dim_.des << " separator: " << row.separator - << " label_hfill : " << row.label_hfill << "\n"; - double x = row.x; + << " label_hfill: " << row.label_hfill + << " row_boundary: " << row.right_boundary() << "\n"; + 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; } @@ -334,63 +353,70 @@ void Row::pop_back() } -void Row::shorten_if_needed(pos_type const keep, int const w) +void Row::shortenIfNeeded(pos_type const keep, int const w) { - if (empty() || width() < w) + if (empty() || width() <= w) return; - /** First, we try to remove elements one by one from the end - * until a separator is found. - */ - int i = elements_.size(); - int new_end = end_; - int new_wid = dim_.wid; - if (i > 0 && elements_[i - 1].type == SEPARATOR && new_end > keep) { - --i; - new_end = elements_[i].pos; - new_wid -= elements_[i].dim.wid; + Elements::iterator const beg = elements_.begin(); + Elements::iterator const end = elements_.end(); + 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; } - while (i > 0 && elements_[i - 1].type != SEPARATOR && new_end > keep) { - --i; - new_end = elements_[i].pos; - new_wid -= elements_[i].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; } - if (i == 0) { - /* If we are here, it means that we have not found a - * separator to shorten the row. There is one case - * where we can do something: when we have one big - * string, maybe with a paragraph marker after it. - */ - Element & front = elements_.front(); - if (!(front.type == STRING - && (elements_.size() == 1 - || (elements_.size() == 2 - && back().type == VIRTUAL)))) - return; - - // If this is a string element, we can try to split it. - if (front.type != STRING) - return; - double xstr = w - x; - // If there is a paragraph marker, it should be taken in account - if (elements_.size() == 2) - xstr -= back().width(); - //FIXME: use FontMetrics::x2pos here?? handle rtl? - pos_type new_pos = front.x2pos(xstr); - front.str = front.str.substr(0, new_pos - pos_); - front.dim.wid = xstr; - front.endpos = new_pos; - end_ = new_pos; - dim_.wid = x + xstr; - // If there is a paragraph marker, it should be removed. - if (elements_.size() == 2) - elements_.pop_back(); + + if (cit == end) { + // This should not happen since the row is too long. + LYXERR0("Something is wrong cannot shorten row: " << *this); return; } - end_ = new_end; - dim_.wid = new_wid; - elements_.erase(elements_.begin() + i, elements_.end()); + + if (cit != beg && cit->type == VIRTUAL) { + // It is not possible to separate a virtual element from the + // previous one. + --cit; + wid -= cit->dim.wid; + } + + if (cit != beg) { + // 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; + } + + /* If we are here, it means that we have not found a separator + * to shorten the row. There is one case where we can do + * something: when we have one big string, maybe with some + * other things after it. + */ + 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(next(cit, 1), end); + } }