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:
Julian Smart
2006-11-20 11:33:44 +00:00
parent 2c40325930
commit ff76711fbe
4 changed files with 132 additions and 20 deletions

View File

@@ -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

View File

@@ -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); }

View File

@@ -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());

View File

@@ -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);