mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-22 13:18:28 +00:00
Handle boundary in getColumnNearX (and more)
Use proper font everywhere for end-of-par marker Fix getColumnNearX for RTL text and for centered/right-justified paragraphs. Let computeRowMetrics update the row width.
This commit is contained in:
parent
f215bb3b92
commit
ff608f46fd
@ -8,13 +8,12 @@ What is done:
|
|||||||
setRowHeight instead of rowBreakPoint and rowHeight.
|
setRowHeight instead of rowBreakPoint and rowHeight.
|
||||||
|
|
||||||
* change breakRow operation to operate on text strings on which
|
* change breakRow operation to operate on text strings on which
|
||||||
metrics are computed. The list of elements is stored in the row object
|
metrics are computed. The list of elements is stored in the row
|
||||||
in visual ordering, not logical.
|
object in visual ordering, not logical.
|
||||||
|
|
||||||
* re-implement cursorX using row elements
|
* re-implement cursorX using row elements
|
||||||
|
|
||||||
* re-implement getColumnNearX using row elements (boundary is not
|
* re-implement getColumnNearX using row elements.
|
||||||
considered yet).
|
|
||||||
|
|
||||||
* Implement proper string metrics computation (with cache), when
|
* Implement proper string metrics computation (with cache), when
|
||||||
lyxrc.force_paint_single_char is false. In this case, remove also
|
lyxrc.force_paint_single_char is false. In this case, remove also
|
||||||
@ -23,7 +22,8 @@ What is done:
|
|||||||
Next steps:
|
Next steps:
|
||||||
|
|
||||||
* get rid of old code of cursorX and getColumnNearX (which have been
|
* get rid of old code of cursorX and getColumnNearX (which have been
|
||||||
kept for comparison purpose, guarded with KEEP_OLD_METRICS_CODE).
|
kept for comparison purpose, guarded with KEEP_OLD_METRICS_CODE in
|
||||||
|
order to check computations).
|
||||||
|
|
||||||
* re-implement row painting using row elements (can it be done?)
|
* re-implement row painting using row elements (can it be done?)
|
||||||
|
|
||||||
@ -31,17 +31,15 @@ Next steps:
|
|||||||
|
|
||||||
* Document the code
|
* Document the code
|
||||||
|
|
||||||
Difference in behavior
|
Difference in behavior (aka bug fixes)
|
||||||
* end of paragraph markers metrics are computed with the font of the
|
|
||||||
actual text, not default font. This will be extended to the other
|
|
||||||
methods.
|
|
||||||
|
|
||||||
* When cursor is after a LtR separator just before a RtL chunk, the
|
* end of paragraph markers metrics are computed with the font of the
|
||||||
|
actual text, not default font.
|
||||||
|
|
||||||
|
* When cursor is after a LTR separator just before a RTL chunk, the
|
||||||
cursor posiiton is computed better with the new code.
|
cursor posiiton is computed better with the new code.
|
||||||
|
|
||||||
Other differences that should be considered as bugs
|
Other differences (aka real bugs)
|
||||||
* words longer than the screen are no monger broken at an arbitrary
|
* words longer than the screen are no monger broken at an arbitrary
|
||||||
point. This is a problem for languages like chinese that do not use
|
point. This is a problem for languages like chinese that do not use
|
||||||
separators.
|
separators.
|
||||||
|
|
||||||
* Boundary is not taken in account properly in getColumnNearX
|
|
||||||
|
37
src/Row.cpp
37
src/Row.cpp
@ -54,7 +54,7 @@ double Row::Element::pos2x(pos_type const i) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pos_type Row::Element::x2pos(double &x) const
|
pos_type Row::Element::x2pos(double &x, bool const low) const
|
||||||
{
|
{
|
||||||
//lyxerr << "x2pos: x=" << x << " w=" << width() << " " << *this;
|
//lyxerr << "x2pos: x=" << x << " w=" << width() << " " << *this;
|
||||||
// if element is rtl, flip x value
|
// if element is rtl, flip x value
|
||||||
@ -84,7 +84,7 @@ pos_type Row::Element::x2pos(double &x) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// round to the closest side
|
// round to the closest side
|
||||||
if (x2 - last_w > w - x2) {
|
if (!low && (x2 - last_w > w - x2)) {
|
||||||
x2 = w;
|
x2 = w;
|
||||||
++i;
|
++i;
|
||||||
} else
|
} else
|
||||||
@ -92,15 +92,13 @@ pos_type Row::Element::x2pos(double &x) const
|
|||||||
|
|
||||||
// is element is rtl, flip values
|
// is element is rtl, flip values
|
||||||
if (rtl) {
|
if (rtl) {
|
||||||
x = last_w - x2;
|
x = width() - x2;
|
||||||
i = endpos - i;
|
|
||||||
} else {
|
} else {
|
||||||
x = x2;
|
x = x2;
|
||||||
i = pos + i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//lyxerr << "=> p=" << i << " x=" << x << endl;
|
//lyxerr << "=> p=" << i << " x=" << x << endl;
|
||||||
return i;
|
return pos + i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -335,9 +333,9 @@ void Row::pop_back()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Row::separate_back(pos_type const keep)
|
void Row::shorten_if_needed(pos_type const keep, int const w)
|
||||||
{
|
{
|
||||||
if (empty())
|
if (empty() || width() < w)
|
||||||
return;
|
return;
|
||||||
int i = elements_.size();
|
int i = elements_.size();
|
||||||
int new_end = end_;
|
int new_end = end_;
|
||||||
@ -353,15 +351,32 @@ void Row::separate_back(pos_type const keep)
|
|||||||
new_end = elements_[i].pos;
|
new_end = elements_[i].pos;
|
||||||
new_wid -= elements_[i].dim.wid;
|
new_wid -= elements_[i].dim.wid;
|
||||||
}
|
}
|
||||||
if (i == 0)
|
if (i == 0) {
|
||||||
|
if (elements_.size() != 1) {
|
||||||
|
LYXERR0("Row is too large but has more than one element. " << *this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#if 1
|
||||||
return;
|
return;
|
||||||
|
#else
|
||||||
|
// does not work yet
|
||||||
|
if (back().type != STRING)
|
||||||
|
return;
|
||||||
|
double xstr = w - x;
|
||||||
|
pos_type new_pos = back().x2pos(xstr, true);
|
||||||
|
back().str = back().str.substr(0, new_pos);
|
||||||
|
back().endpos = new_pos;
|
||||||
|
end_ = new_pos;
|
||||||
|
dim_.wid = x + xstr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
end_ = new_end;
|
end_ = new_end;
|
||||||
dim_.wid = new_wid;
|
dim_.wid = new_wid;
|
||||||
elements_.erase(elements_.begin() + i, elements_.end());
|
elements_.erase(elements_.begin() + i, elements_.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Row::reverseRtL()
|
void Row::reverseRTL()
|
||||||
{
|
{
|
||||||
pos_type i = 0;
|
pos_type i = 0;
|
||||||
pos_type const end = elements_.size();
|
pos_type const end = elements_.size();
|
||||||
@ -372,7 +387,7 @@ void Row::reverseRtL()
|
|||||||
if (i >= end)
|
if (i >= end)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// look for a RtL sequence
|
// look for a RTL sequence
|
||||||
pos_type j = i;
|
pos_type j = i;
|
||||||
while (j < end && elements_[j].font.isRightToLeft())
|
while (j < end && elements_[j].font.isRightToLeft())
|
||||||
++j;
|
++j;
|
||||||
|
25
src/Row.h
25
src/Row.h
@ -69,10 +69,13 @@ public:
|
|||||||
// \param i in the row element
|
// \param i in the row element
|
||||||
double pos2x(pos_type const i) const;
|
double pos2x(pos_type const i) const;
|
||||||
|
|
||||||
// Return character position that is the closest to
|
/** Return character position that is the closest to
|
||||||
// pixel position \param x. The value \param x is
|
* pixel position \param x. The value \param x is
|
||||||
// rounded to the actual pixel position.
|
* rounded to the actual pixel position. If \param
|
||||||
pos_type x2pos(double &x) const;
|
* short is true, the pixel value is rounded by
|
||||||
|
* default.
|
||||||
|
*/
|
||||||
|
pos_type x2pos(double &x, bool low = false) const;
|
||||||
|
|
||||||
// The kind of row element
|
// The kind of row element
|
||||||
Type type;
|
Type type;
|
||||||
@ -186,11 +189,13 @@ public:
|
|||||||
/// remove all row elements
|
/// remove all row elements
|
||||||
void clear() { elements_.clear(); }
|
void clear() { elements_.clear(); }
|
||||||
/**
|
/**
|
||||||
* remove all elements after last separator and update endpos
|
* if row width is too large, remove all elements after last
|
||||||
* if necessary.
|
* separator and update endpos if necessary. If all that
|
||||||
* \param keep is the minimum amount of text to keep.
|
* rename is a large word, cut it to \param width.
|
||||||
|
* \param body_pos minimum amount of text to keep.
|
||||||
|
* \param width maximum width of the row
|
||||||
*/
|
*/
|
||||||
void separate_back(pos_type keep);
|
void shorten_if_needed(pos_type const body_pos, int const width);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If last element of the row is a string, compute its width
|
* If last element of the row is a string, compute its width
|
||||||
@ -199,10 +204,10 @@ public:
|
|||||||
void finalizeLast();
|
void finalizeLast();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find sequences of RtL elements and reverse them.
|
* Find sequences of right-to-left elements and reverse them.
|
||||||
* This should be called once the row is completely built.
|
* This should be called once the row is completely built.
|
||||||
*/
|
*/
|
||||||
void reverseRtL();
|
void reverseRTL();
|
||||||
|
|
||||||
friend std::ostream & operator<<(std::ostream & os, Row const & row);
|
friend std::ostream & operator<<(std::ostream & os, Row const & row);
|
||||||
|
|
||||||
|
@ -636,14 +636,17 @@ void TextMetrics::computeRowMetrics(pit_type const pit,
|
|||||||
//lyxerr << "row.separator " << row.separator << endl;
|
//lyxerr << "row.separator " << row.separator << endl;
|
||||||
//lyxerr << "ns " << ns << endl;
|
//lyxerr << "ns " << ns << endl;
|
||||||
} else if (is_rtl) {
|
} else if (is_rtl) {
|
||||||
|
row.dimension().wid = width;
|
||||||
row.x += w;
|
row.x += w;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LYX_ALIGN_RIGHT:
|
case LYX_ALIGN_RIGHT:
|
||||||
|
row.dimension().wid = width;
|
||||||
row.x += w;
|
row.x += w;
|
||||||
break;
|
break;
|
||||||
case LYX_ALIGN_CENTER:
|
case LYX_ALIGN_CENTER:
|
||||||
|
row.dimension().wid += w / 2;
|
||||||
row.x += w / 2;
|
row.x += w / 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -868,7 +871,7 @@ void TextMetrics::breakRow(Row & row, int const right_margin, pit_type const pit
|
|||||||
// enlarge the last character to hold the end-of-par marker
|
// enlarge the last character to hold the end-of-par marker
|
||||||
Font f(text_->layoutFont(pit));
|
Font f(text_->layoutFont(pit));
|
||||||
f.fontInfo().setColor(Color_paragraphmarker);
|
f.fontInfo().setColor(Color_paragraphmarker);
|
||||||
row.addVirtual(i, docstring(1, char_type(0x00B6)), f, Change());
|
row.addVirtual(i + 1, docstring(1, char_type(0x00B6)), f, Change());
|
||||||
}
|
}
|
||||||
|
|
||||||
// add inline completion width
|
// add inline completion width
|
||||||
@ -916,8 +919,7 @@ void TextMetrics::breakRow(Row & row, int const right_margin, pit_type const pit
|
|||||||
row.finalizeLast();
|
row.finalizeLast();
|
||||||
row.endpos(i);
|
row.endpos(i);
|
||||||
// if the row is too large, try to cut at last separator.
|
// if the row is too large, try to cut at last separator.
|
||||||
if (row.width() >= width)
|
row.shorten_if_needed(body_pos, width);
|
||||||
row.separate_back(body_pos);
|
|
||||||
|
|
||||||
// if the row ends with a separator that is not at end of
|
// if the row ends with a separator that is not at end of
|
||||||
// paragraph, remove it
|
// paragraph, remove it
|
||||||
@ -925,8 +927,8 @@ void TextMetrics::breakRow(Row & row, int const right_margin, pit_type const pit
|
|||||||
&& row.endpos() < par.size())
|
&& row.endpos() < par.size())
|
||||||
row.pop_back();
|
row.pop_back();
|
||||||
|
|
||||||
// make sure that the RtL elements are in reverse ordering
|
// make sure that the RTL elements are in reverse ordering
|
||||||
row.reverseRtL();
|
row.reverseRTL();
|
||||||
|
|
||||||
row.dimension().wid += right_margin;
|
row.dimension().wid += right_margin;
|
||||||
}
|
}
|
||||||
@ -1114,7 +1116,8 @@ void TextMetrics::setRowHeight(Row & row, pit_type const pit,
|
|||||||
pos_type TextMetrics::getColumnNearX(pit_type const pit,
|
pos_type TextMetrics::getColumnNearX(pit_type const pit,
|
||||||
Row const & row, int & x, bool & boundary) const
|
Row const & row, int & x, bool & boundary) const
|
||||||
{
|
{
|
||||||
// FIXME: handle properly boundary (not done now)
|
boundary = false;
|
||||||
|
|
||||||
pos_type pos = row.pos();
|
pos_type pos = row.pos();
|
||||||
if (row.x >= x || row.empty())
|
if (row.x >= x || row.empty())
|
||||||
x = row.x;
|
x = row.x;
|
||||||
@ -1135,9 +1138,29 @@ pos_type TextMetrics::getColumnNearX(pit_type const pit,
|
|||||||
w += cit->width();
|
w += cit->width();
|
||||||
}
|
}
|
||||||
if (cit == row.end())
|
if (cit == row.end())
|
||||||
lyxerr << "NOT FOUND!! x=" << x << ", wid=" << row.width() << endl;
|
lyxerr << "NOT FOUND!! x=" << x
|
||||||
|
<< ", wid=" << row.width() << endl;
|
||||||
|
/** This tests for the case where the cursor is placed
|
||||||
|
* just before a font direction change. See comment on
|
||||||
|
* the boundary_ member in DocIterator.h to understand
|
||||||
|
* how bounddary helps here.
|
||||||
|
*/
|
||||||
|
else if (pos == cit->endpos
|
||||||
|
&& cit + 1 != row.end()
|
||||||
|
&& cit->font.isVisibleRightToLeft() != (cit + 1)->font.isVisibleRightToLeft())
|
||||||
|
boundary = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** This tests for the case where the cursor is set at the end
|
||||||
|
* of a row which has been broken due to a display inset on
|
||||||
|
* next row. This can be recognized because the end of the
|
||||||
|
* last element is the same as the end of the row (there is no
|
||||||
|
* separator at the end of the row)
|
||||||
|
*/
|
||||||
|
if (!row.empty() && pos == row.back().endpos
|
||||||
|
&& row.back().endpos == row.endpos())
|
||||||
|
boundary = true;
|
||||||
|
|
||||||
#if !defined(KEEP_OLD_METRICS_CODE)
|
#if !defined(KEEP_OLD_METRICS_CODE)
|
||||||
return pos - row.pos();
|
return pos - row.pos();
|
||||||
#else
|
#else
|
||||||
@ -1677,7 +1700,7 @@ int TextMetrics::cursorX(CursorSlice const & sl,
|
|||||||
if (lyxrc.paragraph_markers && text_->isRTL(par)) {
|
if (lyxrc.paragraph_markers && text_->isRTL(par)) {
|
||||||
ParagraphList const & pars_ = text_->paragraphs();
|
ParagraphList const & pars_ = text_->paragraphs();
|
||||||
if (size_type(pit + 1) < pars_.size()) {
|
if (size_type(pit + 1) < pars_.size()) {
|
||||||
FontInfo f;
|
FontInfo f(text_->layoutFont(pit));
|
||||||
docstring const s = docstring(1, char_type(0x00B6));
|
docstring const s = docstring(1, char_type(0x00B6));
|
||||||
x2 += theFontMetrics(f).width(s);
|
x2 += theFontMetrics(f).width(s);
|
||||||
}
|
}
|
||||||
|
@ -749,11 +749,10 @@ void RowPainter::paintLast()
|
|||||||
case END_LABEL_NO_LABEL:
|
case END_LABEL_NO_LABEL:
|
||||||
if (lyxrc.paragraph_markers && size_type(pit_ + 1) < pars_.size()) {
|
if (lyxrc.paragraph_markers && size_type(pit_ + 1) < pars_.size()) {
|
||||||
docstring const s = docstring(1, char_type(0x00B6));
|
docstring const s = docstring(1, char_type(0x00B6));
|
||||||
FontInfo f = FontInfo();
|
FontInfo f = FontInfo(text_.layoutFont(pit_));
|
||||||
FontMetrics const & fm = theFontMetrics(f);
|
|
||||||
f.setColor(Color_paragraphmarker);
|
f.setColor(Color_paragraphmarker);
|
||||||
pi_.pain.text(int(x_), yo_, s, f);
|
pi_.pain.text(int(x_), yo_, s, f);
|
||||||
x_ += fm.width(s);
|
x_ += theFontMetrics(f).width(s);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user