Opened 13 months ago

Last modified 13 months ago

#15714 confirmed defect

Caret jumping problem in wxRichTextCtrl text selection

Reported by: ikamakj Owned by:
Priority: normal Milestone:
Component: wxRichText Version: 2.9.5
Keywords: wxRichText selection Cc:
Blocked By: Blocking:
Patch: no

Description

This may be the same bug as #15041, but I want to provide some detailed information. Unlike stated in #15041, the problem is not platform specific.

When text is selected by mouse, the end of the selection jumps abruptly to the last character whenever the mouse goes outside the text control. The problem is present in 2.9.5 but was not in 2.8.10, it is caused by the changes done to hit-testing logic in order to handle sub-objects. The following lines have been added at the beginning of wxRichTextParagraph::HitTest():

if (GetParent() && GetParent()->wxRichTextObject::HitTest(dc, context,

pt, tmpPos, & tempObj, & tempContextObj, flags) == wxRICHTEXT_HITTEST_NONE)

return wxRICHTEXT_HITTEST_NONE;

My observation is from the simple case when there are no nested objects but paragraphs are direct children of wxRichTextBuffer. When the mouse is outside the control, the above code causes wxRichTextParagraph::HitTest() to return wxRICHTEXT_HITTEST_NONE. This return value eventually propagates to wxRichTextBuffer::HitTest(), which thus sets textPosition to be the end position, causing the caret to jump to the end in wxRichTextCtrl::OnMoveMouse().

The jumping can be avoided by adding an extra test for this situation at the end of OnMoveMouse():

if (hitObj && m_dragging && hit != wxRICHTEXT_HITTEST_NONE &&

m_selectionState == wxRichTextCtrlSelectionState_Normal

#if wxUSE_DRAG_AND_DROP

&& !m_preDrag
&& (distance > 4)

#endif

added line:

&& (! (hitObj == (& m_buffer) && ((hit & wxRICHTEXT_HITTEST_OUTSIDE) != 0)))
)

{

SetCaretPositionAfterClick(container, position, hit, true /* extend selection */);

}

This same test is in the arrow key handling (function MoveDown(), with comment "outside the buffer counts as 'do nothing'").

However, this is not a full solution because it only prevents the selection from jumping to the end; the selection still stops following the mouse position as the mouse goes outside, in contrast to common word processors and wxWidgets 2.8. In 2.8 the selection did follow the mouse because the latter part of wxRichTextParagraph::HitTest(), which scans lines, was executed even when the point was outside. (In 2.8 there was, however, an asymmetry: when the mouse was moved above the first line, the selection followed the mouse X coordinate, but when the mouse was moved below the last line, the selection was extended to the end of the text regardless of the X coordinate. This was caused by wxRichTextBuffer::HitTest() setting the position to end in case wxRICHTEXT_HITTEST_NONE, as mentioned above.)

Returning to the 2.8 code in wxRichTextParagraph::HitTest(), i.e., removing the added first lines, would make the mouse behave like in 2.8, but this is not a working solution even in the case of no nested objects, because MoveDown() would then behave incorrectly. When the caret is on the first line and the up arrow key is pressed, wxRichTextParagraph::HitTest() is called with a point that is above the first line (usually negative Y value). The 2.8 logic would then treat the point as belonging to the first line (this is the reason why the selection used to follow the X coordinate even when Y was outside, see above). But this would eventually make MoveDown() to incorrectly return true, even though the caret could not be moved upwards. With the 2.8 logic, MoveDown() would also incorrectly remove the whole selection if the user was selecting text with Shift+up arrow and the first line was already reached.

So there seems to be the fundamental problem that hit-testing cannot be done in the same way for selection by mouse and caret movements using keyboard. Selection by mouse should follow the mouse position even when the mouse goes outside, but keyboard handling should do nothing when the caret is already at top or bottom.

Change History (1)

comment:1 Changed 13 months ago by juliansmart

  • Status changed from new to confirmed

Hi, many thanks - I have committed your fix since it's a lot better than the present behaviour, but I agree more thought is required for more conventional selection behaviour. So I'll leave this open for now.

Note: See TracTickets for help on using tickets.