visual mode for bidi cursor movement

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@22929 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Dov Feldstern 2008-02-10 19:52:45 +00:00
parent a9770a18cd
commit 11a6b3c4c7
31 changed files with 596 additions and 56 deletions

View File

@ -5,6 +5,7 @@
*
* \author Alejandro Aguilar Sierra
* \author Alfredo Braunstein
* \author Dov Feldstern
* \author André Pönitz
* \author Stefan Schimanski
*
@ -453,6 +454,276 @@ bool Cursor::posForward()
}
void Cursor::getSurroundingPos(pos_type & left_pos, pos_type & right_pos)
{
// preparing bidi tables
Paragraph const & par = paragraph();
Buffer const & buf = buffer();
Row const & row = textRow();
Bidi bidi;
bidi.computeTables(par, buf, row);
LYXERR(Debug::RTL, "bidi: " << row.pos() << "--" << row.endpos());
// The cursor is painted *before* the character at pos(), or, if 'boundary'
// is true, *after* the character at (pos() - 1). So we already have one
// known position around the cursor:
pos_type known_pos = boundary() ? pos() - 1 : pos();
// Whether 'known_pos' is to the left or to the right of the cursor depends
// on whether it is an RTL or LTR character...
bool const cur_is_RTL =
par.getFontSettings(buf.params(), known_pos).isVisibleRightToLeft();
// ... in the following manner:
// For an RTL character, "before" means "to the right" and "after" means
// "to the left"; and for LTR, it's the reverse. So, 'known_pos' is to the
// right of the cursor if (RTL && boundary) or (!RTL && !boundary):
bool known_pos_on_right = (cur_is_RTL == boundary());
// So we now know one of the positions surrounding the cursor. Let's
// determine the other one:
if (known_pos_on_right) {
// edge-case: we're at the end of the paragraph, there isn't really any
// position any further to the right
if (known_pos == lastpos()) {
right_pos = -1;
left_pos = row.endpos() - 1;
return;
}
// the normal case
right_pos = known_pos;
// *visual* position of 'left_pos':
pos_type v_left_pos = bidi.log2vis(right_pos) - 1;
// If the position we just identified as 'left_pos' is a "skipped
// separator" (a separator which is at the logical end of a row,
// except for the last row in a paragraph; such separators are not
// painted, so they "are not really there"; note that in bidi text,
// such a separator could appear visually in the middle of a row),
// set 'left_pos' to the *next* position to the left.
if (bidi.inRange(v_left_pos)
&& bidi.vis2log(v_left_pos) + 1 == row.endpos()
&& row.endpos() < lastpos()
&& par.isSeparator(bidi.vis2log(v_left_pos))) {
--v_left_pos;
}
// calculate the logical position of 'left_pos', if in row
if (!bidi.inRange(v_left_pos))
left_pos = -1;
else
left_pos = bidi.vis2log(v_left_pos);
// If the position we identified as 'right_pos' is a "skipped
// separator", set 'right_pos' to the *next* position to the right.
if (right_pos + 1 == row.endpos() && row.endpos() < lastpos()
&& par.isSeparator(right_pos)) {
pos_type v_right_pos = bidi.log2vis(right_pos) + 1;
if (!bidi.inRange(v_right_pos))
right_pos = -1;
else
right_pos = bidi.vis2log(v_right_pos);
}
}
else { // known_pos is on the left
// edge-case: we're at the end of the paragraph, there isn't really any
// position any further to the left
if (known_pos == lastpos()) {
left_pos = -1;
right_pos = row.endpos() - 1;
return;
}
// the normal case
left_pos = known_pos;
// *visual* position of 'right_pos'
pos_type v_right_pos = bidi.log2vis(left_pos) + 1;
// If the position we just identified as 'right_pos' is a "skipped
// separator", set 'right_pos' to the *next* position to the right.
if (bidi.inRange(v_right_pos)
&& bidi.vis2log(v_right_pos) + 1 == row.endpos()
&& row.endpos() < lastpos()
&& par.isSeparator(bidi.vis2log(v_right_pos))) {
++v_right_pos;
}
// calculate the logical position of 'right_pos', if in row
if (!bidi.inRange(v_right_pos))
right_pos = -1;
else
right_pos = bidi.vis2log(v_right_pos);
// If the position we identified as 'left_pos' is a "skipped
// separator", set 'left_pos' to the *next* position to the left.
if (left_pos + 1 == row.endpos() && row.endpos() < lastpos()
&& par.isSeparator(left_pos)) {
pos_type v_left_pos = bidi.log2vis(left_pos) - 1;
if (!bidi.inRange(v_left_pos))
left_pos = -1;
else
left_pos = bidi.vis2log(v_left_pos);
}
}
return;
}
bool Cursor::posVisToNewRow(bool movingLeft)
{
Paragraph const & par = paragraph();
Buffer const & buf = buffer();
Row const & row = textRow();
bool par_is_LTR = !par.isRTL(buf.params());
// 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 (pit() == 0) // no previous paragraph! don't move
return false;
// move to last pos in previous par
--pit();
pos() = lastpos();
boundary(false);
} else { // move to previous row in this par
pos() = row.pos() - 1; // this is guaranteed to be in previous row
boundary(false);
}
}
// if moving left in an RTL paragraph or moving right in an LTR one,
// move to next row
else {
if (row.endpos() == lastpos()) { // we're at last row in paragraph
if (pit() == lastpit()) // last paragraph! don't move
return false;
// move to first row in next par
++pit();
pos() = 0;
boundary(false);
} else { // move to next row in this par
pos() = row.endpos();
boundary(false);
}
}
// make sure we're at left-/right-most pos in new row
posVisToRowExtremity(!movingLeft);
return true;
}
void Cursor::posVisToRowExtremity(bool left)
{
// prepare bidi tables
Paragraph const & par = paragraph();
Buffer const & buf = buffer();
Row const & row = textRow();
Bidi bidi;
bidi.computeTables(par, buf, row);
LYXERR(Debug::RTL, "entering extremity: " << pit() << "," << pos() << ","
<< (boundary() ? 1 : 0));
if (left) { // move to leftmost position
// if this is an RTL paragraph, and we're at the last row in the
// paragraph, move to lastpos
if (par.isRTL(buf.params()) && row.endpos() == lastpos())
pos() = lastpos();
else {
pos() = bidi.vis2log(row.pos());
// Moving to the leftmost position in the row, the cursor should
// normally be placed to the *left* of the leftmost position.
// A very common exception, though, is if the leftmost character
// also happens to be the separator at the (logical) end of the row
// --- in this case, the separator is positioned beyond the left
// margin, and we don't want to move the cursor there (moving to
// the left of the separator is equivalent to moving to the next
// line). So, in this case we actually want to place the cursor
// to the *right* of the leftmost position (the separator).
// Another exception is if we're moving to the logically last
// position in the row, which is *not* a separator: this means
// that the entire row has no separators (if there were any, the
// row would have been broken there); and therefore in this case
// we also move to the *right* of the last position (this indicates
// to the user that there is no space after this position, and is
// consistent with the behavior in the middle of a row --- moving
// right or left moves to the next/previous character; if we were
// to move to the *left* of this position, that would simulate
// a separator which is not really there!).
// Finally, there is an exception to the previous exception: if
// this non-separator-but-last-position-in-row is an inset, then
// we *do* want to stay to the left of it anyway: this is the
// "boundary" which we simulate at insets.
bool right_of_pos = false; // do we want to be to the right of pos?
// as explained above, if at last pos in row, stay to the right
if ((pos() == row.endpos() - 1) && !par.isInset(pos()))
right_of_pos = true;
// Now we know if we want to be to the left or to the right of pos,
// let's make sure we are where we want to be.
bool new_pos_is_RTL =
par.getFontSettings(buf.params(), pos()).isVisibleRightToLeft();
if (new_pos_is_RTL == !right_of_pos) {
++pos();
boundary(true);
}
}
}
else { // move to rightmost position
// if this is an LTR paragraph, and we're at the last row in the
// paragraph, move to lastpos
if (!par.isRTL(buf.params()) && row.endpos() == lastpos())
pos() = lastpos();
else {
pos() = bidi.vis2log(row.endpos() - 1);
// Moving to the rightmost position in the row, the cursor should
// normally be placed to the *right* of the rightmost position.
// A very common exception, though, is if the rightmost character
// also happens to be the separator at the (logical) end of the row
// --- in this case, the separator is positioned beyond the right
// margin, and we don't want to move the cursor there (moving to
// the right of the separator is equivalent to moving to the next
// line). So, in this case we actually want to place the cursor
// to the *left* of the rightmost position (the separator).
// Another exception is if we're moving to the logically last
// position in the row, which is *not* a separator: this means
// that the entire row has no separators (if there were any, the
// row would have been broken there); and therefore in this case
// we also move to the *left* of the last position (this indicates
// to the user that there is no space after this position, and is
// consistent with the behavior in the middle of a row --- moving
// right or left moves to the next/previous character; if we were
// to move to the *right* of this position, that would simulate
// a separator which is not really there!).
// Finally, there is an exception to the previous exception: if
// this non-separator-but-last-position-in-row is an inset, then
// we *do* want to stay to the right of it anyway: this is the
// "boundary" which we simulate at insets.
bool left_of_pos = false; // do we want to be to the left of pos?
// as explained above, if at last pos in row, stay to the left
if ((pos() == row.endpos() - 1) && !par.isInset(pos()))
left_of_pos = true;
// Now we know if we want to be to the left or to the right of pos,
// let's make sure we are where we want to be.
bool new_pos_is_RTL =
par.getFontSettings(buf.params(), pos()).isVisibleRightToLeft();
if (new_pos_is_RTL == left_of_pos) {
++pos();
boundary(true);
}
}
}
LYXERR(Debug::RTL, "leaving extremity: " << pit() << "," << pos() << ","
<< (boundary() ? 1 : 0));
}
CursorSlice Cursor::anchor() const
{
BOOST_ASSERT(anchor_.depth() >= depth());

View File

@ -106,6 +106,12 @@ public:
bool & macromode() { return macromode_; }
/// returns x,y position
void getPos(int & x, int & y) const;
/// return logical positions between which the cursor is situated
/**
* If the cursor is at the edge of a row, the position which is "over the
* edge" will be returned as -1.
*/
void getSurroundingPos(pos_type & left_pos, pos_type & right_pos);
/// the row in the paragraph we're in
Row const & textRow() const;
@ -116,6 +122,22 @@ public:
bool posBackward();
/// move one step forward
bool posForward();
/// move visually to next/previous row
/**
* Assuming we were to keep moving left (right) from the current cursor
* position, place the cursor at the rightmost (leftmost) edge of the
* new row to which we would move according to visual-mode cursor movement.
* This could be either the next or the previous row, depending on the
* direction in which we're moving, and whether we're in an LTR or RTL
* paragraph.
* @note: The new position may even be in a new paragraph.
* @note: This method will not move out of the current slice.
* @return: false if not moved (no more rows to move to in given direction)
* @return: true if moved
*/
bool posVisToNewRow(bool movingLeft);
/// move to right or left extremity of the current row
void posVisToRowExtremity(bool left);
/// insert an inset
void insert(Inset *);

View File

@ -169,11 +169,23 @@ public:
* Returns true if an update is needed after the move.
*/
bool cursorBackward(Cursor & cur);
/// Move cursor visually one position to the left
/**
* \param skip_inset if true, don't enter insets
* Returns true if an update is needed after the move.
*/
bool cursorVisLeft(Cursor & cur, bool skip_inset = false);
/// Move cursor one position forward
/**
* Returns true if an update is needed after the move.
*/
bool cursorForward(Cursor & cur);
/// Move cursor visually one position to the right
/**
* \param skip_inset if true, don't enter insets
* Returns true if an update is needed after the move.
*/
bool cursorVisRight(Cursor & cur, bool skip_inset = false);
///
bool cursorBackwardOneWord(Cursor & cur);
///
@ -241,6 +253,8 @@ public:
///
bool checkAndActivateInset(Cursor & cur, bool front);
///
bool checkAndActivateInsetVisual(Cursor & cur, bool movingForward, bool movingLeft);
///
void write(Buffer const & buf, std::ostream & os) const;

View File

@ -22,6 +22,7 @@
#include "Text.h"
#include "Bidi.h"
#include "Buffer.h"
#include "buffer_funcs.h"
#include "BufferList.h"
@ -594,6 +595,24 @@ bool Text::checkAndActivateInset(Cursor & cur, bool front)
}
bool Text::checkAndActivateInsetVisual(Cursor & cur, bool movingForward, bool movingLeft)
{
if (cur.selection())
return false;
if (cur.pos() == -1)
return false;
if (cur.pos() == cur.lastpos())
return false;
Paragraph & par = cur.paragraph();
Inset * inset = par.isInset(cur.pos()) ? par.getInset(cur.pos()) : 0;
if (!inset || inset->editable() != Inset::HIGHLY_EDITABLE)
return false;
inset->edit(cur, movingForward,
movingLeft ? Inset::ENTER_FROM_RIGHT : Inset::ENTER_FROM_LEFT);
return true;
}
bool Text::cursorBackward(Cursor & cur)
{
// Tell BufferView to test for FitCursor in any case!
@ -636,6 +655,166 @@ bool Text::cursorBackward(Cursor & cur)
}
bool Text::cursorVisLeft(Cursor & cur, bool skip_inset)
{
pit_type new_pit = cur.pit(); // the paragraph to which we will move
pos_type new_pos; // the position we will move to
bool new_boundary; // will we move to a boundary position?
pos_type left_pos; // position visually left of current cursor
pos_type right_pos; // position visually right of current cursor
bool new_pos_is_RTL; // is new position we're moving to RTL?
cur.getSurroundingPos(left_pos, right_pos);
LYXERR(Debug::RTL, left_pos <<"|"<< right_pos << " (pos: "<<cur.pos()<<")");
// Are we at an inset?
Cursor temp_cur = cur;
temp_cur.pos() = left_pos;
temp_cur.boundary(false);
if (!skip_inset &&
checkAndActivateInsetVisual(temp_cur, left_pos >= cur.pos(), true)) {
LYXERR(Debug::RTL, "entering inset at: " << temp_cur.pos());
cur = temp_cur; // set the real cursor to new position inside inset!
return false;
}
// Are we already at leftmost pos in row?
if (left_pos == -1) {
Cursor new_cur = cur;
if (!new_cur.posVisToNewRow(true)) {
LYXERR(Debug::RTL, "not moving!");
return false;
}
// we actually move the cursor at the end of this function, for now
// just keep track of the new position...
new_pit = new_cur.pit();
new_pos = new_cur.pos();
new_boundary = new_cur.boundary();
LYXERR(Debug::RTL, "left edge, moving: " << int(new_pit) << ","
<< int(new_pos) << "," << (new_boundary ? 1 : 0));
}
// normal movement to the left
else {
// Recall, if the cursor is at position 'x', that means *before*
// the character at position 'x'. In RTL, "before" means "to the
// right of", in LTR, "to the left of". So currently our situation
// is this: the position to our left is 'left_pos' (i.e., we're
// currently to the right of 'left_pos'). In order to move to the
// left, it depends whether or not the character at 'left_pos' is RTL.
new_pos_is_RTL = cur.paragraph().getFontSettings(
cur.bv().buffer().params(), left_pos).isVisibleRightToLeft();
// If the character at 'left_pos' *is* RTL, then in order to move to
// the left of it, we need to be *after* 'left_pos', i.e., move to
// position 'left_pos' + 1.
if (new_pos_is_RTL) {
new_pos = left_pos + 1;
// if the position *after* left_pos is not RTL, set boundary to
// true (we want to be *after* left_pos, not before left_pos + 1!)
new_boundary = !cur.paragraph().getFontSettings(
cur.bv().buffer().params(), new_pos).isVisibleRightToLeft();
}
// Otherwise (if the character at position 'left_pos' is LTR), then
// moving to the left of it is as easy as setting the new position
// to 'left_pos'.
else {
new_pos = left_pos;
new_boundary = false;
}
}
LYXERR(Debug::RTL, "moving to: " << new_pos
<< (new_boundary ? " (boundary)" : ""));
return setCursor(cur, new_pit, new_pos, true, new_boundary);
}
bool Text::cursorVisRight(Cursor & cur, bool skip_inset)
{
pit_type new_pit = cur.pit(); // the paragraph to which we will move
pos_type new_pos; // the position we will move to
bool new_boundary; // will we move to a boundary position?
pos_type left_pos; // position visually left of current cursor
pos_type right_pos; // position visually right of current cursor
bool new_pos_is_RTL; // is new position we're moving to RTL?
cur.getSurroundingPos(left_pos, right_pos);
LYXERR(Debug::RTL, left_pos <<"|"<< right_pos << " (pos: "<<cur.pos()<<")");
// Are we at an inset?
Cursor temp_cur = cur;
temp_cur.pos() = right_pos;
temp_cur.boundary(false);
if (!skip_inset &&
checkAndActivateInsetVisual(temp_cur, right_pos >= cur.pos(), false)) {
LYXERR(Debug::RTL, "entering inset at: " << temp_cur.pos());
cur = temp_cur; // set the real cursor to new position inside inset!
return false;
}
// Are we already at rightmost pos in row?
if (right_pos == -1) {
Cursor new_cur = cur;
if (!new_cur.posVisToNewRow(false)) {
LYXERR(Debug::RTL, "not moving!");
return false;
}
// we actually move the cursor at the end of this function, for now
// just keep track of the new position...
new_pit = new_cur.pit();
new_pos = new_cur.pos();
new_boundary = new_cur.boundary();
LYXERR(Debug::RTL, "right edge, moving: " << int(new_pit) << ","
<< int(new_pos) << "," << (new_boundary ? 1 : 0));
}
// normal movement to the right
else {
// Recall, if the cursor is at position 'x', that means *before*
// the character at position 'x'. In RTL, "before" means "to the
// right of", in LTR, "to the left of". So currently our situation
// is this: the position to our right is 'right_pos' (i.e., we're
// currently to the left of 'right_pos'). In order to move to the
// right, it depends whether or not the character at 'right_pos' is RTL.
new_pos_is_RTL = cur.paragraph().getFontSettings(
cur.bv().buffer().params(), right_pos).isVisibleRightToLeft();
// If the character at 'right_pos' *is* LTR, then in order to move to
// the right of it, we need to be *after* 'right_pos', i.e., move to
// position 'right_pos' + 1.
if (!new_pos_is_RTL) {
new_pos = right_pos + 1;
// if the position *after* right_pos is RTL, set boundary to
// true (we want to be *after* right_pos, not before right_pos + 1!)
new_boundary = cur.paragraph().getFontSettings(
cur.bv().buffer().params(), new_pos).isVisibleRightToLeft();
}
// Otherwise (if the character at position 'right_pos' is RTL), then
// moving to the right of it is as easy as setting the new position
// to 'right_pos'.
else {
new_pos = right_pos;
new_boundary = false;
}
}
LYXERR(Debug::RTL, "moving to: " << new_pos
<< (new_boundary ? " (boundary)" : ""));
return setCursor(cur, new_pit, new_pos, true, new_boundary);
}
bool Text::cursorForward(Cursor & cur)
{
// Tell BufferView to test for FitCursor in any case!

View File

@ -531,29 +531,50 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
case LFUN_CHAR_LEFT:
case LFUN_CHAR_LEFT_SELECT:
//FIXME: for visual cursor, really move left
if (reverseDirectionNeeded(cur)) {
cmd.action = cmd.action == LFUN_CHAR_LEFT_SELECT ?
LFUN_CHAR_FORWARD_SELECT : LFUN_CHAR_FORWARD;
if (lyxrc.visual_cursor) {
needsUpdate |= cur.selHandle(cmd.action == LFUN_CHAR_LEFT_SELECT);
needsUpdate |= cursorVisLeft(cur);
if (!needsUpdate && oldTopSlice == cur.top()
&& cur.boundary() == oldBoundary) {
cur.undispatched();
cmd = FuncRequest(LFUN_FINISHED_LEFT);
}
} else {
cmd.action = cmd.action == LFUN_CHAR_LEFT_SELECT ?
if (reverseDirectionNeeded(cur)) {
cmd.action = cmd.action == LFUN_CHAR_LEFT_SELECT ?
LFUN_CHAR_FORWARD_SELECT : LFUN_CHAR_FORWARD;
} else {
cmd.action = cmd.action == LFUN_CHAR_LEFT_SELECT ?
LFUN_CHAR_BACKWARD_SELECT : LFUN_CHAR_BACKWARD;
}
dispatch(cur, cmd);
return;
}
dispatch(cur, cmd);
return;
break;
case LFUN_CHAR_RIGHT:
case LFUN_CHAR_RIGHT_SELECT:
//FIXME: for visual cursor, really move right
if (reverseDirectionNeeded(cur)) {
cmd.action = cmd.action == LFUN_CHAR_RIGHT_SELECT ?
LFUN_CHAR_BACKWARD_SELECT : LFUN_CHAR_BACKWARD;
if (lyxrc.visual_cursor) {
needsUpdate |= cur.selHandle(cmd.action == LFUN_CHAR_RIGHT_SELECT);
needsUpdate |= cursorVisRight(cur);
if (!needsUpdate && oldTopSlice == cur.top()
&& cur.boundary() == oldBoundary) {
cur.undispatched();
cmd = FuncRequest(LFUN_FINISHED_RIGHT);
}
} else {
cmd.action = cmd.action == LFUN_CHAR_RIGHT_SELECT ?
if (reverseDirectionNeeded(cur)) {
cmd.action = cmd.action == LFUN_CHAR_RIGHT_SELECT ?
LFUN_CHAR_BACKWARD_SELECT : LFUN_CHAR_BACKWARD;
} else {
cmd.action = cmd.action == LFUN_CHAR_RIGHT_SELECT ?
LFUN_CHAR_FORWARD_SELECT : LFUN_CHAR_FORWARD;
}
dispatch(cur, cmd);
return;
}
dispatch(cur, cmd);
return;
break;
case LFUN_UP_SELECT:
case LFUN_DOWN_SELECT:
@ -1582,18 +1603,24 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
case LFUN_FINISHED_LEFT:
LYXERR(Debug::DEBUG, "handle LFUN_FINISHED_LEFT:\n" << cur);
if (reverseDirectionNeeded(cur)) {
++cur.pos();
cur.setCurrentFont();
}
// We're leaving an inset, going left. If the inset is LTR, we're
// leaving from the front, so we should not move (remain at --- but
// not in --- the inset). If the inset is RTL, move left, without
// entering the inset itself; i.e., move to after the inset.
if (cur.paragraph().getFontSettings(
cur.bv().buffer().params(), cur.pos()).isRightToLeft())
cursorVisLeft(cur, true);
break;
case LFUN_FINISHED_RIGHT:
LYXERR(Debug::DEBUG, "handle LFUN_FINISHED_RIGHT:\n" << cur);
if (!reverseDirectionNeeded(cur)) {
++cur.pos();
cur.setCurrentFont();
}
// We're leaving an inset, going right. If the inset is RTL, we're
// leaving from the front, so we should not move (remain at --- but
// not in --- the inset). If the inset is LTR, move right, without
// entering the inset itself; i.e., move to after the inset.
if (!cur.paragraph().getFontSettings(
cur.bv().buffer().params(), cur.pos()).isRightToLeft())
cursorVisRight(cur, true);
break;
case LFUN_FINISHED_BACKWARD:

View File

@ -213,7 +213,7 @@ bool Inset::getStatus(Cursor &, FuncRequest const & cmd,
}
void Inset::edit(Cursor &, bool)
void Inset::edit(Cursor &, bool, EntryDirectionType)
{
LYXERR(Debug::INSETS, "edit left/right");
}

View File

@ -65,6 +65,12 @@ namespace graphics { class PreviewLoader; }
class Inset {
public:
///
enum EntryDirectionType {
IGNORE_ENTRY_DIRECTION,
ENTER_FROM_RIGHT,
ENTER_FROM_LEFT,
};
///
typedef ptrdiff_t difference_type;
/// short of anything else reasonable
@ -119,7 +125,8 @@ public:
FuncStatus & status) const;
/// cursor enters
virtual void edit(Cursor & cur, bool left);
virtual void edit(Cursor & cur, bool front,
EntryDirectionType entry_from = IGNORE_ENTRY_DIRECTION);
/// cursor enters
virtual Inset * editXY(Cursor & cur, int x, int y);

View File

@ -162,10 +162,10 @@ void InsetCaption::draw(PainterInfo & pi, int x, int y) const
}
void InsetCaption::edit(Cursor & cur, bool left)
void InsetCaption::edit(Cursor & cur, bool front, EntryDirectionType entry_from)
{
cur.push(*this);
InsetText::edit(cur, left);
InsetText::edit(cur, front, entry_from);
}

View File

@ -49,7 +49,7 @@ public:
///
virtual void draw(PainterInfo & pi, int x, int y) const;
///
virtual void edit(Cursor & cur, bool left);
virtual void edit(Cursor & cur, bool front, EntryDirectionType entry_from);
///
virtual Inset * editXY(Cursor & cur, int x, int y);
///

View File

@ -466,11 +466,11 @@ docstring const InsetCollapsable::getNewLabel(docstring const & l) const
}
void InsetCollapsable::edit(Cursor & cur, bool left)
void InsetCollapsable::edit(Cursor & cur, bool front, EntryDirectionType entry_from)
{
//lyxerr << "InsetCollapsable: edit left/right" << endl;
cur.push(*this);
InsetText::edit(cur, left);
InsetText::edit(cur, front, entry_from);
}

View File

@ -162,7 +162,8 @@ protected:
///
virtual void doDispatch(Cursor & cur, FuncRequest & cmd);
///
void edit(Cursor & cur, bool left);
void edit(Cursor & cur, bool front,
EntryDirectionType entry_from = IGNORE_ENTRY_DIRECTION);
///
Inset * editXY(Cursor & cur, int x, int y);
///

View File

@ -160,7 +160,7 @@ bool InsetCommand::getStatus(Cursor & cur, FuncRequest const & cmd,
}
void InsetCommand::edit(Cursor & cur, bool)
void InsetCommand::edit(Cursor & cur, bool, EntryDirectionType)
{
if (!mailer_name_.empty())
InsetCommandMailer(mailer_name_, *this).showDialog(&cur.bv());

View File

@ -72,7 +72,8 @@ public:
return p_[name];
}
///
void edit(Cursor & cur, bool left);
void edit(Cursor & cur, bool front,
EntryDirectionType entry_from = IGNORE_ENTRY_DIRECTION);
///
RenderButton & button() const { return button_; }
///

View File

@ -516,7 +516,7 @@ void InsetExternal::updateEmbeddedFile(Buffer const & buf,
}
void InsetExternal::edit(Cursor & cur, bool)
void InsetExternal::edit(Cursor & cur, bool, EntryDirectionType)
{
InsetExternalMailer(*this).showDialog(&cur.bv());
}

View File

@ -145,7 +145,7 @@ public:
///
void addPreview(graphics::PreviewLoader &) const;
///
void edit(Cursor & cur, bool left);
void edit(Cursor & cur, bool front, EntryDirectionType entry_from);
///
bool getStatus(Cursor &, FuncRequest const &, FuncStatus &) const;
/// external file can be embedded

View File

@ -239,7 +239,7 @@ void InsetGraphics::updateEmbeddedFile(Buffer const & buf,
}
void InsetGraphics::edit(Cursor & cur, bool)
void InsetGraphics::edit(Cursor & cur, bool, EntryDirectionType)
{
InsetGraphicsMailer(*this).showDialog(&cur.bv());
}

View File

@ -73,7 +73,7 @@ public:
///
void draw(PainterInfo & pi, int x, int y) const;
///
void edit(Cursor & cur, bool left);
void edit(Cursor & cur, bool front, EntryDirectionType entry_from);
///
void editGraphics(InsetGraphicsParams const &, Buffer const &) const;
///

View File

@ -3151,7 +3151,7 @@ docstring const InsetTabular::editMessage() const
}
void InsetTabular::edit(Cursor & cur, bool left)
void InsetTabular::edit(Cursor & cur, bool, EntryDirectionType)
{
//lyxerr << "InsetTabular::edit: " << this << endl;
cur.finishUndo();

View File

@ -745,7 +745,7 @@ public:
/// set the owning buffer
void buffer(Buffer const * buf);
/// lock cell with given index
void edit(Cursor & cur, bool left);
void edit(Cursor & cur, bool front, EntryDirectionType entry_from);
///
Inset * editXY(Cursor & cur, int x, int y);
/// can we go further down on mouse click?

View File

@ -200,11 +200,20 @@ docstring const InsetText::editMessage() const
}
void InsetText::edit(Cursor & cur, bool left)
void InsetText::edit(Cursor & cur, bool front, EntryDirectionType entry_from)
{
//lyxerr << "InsetText: edit left/right" << endl;
int const pit = left ? 0 : paragraphs().size() - 1;
int const pos = left ? 0 : paragraphs().back().size();
pit_type const pit = front ? 0 : paragraphs().size() - 1;
pos_type pos = front ? 0 : paragraphs().back().size();
// if visual information is not to be ignored, move to extreme right/left
if (entry_from != IGNORE_ENTRY_DIRECTION) {
Cursor temp_cur = cur;
temp_cur.pit() = pit;
temp_cur.pos() = pos;
temp_cur.posVisToRowExtremity(entry_from == ENTER_FROM_LEFT);
pos = temp_cur.pos();
}
text_.setCursor(cur.top(), pit, pos);
cur.clearSelection();
cur.finishUndo();

View File

@ -113,7 +113,7 @@ public:
void addPreview(graphics::PreviewLoader &) const;
///
void edit(Cursor & cur, bool left);
void edit(Cursor & cur, bool front, EntryDirectionType entry_from);
///
Inset * editXY(Cursor & cur, int x, int y);

View File

@ -1310,10 +1310,12 @@ void InsetMathHull::handleFont2(Cursor & cur, docstring const & arg)
}
void InsetMathHull::edit(Cursor & cur, bool front)
void InsetMathHull::edit(Cursor & cur, bool front, EntryDirectionType entry_from)
{
cur.push(*this);
front ? idxFirst(cur) : idxLast(cur);
bool enter_front = (entry_from == Inset::ENTER_FROM_LEFT ||
(entry_from == Inset::IGNORE_ENTRY_DIRECTION && front));
enter_front ? idxFirst(cur) : idxLast(cur);
// The inset formula dimension is not necessarily the same as the
// one of the instant preview image, so we have to indicate to the
// BufferView that a metrics update is needed.

View File

@ -199,7 +199,8 @@ public:
///
EDITABLE editable() const { return HIGHLY_EDITABLE; }
///
void edit(Cursor & cur, bool front);
void edit(Cursor & cur, bool front,
EntryDirectionType entry_from = IGNORE_ENTRY_DIRECTION);
///
Inset * editXY(Cursor & cur, int x, int y);
///

View File

@ -1205,11 +1205,13 @@ bool InsetMathNest::getStatus(Cursor & cur, FuncRequest const & cmd,
}
void InsetMathNest::edit(Cursor & cur, bool left)
void InsetMathNest::edit(Cursor & cur, bool front, EntryDirectionType entry_from)
{
cur.push(*this);
cur.idx() = left ? 0 : cur.lastidx();
cur.pos() = left ? 0 : cur.lastpos();
bool enter_front = (entry_from == Inset::ENTER_FROM_RIGHT ||
(entry_from == Inset::IGNORE_ENTRY_DIRECTION && front));
cur.idx() = enter_front ? 0 : cur.lastidx();
cur.pos() = enter_front ? 0 : cur.lastpos();
cur.resetAnchor();
//lyxerr << "InsetMathNest::edit, cur:\n" << cur << endl;
}

View File

@ -48,7 +48,8 @@ public:
void cursorPos(BufferView const & bv, CursorSlice const & sl,
bool boundary, int & x, int & y) const;
///
void edit(Cursor & cur, bool left);
void edit(Cursor & cur, bool front,
EntryDirectionType entry_from = IGNORE_ENTRY_DIRECTION);
///
Inset * editXY(Cursor & cur, int x, int y);

View File

@ -509,10 +509,10 @@ void MathMacro::validate(LaTeXFeatures & features) const
}
void MathMacro::edit(Cursor & cur, bool left)
void MathMacro::edit(Cursor & cur, bool front, EntryDirectionType entry_from)
{
cur.updateFlags(Update::Force);
InsetMathNest::edit(cur, left);
InsetMathNest::edit(cur, front, entry_from);
}

View File

@ -46,7 +46,7 @@ public:
void cursorPos(BufferView const & bv, CursorSlice const & sl,
bool boundary, int & x, int & y) const;
///
void edit(Cursor & cur, bool left);
void edit(Cursor & cur, bool front, EntryDirectionType entry_from);
///
Inset * editXY(Cursor & cur, int x, int y);

View File

@ -533,11 +533,11 @@ void MathMacroTemplate::draw(PainterInfo & pi, int x, int y) const
}
void MathMacroTemplate::edit(Cursor & cur, bool left)
void MathMacroTemplate::edit(Cursor & cur, bool front, EntryDirectionType entry_from)
{
updateLook();
cur.updateFlags(Update::Force);
InsetMathNest::edit(cur, left);
InsetMathNest::edit(cur, front, entry_from);
}

View File

@ -38,7 +38,7 @@ public:
///
EDITABLE editable() const { return HIGHLY_EDITABLE; }
///
void edit(Cursor & cur, bool left);
void edit(Cursor & cur, bool front, EntryDirectionType entry_from);
///
bool notifyCursorLeaves(Cursor & cur);
///

View File

@ -64,6 +64,7 @@ ErrorItem errorTags[] = {
{ Debug::PAINTING, "painting", N_("RowPainter profiling")},
{ Debug::SCROLLING, "scrolling", N_("scrolling debugging")},
{ Debug::MACROS, "macros", N_("Math macros")},
{ Debug::RTL, "rtl", N_("RTL/Bidi")},
{ Debug::DEBUG, "debug", N_("Developers' general debug messages")},
{ Debug::ANY, "any", N_("All debugging messages")}
};

View File

@ -93,6 +93,8 @@ namespace Debug {
SCROLLING = (1 << 25),
///
MACROS = (1 << 26),
/// rtl-related
RTL = (1 << 27),
///
DEBUG = (1 << 31),
///