[LyX/master] Improve cursor movement with boundaries
Jean-Marc Lasgouttes
lasgouttes at lyx.org
Fri Nov 22 15:40:22 UTC 2024
commit ecac032a940009029a21676a73599b3c7a8a15c6
Author: Jean-Marc Lasgouttes <lasgouttes at lyx.org>
Date: Fri Nov 22 16:30:48 2024 +0100
Improve cursor movement with boundaries
Introduce a new NoEndBoundary flag for insets like InsetNewline.
Indroduce Row::start_boundary() that is true when previous Row has
end_boundary() set.
Use this to improve cursor movement around row boundaries (both for
logical ad visible cursor movement). The new code remove some of the
newline/separator hardcoding.
---
src/Cursor.cpp | 4 +++-
src/Row.h | 6 ++++++
src/RowFlags.h | 2 ++
src/Text.cpp | 50 ++++++++-------------------------------------
src/TextMetrics.cpp | 11 +++++++++-
src/insets/InsetNewline.cpp | 4 ++--
src/insets/InsetSeparator.h | 2 +-
7 files changed, 33 insertions(+), 46 deletions(-)
diff --git a/src/Cursor.cpp b/src/Cursor.cpp
index 225e4a685c..c67f38f178 100644
--- a/src/Cursor.cpp
+++ b/src/Cursor.cpp
@@ -1288,7 +1288,9 @@ bool Cursor::posVisToNewRow(bool movingLeft)
// if moving left in an LTR paragraph or moving right in an
// RTL one, move to previous row
if (par_is_LTR == movingLeft) {
- if (row.pos() == 0) { // we're at first row in paragraph
+ if (row.start_boundary())
+ boundary(true);
+ else if (row.pos() == 0) { // we're at first row in paragraph
if (pit() == 0) // no previous paragraph! don't move
return false;
// move to last pos in previous par
diff --git a/src/Row.h b/src/Row.h
index babe11510f..a1852e240e 100644
--- a/src/Row.h
+++ b/src/Row.h
@@ -212,6 +212,10 @@ public:
///
pos_type endpos() const { return end_; }
///
+ void start_boundary(bool b) { start_boundary_ = b; }
+ ///
+ bool start_boundary() const { return start_boundary_; }
+ ///
void end_boundary(bool b) { end_boundary_ = b; }
///
bool end_boundary() const { return end_boundary_; }
@@ -373,6 +377,8 @@ private:
pos_type pos_ = 0;
/// one behind last pos covered by this row
pos_type end_ = 0;
+ // Is there a boundary at the start of the row (display inset...)
+ bool start_boundary_ = false;
// Is there a boundary at the end of the row (display inset...)
bool end_boundary_ = false;
// Shall the row be flushed when it is supposed to be justified?
diff --git a/src/RowFlags.h b/src/RowFlags.h
index ccc7f5b46c..6f754dffb4 100644
--- a/src/RowFlags.h
+++ b/src/RowFlags.h
@@ -53,6 +53,8 @@ enum RowFlags {
// (default is center)
AlignLeft = 1 << 11,
AlignRight = 1 << 12,
+ // Forbid boundary after this element
+ NoEndBoundary = 1 << 13,
// A display element breaks row at both ends
Display = FlushBefore | BreakBefore | BreakAfter,
// Flags that concern breaking after element
diff --git a/src/Text.cpp b/src/Text.cpp
index b4d5232c7d..fa00e8b6f3 100644
--- a/src/Text.cpp
+++ b/src/Text.cpp
@@ -3054,29 +3054,16 @@ bool Text::cursorBackward(Cursor & cur)
// Tell BufferView to test for FitCursor in any case!
cur.screenUpdateFlags(Update::FitCursor);
+ // if on right side of a row boundary (at row start), skip it,
+ // i.e. set boundary to true, i.e. go only logically left
+ if (!cur.boundary()
+ && cur.textRow().pos() == cur.pos()
+ && cur.textRow().start_boundary()) {
+ return setCursor(cur, cur.pit(), cur.pos(), true, true);
+ }
+
// not at paragraph start?
if (cur.pos() > 0) {
- // if on right side of boundary (i.e. not at paragraph end, but line end)
- // -> skip it, i.e. set boundary to true, i.e. go only logically left
- // there are some exceptions to ignore this: lineseps, newlines, spaces
-#if 0
- // some effectless debug code to see the values in the debugger
- bool bound = cur.boundary();
- int rowpos = cur.textRow().pos();
- int pos = cur.pos();
- bool sep = cur.paragraph().isSeparator(cur.pos() - 1);
- bool newline = cur.paragraph().isNewline(cur.pos() - 1);
- bool linesep = cur.paragraph().isLineSeparator(cur.pos() - 1);
-#endif
- if (!cur.boundary() &&
- cur.textRow().pos() == cur.pos() &&
- !cur.paragraph().isLineSeparator(cur.pos() - 1) &&
- !cur.paragraph().isNewline(cur.pos() - 1) &&
- !cur.paragraph().isEnvSeparator(cur.pos() - 1) &&
- !cur.paragraph().isSeparator(cur.pos() - 1)) {
- return setCursor(cur, cur.pit(), cur.pos(), true, true);
- }
-
// go left and try to enter inset
if (checkAndActivateInset(cur, false))
return false;
@@ -3143,33 +3130,14 @@ bool Text::cursorForward(Cursor & cur)
// next position is left of boundary,
// but go to next line for special cases like space, newline, linesep
-#if 0
- // some effectless debug code to see the values in the debugger
- int endpos = cur.textRow().endpos();
- int lastpos = cur.lastpos();
- int pos = cur.pos();
- bool linesep = cur.paragraph().isLineSeparator(cur.pos());
- bool newline = cur.paragraph().isNewline(cur.pos());
- bool sep = cur.paragraph().isSeparator(cur.pos());
- if (cur.pos() != cur.lastpos()) {
- bool linesep2 = cur.paragraph().isLineSeparator(cur.pos()+1);
- bool newline2 = cur.paragraph().isNewline(cur.pos()+1);
- bool sep2 = cur.paragraph().isSeparator(cur.pos()+1);
- }
-#endif
if (cur.textRow().endpos() == cur.pos() + 1) {
if (cur.paragraph().isEnvSeparator(cur.pos()) &&
cur.pos() + 1 == cur.lastpos() &&
cur.pit() != cur.lastpit()) {
// move to next paragraph
return setCursor(cur, cur.pit() + 1, 0, true, false);
- } else if (cur.textRow().endpos() != cur.lastpos() &&
- !cur.paragraph().isNewline(cur.pos()) &&
- !cur.paragraph().isEnvSeparator(cur.pos()) &&
- !cur.paragraph().isLineSeparator(cur.pos()) &&
- !cur.paragraph().isSeparator(cur.pos())) {
+ } else if (cur.textRow().end_boundary())
return setCursor(cur, cur.pit(), cur.pos() + 1, true, true);
- }
}
// in front of RTL boundary? Stay on this side of the boundary because:
diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp
index 84e43c1d7d..3d98213da7 100644
--- a/src/TextMetrics.cpp
+++ b/src/TextMetrics.cpp
@@ -1147,7 +1147,9 @@ void cleanupRow(Row & row, bool at_end)
if (!at_end && !row.flushed())
row.back().rtrim();
// boundary exists when there was no space at the end of row
- row.end_boundary(!at_end && row.back().endpos == row.endpos());
+ row.end_boundary(!at_end
+ && row.back().endpos == row.endpos()
+ && !(row.back().row_flags & NoEndBoundary));
// make sure that the RTL elements are in reverse ordering
row.reverseRTL();
}
@@ -1250,6 +1252,13 @@ RowList TextMetrics::breakParagraph(Row const & bigrow) const
rows.back().needsChangeBar(true);
}
+ // Set start_boundary to be equal to the previous row's end boundary
+ bool sb = false;
+ for (auto & row : rows) {
+ row.start_boundary(sb);
+ sb = row.end_boundary();
+ }
+
return rows;
}
diff --git a/src/insets/InsetNewline.cpp b/src/insets/InsetNewline.cpp
index 38898c8ecd..8878fa95bf 100644
--- a/src/insets/InsetNewline.cpp
+++ b/src/insets/InsetNewline.cpp
@@ -44,9 +44,9 @@ InsetNewline::InsetNewline() : Inset(nullptr)
int InsetNewline::rowFlags() const
{
if (params_.kind == InsetNewlineParams::LINEBREAK)
- return AlwaysBreakAfter;
+ return AlwaysBreakAfter | NoEndBoundary;
else
- return AlwaysBreakAfter | Flush;
+ return AlwaysBreakAfter | NoEndBoundary | Flush;
}
diff --git a/src/insets/InsetSeparator.h b/src/insets/InsetSeparator.h
index dba716c6aa..dbe549d626 100644
--- a/src/insets/InsetSeparator.h
+++ b/src/insets/InsetSeparator.h
@@ -65,7 +65,7 @@ public:
return docstring();
}
///
- int rowFlags() const override { return BreakAfter | Flush; }
+ int rowFlags() const override { return BreakAfter | Flush | NoEndBoundary; }
///
bool nextnoindent() const { return params_.kind == InsetSeparatorParams::PLAIN; }
private:
More information about the lyx-cvs
mailing list