If we do not do that, it is not possible to position the cursor after
a long inset with the mouse.
To do this, it is necessary to add the pit information to the Row
object. This is a good idea in any case, and will allow to simplify
some code later on.
Fixes bug #10094.
(cherry picked from commit 8851645799ef67015e49fd75b9dfeed65d685e85)
When an inset is separated from the adjacent string by a space, it is
reasonable to be able to break the string after the space.
Unfortunately, QTextLayout does not do that.
This patch reverts the workaround inserted in 71378268 and replaces it
with a different trick: the string is enlosed between a pair of
zero-width non breaking space characters, so that the leading/trailing
spaces are now normal spaces, where QTextLayout will agree to break
the string.
Fixes bug #9921 for good.
The wordSpacing property of a QFont object applies only once when there are multiple spaces between words. Therefore Row::Element::countSeparators shall not count spaces, but groups of spaces.
Fixes bug #9808.
When a row is too large due to a wide inset, it does not make sense to
break text before if the problem is the same in the next row.
Therefore give up breaking in this case.
Note that this was explicitely taken care of in the old-world
rowBreakPoint code.
Fixes bug #9691.
Instead of remembering the last breakable element in the row, search
backward in the row and consider all string elements one by one until
a correct place to break is found.
This fixes the case where the row ends with a string, but there is no
space soon enough in the string to break it here. In this case, we
need to consider the previous row.
The first change is to concentrate on the last ro elements that contain separators and try to break it a a width that is shorter than both
- its current width (we want to break it, after all)
- the amount of space available.
This simple heuristic seems to give good results.
* GuiFontMetrics::pos2x, x2pos: add support for inter-word spacing.
* GuiPainter::text: idem
* Row::Element::countSeparators:
Row::countSeparators: new methods that count spaces in strings.
Row::setSeparatorExtraWidth: new method (code lifted from TextMetrics.cpp).
* TextMetrics::computeRowMetrics: rely on the above methods.
* RowPainter::paintMispelledMarked: pass only a Row::Element object reference
RowPainter::paintStringAndSel: idem; do not rely on values returned by
Painter::text (trailing spaces do not honor wordspacing value).
The goal of this commit is to make painting faster by reducing the
number of strings to paint. To this end, it is necessary to include
spaces in row elements.
Also importantly, this commit should fix existing problems with line
breaking in chinese text.
* TextMetrics::breakRow: do not do anything special for word separators.
* Row::add: when adding a character to a row element, keep the string
width updated. If need be, it is possible to tweak this by updating
every 10 characters, for example.
* GuiFontMetrics::breakAt (new): use QTextLayout to break text either
at word boundary or at an arbitrary width.
* Row::Element::breakAt: use the above method.
* Row::shortenIfNeeded: simplify now that because there is no need for
handling separator elements. This will be taken care of by the
improved breakAt.
Two things remain to be done:
* remove all traces of separator row element
* re-implement text justification.
Newer boost versions use complicated type traits for boost::next and
boost::prior, which do not work with the RandomAccessList iterators.
The long term solution is to use std::next and std::prev, for now supply
simple replacements for compilers that do not support C++11 yet.
All the code that is run before row metrics have been computed should use int arithmetic. After metrics have been computed, we still need doubles because fully justified rows use double for Row::Element::extra.
Rename Row::x to Row::left_margin and change its type to int.
Rename Row::Element::width() to full_width(). In some places of the code, use dim.wid (the int version without the extra separator) because metrics have not been computed.
Let Row::Element::x2pos take a int& argument instead of double&
Let Row::Element::breakAt take a int argument instead of double
This makes virtually impossible copying a separator inset whithout
also copying the end of paragraph. These insets are not supposed to
be directly inserted by users. For example, the parbreak version
represents a LaTeX paragraph break, not a LyX one. So, if it is
possible to copy and paste it by alone, an unsespecting user may be
surprised to see a paragraph break in the output but not on the LyX
screen (because of the lack of indentation, for example).
In this way, it also becomes a LyX par break from a user point of
view, not any more useful than simply introducing a par break by
hitting <return> (except in those cases where it makes a difference,
in which case they are automatically inserted by LyX).
Moreover, breaks row at insets when there is no suitable separator.
Also make the code of Row::shorten_if_needed somewhat simpler by using
iterators and factoring the code.
Fixes: #9120
The old implementation of Row::Element::pos2x and x2pos did not work
correctly with Arabic text, because characters can have shapes that
depend on context.
This new implementation leverages QTextLayout in a simplified way,
since only one word is added to the layout.
This allows to make Row::Element::x2pos more readable.
Fixes: #9115.
All these problems are related to what happens at the extreme points of rows
* since VIRTUAL elements have a width but no contents, they have to
be treated specially at some places. It would have been better to
avoid testing for them explicitly, but I did not find a way.
* Improve and cleanup the code in breakRow and fix in passing a crash
when clicking on the right of an incomplete MARGIN_MANUAL
paragraph.
* improve the computation of row width in TextMetrics::computeRowMetrics.
* handle properly the case where a position if not found on the row
in both cursorX and getPosNearX (actually, this happens when
selecting).
* Some code cleanup and comments.
The fact that the bug was still present in the features/str-metrics
branch comes from a goof in the initial implementation of 'virtual'
row elements (completion and end-of-par markers). Now that this is
corrected, everything works as it should.
The fact that the bug is present in master is due to some other reason
that is not useful to investigate now.
* fix handling of boundary situations in Row::Elements::x2pos;
* fix handling of boundary situations in TextMetrics::getColumnNearX;
* make sure to always use Font::isVisibleRightToLeft instead of Font::isRightToLeft;
* Improve debug messages.
The horizontal position of the inset was not taken in account.
The rounding is not always the same as with the old code, but this
is not really important.
Additional changes:
* improve debug output of rows
* remove Bidi& argument of the RowPainter constructor, since it is always
an empty Bifi that is passed. This means that the Bidi class is not
used at all any more in TextMetrics.cpp. The only remaining user is
RowPainter.
Break words longer than the screen width. The code is more complicated
than I would like, but I have no better idea right now.
Implement properly the notion of a row broken by a display inset. This is useful in different places.
Also fix a bug with last line of a paragraph spotted by Kornel.
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.
* convert cursorX to new scheme; old computation is still there for the sake of comparison.
* use Row to compute separator width in computeRowMetrics; again, the old code is retained for now.
* Get rid of rowWidth()
* Row now contains a vector of Elements
* replace Row::dump by a proper << operator
* the width is updated as elements are added
* breakRow is reimplmented to use this infrastructure
1. When a listing is inserted in a bit of text, the line above the listing is not drawn over the full width like it is done for lines above other insets. This is because InsetListing has a AlignLeft alignment. Now, if you start selecting downwards with the mouse in this empty area, strange selection drawings appear (see attachment).
This is caused by the fact that starting your selection at such a place, causes beg.boundary() to be true in TextMetrics::drawRowSelection(..). This is correct, but this value is true for _all_ selected lines. Now, the selection acts as if it is RTL text. Therefore, just like for end.boundary, this value needs to be reset for every line.
2. Starting your selection in an end margin often causes the selection in this end margin to be painted later. This is because when starting your selection in an end margin, you may have set a (possible empty) selection before really selecting the end margin. The problem is that the checksum (computed later) is the same for this empty selection and for the end margin selection. Therfore, we need a call to cur.setSelection() before evaluating cur.selection().
3. In the following two lines, it is assumed that there is only an end margin to be painted if the selection extends to the next paragraph. This is not true for the above described case of an AlignLeft Inset. Then, the margin has also be drawn within a paragraph
4. The end and begin margins are only painted when the selection extends into the following or previous paragraph. This difference is not resembled in the checksum if you first select a row completely and then procede to the next or previous paragraph as the selection remains at the end of a row. This also holds for the AlignLeft case. Therefore I added a term to the checksum to monitor whether the end and begin margins need to be drawn.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@26399 a592a061-630c-0410-9148-cb99ea01b6c8