[LyX/master] Cleanup TextMetrics::getPosNearX
Jean-Marc Lasgouttes
lasgouttes at lyx.org
Mon Nov 25 14:55:36 UTC 2024
commit 91d1ad319d51cba51463f0fd040fbcf4d6c2c2be
Author: Jean-Marc Lasgouttes <lasgouttes at lyx.org>
Date: Mon Nov 25 15:40:56 2024 +0100
Cleanup TextMetrics::getPosNearX
This function mostly iterates though a row. Therefore it makes sense
to turn it into a wrapper around an new Row::x2pos() function.
Take this opportunity to use the C++17 structured bindings declaration
instead of passing a bool variable by address (which is only an output
variable).
No change intended.
---
src/Cursor.cpp | 11 +++---
src/Row.cpp | 64 +++++++++++++++++++++++++++++++
src/Row.h | 14 +++++--
src/TextMetrics.cpp | 81 ++++++----------------------------------
src/TextMetrics.h | 2 +-
src/frontends/qt/GuiWorkArea.cpp | 4 +-
6 files changed, 95 insertions(+), 81 deletions(-)
diff --git a/src/Cursor.cpp b/src/Cursor.cpp
index c67f38f178..6514a2b344 100644
--- a/src/Cursor.cpp
+++ b/src/Cursor.cpp
@@ -1330,12 +1330,13 @@ void Cursor::posVisToRowExtremity(bool left)
LYXERR(Debug::RTL, "entering extremity: " << pit() << "," << pos() << ","
<< (boundary() ? 1 : 0));
+ // FIXME: no need for metrics here!
TextMetrics const & tm = bv_->textMetrics(text());
// Looking for extremities is like clicking on the left or the
// right of the row.
int x = tm.origin().x + (left ? 0 : textRow().width());
- bool b = false;
- pos() = tm.getPosNearX(textRow(), x, b);
+ auto [p, b] = tm.getPosNearX(textRow(), x);
+ pos() = p;
boundary(b);
LYXERR(Debug::RTL, "leaving extremity: " << pit() << "," << pos() << ","
@@ -2286,9 +2287,9 @@ bool Cursor::upDownInText(bool up)
}
Row const & real_next_row = tm.parMetrics(pit()).rows()[next_row];
- bool bound = false;
- top().pos() = tm.getPosNearX(real_next_row, xo, bound);
- boundary(bound);
+ auto [b, p] = tm.getPosNearX(real_next_row, xo);
+ pos() = p;
+ boundary(b);
// When selection==false, this is done by TextMetrics::editXY
setCurrentFont();
diff --git a/src/Row.cpp b/src/Row.cpp
index b85ef3d18b..d6c45c2ad6 100644
--- a/src/Row.cpp
+++ b/src/Row.cpp
@@ -415,6 +415,70 @@ bool Row::setExtraWidth(int w)
}
+pair<pos_type, bool> Row::x2pos(int & x) const
+{
+ pos_type retpos = pos();
+ bool boundary = false;
+ if (empty())
+ x = left_margin;
+ else if (x <= left_margin) {
+ retpos = front().left_pos();
+ x = left_margin;
+ } else if (x >= width()) {
+ retpos = back().right_pos();
+ x = width();
+ } else {
+ double w = left_margin;
+ const_iterator cit = begin();
+ const_iterator cend = end();
+ for ( ; cit != cend; ++cit) {
+ if (w <= x && w + cit->full_width() > x) {
+ int x_offset = int(x - w);
+ retpos = cit->x2pos(x_offset);
+ x = int(x_offset + w);
+ break;
+ }
+ w += cit->full_width();
+ }
+ if (cit == end()) {
+ retpos = back().right_pos();
+ x = width();
+ }
+ /** 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 boundary helps here.
+ */
+ else if (retpos == cit->endpos
+ && ((!cit->isRTL() && cit + 1 != end()
+ && (cit + 1)->isRTL())
+ || (cit->isRTL() && cit != begin()
+ && !(cit - 1)->isRTL())))
+ boundary = true;
+ }
+
+ if (empty())
+ boundary = end_boundary();
+ /** This tests for the case where the cursor is set at the end
+ * of a row which has been broken due something else than a
+ * separator (a display inset or a forced breaking of the
+ * row). We know that there is a separator when the end of the
+ * row is larger than the end of its last element.
+ */
+ else if (retpos == back().endpos && back().endpos == endpos()) {
+ // FIXME: need a row flag here to say that cursor cannot be at the end
+ Inset const * inset = back().inset;
+ if (inset && (inset->lyxCode() == NEWLINE_CODE
+ || inset->lyxCode() == SEPARATOR_CODE))
+ retpos = back().pos;
+ else
+ boundary = end_boundary();
+ }
+
+ return make_pair(retpos, boundary);
+}
+
+
bool Row::sameString(Font const & f, Change const & ch) const
{
if (elements_.empty())
diff --git a/src/Row.h b/src/Row.h
index a1852e240e..cfb7427269 100644
--- a/src/Row.h
+++ b/src/Row.h
@@ -91,14 +91,14 @@ public:
* \param i in the row element.
*/
double pos2x(pos_type const i) const;
- /** Return character position that is the closest to
- * pixel position \param x. The value \param x is
- * adjusted to the actual pixel position.
+ /** Return character position that is the closest to pixel
+ * position \param x. The value \param x is adjusted to the
+ * actual pixel position.
*/
pos_type x2pos(int &x) const;
/** Break the element in two if possible, so that its width is less
* than the required values.
- * \return true if something has been done ; false if this is
+ * \return true if something has been done; false if this is
* not needed or not possible.
* \param width: maximum width of the row.
* \param next_width: available width on next rows.
@@ -252,6 +252,12 @@ public:
// distributed among expanders. \return false if the justification fails.
bool setExtraWidth(int w);
+ /** Return character position and boundary value that are the
+ * closest to pixel position \param x. The value \param x is
+ * adjusted to the actual pixel position.
+ */
+ std::pair<pos_type, bool> x2pos(int & x) const;
+
///
void add(pos_type pos, Inset const * ins, Dimension const & dim,
Font const & f, Change const & ch);
diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp
index 3d98213da7..48215c0216 100644
--- a/src/TextMetrics.cpp
+++ b/src/TextMetrics.cpp
@@ -1432,8 +1432,7 @@ void TextMetrics::setRowHeight(Row & row) const
// x is an absolute screen coord
// returns the column near the specified x-coordinate of the row
// x is set to the real beginning of this column
-pos_type TextMetrics::getPosNearX(Row const & row, int & x,
- bool & boundary) const
+pair<pos_type, bool> TextMetrics::getPosNearX(Row const & row, int & x) const
{
//LYXERR0("getPosNearX(" << x << ") row=" << row);
/// For the main Text, it is possible that this pit is not
@@ -1446,70 +1445,16 @@ pos_type TextMetrics::getPosNearX(Row const & row, int & x,
int const offset = bv_->horizScrollOffset(text_, row.pit(), row.pos());
x += offset;
- pos_type pos = row.pos();
- boundary = false;
- if (row.empty())
- x = row.left_margin;
- else if (x <= row.left_margin) {
- pos = row.front().left_pos();
- x = row.left_margin;
- } else if (x >= row.width()) {
- pos = row.back().right_pos();
- x = row.width();
- } else {
- double w = row.left_margin;
- Row::const_iterator cit = row.begin();
- Row::const_iterator cend = row.end();
- for ( ; cit != cend; ++cit) {
- if (w <= x && w + cit->full_width() > x) {
- int x_offset = int(x - w);
- pos = cit->x2pos(x_offset);
- x = int(x_offset + w);
- break;
- }
- w += cit->full_width();
- }
- if (cit == row.end()) {
- pos = row.back().right_pos();
- x = row.width();
- }
- /** 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 boundary helps here.
- */
- else if (pos == cit->endpos
- && ((!cit->isRTL() && cit + 1 != row.end()
- && (cit + 1)->isRTL())
- || (cit->isRTL() && cit != row.begin()
- && !(cit - 1)->isRTL())))
- boundary = true;
- }
-
- if (row.empty())
- boundary = row.end_boundary();
- /** This tests for the case where the cursor is set at the end
- * of a row which has been broken due something else than a
- * separator (a display inset or a forced breaking of the
- * row). We know that there is a separator when the end of the
- * row is larger than the end of its last element.
- */
- else if (pos == row.back().endpos && row.back().endpos == row.endpos()) {
- Inset const * inset = row.back().inset;
- if (inset && (inset->lyxCode() == NEWLINE_CODE
- || inset->lyxCode() == SEPARATOR_CODE))
- pos = row.back().pos;
- else
- boundary = row.end_boundary();
- }
+ auto [pos, boundary] = row.x2pos(x);
x += xo - offset;
//LYXERR0("getPosNearX ==> pos=" << pos << ", boundary=" << boundary);
- return pos;
+ return make_pair(pos, boundary);
}
+// FIXME: only InsetTabular uses this. Remove?
pos_type TextMetrics::x2pos(pit_type pit, int row, int x) const
{
// We play safe and use parMetrics(pit) to make sure the
@@ -1519,9 +1464,8 @@ pos_type TextMetrics::x2pos(pit_type pit, int row, int x) const
ParagraphMetrics const & pm = parMetrics(pit);
LBUFERR(row < int(pm.rows().size()));
- bool bound = false;
Row const & r = pm.rows()[row];
- return getPosNearX(r, x, bound);
+ return getPosNearX(r, x).first;
}
@@ -1645,8 +1589,8 @@ Inset * TextMetrics::editXY(Cursor & cur, int x, int y,
if (!e) {
// No inset, set position in the text
- bool bound = false; // is modified by getPosNearX
- cur.pos() = getPosNearX(row, x, bound);
+ auto [pos, bound] = getPosNearX(row, x);
+ cur.pos() = pos;
cur.boundary(bound);
cur.setCurrentFont();
cur.setTargetX(x);
@@ -1668,8 +1612,9 @@ Inset * TextMetrics::editXY(Cursor & cur, int x, int y,
if (cur.text() == text_ && cur.pos() == e->pos) {
// non-editable inset, set cursor after the inset if x is
// nearer to that position (bug 9628)
- bool bound = false; // is modified by getPosNearX
- cur.pos() = getPosNearX(row, x, bound);
+ // No inset, set position in the text
+ auto [pos, bound] = getPosNearX(row, x);
+ cur.pos() = pos;
cur.boundary(bound);
cur.setCurrentFont();
cur.setTargetX(x);
@@ -1681,7 +1626,7 @@ Inset * TextMetrics::editXY(Cursor & cur, int x, int y,
}
-void TextMetrics::setCursorFromCoordinates(Cursor & cur, int const x, int const y)
+void TextMetrics::setCursorFromCoordinates(Cursor & cur, int x, int const y)
{
LASSERT(text_ == cur.text(), return);
pit_type const pit = getPitNearY(y);
@@ -1706,9 +1651,7 @@ void TextMetrics::setCursorFromCoordinates(Cursor & cur, int const x, int const
LYXERR(Debug::PAINTING, "row " << r << " from pos: " << row.pos());
- bool bound = false;
- int xx = x;
- pos_type const pos = getPosNearX(row, xx, bound);
+ auto [pos, bound] = getPosNearX(row, x);
LYXERR(Debug::PAINTING, "setting cursor pit: " << pit << " pos: " << pos);
diff --git a/src/TextMetrics.h b/src/TextMetrics.h
index 02b27cf067..69d0e4853b 100644
--- a/src/TextMetrics.h
+++ b/src/TextMetrics.h
@@ -189,7 +189,7 @@ public:
/// returns the position near the specified x-coordinate of the row.
/// x is an absolute screen coord, it is set to the real beginning
/// of this column. This takes in account horizontal cursor row scrolling.
- pos_type getPosNearX(Row const & row, int & x, bool & boundary) const;
+ std::pair<pos_type, bool> getPosNearX(Row const & row, int & x) const;
/// returns pos in given par at given x coord.
pos_type x2pos(pit_type pit, int row, int x) const;
diff --git a/src/frontends/qt/GuiWorkArea.cpp b/src/frontends/qt/GuiWorkArea.cpp
index c6885b0f67..63eb84168a 100644
--- a/src/frontends/qt/GuiWorkArea.cpp
+++ b/src/frontends/qt/GuiWorkArea.cpp
@@ -975,6 +975,7 @@ void GuiWorkArea::generateSyntheticMouseEvent()
return;
TextMetrics const & tm = d->buffer_view_->textMetrics(text);
+ // FIXME: use TextMetrics::setCursorFromCoordinates.
// Quit gracefully if there are no metrics, since otherwise next
// line would crash (bug #10324).
// This situation seems related to a (not yet understood) timing problem.
@@ -1001,9 +1002,8 @@ void GuiWorkArea::generateSyntheticMouseEvent()
}
// Find the position of the cursor
- bool bound;
int x = d->synthetic_mouse_event_.cmd.x();
- pos_type const pos = tm.getPosNearX(*rit, x, bound);
+ auto [pos, bound] = tm.getPosNearX(*rit, x);
// Set the cursor
cur.pit() = pit;
More information about the lyx-cvs
mailing list