mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-25 10:58:52 +00:00
Avoid row breaking at inconvenient places.
When it turns out that breaking a STRING row element was not sufficient in Row::shortenIfNeeded, we still remember the shortest width that one can obtain. Later, when we try to split a previous element of the row, we have a better idea of how much of the row remains after it. To this end, change the signature of Element::splitAt to use an enum: FIT (was: force=false), FORCE (was: force= true) and BEST_EFFORT (split at max_width, but do not return an error if the string is too large). Fixes bug #12660.
This commit is contained in:
parent
1ca43e1938
commit
71d9f6e90d
25
src/Row.cpp
25
src/Row.cpp
@ -123,7 +123,7 @@ pos_type Row::Element::x2pos(int &x) const
|
||||
}
|
||||
|
||||
|
||||
bool Row::Element::splitAt(int const width, int next_width, bool force,
|
||||
bool Row::Element::splitAt(int const width, int next_width, SplitType split_type,
|
||||
Row::Elements & tail)
|
||||
{
|
||||
// Not a string or already OK.
|
||||
@ -142,13 +142,13 @@ bool Row::Element::splitAt(int const width, int next_width, bool force,
|
||||
|
||||
bool const wrap_any = !font.language()->wordWrap();
|
||||
FontMetrics::Breaks breaks = fm.breakString(str, width, next_width,
|
||||
isRTL(), wrap_any | force);
|
||||
isRTL(), wrap_any || split_type == FORCE);
|
||||
|
||||
/** if breaking did not really work, give up
|
||||
* case 1: we do not force break and the first element is longer than the limit;
|
||||
* case 1: split type is FIT and the first element is longer than the limit;
|
||||
* case 2: the first break occurs at the front of the string
|
||||
*/
|
||||
if ((!force && breaks.front().nspc_wid > width)
|
||||
if ((split_type == FIT && breaks.front().nspc_wid > width)
|
||||
|| (breaks.size() > 1 && breaks.front().len == 0)) {
|
||||
if (dim.wid == 0)
|
||||
dim.wid = fm.width(str);
|
||||
@ -548,6 +548,8 @@ Row::Elements Row::shortenIfNeeded(int const max_width, int const next_width)
|
||||
Elements::iterator const beg = elements_.begin();
|
||||
Elements::iterator const end = elements_.end();
|
||||
int wid = left_margin;
|
||||
// the smallest row width we know we can achieve by breaking a string.
|
||||
int min_row_wid = dim_.wid;
|
||||
|
||||
// Search for the first element that goes beyond right margin
|
||||
Elements::iterator cit = beg;
|
||||
@ -600,14 +602,23 @@ Row::Elements Row::shortenIfNeeded(int const max_width, int const next_width)
|
||||
* - shorter than the natural width of the element, in order to enforce
|
||||
* break-up.
|
||||
*/
|
||||
if (brk.splitAt(min(max_width - wid_brk, brk.dim.wid - 2), next_width, false, tail)) {
|
||||
int const split_width = min(max_width - wid_brk, brk.dim.wid - 2);
|
||||
if (brk.splitAt(split_width, next_width, BEST_EFFORT, tail)) {
|
||||
// if we did not manage to fit a part of the element into
|
||||
// the split_width limit, at least remember that we can
|
||||
// shorten the row if needed.
|
||||
if (brk.dim.wid > split_width) {
|
||||
min_row_wid = wid_brk + brk.dim.wid;
|
||||
tail.clear();
|
||||
continue;
|
||||
}
|
||||
/* if this element originally did not cause a row overflow
|
||||
* in itself, and the remainder of the row would still be
|
||||
* too large after breaking, then we will have issues in
|
||||
* next row. Thus breaking does not help.
|
||||
*/
|
||||
if (wid_brk + cit_brk->dim.wid < max_width
|
||||
&& dim_.wid - (wid_brk + brk.dim.wid) >= next_width) {
|
||||
&& min_row_wid - (wid_brk + brk.dim.wid) >= next_width) {
|
||||
tail.clear();
|
||||
break;
|
||||
}
|
||||
@ -641,7 +652,7 @@ Row::Elements Row::shortenIfNeeded(int const max_width, int const next_width)
|
||||
* shorten the row. Let's try to break it again, but force
|
||||
* splitting this time.
|
||||
*/
|
||||
if (cit->splitAt(max_width - wid, next_width, true, tail)) {
|
||||
if (cit->splitAt(max_width - wid, next_width, FORCE, tail)) {
|
||||
end_ = cit->endpos;
|
||||
dim_.wid = wid + cit->dim.wid;
|
||||
// If there are other elements, they should be removed.
|
||||
|
14
src/Row.h
14
src/Row.h
@ -55,6 +55,14 @@ public:
|
||||
// by the initial width
|
||||
MARGINSPACE
|
||||
};
|
||||
enum SplitType {
|
||||
// split string to fit requested width, fail if string remains too long
|
||||
FIT,
|
||||
// if the requested width is too small, accept the first possible break
|
||||
BEST_EFFORT,
|
||||
// cut string at any place, even for languages that wrap at word delimiters
|
||||
FORCE
|
||||
};
|
||||
|
||||
/**
|
||||
* One element of a Row. It has a set of attributes that can be used
|
||||
@ -94,14 +102,12 @@ public:
|
||||
* not needed or not possible.
|
||||
* \param width: maximum width of the row.
|
||||
* \param next_width: available width on next rows.
|
||||
* \param force: if true, cut string at any place, even for
|
||||
* languages that wrap at word delimiters; if false, do not
|
||||
* break at all if first element would larger than \c width.
|
||||
* \param split_type: indicate how the string should be split.
|
||||
* \param tail: a vector of elements where the remainder of
|
||||
* the text will be appended (empty if nothing happened).
|
||||
*/
|
||||
// FIXME: ideally last parameter should be Elements&, but it is not possible.
|
||||
bool splitAt(int width, int next_width, bool force, std::vector<Element> & tail);
|
||||
bool splitAt(int width, int next_width, SplitType split_type, std::vector<Element> & tail);
|
||||
// remove trailing spaces (useful for end of row)
|
||||
void rtrim();
|
||||
|
||||
|
@ -1150,7 +1150,7 @@ RowList TextMetrics::breakParagraph(Row const & bigrow) const
|
||||
// pile, or the place when we were in main row
|
||||
Row::Element elt = *fcit;
|
||||
Row::Elements tail;
|
||||
elt.splitAt(width - rows.back().width(), next_width, false, tail);
|
||||
elt.splitAt(width - rows.back().width(), next_width, Row::FIT, tail);
|
||||
Row & rb = rows.back();
|
||||
if (elt.type == Row::MARGINSPACE)
|
||||
elt.dim.wid = max(elt.dim.wid, leftMargin(bigrow.pit()) - rb.width());
|
||||
|
Loading…
Reference in New Issue
Block a user