]> git.saurik.com Git - wxWidgets.git/commitdiff
Fixed a bug setting caret position after setting or clearing selection
authorJulian Smart <julian@anthemion.co.uk>
Mon, 20 Nov 2006 11:33:44 +0000 (11:33 +0000)
committerJulian Smart <julian@anthemion.co.uk>
Mon, 20 Nov 2006 11:33:44 +0000 (11:33 +0000)
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

include/wx/richtext/richtextbuffer.h
include/wx/richtext/richtextctrl.h
src/richtext/richtextbuffer.cpp
src/richtext/richtextctrl.cpp

index c5a638fb14eba545f2abe2d035a945da97ba9eb9..011d1b621bb2b12e0c0deabef77290c120079642 100644 (file)
 #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
index 55049a7d4eb030752c1d522e6e5b7604c051fcc7..36063e01571fdb61b8ec77bc77bdc4ce0c5e60ba 100644 (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); }
index 2ac10201af4ad6412fec06fb5c6db620611bab47..49c609d05381f2cb94efe679880434ea944ca30b 100644 (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());
+
+        // 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 (childSize.x + currentWidth > availableSpaceForText)
+        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());
index 9fc9317ce0f20a83fab41ad69514d44f8ca0679e..b592eba83d6f865c6786cdf662d81012e29ebe86 100644 (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();