Fixed a bug setting caret position after setting or clearing selection
Implemented forced line breaks within a paragraph, entered with Shift-Return. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@43540 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -70,6 +70,12 @@
|
|||||||
#include "wx/dataobj.h"
|
#include "wx/dataobj.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Special characters
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern WXDLLIMPEXP_RICHTEXT const wxChar wxRichTextLineBreakChar;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* File types
|
* File types
|
||||||
*/
|
*/
|
||||||
@@ -1344,6 +1350,9 @@ public:
|
|||||||
/// Get combined attributes of the base style and paragraph style.
|
/// Get combined attributes of the base style and paragraph style.
|
||||||
wxTextAttrEx GetCombinedAttributes() const;
|
wxTextAttrEx GetCombinedAttributes() const;
|
||||||
|
|
||||||
|
/// Get the first position from pos that has a line break character.
|
||||||
|
long GetFirstLineBreakPosition(long pos);
|
||||||
|
|
||||||
/// Create default tabstop array
|
/// Create default tabstop array
|
||||||
static void InitDefaultTabs();
|
static void InitDefaultTabs();
|
||||||
|
|
||||||
@@ -1413,6 +1422,9 @@ public:
|
|||||||
/// Dump to output stream for debugging
|
/// Dump to output stream for debugging
|
||||||
virtual void Dump(wxTextOutputStream& stream);
|
virtual void Dump(wxTextOutputStream& stream);
|
||||||
|
|
||||||
|
/// Get the first position from pos that has a line break character.
|
||||||
|
long GetFirstLineBreakPosition(long pos);
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
|
|
||||||
/// Get the text
|
/// Get the text
|
||||||
|
@@ -302,6 +302,9 @@ public:
|
|||||||
/// Insert a newline (actually paragraph) at the current insertion point.
|
/// Insert a newline (actually paragraph) at the current insertion point.
|
||||||
virtual bool Newline();
|
virtual bool Newline();
|
||||||
|
|
||||||
|
/// Insert a line break at the current insertion point.
|
||||||
|
virtual bool LineBreak();
|
||||||
|
|
||||||
/// Set basic (overall) style
|
/// Set basic (overall) style
|
||||||
virtual void SetBasicStyle(const wxTextAttrEx& style) { GetBuffer().SetBasicStyle(style); }
|
virtual void SetBasicStyle(const wxTextAttrEx& style) { GetBuffer().SetBasicStyle(style); }
|
||||||
virtual void SetBasicStyle(const wxRichTextAttr& style) { GetBuffer().SetBasicStyle(style); }
|
virtual void SetBasicStyle(const wxRichTextAttr& style) { GetBuffer().SetBasicStyle(style); }
|
||||||
|
@@ -46,6 +46,8 @@ WX_DEFINE_LIST(wxRichTextLineList)
|
|||||||
// Switch off if the platform doesn't like it for some reason
|
// Switch off if the platform doesn't like it for some reason
|
||||||
#define wxRICHTEXT_USE_OPTIMIZED_DRAWING 1
|
#define wxRICHTEXT_USE_OPTIMIZED_DRAWING 1
|
||||||
|
|
||||||
|
const wxChar wxRichTextLineBreakChar = (wxChar) 29;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* wxRichTextObject
|
* wxRichTextObject
|
||||||
* This is the base for drawable objects.
|
* This is the base for drawable objects.
|
||||||
@@ -3183,6 +3185,7 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
|
|||||||
// can't tell the position until the size is determined. So possibly introduce
|
// can't tell the position until the size is determined. So possibly introduce
|
||||||
// another layout phase.
|
// another layout phase.
|
||||||
|
|
||||||
|
// TODO: can't this be called only once per child?
|
||||||
child->Layout(dc, rect, style);
|
child->Layout(dc, rect, style);
|
||||||
|
|
||||||
// Available width depends on whether we're on the first or subsequent lines
|
// Available width depends on whether we're on the first or subsequent lines
|
||||||
@@ -3194,17 +3197,31 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
|
|||||||
// and found a suitable point some way into the child. So get the size for the fragment
|
// and found a suitable point some way into the child. So get the size for the fragment
|
||||||
// if necessary.
|
// if necessary.
|
||||||
|
|
||||||
|
long nextBreakPos = GetFirstLineBreakPosition(lastEndPos+1);
|
||||||
|
long lastPosToUse = child->GetRange().GetEnd();
|
||||||
|
bool lineBreakInThisObject = (nextBreakPos > -1 && nextBreakPos <= child->GetRange().GetEnd());
|
||||||
|
|
||||||
|
if (lineBreakInThisObject)
|
||||||
|
lastPosToUse = nextBreakPos;
|
||||||
|
|
||||||
wxSize childSize;
|
wxSize childSize;
|
||||||
int childDescent = 0;
|
int childDescent = 0;
|
||||||
if (lastEndPos == child->GetRange().GetStart() - 1)
|
|
||||||
|
if ((nextBreakPos == -1) && (lastEndPos == child->GetRange().GetStart() - 1)) // i.e. we want to get the whole thing
|
||||||
{
|
{
|
||||||
childSize = child->GetCachedSize();
|
childSize = child->GetCachedSize();
|
||||||
childDescent = child->GetDescent();
|
childDescent = child->GetDescent();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
GetRangeSize(wxRichTextRange(lastEndPos+1, child->GetRange().GetEnd()), childSize, childDescent, dc, wxRICHTEXT_UNFORMATTED,rect.GetPosition());
|
GetRangeSize(wxRichTextRange(lastEndPos+1, lastPosToUse), childSize, childDescent, dc, wxRICHTEXT_UNFORMATTED, rect.GetPosition());
|
||||||
|
|
||||||
if (childSize.x + currentWidth > availableSpaceForText)
|
// Cases:
|
||||||
|
// 1) There was a line break BEFORE the natural break
|
||||||
|
// 2) There was a line break AFTER the natural break
|
||||||
|
// 3) The child still fits (carry on)
|
||||||
|
|
||||||
|
if ((lineBreakInThisObject && (childSize.x + currentWidth <= availableSpaceForText)) ||
|
||||||
|
(childSize.x + currentWidth > availableSpaceForText))
|
||||||
{
|
{
|
||||||
long wrapPosition = 0;
|
long wrapPosition = 0;
|
||||||
|
|
||||||
@@ -3873,6 +3890,13 @@ bool wxRichTextParagraph::FindWrapPosition(const wxRichTextRange& range, wxDC& d
|
|||||||
|
|
||||||
wxString plainText;
|
wxString plainText;
|
||||||
if (GetContiguousPlainText(plainText, wxRichTextRange(range.GetStart(), breakPosition), false))
|
if (GetContiguousPlainText(plainText, wxRichTextRange(range.GetStart(), breakPosition), false))
|
||||||
|
{
|
||||||
|
int newLinePos = plainText.Find(wxRichTextLineBreakChar);
|
||||||
|
if (newLinePos != wxNOT_FOUND)
|
||||||
|
{
|
||||||
|
breakPosition = wxMax(0, range.GetStart() + newLinePos);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
int spacePos = plainText.Find(wxT(' '), true);
|
int spacePos = plainText.Find(wxT(' '), true);
|
||||||
if (spacePos != wxNOT_FOUND)
|
if (spacePos != wxNOT_FOUND)
|
||||||
@@ -3881,6 +3905,7 @@ bool wxRichTextParagraph::FindWrapPosition(const wxRichTextRange& range, wxDC& d
|
|||||||
breakPosition = breakPosition - positionsFromEndOfString;
|
breakPosition = breakPosition - positionsFromEndOfString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
wrapPosition = breakPosition;
|
wrapPosition = breakPosition;
|
||||||
|
|
||||||
@@ -4036,6 +4061,27 @@ void wxRichTextParagraph::ClearDefaultTabs()
|
|||||||
sm_defaultTabs.Clear();
|
sm_defaultTabs.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the first position from pos that has a line break character.
|
||||||
|
long wxRichTextParagraph::GetFirstLineBreakPosition(long pos)
|
||||||
|
{
|
||||||
|
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
|
||||||
|
while (node)
|
||||||
|
{
|
||||||
|
wxRichTextObject* obj = node->GetData();
|
||||||
|
if (pos >= obj->GetRange().GetStart() && pos <= obj->GetRange().GetEnd())
|
||||||
|
{
|
||||||
|
wxRichTextPlainText* textObj = wxDynamicCast(obj, wxRichTextPlainText);
|
||||||
|
if (textObj)
|
||||||
|
{
|
||||||
|
long breakPos = textObj->GetFirstLineBreakPosition(pos);
|
||||||
|
if (breakPos > -1)
|
||||||
|
return breakPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node = node->GetNext();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* wxRichTextLine
|
* wxRichTextLine
|
||||||
@@ -4107,8 +4153,13 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
|
|||||||
|
|
||||||
int offset = GetRange().GetStart();
|
int offset = GetRange().GetStart();
|
||||||
|
|
||||||
|
// Replace line break characters with spaces
|
||||||
|
wxString str = m_text;
|
||||||
|
wxString toRemove = wxRichTextLineBreakChar;
|
||||||
|
str.Replace(toRemove, wxT(" "));
|
||||||
|
|
||||||
long len = range.GetLength();
|
long len = range.GetLength();
|
||||||
wxString stringChunk = m_text.Mid(range.GetStart() - offset, (size_t) len);
|
wxString stringChunk = str.Mid(range.GetStart() - offset, (size_t) len);
|
||||||
if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
|
if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
|
||||||
stringChunk.MakeUpper();
|
stringChunk.MakeUpper();
|
||||||
|
|
||||||
@@ -4149,7 +4200,7 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
|
|||||||
int fragmentLen = s1 - r1 + 1;
|
int fragmentLen = s1 - r1 + 1;
|
||||||
if (fragmentLen < 0)
|
if (fragmentLen < 0)
|
||||||
wxLogDebug(wxT("Mid(%d, %d"), (int)(r1 - offset), (int)fragmentLen);
|
wxLogDebug(wxT("Mid(%d, %d"), (int)(r1 - offset), (int)fragmentLen);
|
||||||
wxString stringFragment = m_text.Mid(r1 - offset, fragmentLen);
|
wxString stringFragment = str.Mid(r1 - offset, fragmentLen);
|
||||||
|
|
||||||
DrawTabbedString(dc, textAttr, rect, stringFragment, x, y, false);
|
DrawTabbedString(dc, textAttr, rect, stringFragment, x, y, false);
|
||||||
|
|
||||||
@@ -4157,8 +4208,8 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
|
|||||||
if (stringChunk.Find(wxT("\t")) == wxNOT_FOUND)
|
if (stringChunk.Find(wxT("\t")) == wxNOT_FOUND)
|
||||||
{
|
{
|
||||||
// Compensate for kerning difference
|
// Compensate for kerning difference
|
||||||
wxString stringFragment2(m_text.Mid(r1 - offset, fragmentLen+1));
|
wxString stringFragment2(str.Mid(r1 - offset, fragmentLen+1));
|
||||||
wxString stringFragment3(m_text.Mid(r1 - offset + fragmentLen, 1));
|
wxString stringFragment3(str.Mid(r1 - offset + fragmentLen, 1));
|
||||||
|
|
||||||
wxCoord w1, h1, w2, h2, w3, h3;
|
wxCoord w1, h1, w2, h2, w3, h3;
|
||||||
dc.GetTextExtent(stringFragment, & w1, & h1);
|
dc.GetTextExtent(stringFragment, & w1, & h1);
|
||||||
@@ -4180,7 +4231,7 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
|
|||||||
int fragmentLen = s2 - s1 + 1;
|
int fragmentLen = s2 - s1 + 1;
|
||||||
if (fragmentLen < 0)
|
if (fragmentLen < 0)
|
||||||
wxLogDebug(wxT("Mid(%d, %d"), (int)(s1 - offset), (int)fragmentLen);
|
wxLogDebug(wxT("Mid(%d, %d"), (int)(s1 - offset), (int)fragmentLen);
|
||||||
wxString stringFragment = m_text.Mid(s1 - offset, fragmentLen);
|
wxString stringFragment = str.Mid(s1 - offset, fragmentLen);
|
||||||
|
|
||||||
DrawTabbedString(dc, textAttr, rect, stringFragment, x, y, true);
|
DrawTabbedString(dc, textAttr, rect, stringFragment, x, y, true);
|
||||||
|
|
||||||
@@ -4188,8 +4239,8 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
|
|||||||
if (stringChunk.Find(wxT("\t")) == wxNOT_FOUND)
|
if (stringChunk.Find(wxT("\t")) == wxNOT_FOUND)
|
||||||
{
|
{
|
||||||
// Compensate for kerning difference
|
// Compensate for kerning difference
|
||||||
wxString stringFragment2(m_text.Mid(s1 - offset, fragmentLen+1));
|
wxString stringFragment2(str.Mid(s1 - offset, fragmentLen+1));
|
||||||
wxString stringFragment3(m_text.Mid(s1 - offset + fragmentLen, 1));
|
wxString stringFragment3(str.Mid(s1 - offset + fragmentLen, 1));
|
||||||
|
|
||||||
wxCoord w1, h1, w2, h2, w3, h3;
|
wxCoord w1, h1, w2, h2, w3, h3;
|
||||||
dc.GetTextExtent(stringFragment, & w1, & h1);
|
dc.GetTextExtent(stringFragment, & w1, & h1);
|
||||||
@@ -4211,7 +4262,7 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
|
|||||||
int fragmentLen = r2 - s2 + 1;
|
int fragmentLen = r2 - s2 + 1;
|
||||||
if (fragmentLen < 0)
|
if (fragmentLen < 0)
|
||||||
wxLogDebug(wxT("Mid(%d, %d"), (int)(s2 - offset), (int)fragmentLen);
|
wxLogDebug(wxT("Mid(%d, %d"), (int)(s2 - offset), (int)fragmentLen);
|
||||||
wxString stringFragment = m_text.Mid(s2 - offset, fragmentLen);
|
wxString stringFragment = str.Mid(s2 - offset, fragmentLen);
|
||||||
|
|
||||||
DrawTabbedString(dc, textAttr, rect, stringFragment, x, y, false);
|
DrawTabbedString(dc, textAttr, rect, stringFragment, x, y, false);
|
||||||
}
|
}
|
||||||
@@ -4337,6 +4388,9 @@ bool wxRichTextPlainText::Layout(wxDC& dc, const wxRect& WXUNUSED(rect), int WXU
|
|||||||
if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
|
if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
|
||||||
str.MakeUpper();
|
str.MakeUpper();
|
||||||
|
|
||||||
|
wxString toReplace = wxRichTextLineBreakChar;
|
||||||
|
str.Replace(toReplace, wxT(" "));
|
||||||
|
|
||||||
wxCoord w, h;
|
wxCoord w, h;
|
||||||
dc.GetTextExtent(str, & w, & h, & m_descent);
|
dc.GetTextExtent(str, & w, & h, & m_descent);
|
||||||
m_size = wxSize(w, dc.GetCharHeight());
|
m_size = wxSize(w, dc.GetCharHeight());
|
||||||
@@ -4373,7 +4427,12 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
|
|||||||
|
|
||||||
int startPos = range.GetStart() - GetRange().GetStart();
|
int startPos = range.GetStart() - GetRange().GetStart();
|
||||||
long len = range.GetLength();
|
long len = range.GetLength();
|
||||||
wxString stringChunk = m_text.Mid(startPos, (size_t) len);
|
|
||||||
|
wxString str(m_text);
|
||||||
|
wxString toReplace = wxRichTextLineBreakChar;
|
||||||
|
str.Replace(toReplace, wxT(" "));
|
||||||
|
|
||||||
|
wxString stringChunk = str.Mid(startPos, (size_t) len);
|
||||||
|
|
||||||
if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
|
if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
|
||||||
stringChunk.MakeUpper();
|
stringChunk.MakeUpper();
|
||||||
@@ -4432,7 +4491,8 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
|
|||||||
/// the first part in 'this'.
|
/// the first part in 'this'.
|
||||||
wxRichTextObject* wxRichTextPlainText::DoSplit(long pos)
|
wxRichTextObject* wxRichTextPlainText::DoSplit(long pos)
|
||||||
{
|
{
|
||||||
int index = pos - GetRange().GetStart();
|
long index = pos - GetRange().GetStart();
|
||||||
|
|
||||||
if (index < 0 || index >= (int) m_text.length())
|
if (index < 0 || index >= (int) m_text.length())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -4520,6 +4580,23 @@ void wxRichTextPlainText::Dump(wxTextOutputStream& stream)
|
|||||||
stream << m_text << wxT("\n");
|
stream << m_text << wxT("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the first position from pos that has a line break character.
|
||||||
|
long wxRichTextPlainText::GetFirstLineBreakPosition(long pos)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int len = m_text.length();
|
||||||
|
int startPos = pos - m_range.GetStart();
|
||||||
|
for (i = startPos; i < len; i++)
|
||||||
|
{
|
||||||
|
wxChar ch = m_text[i];
|
||||||
|
if (ch == wxRichTextLineBreakChar)
|
||||||
|
{
|
||||||
|
return i + m_range.GetStart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* wxRichTextBuffer
|
* wxRichTextBuffer
|
||||||
* This is a kind of box, used to represent the whole buffer
|
* This is a kind of box, used to represent the whole buffer
|
||||||
@@ -7775,6 +7852,10 @@ bool wxRichTextPlainTextHandler::DoSaveFile(wxRichTextBuffer *buffer, wxOutputSt
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
wxString text = buffer->GetText();
|
wxString text = buffer->GetText();
|
||||||
|
|
||||||
|
wxString newLine = wxRichTextLineBreakChar;
|
||||||
|
text.Replace(newLine, wxT("\n"));
|
||||||
|
|
||||||
wxCharBuffer buf = text.ToAscii();
|
wxCharBuffer buf = text.ToAscii();
|
||||||
|
|
||||||
stream.Write((const char*) buf, text.length());
|
stream.Write((const char*) buf, text.length());
|
||||||
|
@@ -556,7 +556,15 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
|
|||||||
|
|
||||||
DeleteSelectedContent(& newPos);
|
DeleteSelectedContent(& newPos);
|
||||||
|
|
||||||
|
if (event.ShiftDown())
|
||||||
|
{
|
||||||
|
wxString text;
|
||||||
|
text = wxRichTextLineBreakChar;
|
||||||
|
GetBuffer().InsertTextWithUndo(newPos+1, text, this);
|
||||||
|
}
|
||||||
|
else
|
||||||
GetBuffer().InsertNewlineWithUndo(newPos+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE);
|
GetBuffer().InsertNewlineWithUndo(newPos+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE);
|
||||||
|
|
||||||
EndBatchUndo();
|
EndBatchUndo();
|
||||||
SetDefaultStyleToCursorStyle();
|
SetDefaultStyleToCursorStyle();
|
||||||
|
|
||||||
@@ -2092,6 +2100,13 @@ bool wxRichTextCtrl::Newline()
|
|||||||
return GetBuffer().InsertNewlineWithUndo(m_caretPosition+1, this);
|
return GetBuffer().InsertNewlineWithUndo(m_caretPosition+1, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Insert a line break at the current insertion point.
|
||||||
|
bool wxRichTextCtrl::LineBreak()
|
||||||
|
{
|
||||||
|
wxString text;
|
||||||
|
text = wxRichTextLineBreakChar;
|
||||||
|
return GetBuffer().InsertTextWithUndo(m_caretPosition+1, text, this);
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Clipboard operations
|
// Clipboard operations
|
||||||
@@ -2240,6 +2255,7 @@ void wxRichTextCtrl::DoSetSelection(long from, long to, bool WXUNUSED(scrollCare
|
|||||||
{
|
{
|
||||||
m_selectionAnchor = from;
|
m_selectionAnchor = from;
|
||||||
m_selectionRange.SetRange(from, to-1);
|
m_selectionRange.SetRange(from, to-1);
|
||||||
|
if (from > -2)
|
||||||
m_caretPosition = from-1;
|
m_caretPosition = from-1;
|
||||||
|
|
||||||
Refresh(false);
|
Refresh(false);
|
||||||
|
Reference in New Issue
Block a user