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"
#endif
/*!
* Special characters
*/
extern WXDLLIMPEXP_RICHTEXT const wxChar wxRichTextLineBreakChar;
/*!
* File types
*/
@@ -1344,6 +1350,9 @@ public:
/// Get combined attributes of the base style and paragraph style.
wxTextAttrEx GetCombinedAttributes() const;
/// Get the first position from pos that has a line break character.
long GetFirstLineBreakPosition(long pos);
/// Create default tabstop array
static void InitDefaultTabs();
@@ -1413,6 +1422,9 @@ public:
/// Dump to output stream for debugging
virtual void Dump(wxTextOutputStream& stream);
/// Get the first position from pos that has a line break character.
long GetFirstLineBreakPosition(long pos);
// Accessors
/// Get the text

View File

@@ -302,6 +302,9 @@ public:
/// Insert a newline (actually paragraph) at the current insertion point.
virtual bool Newline();
/// Insert a line break at the current insertion point.
virtual bool LineBreak();
/// Set basic (overall) style
virtual void SetBasicStyle(const wxTextAttrEx& 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
#define wxRICHTEXT_USE_OPTIMIZED_DRAWING 1
const wxChar wxRichTextLineBreakChar = (wxChar) 29;
/*!
* wxRichTextObject
* 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
// another layout phase.
// TODO: can't this be called only once per child?
child->Layout(dc, rect, style);
// Available width depends on whether we're on the first or subsequent lines
@@ -3193,18 +3196,32 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
// We may only be looking at part of a child, if we searched back for wrapping
// and found a suitable point some way into the child. So get the size for the fragment
// 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;
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();
childDescent = child->GetDescent();
}
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;
@@ -3874,11 +3891,19 @@ bool wxRichTextParagraph::FindWrapPosition(const wxRichTextRange& range, wxDC& d
wxString plainText;
if (GetContiguousPlainText(plainText, wxRichTextRange(range.GetStart(), breakPosition), false))
{
int spacePos = plainText.Find(wxT(' '), true);
if (spacePos != wxNOT_FOUND)
int newLinePos = plainText.Find(wxRichTextLineBreakChar);
if (newLinePos != wxNOT_FOUND)
{
int positionsFromEndOfString = plainText.length() - spacePos - 1;
breakPosition = breakPosition - positionsFromEndOfString;
breakPosition = wxMax(0, range.GetStart() + newLinePos);
}
else
{
int spacePos = plainText.Find(wxT(' '), true);
if (spacePos != wxNOT_FOUND)
{
int positionsFromEndOfString = plainText.length() - spacePos - 1;
breakPosition = breakPosition - positionsFromEndOfString;
}
}
}
@@ -4036,6 +4061,27 @@ void wxRichTextParagraph::ClearDefaultTabs()
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
@@ -4107,8 +4153,13 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
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();
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))
stringChunk.MakeUpper();
@@ -4149,7 +4200,7 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
int fragmentLen = s1 - r1 + 1;
if (fragmentLen < 0)
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);
@@ -4157,8 +4208,8 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
if (stringChunk.Find(wxT("\t")) == wxNOT_FOUND)
{
// Compensate for kerning difference
wxString stringFragment2(m_text.Mid(r1 - offset, fragmentLen+1));
wxString stringFragment3(m_text.Mid(r1 - offset + fragmentLen, 1));
wxString stringFragment2(str.Mid(r1 - offset, fragmentLen+1));
wxString stringFragment3(str.Mid(r1 - offset + fragmentLen, 1));
wxCoord w1, h1, w2, h2, w3, h3;
dc.GetTextExtent(stringFragment, & w1, & h1);
@@ -4180,7 +4231,7 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
int fragmentLen = s2 - s1 + 1;
if (fragmentLen < 0)
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);
@@ -4188,8 +4239,8 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
if (stringChunk.Find(wxT("\t")) == wxNOT_FOUND)
{
// Compensate for kerning difference
wxString stringFragment2(m_text.Mid(s1 - offset, fragmentLen+1));
wxString stringFragment3(m_text.Mid(s1 - offset + fragmentLen, 1));
wxString stringFragment2(str.Mid(s1 - offset, fragmentLen+1));
wxString stringFragment3(str.Mid(s1 - offset + fragmentLen, 1));
wxCoord w1, h1, w2, h2, w3, h3;
dc.GetTextExtent(stringFragment, & w1, & h1);
@@ -4211,7 +4262,7 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
int fragmentLen = r2 - s2 + 1;
if (fragmentLen < 0)
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);
}
@@ -4337,6 +4388,9 @@ bool wxRichTextPlainText::Layout(wxDC& dc, const wxRect& WXUNUSED(rect), int WXU
if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
str.MakeUpper();
wxString toReplace = wxRichTextLineBreakChar;
str.Replace(toReplace, wxT(" "));
wxCoord w, h;
dc.GetTextExtent(str, & w, & h, & m_descent);
m_size = wxSize(w, dc.GetCharHeight());
@@ -4373,7 +4427,12 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
int startPos = range.GetStart() - GetRange().GetStart();
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))
stringChunk.MakeUpper();
@@ -4432,7 +4491,8 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
/// the first part in 'this'.
wxRichTextObject* wxRichTextPlainText::DoSplit(long pos)
{
int index = pos - GetRange().GetStart();
long index = pos - GetRange().GetStart();
if (index < 0 || index >= (int) m_text.length())
return NULL;
@@ -4446,7 +4506,7 @@ wxRichTextObject* wxRichTextPlainText::DoSplit(long pos)
newObject->SetRange(wxRichTextRange(pos, GetRange().GetEnd()));
GetRange().SetEnd(pos-1);
return newObject;
}
@@ -4520,6 +4580,23 @@ void wxRichTextPlainText::Dump(wxTextOutputStream& stream)
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
* This is a kind of box, used to represent the whole buffer
@@ -7775,6 +7852,10 @@ bool wxRichTextPlainTextHandler::DoSaveFile(wxRichTextBuffer *buffer, wxOutputSt
return false;
wxString text = buffer->GetText();
wxString newLine = wxRichTextLineBreakChar;
text.Replace(newLine, wxT("\n"));
wxCharBuffer buf = text.ToAscii();
stream.Write((const char*) buf, text.length());

View File

@@ -556,7 +556,15 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
DeleteSelectedContent(& newPos);
GetBuffer().InsertNewlineWithUndo(newPos+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE);
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);
EndBatchUndo();
SetDefaultStyleToCursorStyle();
@@ -2092,6 +2100,13 @@ bool wxRichTextCtrl::Newline()
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
@@ -2240,7 +2255,8 @@ void wxRichTextCtrl::DoSetSelection(long from, long to, bool WXUNUSED(scrollCare
{
m_selectionAnchor = from;
m_selectionRange.SetRange(from, to-1);
m_caretPosition = from-1;
if (from > -2)
m_caretPosition = from-1;
Refresh(false);
PositionCaret();