]> git.saurik.com Git - wxWidgets.git/blobdiff - src/richtext/richtextctrl.cpp
Typo.
[wxWidgets.git] / src / richtext / richtextctrl.cpp
index e376c262f8856ba9527166cf1651e46392a4c4d6..b77d1a2fc1866ee7d813af565a9293caa93ebbbd 100644 (file)
@@ -1,10 +1,10 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        richeditctrl.cpp
+// Name:        src/richtext/richeditctrl.cpp
 // Purpose:     A rich edit control
 // Author:      Julian Smart
-// Modified by: 
+// Modified by:
 // Created:     2005-09-30
-// RCS-ID:      
+// RCS-ID:      $Id$
 // Copyright:   (c) Julian Smart
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
-  #pragma hdrstop
+    #pragma hdrstop
 #endif
 
-#ifndef WX_PRECOMP
-  #include "wx/wx.h"
-#endif
+#if wxUSE_RICHTEXT
 
-#include "wx/image.h"
+#include "wx/richtext/richtextctrl.h"
+#include "wx/richtext/richtextstyles.h"
 
-#if wxUSE_RICHTEXT
+#ifndef WX_PRECOMP
+    #include "wx/wx.h"
+    #include "wx/settings.h"
+#endif
 
 #include "wx/textfile.h"
 #include "wx/ffile.h"
-#include "wx/settings.h"
 #include "wx/filename.h"
 #include "wx/dcbuffer.h"
-
-#include "wx/richtext/richtextctrl.h"
 #include "wx/arrimpl.cpp"
 
+// DLL options compatibility check:
+#include "wx/app.h"
+WX_CHECK_BUILD_OPTIONS("wxRichTextCtrl")
+
 DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_ITEM_SELECTED)
 DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_ITEM_DESELECTED)
 DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_LEFT_CLICK)
@@ -56,6 +59,8 @@ BEGIN_EVENT_TABLE( wxRichTextCtrl, wxScrolledWindow )
 #endif
     EVT_PAINT(wxRichTextCtrl::OnPaint)
     EVT_ERASE_BACKGROUND(wxRichTextCtrl::OnEraseBackground)
+    EVT_IDLE(wxRichTextCtrl::OnIdle)
+    EVT_SCROLLWIN(wxRichTextCtrl::OnScroll)
     EVT_LEFT_DOWN(wxRichTextCtrl::OnLeftClick)
     EVT_MOTION(wxRichTextCtrl::OnMoveMouse)
     EVT_LEFT_UP(wxRichTextCtrl::OnLeftUp)
@@ -102,17 +107,17 @@ wxRichTextCtrl::wxRichTextCtrl()
     Init();
 }
 
-wxRichTextCtrl::wxRichTextCtrl( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style)
+wxRichTextCtrl::wxRichTextCtrl( wxWindow* parent, wxWindowID id, const wxString& value, const wxPoint& pos, const wxSize& size, long style)
 #if wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE
     : wxScrollHelper(this)
 #endif
 {
     Init();
-    Create(parent, id, pos, size, style);
+    Create(parent, id, value, pos, size, style);
 }
 
 /// Creation
-bool wxRichTextCtrl::Create( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style)
+bool wxRichTextCtrl::Create( wxWindow* parent, wxWindowID id, const wxString& value, const wxPoint& pos, const wxSize& size, long style)
 {
 #if wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE
     if (!wxTextCtrlBase::Create(parent, id, pos, size, style|wxFULL_REPAINT_ON_RESIZE
@@ -128,7 +133,7 @@ bool wxRichTextCtrl::Create( wxWindow* parent, wxWindowID id, const wxPoint& pos
     {
         SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
     }
-    
+
     GetBuffer().SetRichTextCtrl(this);
 
     wxTextAttrEx attributes;
@@ -137,26 +142,27 @@ bool wxRichTextCtrl::Create( wxWindow* parent, wxWindowID id, const wxPoint& pos
     attributes.SetBackgroundColour(*wxWHITE);
     attributes.SetAlignment(wxTEXT_ALIGNMENT_LEFT);
     attributes.SetFlags(wxTEXT_ATTR_ALL);
-
-    SetDefaultStyle(attributes);
     SetBasicStyle(attributes);
 
-    SetBackgroundColour(*wxWHITE);    
+    // The default attributes will be merged with base attributes, so
+    // can be empty to begin with
+    wxTextAttrEx defaultAttributes;
+    SetDefaultStyle(defaultAttributes);
+
+    SetBackgroundColour(*wxWHITE);
     SetBackgroundStyle(wxBG_STYLE_CUSTOM);
 
-    // Tell the sizers to use the given or best size    
+    // Tell the sizers to use the given or best size
     SetBestFittingSize(size);
-    
+
     // Create a buffer
     RecreateBuffer(size);
 
-    wxCaret* caret = new wxCaret(this, wxRICHTEXT_DEFAULT_CARET_WIDTH, 16);
-    SetCaret(caret);
-    caret->Show();
-    PositionCaret();
-
     SetCursor(wxCursor(wxCURSOR_IBEAM));
-    
+
+    if (!value.IsEmpty())
+        SetValue(value);
+
     return true;
 }
 
@@ -177,6 +183,11 @@ void wxRichTextCtrl::Init()
     m_editable = true;
     m_caretAtLineStart = false;
     m_dragging = false;
+    m_fullLayoutRequired = false;
+    m_fullLayoutTime = 0;
+    m_fullLayoutSavedPosition = 0;
+    m_delayedLayoutThreshold = wxRICHTEXT_DEFAULT_DELAYED_LAYOUT_THRESHOLD;
+    m_caretPositionForDefaultStyle = -2;
 }
 
 /// Call Freeze to prevent refresh
@@ -186,14 +197,14 @@ void wxRichTextCtrl::Freeze()
 }
 
 /// Call Thaw to refresh
-void wxRichTextCtrl::Thaw(bool refresh)
+void wxRichTextCtrl::Thaw()
 {
     m_freezeCount --;
 
-    if (m_freezeCount == 0 && refresh)
+    if (m_freezeCount == 0)
     {
         SetupScrollbars();
-        Refresh();
+        Refresh(false);
     }
 }
 
@@ -203,13 +214,16 @@ void wxRichTextCtrl::Clear()
     m_buffer.Reset();
     m_buffer.SetDirty(true);
     m_caretPosition = -1;
+    m_caretPositionForDefaultStyle = -2;
     m_caretAtLineStart = false;
     m_selectionRange.SetRange(-2, -2);
 
+    SetScrollbars(0, 0, 0, 0, 0, 0);
+
     if (m_freezeCount == 0)
     {
         SetupScrollbars();
-        Refresh();
+        Refresh(false);
     }
     SendUpdateEvent();
 }
@@ -217,30 +231,41 @@ void wxRichTextCtrl::Clear()
 /// Painting
 void wxRichTextCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
 {
-    wxBufferedPaintDC dc(this, m_bufferBitmap);
+    if (GetCaret())
+        GetCaret()->Hide();
 
-    PrepareDC(dc);
+    {
+        wxBufferedPaintDC dc(this, m_bufferBitmap);
+        //wxLogDebug(wxT("OnPaint"));
 
-    if (m_freezeCount > 0)
-        return;
+        PrepareDC(dc);
 
-    dc.SetFont(GetFont());
-    // Paint the background
-    PaintBackground(dc);
+        if (m_freezeCount > 0)
+            return;
 
-    wxRegion dirtyRegion = GetUpdateRegion();
+        dc.SetFont(GetFont());
 
-    wxRect availableSpace(wxPoint(0, 0), GetClientSize());
-    if (GetBuffer().GetDirty())
-    {
-        GetBuffer().Layout(dc, availableSpace, wxRICHTEXT_FIXED_WIDTH|wxRICHTEXT_VARIABLE_HEIGHT);
-        GetBuffer().SetDirty(false);
-        SetupScrollbars();
-        PositionCaret();
+        // Paint the background
+        PaintBackground(dc);
+
+        wxRegion dirtyRegion = GetUpdateRegion();
+
+        wxRect drawingArea(GetLogicalPoint(wxPoint(0, 0)), GetClientSize());
+        wxRect availableSpace(GetClientSize());
+        if (GetBuffer().GetDirty())
+        {
+            GetBuffer().Layout(dc, availableSpace, wxRICHTEXT_FIXED_WIDTH|wxRICHTEXT_VARIABLE_HEIGHT);
+            GetBuffer().SetDirty(false);
+            SetupScrollbars();
+        }
+
+        GetBuffer().Draw(dc, GetBuffer().GetRange(), GetInternalSelectionRange(), drawingArea, 0 /* descent */, 0 /* flags */);
     }
 
-    GetBuffer().Draw(dc, GetBuffer().GetRange(), GetSelectionRange(), availableSpace, 0 /* descent */, 0 /* flags */);
+    if (GetCaret())
+        GetCaret()->Show();
+
+    PositionCaret();
 }
 
 // Empty implementation, to prevent flicker
@@ -250,14 +275,21 @@ void wxRichTextCtrl::OnEraseBackground(wxEraseEvent& WXUNUSED(event))
 
 void wxRichTextCtrl::OnSetFocus(wxFocusEvent& WXUNUSED(event))
 {
+    wxCaret* caret = new wxCaret(this, wxRICHTEXT_DEFAULT_CARET_WIDTH, 16);
+    SetCaret(caret);
+    caret->Show();
+    PositionCaret();
+
     if (!IsFrozen())
-        Refresh();
+        Refresh(false);
 }
 
 void wxRichTextCtrl::OnKillFocus(wxFocusEvent& WXUNUSED(event))
 {
+    SetCaret(NULL);
+
     if (!IsFrozen())
-        Refresh();
+        Refresh(false);
 }
 
 /// Left-click
@@ -268,7 +300,7 @@ void wxRichTextCtrl::OnLeftClick(wxMouseEvent& event)
     wxClientDC dc(this);
     PrepareDC(dc);
     dc.SetFont(GetFont());
+
     long position = 0;
     int hit = GetBuffer().HitTest(dc, event.GetLogicalPosition(dc), position);
 
@@ -290,7 +322,7 @@ void wxRichTextCtrl::OnLeftClick(wxMouseEvent& event)
             wxRichTextParagraph* para = GetBuffer().GetParagraphAtPosition(position);
             wxRichTextLine* line = GetBuffer().GetLineAtPosition(position);
 
-            if (line && para && line->GetRange().GetStart() == position && para->GetRange().GetStart() != position)
+            if (line && para && line->GetAbsoluteRange().GetStart() == position && para->GetRange().GetStart() != position)
                 caretAtLineStart = true;
             position --;
         }
@@ -338,7 +370,7 @@ void wxRichTextCtrl::OnMoveMouse(wxMouseEvent& event)
     wxClientDC dc(this);
     PrepareDC(dc);
     dc.SetFont(GetFont());
+
     long position = 0;
     wxPoint logicalPt = event.GetLogicalPosition(dc);
     int hit = GetBuffer().HitTest(dc, logicalPt, position);
@@ -357,7 +389,7 @@ void wxRichTextCtrl::OnMoveMouse(wxMouseEvent& event)
             wxRichTextParagraph* para = GetBuffer().GetParagraphAtPosition(position);
             wxRichTextLine* line = GetBuffer().GetLineAtPosition(position);
 
-            if (line && para && line->GetRange().GetStart() == position && para->GetRange().GetStart() != position)
+            if (line && para && line->GetAbsoluteRange().GetStart() == position && para->GetRange().GetStart() != position)
                 caretAtLineStart = true;
             position --;
         }
@@ -365,12 +397,12 @@ void wxRichTextCtrl::OnMoveMouse(wxMouseEvent& event)
         if (m_caretPosition != position)
         {
             bool extendSel = ExtendSelection(m_caretPosition, position, wxRICHTEXT_SHIFT_DOWN);
-            
+
             MoveCaret(position, caretAtLineStart);
             SetDefaultStyleToCursorStyle();
-            
+
             if (extendSel)
-                Refresh();
+                Refresh(false);
         }
     }
 }
@@ -412,13 +444,21 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
         event.GetKeyCode() == WXK_HOME ||
         event.GetKeyCode() == WXK_PAGEUP ||
         event.GetKeyCode() == WXK_PAGEDOWN ||
-        event.GetKeyCode() == WXK_PRIOR ||
-        event.GetKeyCode() == WXK_NEXT ||
         event.GetKeyCode() == WXK_END)
     {
-        Navigate(event.GetKeyCode(), flags);
+        KeyboardNavigate(event.GetKeyCode(), flags);
+        return;
     }
-    else if (event.GetKeyCode() == WXK_RETURN)
+
+    // all the other keys modify the controls contents which shouldn't be
+    // possible if we're read-only
+    if ( !IsEditable() )
+    {
+        event.Skip();
+        return;
+    }
+
+    if (event.GetKeyCode() == WXK_RETURN)
     {
         BeginBatchUndo(_("Insert Text"));
 
@@ -426,7 +466,7 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
 
         DeleteSelectedContent(& newPos);
 
-        GetBuffer().InsertNewlineWithUndo(newPos+1, this);
+        GetBuffer().InsertNewlineWithUndo(newPos+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE);
 
         wxRichTextEvent cmdEvent(
             wxEVT_COMMAND_RICHTEXT_RETURN,
@@ -437,6 +477,8 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
 
         EndBatchUndo();
         SetDefaultStyleToCursorStyle();
+
+        ScrollIntoView(m_caretPosition, WXK_RIGHT);
     }
     else if (event.GetKeyCode() == WXK_BACK)
     {
@@ -466,6 +508,7 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
             SetDefaultStyleToCursorStyle();
         }
 
+        ScrollIntoView(m_caretPosition, WXK_LEFT);
     }
     else if (event.GetKeyCode() == WXK_DELETE)
     {
@@ -502,16 +545,13 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
         DeleteSelectedContent(& newPos);
 
         wxString str = (wxChar) event.GetKeyCode();
-        GetBuffer().InsertTextWithUndo(newPos+1, str, this);
+        GetBuffer().InsertTextWithUndo(newPos+1, str, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE);
 
         EndBatchUndo();
 
         SetDefaultStyleToCursorStyle();
+        ScrollIntoView(m_caretPosition, WXK_RIGHT);
     }
-#if 0
-    else
-        event.Skip();
-#endif
 }
 
 /// Delete content if there is a selection, e.g. when pressing a key.
@@ -565,10 +605,9 @@ Adding Shift does the above but starts/extends selection.
 
  */
 
-bool wxRichTextCtrl::Navigate(int keyCode, int flags)
+bool wxRichTextCtrl::KeyboardNavigate(int keyCode, int flags)
 {
     bool success = false;
-    Freeze();
 
     if (keyCode == WXK_RIGHT)
     {
@@ -598,11 +637,11 @@ bool wxRichTextCtrl::Navigate(int keyCode, int flags)
         else
             success = MoveDown(1, flags);
     }
-    else if (keyCode == WXK_PAGEUP || keyCode == WXK_PRIOR)
+    else if (keyCode == WXK_PAGEUP)
     {
         success = PageUp(1, flags);
     }
-    else if (keyCode == WXK_PAGEDOWN || keyCode == WXK_NEXT)
+    else if (keyCode == WXK_PAGEDOWN)
     {
         success = PageDown(1, flags);
     }
@@ -627,9 +666,6 @@ bool wxRichTextCtrl::Navigate(int keyCode, int flags)
         SetDefaultStyleToCursorStyle();
     }
 
-    // Only refresh if something changed
-    Thaw(success);
-
     return success;
 }
 
@@ -662,7 +698,7 @@ bool wxRichTextCtrl::ExtendSelection(long oldPos, long newPos, int flags)
         {
             wxLogDebug(wxT("Strange selection range"));
         }
-        
+
         return true;
     }
     else
@@ -681,16 +717,16 @@ bool wxRichTextCtrl::ScrollIntoView(long position, int keyCode)
     int ppuX, ppuY;
     GetScrollPixelsPerUnit(& ppuX, & ppuY);
 
-    int startX, startY;
-    GetViewStart(& startX, & startY);
-    startX = 0;
-    startY = startY * ppuY;
+    int startXUnits, startYUnits;
+    GetViewStart(& startXUnits, & startYUnits);
+    int startY = startYUnits * ppuY;
 
-    int sx, sy;
+    int sx = 0, sy = 0;
     GetVirtualSize(& sx, & sy);
-    sx = 0;
+    int sxUnits = 0;
+    int syUnits = 0;
     if (ppuY != 0)
-        sy = sy/ppuY;
+        syUnits = sy/ppuY;
 
     wxRect rect = line->GetRect();
 
@@ -699,42 +735,72 @@ bool wxRichTextCtrl::ScrollIntoView(long position, int keyCode)
     wxSize clientSize = GetClientSize();
 
     // Going down
-    if (keyCode == WXK_DOWN || keyCode == WXK_RIGHT || keyCode == WXK_END || keyCode == WXK_NEXT || keyCode == WXK_PAGEDOWN)
+    if (keyCode == WXK_DOWN || keyCode == WXK_RIGHT || keyCode == WXK_END || keyCode == WXK_PAGEDOWN)
     {
         if ((rect.y + rect.height) > (clientSize.y + startY))
         {
             // Make it scroll so this item is at the bottom
             // of the window
             int y = rect.y - (clientSize.y - rect.height);
-            SetScrollbars(ppuX, ppuY, sx, sy, 0, (int) (0.5 + y/ppuY));
+            int yUnits = (int) (0.5 + ((float) y)/(float) ppuY);
+
+            // If we're still off the screen, scroll another line down
+            if ((rect.y + rect.height) > (clientSize.y + (yUnits*ppuY)))
+                yUnits ++;
+
+            if (startYUnits != yUnits)
+            {
+                SetScrollbars(ppuX, ppuY, sxUnits, syUnits, 0, yUnits);
+                scrolled = true;
+            }
         }
         else if (rect.y < startY)
         {
             // Make it scroll so this item is at the top
             // of the window
             int y = rect.y ;
-            SetScrollbars(ppuX, ppuY, sx, sy, 0, (int) (0.5 + y/ppuY));
+            int yUnits = (int) (0.5 + ((float) y)/(float) ppuY);
+
+            if (startYUnits != yUnits)
+            {
+                SetScrollbars(ppuX, ppuY, sxUnits, syUnits, 0, yUnits);
+                scrolled = true;
+            }
         }
-        scrolled = true;
     }
     // Going up
-    else if (keyCode == WXK_UP || keyCode == WXK_LEFT || keyCode == WXK_HOME || keyCode == WXK_PRIOR || keyCode == WXK_PAGEUP)
+    else if (keyCode == WXK_UP || keyCode == WXK_LEFT || keyCode == WXK_HOME || keyCode == WXK_PAGEUP )
     {
         if (rect.y < startY)
         {
             // Make it scroll so this item is at the top
             // of the window
             int y = rect.y ;
-            SetScrollbars(ppuX, ppuY, sx, sy, 0, (int) (0.5 + y/ppuY));
+            int yUnits = (int) (0.5 + ((float) y)/(float) ppuY);
+
+            if (startYUnits != yUnits)
+            {
+                SetScrollbars(ppuX, ppuY, sxUnits, syUnits, 0, yUnits);
+                scrolled = true;
+            }
         }
         else if ((rect.y + rect.height) > (clientSize.y + startY))
         {
             // Make it scroll so this item is at the bottom
             // of the window
             int y = rect.y - (clientSize.y - rect.height);
-            SetScrollbars(ppuX, ppuY, sx, sy, 0, (int) (0.5 + y/ppuY));
+            int yUnits = (int) (0.5 + ((float) y)/(float) ppuY);
+
+            // If we're still off the screen, scroll another line down
+            if ((rect.y + rect.height) > (clientSize.y + (yUnits*ppuY)))
+                yUnits ++;
+
+            if (startYUnits != yUnits)
+            {
+                SetScrollbars(ppuX, ppuY, sxUnits, syUnits, 0, yUnits);
+                scrolled = true;
+            }
         }
-        scrolled = true;
     }
     PositionCaret();
 
@@ -757,7 +823,7 @@ bool wxRichTextCtrl::IsPositionVisible(long pos) const
     startX = 0;
     startY = startY * ppuY;
 
-    int sx, sy;
+    int sx = 0, sy = 0;
     GetVirtualSize(& sx, & sy);
     sx = 0;
     if (ppuY != 0)
@@ -791,10 +857,12 @@ void wxRichTextCtrl::MoveCaretForward(long oldPosition)
 
         if (line)
         {
+            wxRichTextRange lineRange = line->GetAbsoluteRange();
+
             // We're at the end of a line. See whether we need to
             // stay at the same actual caret position but change visual
             // position, or not.
-            if (oldPosition == line->GetRange().GetEnd())
+            if (oldPosition == lineRange.GetEnd())
             {
                 if (m_caretAtLineStart)
                 {
@@ -808,7 +876,7 @@ void wxRichTextCtrl::MoveCaretForward(long oldPosition)
                     // the same position but indicate that we're to show
                     // at the start of the next line.
                     m_caretPosition = oldPosition;
-                    m_caretAtLineStart = true;                    
+                    m_caretAtLineStart = true;
                 }
                 SetDefaultStyleToCursorStyle();
                 return;
@@ -834,16 +902,18 @@ void wxRichTextCtrl::MoveCaretBack(long oldPosition)
 
         if (line)
         {
+            wxRichTextRange lineRange = line->GetAbsoluteRange();
+
             // We're at the start of a line. See whether we need to
             // stay at the same actual caret position but change visual
             // position, or not.
-            if (oldPosition == line->GetRange().GetStart())
+            if (oldPosition == lineRange.GetStart())
             {
                 m_caretPosition = oldPosition-1;
                 m_caretAtLineStart = true;
                 return;
             }
-            else if (oldPosition == line->GetRange().GetEnd())
+            else if (oldPosition == lineRange.GetEnd())
             {
                 if (m_caretAtLineStart)
                 {
@@ -894,12 +964,12 @@ bool wxRichTextCtrl::MoveRight(int noPositions, int flags)
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (!IsFrozen())
-            Refresh(); // TODO: optimize so that if we didn't change the selection, we don't refresh
+        if (extendSel)
+            Refresh(false);
         return true;
     }
     else
-        return false;    
+        return false;
 }
 
 /// Move left
@@ -923,12 +993,12 @@ bool wxRichTextCtrl::MoveLeft(int noPositions, int flags)
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (!IsFrozen())
-            Refresh();
+        if (extendSel)
+            Refresh(false);
         return true;
     }
     else
-        return false;    
+        return false;
 }
 
 /// Move up
@@ -940,6 +1010,9 @@ bool wxRichTextCtrl::MoveUp(int noLines, int flags)
 /// Move up
 bool wxRichTextCtrl::MoveDown(int noLines, int flags)
 {
+    if (!GetCaret())
+        return false;
+
     long lineNumber = GetBuffer().GetVisibleLineNumber(m_caretPosition, true, m_caretAtLineStart);
     wxPoint pt = GetCaret()->GetPosition();
     long newLine = lineNumber + noLines;
@@ -962,8 +1035,8 @@ bool wxRichTextCtrl::MoveDown(int noLines, int flags)
 
     wxRichTextLine* lineObj = GetBuffer().GetLineForVisibleLineNumber(newLine);
     if (lineObj)
-    {                
-        pt.y = lineObj->GetAbsolutePosition().y + 2;                
+    {
+        pt.y = lineObj->GetAbsolutePosition().y + 2;
     }
     else
         return false;
@@ -972,9 +1045,9 @@ bool wxRichTextCtrl::MoveDown(int noLines, int flags)
     wxClientDC dc(this);
     PrepareDC(dc);
     dc.SetFont(GetFont());
-    
+
     int hitTest = GetBuffer().HitTest(dc, pt, newPos);
-    
+
     if (hitTest != wxRICHTEXT_HITTEST_NONE)
     {
         // If end of previous line, and hitTest is wxRICHTEXT_HITTEST_BEFORE,
@@ -984,13 +1057,14 @@ bool wxRichTextCtrl::MoveDown(int noLines, int flags)
         if (hitTest == wxRICHTEXT_HITTEST_BEFORE)
         {
             wxRichTextLine* thisLine = GetBuffer().GetLineAtPosition(newPos-1);
-            if (thisLine && (newPos-1) == thisLine->GetRange().GetEnd())
+            wxRichTextRange lineRange;
+            if (thisLine)
+                lineRange = thisLine->GetAbsoluteRange();
+
+            if (thisLine && (newPos-1) == lineRange.GetEnd())
             {
-                // if (para->GetRange().GetStart() != thisLine->GetRange().GetStart())
-                {
-                    newPos --;
-                    caretLineStart = true;
-                }
+                newPos --;
+                caretLineStart = true;
             }
             else
             {
@@ -1002,19 +1076,20 @@ bool wxRichTextCtrl::MoveDown(int noLines, int flags)
 
         long newSelEnd = newPos;
 
-        if (!ExtendSelection(m_caretPosition, newSelEnd, flags))
+        bool extendSel = ExtendSelection(m_caretPosition, newSelEnd, flags);
+        if (!extendSel)
             SelectNone();
 
         SetCaretPosition(newPos, caretLineStart);
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (!IsFrozen())
-            Refresh();
+        if (extendSel)
+            Refresh(false);
         return true;
     }
-    else
-        return false;
+
+    return false;
 }
 
 /// Move to the end of the paragraph
@@ -1024,15 +1099,16 @@ bool wxRichTextCtrl::MoveToParagraphEnd(int flags)
     if (para)
     {
         long newPos = para->GetRange().GetEnd() - 1;
-        if (!ExtendSelection(m_caretPosition, newPos, flags))
+        bool extendSel = ExtendSelection(m_caretPosition, newPos, flags);
+        if (!extendSel)
             SelectNone();
 
         SetCaretPosition(newPos);
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (!IsFrozen())
-            Refresh();
+        if (extendSel)
+            Refresh(false);
         return true;
     }
 
@@ -1046,15 +1122,16 @@ bool wxRichTextCtrl::MoveToParagraphStart(int flags)
     if (para)
     {
         long newPos = para->GetRange().GetStart() - 1;
-        if (!ExtendSelection(m_caretPosition, newPos, flags))
+        bool extendSel = ExtendSelection(m_caretPosition, newPos, flags);
+        if (!extendSel)
             SelectNone();
 
         SetCaretPosition(newPos);
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (!IsFrozen())
-            Refresh();
+        if (extendSel)
+            Refresh(false);
         return true;
     }
 
@@ -1068,16 +1145,18 @@ bool wxRichTextCtrl::MoveToLineEnd(int flags)
 
     if (line)
     {
-        long newPos = line->GetRange().GetEnd();
-        if (!ExtendSelection(m_caretPosition, newPos, flags))
+        wxRichTextRange lineRange = line->GetAbsoluteRange();
+        long newPos = lineRange.GetEnd();
+        bool extendSel = ExtendSelection(m_caretPosition, newPos, flags);
+        if (!extendSel)
             SelectNone();
 
         SetCaretPosition(newPos);
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (!IsFrozen())
-            Refresh();
+        if (extendSel)
+            Refresh(false);
         return true;
     }
 
@@ -1090,19 +1169,21 @@ bool wxRichTextCtrl::MoveToLineStart(int flags)
     wxRichTextLine* line = GetVisibleLineForCaretPosition(m_caretPosition);
     if (line)
     {
-        long newPos = line->GetRange().GetStart()-1;
+        wxRichTextRange lineRange = line->GetAbsoluteRange();
+        long newPos = lineRange.GetStart()-1;
 
-        if (!ExtendSelection(m_caretPosition, newPos, flags))
+        bool extendSel = ExtendSelection(m_caretPosition, newPos, flags);
+        if (!extendSel)
             SelectNone();
 
         wxRichTextParagraph* para = GetBuffer().GetParagraphForLine(line);
 
-        SetCaretPosition(newPos, para->GetRange().GetStart() != line->GetRange().GetStart());
+        SetCaretPosition(newPos, para->GetRange().GetStart() != lineRange.GetStart());
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (!IsFrozen())
-            Refresh();
+        if (extendSel)
+            Refresh(false);
         return true;
     }
 
@@ -1114,19 +1195,20 @@ bool wxRichTextCtrl::MoveHome(int flags)
 {
     if (m_caretPosition != -1)
     {
-        if (!ExtendSelection(m_caretPosition, -1, flags))
+        bool extendSel = ExtendSelection(m_caretPosition, -1, flags);
+        if (!extendSel)
             SelectNone();
 
         SetCaretPosition(-1);
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (!IsFrozen())
-            Refresh();
+        if (extendSel)
+            Refresh(false);
         return true;
     }
     else
-        return false;    
+        return false;
 }
 
 /// Move to the end of the buffer
@@ -1136,19 +1218,20 @@ bool wxRichTextCtrl::MoveEnd(int flags)
 
     if (m_caretPosition != endPos)
     {
-        if (!ExtendSelection(m_caretPosition, endPos, flags))
+        bool extendSel = ExtendSelection(m_caretPosition, endPos, flags);
+        if (!extendSel)
             SelectNone();
 
         SetCaretPosition(endPos);
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (!IsFrozen())
-            Refresh();
+        if (extendSel)
+            Refresh(false);
         return true;
     }
     else
-        return false;    
+        return false;
 }
 
 /// Move noPages pages up
@@ -1170,20 +1253,22 @@ bool wxRichTextCtrl::PageDown(int noPages, int flags)
         wxRichTextLine* newLine = GetBuffer().GetLineAtYPosition(newY);
         if (newLine)
         {
-            long pos = newLine->GetRange().GetStart()-1;
+            wxRichTextRange lineRange = newLine->GetAbsoluteRange();
+            long pos = lineRange.GetStart()-1;
             if (pos != m_caretPosition)
             {
                 wxRichTextParagraph* para = GetBuffer().GetParagraphForLine(newLine);
 
-                if (!ExtendSelection(m_caretPosition, pos, flags))
+                bool extendSel = ExtendSelection(m_caretPosition, pos, flags);
+                if (!extendSel)
                     SelectNone();
 
-                SetCaretPosition(pos, para->GetRange().GetStart() != newLine->GetRange().GetStart());
+                SetCaretPosition(pos, para->GetRange().GetStart() != lineRange.GetStart());
                 PositionCaret();
                 SetDefaultStyleToCursorStyle();
 
-                if (!IsFrozen())
-                    Refresh();
+                if (extendSel)
+                    Refresh(false);
                 return true;
             }
         }
@@ -1194,19 +1279,19 @@ bool wxRichTextCtrl::PageDown(int noPages, int flags)
 
 // Finds the caret position for the next word
 long wxRichTextCtrl::FindNextWordPosition(int direction) const
-{    
+{
     long endPos = GetBuffer().GetRange().GetEnd();
 
     if (direction > 0)
     {
         long i = m_caretPosition+1+direction; // +1 for conversion to character pos
-        
+
         // First skip current text to space
         while (i < endPos && i > -1)
         {
             // i is in character, not caret positions
             wxString text = GetBuffer().GetTextForRange(wxRichTextRange(i, i));
-            if (text != wxT(" ") && !text.IsEmpty())
+            if (text != wxT(" ") && !text.empty())
                 i += direction;
             else
             {
@@ -1217,9 +1302,9 @@ long wxRichTextCtrl::FindNextWordPosition(int direction) const
         {
             // i is in character, not caret positions
             wxString text = GetBuffer().GetTextForRange(wxRichTextRange(i, i));
-            if (text.IsEmpty()) // End of paragraph, or maybe an image
+            if (text.empty()) // End of paragraph, or maybe an image
                 return wxMax(-1, i - 1);
-            else if (text == wxT(" ") || text.IsEmpty())
+            else if (text == wxT(" ") || text.empty())
                 i += direction;
             else
             {
@@ -1240,9 +1325,9 @@ long wxRichTextCtrl::FindNextWordPosition(int direction) const
         {
             // i is in character, not caret positions
             wxString text = GetBuffer().GetTextForRange(wxRichTextRange(i, i));
-            if (text.IsEmpty()) // End of paragraph, or maybe an image
+            if (text.empty()) // End of paragraph, or maybe an image
                 break;
-            else if (text == wxT(" ") || text.IsEmpty())
+            else if (text == wxT(" ") || text.empty())
                 i += direction;
             else
                 break;
@@ -1252,12 +1337,11 @@ long wxRichTextCtrl::FindNextWordPosition(int direction) const
         {
             // i is in character, not caret positions
             wxString text = GetBuffer().GetTextForRange(wxRichTextRange(i, i));
-            if (text != wxT(" ") /* && !text.IsEmpty() */)
+            if (text != wxT(" ") /* && !text.empty() */)
                 i += direction;
             else
             {
                 return i;
-                break;
             }
         }
         if (i < -1)
@@ -1273,19 +1357,20 @@ bool wxRichTextCtrl::WordLeft(int WXUNUSED(n), int flags)
     if (pos != m_caretPosition)
     {
         wxRichTextParagraph* para = GetBuffer().GetParagraphAtPosition(pos, true);
-        
-        if (!ExtendSelection(m_caretPosition, pos, flags))
+
+        bool extendSel = ExtendSelection(m_caretPosition, pos, flags);
+        if (!extendSel)
             SelectNone();
-        
+
         SetCaretPosition(pos, para->GetRange().GetStart() != pos);
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (!IsFrozen())
-            Refresh();
+        if (extendSel)
+            Refresh(false);
         return true;
     }
-    
+
     return false;
 }
 
@@ -1296,34 +1381,77 @@ bool wxRichTextCtrl::WordRight(int WXUNUSED(n), int flags)
     if (pos != m_caretPosition)
     {
         wxRichTextParagraph* para = GetBuffer().GetParagraphAtPosition(pos, true);
-        
-        if (!ExtendSelection(m_caretPosition, pos, flags))
+
+        bool extendSel = ExtendSelection(m_caretPosition, pos, flags);
+        if (!extendSel)
             SelectNone();
-        
+
         SetCaretPosition(pos, para->GetRange().GetStart() != pos);
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (!IsFrozen())
-            Refresh();
+        if (extendSel)
+            Refresh(false);
         return true;
     }
-    
+
     return false;
 }
 
 /// Sizing
 void wxRichTextCtrl::OnSize(wxSizeEvent& event)
 {
-    GetBuffer().SetDirty(true);
-    
+    // Only do sizing optimization for large buffers
+    if (GetBuffer().GetRange().GetEnd() > m_delayedLayoutThreshold)
+    {
+        m_fullLayoutRequired = true;
+        m_fullLayoutTime = wxGetLocalTimeMillis();
+        m_fullLayoutSavedPosition = GetFirstVisiblePosition();
+        LayoutContent(true /* onlyVisibleRect */);
+    }
+    else
+        GetBuffer().Invalidate(wxRICHTEXT_ALL);
+
     RecreateBuffer();
 
     event.Skip();
 }
 
+
+/// Idle-time processing
+void wxRichTextCtrl::OnIdle(wxIdleEvent& event)
+{
+    const int layoutInterval = wxRICHTEXT_DEFAULT_LAYOUT_INTERVAL;
+
+    if (m_fullLayoutRequired && (wxGetLocalTimeMillis() > (m_fullLayoutTime + layoutInterval)))
+    {
+        m_fullLayoutRequired = false;
+        m_fullLayoutTime = 0;
+        GetBuffer().Invalidate(wxRICHTEXT_ALL);
+        ShowPosition(m_fullLayoutSavedPosition);
+        Refresh(false);
+    }
+
+    if (m_caretPositionForDefaultStyle != -2)
+    {
+        // If the caret position has changed, no longer reflect the default style
+        // in the UI.
+        if (GetCaretPosition() != m_caretPositionForDefaultStyle)
+            m_caretPositionForDefaultStyle = -2;
+    }
+
+    event.Skip();
+}
+
+/// Scrolling
+void wxRichTextCtrl::OnScroll(wxScrollWinEvent& event)
+{
+    // Not used
+    event.Skip();
+}
+
 /// Set up scrollbars, e.g. after a resize
-void wxRichTextCtrl::SetupScrollbars()
+void wxRichTextCtrl::SetupScrollbars(bool atTop)
 {
     if (m_freezeCount)
         return;
@@ -1336,19 +1464,21 @@ void wxRichTextCtrl::SetupScrollbars()
 
     // TODO: reimplement scrolling so we scroll by line, not by fixed number
     // of pixels. See e.g. wxVScrolledWindow for ideas.
-    int pixelsPerUnit = 5; // 10;
+    int pixelsPerUnit = 5;
     wxSize clientSize = GetClientSize();
 
     int maxHeight = GetBuffer().GetCachedSize().y;
 
-    int unitsY = maxHeight/pixelsPerUnit;
+    // Round up so we have at least maxHeight pixels
+    int unitsY = (int) (((float)maxHeight/(float)pixelsPerUnit) + 0.5);
+
+    int startX = 0, startY = 0;
+    if (!atTop)
+        GetViewStart(& startX, & startY);
 
-    int startX, startY;
-    GetViewStart(& startX, & startY);
-    
     int maxPositionX = 0; // wxMax(sz.x - clientSize.x, 0);
-    int maxPositionY = (wxMax(maxHeight - clientSize.y, 0))/pixelsPerUnit;
-    
+    int maxPositionY = (int) ((((float)(wxMax((unitsY*pixelsPerUnit) - clientSize.y, 0)))/((float)pixelsPerUnit)) + 0.5);
+
     // Move to previous scroll position if
     // possible
     SetScrollbars(0, pixelsPerUnit,
@@ -1366,10 +1496,10 @@ void wxRichTextCtrl::PaintBackground(wxDC& dc)
     // Clear the background
     dc.SetBrush(wxBrush(backgroundColour));
     dc.SetPen(*wxTRANSPARENT_PEN);
-    wxRect windowRect(wxPoint(0, 0), GetClientSize());    
+    wxRect windowRect(GetClientSize());
     windowRect.x -= 2; windowRect.y -= 2;
     windowRect.width += 4; windowRect.height += 4;
-    
+
     // We need to shift the rectangle to take into account
     // scrolling. Converting device to logical coordinates.
     CalcUnscrolledPosition(windowRect.x, windowRect.y, & windowRect.x, & windowRect.y);
@@ -1382,10 +1512,10 @@ bool wxRichTextCtrl::RecreateBuffer(const wxSize& size)
     wxSize sz = size;
     if (sz == wxDefaultSize)
         sz = GetClientSize();
-        
+
     if (sz.x < 1 || sz.y < 1)
         return false;
-        
+
     if (!m_bufferBitmap.Ok() || m_bufferBitmap.GetWidth() < sz.x || m_bufferBitmap.GetHeight() < sz.y)
         m_bufferBitmap = wxBitmap(sz.x, sz.y);
     return m_bufferBitmap.Ok();
@@ -1395,17 +1525,39 @@ bool wxRichTextCtrl::RecreateBuffer(const wxSize& size)
 // file IO functions
 // ----------------------------------------------------------------------------
 
-bool wxRichTextCtrl::LoadFile(const wxString& filename, int type)
+#if !wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE
+bool wxRichTextCtrl::LoadFile(const wxString& filename, int fileType)
 {
-    bool success = GetBuffer().LoadFile(filename, type);
+    return DoLoadFile(filename, fileType);
+}
+
+bool wxRichTextCtrl::SaveFile(const wxString& filename, int fileType)
+{
+    wxString filenameToUse = filename.empty() ? m_filename : filename;
+    if ( filenameToUse.empty() )
+    {
+        // what kind of message to give? is it an error or a program bug?
+        wxLogDebug(wxT("Can't save textctrl to file without filename."));
+
+        return false;
+    }
+
+    return DoSaveFile(filenameToUse, fileType);
+}
+#endif
+
+bool wxRichTextCtrl::DoLoadFile(const wxString& filename, int fileType)
+{
+    bool success = GetBuffer().LoadFile(filename, fileType);
     if (success)
         m_filename = filename;
 
     DiscardEdits();
     SetInsertionPoint(0);
-    Layout();
+    LayoutContent();
     PositionCaret();
-    Refresh();
+    SetupScrollbars(true);
+    Refresh(false);
     SendUpdateEvent();
 
     if (success)
@@ -1413,30 +1565,20 @@ bool wxRichTextCtrl::LoadFile(const wxString& filename, int type)
     else
     {
         wxLogError(_("File couldn't be loaded."));
-        
+
         return false;
     }
 }
 
-bool wxRichTextCtrl::SaveFile(const wxString& filename, int type)
+bool wxRichTextCtrl::DoSaveFile(const wxString& filename, int fileType)
 {
-    wxString filenameToUse = filename.empty() ? m_filename : filename;
-    if ( filenameToUse.empty() )
+    if (GetBuffer().SaveFile(filename, fileType))
     {
-        // what kind of message to give? is it an error or a program bug?
-        wxLogDebug(wxT("Can't save textctrl to file without filename."));
-
-        return false;
-    }
-
-    if (GetBuffer().SaveFile(filenameToUse, type))
-    {
-        m_filename = filenameToUse;
+        m_filename = filename;
 
         DiscardEdits();
 
         return true;
-
     }
 
     wxLogError(_("The text couldn't be saved."));
@@ -1466,14 +1608,15 @@ wxRichTextRange wxRichTextCtrl::AddImage(const wxImage& image)
 
 void wxRichTextCtrl::SelectAll()
 {
-    SetSelection(0, GetLastPosition());
+    SetSelection(0, GetLastPosition()+1);
     m_selectionAnchor = -1;
 }
 
 /// Select none
 void wxRichTextCtrl::SelectNone()
 {
-    SetSelection(-2, -2);
+    if (!(GetSelectionRange() == wxRichTextRange(-2, -2)))
+        SetSelection(-2, -2);
     m_selectionAnchor = -2;
 }
 
@@ -1486,17 +1629,20 @@ wxString wxRichTextCtrl::GetStringSelection() const
 }
 
 // do the window-specific processing after processing the update event
+#if !wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE
 void wxRichTextCtrl::DoUpdateWindowUI(wxUpdateUIEvent& event)
 {
-    if ( event.GetSetEnabled() )
-        Enable(event.GetEnabled());
+    // call inherited
+    wxWindowBase::DoUpdateWindowUI(event);
 
+    // update text
     if ( event.GetSetText() )
     {
         if ( event.GetText() != GetValue() )
             SetValue(event.GetText());
     }
 }
+#endif // !wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE
 
 // ----------------------------------------------------------------------------
 // hit testing
@@ -1526,15 +1672,25 @@ wxRichTextCtrl::HitTest(const wxPoint& pt,
     wxClientDC dc((wxRichTextCtrl*) this);
     ((wxRichTextCtrl*)this)->PrepareDC(dc);
 
-    int hit = ((wxRichTextCtrl*)this)->GetBuffer().HitTest(dc, pt, *pos);
-    if (hit == wxRICHTEXT_HITTEST_BEFORE)
-        return wxTE_HT_BEFORE;
-    else if (hit == wxRICHTEXT_HITTEST_AFTER)
-        return wxTE_HT_BEYOND;
-    else if (hit == wxRICHTEXT_HITTEST_ON)
-        return wxTE_HT_ON_TEXT;
-    else
-        return wxTE_HT_UNKNOWN;
+    // Buffer uses logical position (relative to start of buffer)
+    // so convert
+    wxPoint pt2 = GetLogicalPoint(pt);
+
+    int hit = ((wxRichTextCtrl*)this)->GetBuffer().HitTest(dc, pt2, *pos);
+
+    switch ( hit )
+    {
+        case wxRICHTEXT_HITTEST_BEFORE:
+            return wxTE_HT_BEFORE;
+
+        case wxRICHTEXT_HITTEST_AFTER:
+            return wxTE_HT_BEYOND;
+
+        case wxRICHTEXT_HITTEST_ON:
+            return wxTE_HT_ON_TEXT;
+    }
+
+    return wxTE_HT_UNKNOWN;
 }
 
 // ----------------------------------------------------------------------------
@@ -1548,7 +1704,8 @@ wxString wxRichTextCtrl::GetValue() const
 
 wxString wxRichTextCtrl::GetRange(long from, long to) const
 {
-    return GetBuffer().GetTextForRange(wxRichTextRange(from, to));
+    // Public API for range is different from internals
+    return GetBuffer().GetTextForRange(wxRichTextRange(from, to-1));
 }
 
 void wxRichTextCtrl::SetValue(const wxString& value)
@@ -1586,7 +1743,9 @@ void wxRichTextCtrl::WriteText(const wxString& value)
 
 void wxRichTextCtrl::DoWriteText(const wxString& value, bool WXUNUSED(selectionOnly))
 {
-    GetBuffer().InsertTextWithUndo(m_caretPosition+1, value, this);
+    wxString valueDos = wxTextFile::Translate(value, wxTextFileType_Unix);
+
+    GetBuffer().InsertTextWithUndo(m_caretPosition+1, valueDos, this);
 }
 
 void wxRichTextCtrl::AppendText(const wxString& text)
@@ -1604,8 +1763,8 @@ bool wxRichTextCtrl::WriteImage(const wxImage& image, int bitmapType)
     wxImage image2 = image;
     if (imageBlock.MakeImageBlock(image2, bitmapType))
         return WriteImage(imageBlock);
-    else
-        return false;
+
+    return false;
 }
 
 bool wxRichTextCtrl::WriteImage(const wxString& filename, int bitmapType)
@@ -1615,8 +1774,8 @@ bool wxRichTextCtrl::WriteImage(const wxString& filename, int bitmapType)
     wxImage image;
     if (imageBlock.MakeImageBlock(filename, bitmapType, image, false))
         return WriteImage(imageBlock);
-    else
-        return false;
+
+    return false;
 }
 
 bool wxRichTextCtrl::WriteImage(const wxRichTextImageBlock& imageBlock)
@@ -1629,13 +1788,12 @@ bool wxRichTextCtrl::WriteImage(const wxBitmap& bitmap, int bitmapType)
     if (bitmap.Ok())
     {
         wxRichTextImageBlock imageBlock;
-        
+
         wxImage image = bitmap.ConvertToImage();
         if (image.Ok() && imageBlock.MakeImageBlock(image, bitmapType))
             return WriteImage(imageBlock);
-        else
-            return false;
     }
+
     return false;
 }
 
@@ -1654,7 +1812,7 @@ void wxRichTextCtrl::Copy()
 {
     if (CanCopy())
     {
-        wxRichTextRange range = GetSelectionRange();
+        wxRichTextRange range = GetInternalSelectionRange();
         GetBuffer().CopyToClipboard(range);
     }
 }
@@ -1663,12 +1821,12 @@ void wxRichTextCtrl::Cut()
 {
     if (CanCut())
     {
-        wxRichTextRange range = GetSelectionRange();
+        wxRichTextRange range = GetInternalSelectionRange();
         GetBuffer().CopyToClipboard(range);
 
         DeleteSelectedContent();
-        Layout();
-        Refresh();
+        LayoutContent();
+        Refresh(false);
     }
 }
 
@@ -1677,10 +1835,10 @@ void wxRichTextCtrl::Paste()
     if (CanPaste())
     {
         BeginBatchUndo(_("Paste"));
-        
+
         long newPos = m_caretPosition;
         DeleteSelectedContent(& newPos);
-        
+
         GetBuffer().PasteFromClipboard(newPos);
 
         EndBatchUndo();
@@ -1763,6 +1921,8 @@ void wxRichTextCtrl::GetSelection(long* from, long* to) const
 {
     *from = m_selectionRange.GetStart();
     *to = m_selectionRange.GetEnd();
+    if ((*to) != -1 && (*to) != -2)
+        (*to) ++;
 }
 
 bool wxRichTextCtrl::IsEditable() const
@@ -1781,7 +1941,7 @@ void wxRichTextCtrl::SetSelection(long from, long to)
     if ( (from == -1) && (to == -1) )
     {
         from = 0;
-        to = GetLastPosition();
+        to = GetLastPosition()+1;
     }
 
     DoSetSelection(from, to);
@@ -1790,9 +1950,8 @@ void wxRichTextCtrl::SetSelection(long from, long to)
 void wxRichTextCtrl::DoSetSelection(long from, long to, bool WXUNUSED(scrollCaret))
 {
     m_selectionAnchor = from;
-    m_selectionRange.SetRange(from, to);
-    if (!IsFrozen())
-        Refresh();
+    m_selectionRange.SetRange(from, to-1);
+    Refresh(false);
     PositionCaret();
 }
 
@@ -1820,9 +1979,9 @@ void wxRichTextCtrl::Remove(long from, long to)
         from,                           // New caret position
         this);
 
-    Layout();
+    LayoutContent();
     if (!IsFrozen())
-        Refresh();
+        Refresh(false);
 }
 
 bool wxRichTextCtrl::IsModified() const
@@ -1837,6 +1996,7 @@ void wxRichTextCtrl::MarkDirty()
 
 void wxRichTextCtrl::DiscardEdits()
 {
+    m_caretPositionForDefaultStyle = -2;
     m_buffer.Modify(false);
     m_buffer.GetCommandProcessor()->ClearCommands();
 }
@@ -1911,10 +2071,10 @@ bool wxRichTextCtrl::CanRedo() const
 }
 
 // ----------------------------------------------------------------------------
-// implemenation details
+// implementation details
 // ----------------------------------------------------------------------------
 
-void wxRichTextCtrl::Command(wxCommandEvent & event)
+void wxRichTextCtrl::Command(wxCommandEvent& event)
 {
     SetValue(event.GetString());
     GetEventHandler()->ProcessEvent(event);
@@ -2064,12 +2224,17 @@ void wxRichTextCtrl::OnContextMenu(wxContextMenuEvent& WXUNUSED(event))
 
 bool wxRichTextCtrl::SetStyle(long start, long end, const wxTextAttrEx& style)
 {
-    return GetBuffer().SetStyle(wxRichTextRange(start, end), style);
+    return GetBuffer().SetStyle(wxRichTextRange(start, end-1), style);
+}
+
+bool wxRichTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
+{
+    return GetBuffer().SetStyle(wxRichTextRange(start, end-1), wxTextAttrEx(style));
 }
 
 bool wxRichTextCtrl::SetStyle(const wxRichTextRange& range, const wxRichTextAttr& style)
 {
-    return GetBuffer().SetStyle(range, style);
+    return GetBuffer().SetStyle(range.ToInternal(), style);
 }
 
 bool wxRichTextCtrl::SetDefaultStyle(const wxTextAttrEx& style)
@@ -2077,21 +2242,67 @@ bool wxRichTextCtrl::SetDefaultStyle(const wxTextAttrEx& style)
     return GetBuffer().SetDefaultStyle(style);
 }
 
+bool wxRichTextCtrl::SetDefaultStyle(const wxTextAttr& style)
+{
+    return GetBuffer().SetDefaultStyle(wxTextAttrEx(style));
+}
+
 const wxTextAttrEx& wxRichTextCtrl::GetDefaultStyleEx() const
 {
     return GetBuffer().GetDefaultStyle();
 }
 
-bool wxRichTextCtrl::GetStyle(long position, wxTextAttrEx& style) const
+const wxTextAttr& wxRichTextCtrl::GetDefaultStyle() const
+{
+    return GetBuffer().GetDefaultStyle();
+}
+
+bool wxRichTextCtrl::GetStyle(long position, wxTextAttr& style)
+{
+    wxTextAttrEx attr(style);
+    if (GetBuffer().GetStyle(position, attr))
+    {
+        style = attr;
+        return true;
+    }
+    else
+        return false;
+}
+
+bool wxRichTextCtrl::GetStyle(long position, wxTextAttrEx& style)
 {
     return GetBuffer().GetStyle(position, style);
 }
 
-bool wxRichTextCtrl::GetStyle(long position, wxRichTextAttr& style) const
+bool wxRichTextCtrl::GetStyle(long position, wxRichTextAttr& style)
 {
     return GetBuffer().GetStyle(position, style);
 }
 
+/// Get the content (uncombined) attributes for this position.
+
+bool wxRichTextCtrl::GetUncombinedStyle(long position, wxTextAttr& style)
+{
+    wxTextAttrEx attr(style);
+    if (GetBuffer().GetUncombinedStyle(position, attr))
+    {
+        style = attr;
+        return true;
+    }
+    else
+        return false;
+}
+
+bool wxRichTextCtrl::GetUncombinedStyle(long position, wxTextAttrEx& style)
+{
+    return GetBuffer().GetUncombinedStyle(position, style);
+}
+
+bool wxRichTextCtrl::GetUncombinedStyle(long position, wxRichTextAttr& style)
+{
+    return GetBuffer().GetUncombinedStyle(position, style);
+}
+
 /// Set font, and also the buffer attributes
 bool wxRichTextCtrl::SetFont(const wxFont& font)
 {
@@ -2104,13 +2315,21 @@ bool wxRichTextCtrl::SetFont(const wxFont& font)
     wxTextAttrEx attr = GetBuffer().GetAttributes();
     attr.SetFont(font);
     GetBuffer().SetBasicStyle(attr);
+
+#if !wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE
+    // Don't set the default style, since it will be inherited from
+    // the basic style.
     GetBuffer().SetDefaultStyle(attr);
+#endif
+
+    GetBuffer().Invalidate(wxRICHTEXT_ALL);
+    Refresh(false);
 
     return true;
 }
 
-/// Transform logical to physical (unscrolling)
-wxPoint wxRichTextCtrl::GetPhysicalPoint(const wxPoint& ptLogical)
+/// Transform logical to physical
+wxPoint wxRichTextCtrl::GetPhysicalPoint(const wxPoint& ptLogical) const
 {
     wxPoint pt;
     CalcScrolledPosition(ptLogical.x, ptLogical.y, & pt.x, & pt.y);
@@ -2119,7 +2338,7 @@ wxPoint wxRichTextCtrl::GetPhysicalPoint(const wxPoint& ptLogical)
 }
 
 /// Transform physical to logical
-wxPoint wxRichTextCtrl::GetLogicalPoint(const wxPoint& ptPhysical)
+wxPoint wxRichTextCtrl::GetLogicalPoint(const wxPoint& ptPhysical) const
 {
     wxPoint pt;
     CalcUnscrolledPosition(ptPhysical.x, ptPhysical.y, & pt.x, & pt.y);
@@ -2130,14 +2349,21 @@ wxPoint wxRichTextCtrl::GetLogicalPoint(const wxPoint& ptPhysical)
 /// Position the caret
 void wxRichTextCtrl::PositionCaret()
 {
+    if (!GetCaret())
+        return;
+
+    //wxLogDebug(wxT("PositionCaret"));
+
     wxRect caretRect;
     if (GetCaretPositionForIndex(GetCaretPosition(), caretRect))
     {
         wxPoint originalPt = caretRect.GetPosition();
         wxPoint pt = GetPhysicalPoint(originalPt);
-
-        GetCaret()->Move(pt);
-        GetCaret()->SetSize(caretRect.GetSize());
+        if (GetCaret()->GetPosition() != pt)
+        {
+            GetCaret()->Move(pt);
+            GetCaret()->SetSize(caretRect.GetSize());
+        }
     }
 }
 
@@ -2146,7 +2372,7 @@ bool wxRichTextCtrl::GetCaretPositionForIndex(long position, wxRect& rect)
 {
     wxClientDC dc(this);
     dc.SetFont(GetFont());
+
     PrepareDC(dc);
 
     wxPoint pt;
@@ -2157,8 +2383,8 @@ bool wxRichTextCtrl::GetCaretPositionForIndex(long position, wxRect& rect)
         rect = wxRect(pt, wxSize(wxRICHTEXT_DEFAULT_CARET_WIDTH, height));
         return true;
     }
-    else
-        return false;
+
+    return false;
 }
 
 /// Gets the line for the visible caret position. If the caret is
@@ -2171,8 +2397,9 @@ wxRichTextLine* wxRichTextCtrl::GetVisibleLineForCaretPosition(long caretPositio
     wxRichTextParagraph* para = GetBuffer().GetParagraphAtPosition(caretPosition, true);
     if (line)
     {
-        if (caretPosition == line->GetRange().GetStart()-1 &&
-            (para->GetRange().GetStart() != line->GetRange().GetStart()))
+        wxRichTextRange lineRange = line->GetAbsoluteRange();
+        if (caretPosition == lineRange.GetStart()-1 &&
+            (para->GetRange().GetStart() != lineRange.GetStart()))
         {
             if (!m_caretAtLineStart)
                 line = GetBuffer().GetLineAtPosition(caretPosition-1, true);
@@ -2186,7 +2413,7 @@ wxRichTextLine* wxRichTextCtrl::GetVisibleLineForCaretPosition(long caretPositio
 bool wxRichTextCtrl::MoveCaret(long pos, bool showAtLineStart)
 {
     if (GetBuffer().GetDirty())
-        Layout();
+        LayoutContent();
 
     if (pos <= GetBuffer().GetRange().GetEnd())
     {
@@ -2202,40 +2429,50 @@ bool wxRichTextCtrl::MoveCaret(long pos, bool showAtLineStart)
 
 /// Layout the buffer: which we must do before certain operations, such as
 /// setting the caret position.
-bool wxRichTextCtrl::Layout()
+bool wxRichTextCtrl::LayoutContent(bool onlyVisibleRect)
 {
-    wxRect availableSpace(wxPoint(0, 0), GetClientSize());
-    if (availableSpace.width == 0)
-        availableSpace.width = 10;
-    if (availableSpace.height == 0)
-        availableSpace.height = 10;
+    if (GetBuffer().GetDirty() || onlyVisibleRect)
+    {
+        wxRect availableSpace(GetClientSize());
+        if (availableSpace.width == 0)
+            availableSpace.width = 10;
+        if (availableSpace.height == 0)
+            availableSpace.height = 10;
 
-    wxClientDC dc(this);
-    dc.SetFont(GetFont());
-    PrepareDC(dc);
+        int flags = wxRICHTEXT_FIXED_WIDTH|wxRICHTEXT_VARIABLE_HEIGHT;
+        if (onlyVisibleRect)
+        {
+            flags |= wxRICHTEXT_LAYOUT_SPECIFIED_RECT;
+            availableSpace.SetPosition(GetLogicalPoint(wxPoint(0, 0)));
+        }
 
-    GetBuffer().Defragment();
-    GetBuffer().UpdateRanges();     // If items were deleted, ranges need recalculation
-    GetBuffer().Layout(dc, availableSpace, wxRICHTEXT_FIXED_WIDTH|wxRICHTEXT_VARIABLE_HEIGHT);
-    GetBuffer().SetDirty(false);
-    
-    if (!IsFrozen())
-        SetupScrollbars();
+        wxClientDC dc(this);
+        dc.SetFont(GetFont());
+
+        PrepareDC(dc);
+
+        GetBuffer().Defragment();
+        GetBuffer().UpdateRanges();     // If items were deleted, ranges need recalculation
+        GetBuffer().Layout(dc, availableSpace, flags);
+        GetBuffer().SetDirty(false);
+
+        if (!IsFrozen())
+            SetupScrollbars();
+    }
 
     return true;
 }
 
 /// Is all of the selection bold?
-bool wxRichTextCtrl::IsSelectionBold() const
+bool wxRichTextCtrl::IsSelectionBold()
 {
     if (HasSelection())
     {
         wxRichTextAttr attr;
-        wxRichTextRange range = GetSelectionRange();
+        wxRichTextRange range = GetInternalSelectionRange();
         attr.SetFlags(wxTEXT_ATTR_FONT_WEIGHT);
         attr.SetFontWeight(wxBOLD);
-        
+
         return HasCharacterAttributes(range, attr);
     }
     else
@@ -2244,9 +2481,12 @@ bool wxRichTextCtrl::IsSelectionBold() const
         // to see what the effect would be if we started typing.
         wxRichTextAttr attr;
         attr.SetFlags(wxTEXT_ATTR_FONT_WEIGHT);
-        if (GetStyle(GetCaretPosition()+1, attr))
+
+        long pos = GetAdjustedCaretPosition(GetCaretPosition());
+        if (GetStyle(pos, attr))
         {
-            wxRichTextApplyStyle(attr, GetDefaultStyleEx());
+            if (IsDefaultStyleShowing())
+                wxRichTextApplyStyle(attr, GetDefaultStyleEx());
             return attr.GetFontWeight() == wxBOLD;
         }
     }
@@ -2254,15 +2494,15 @@ bool wxRichTextCtrl::IsSelectionBold() const
 }
 
 /// Is all of the selection italics?
-bool wxRichTextCtrl::IsSelectionItalics() const
+bool wxRichTextCtrl::IsSelectionItalics()
 {
     if (HasSelection())
     {
-        wxRichTextRange range = GetSelectionRange();
+        wxRichTextRange range = GetInternalSelectionRange();
         wxRichTextAttr attr;
         attr.SetFlags(wxTEXT_ATTR_FONT_ITALIC);
         attr.SetFontStyle(wxITALIC);
-        
+
         return HasCharacterAttributes(range, attr);
     }
     else
@@ -2271,9 +2511,12 @@ bool wxRichTextCtrl::IsSelectionItalics() const
         // to see what the effect would be if we started typing.
         wxRichTextAttr attr;
         attr.SetFlags(wxTEXT_ATTR_FONT_ITALIC);
-        if (GetStyle(GetCaretPosition()+1, attr))
+
+        long pos = GetAdjustedCaretPosition(GetCaretPosition());
+        if (GetStyle(pos, attr))
         {
-            wxRichTextApplyStyle(attr, GetDefaultStyleEx());
+            if (IsDefaultStyleShowing())
+                wxRichTextApplyStyle(attr, GetDefaultStyleEx());
             return attr.GetFontStyle() == wxITALIC;
         }
     }
@@ -2281,15 +2524,15 @@ bool wxRichTextCtrl::IsSelectionItalics() const
 }
 
 /// Is all of the selection underlined?
-bool wxRichTextCtrl::IsSelectionUnderlined() const
+bool wxRichTextCtrl::IsSelectionUnderlined()
 {
     if (HasSelection())
     {
-        wxRichTextRange range = GetSelectionRange();
+        wxRichTextRange range = GetInternalSelectionRange();
         wxRichTextAttr attr;
         attr.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE);
         attr.SetFontUnderlined(true);
-        
+
         return HasCharacterAttributes(range, attr);
     }
     else
@@ -2298,9 +2541,12 @@ bool wxRichTextCtrl::IsSelectionUnderlined() const
         // to see what the effect would be if we started typing.
         wxRichTextAttr attr;
         attr.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE);
-        if (GetStyle(GetCaretPosition()+1, attr))
+        long pos = GetAdjustedCaretPosition(GetCaretPosition());
+
+        if (GetStyle(pos, attr))
         {
-            wxRichTextApplyStyle(attr, GetDefaultStyleEx());
+            if (IsDefaultStyleShowing())
+                wxRichTextApplyStyle(attr, GetDefaultStyleEx());
             return attr.GetFontUnderlined();
         }
     }
@@ -2317,7 +2563,7 @@ bool wxRichTextCtrl::ApplyBoldToSelection()
     if (HasSelection())
         return SetStyle(GetSelectionRange(), attr);
     else
-        SetDefaultStyle(attr);
+        SetAndShowDefaultStyle(attr);
     return true;
 }
 
@@ -2331,7 +2577,7 @@ bool wxRichTextCtrl::ApplyItalicToSelection()
     if (HasSelection())
         return SetStyle(GetSelectionRange(), attr);
     else
-        SetDefaultStyle(attr);
+        SetAndShowDefaultStyle(attr);
     return true;
 }
 
@@ -2340,24 +2586,24 @@ bool wxRichTextCtrl::ApplyUnderlineToSelection()
 {
     wxRichTextAttr attr;
     attr.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE);
-    attr.SetFontWeight(!IsSelectionUnderlined());
+    attr.SetFontUnderlined(!IsSelectionUnderlined());
 
     if (HasSelection())
         return SetStyle(GetSelectionRange(), attr);
     else
-        SetDefaultStyle(attr);
+        SetAndShowDefaultStyle(attr);
     return true;
 }
 
 /// Is all of the selection aligned according to the specified flag?
-bool wxRichTextCtrl::IsSelectionAligned(wxTextAttrAlignment alignment) const
+bool wxRichTextCtrl::IsSelectionAligned(wxTextAttrAlignment alignment)
 {
     if (HasSelection())
     {
-        wxRichTextRange range = GetSelectionRange();
+        wxRichTextRange range = GetInternalSelectionRange();
         wxRichTextAttr attr;
         attr.SetAlignment(alignment);
-        
+
         return HasParagraphAttributes(range, attr);
     }
     else
@@ -2381,26 +2627,113 @@ bool wxRichTextCtrl::ApplyAlignmentToSelection(wxTextAttrAlignment alignment)
     {
         wxRichTextParagraph* para = GetBuffer().GetParagraphAtPosition(GetCaretPosition()+1);
         if (para)
-            return SetStyle(para->GetRange(), attr);
+            return SetStyle(para->GetRange().FromInternal(), attr);
     }
     return true;
 }
 
+/// Apply a named style to the selection
+void wxRichTextCtrl::ApplyStyle(wxRichTextStyleDefinition* def)
+{
+    // Flags are defined within each definition, so only certain
+    // attributes are applied.
+    wxRichTextAttr attr(def->GetStyle());
+
+    // Make sure the attr has the style name
+    if (def->IsKindOf(CLASSINFO(wxRichTextParagraphStyleDefinition)))
+        attr.SetParagraphStyleName(def->GetName());
+    else
+        attr.SetCharacterStyleName(def->GetName());
+
+    if (HasSelection())
+        SetStyle(GetSelectionRange(), attr);
+    else
+        SetAndShowDefaultStyle(attr);
+}
+
+/// Apply the style sheet to the buffer, for example if the styles have changed.
+bool wxRichTextCtrl::ApplyStyleSheet(wxRichTextStyleSheet* styleSheet)
+{
+    if (!styleSheet)
+        styleSheet = GetBuffer().GetStyleSheet();
+    if (!styleSheet)
+        return false;
+
+    if (GetBuffer().ApplyStyleSheet(styleSheet))
+    {
+        GetBuffer().Invalidate(wxRICHTEXT_ALL);
+        Refresh(false);
+        return true;
+    }
+    else
+        return false;
+}
+
 /// Sets the default style to the style under the cursor
 bool wxRichTextCtrl::SetDefaultStyleToCursorStyle()
 {
     wxTextAttrEx attr;
     attr.SetFlags(wxTEXT_ATTR_CHARACTER);
 
-    if (GetStyle(GetCaretPosition(), attr))
+    // If at the start of a paragraph, use the next position.
+    long pos = GetAdjustedCaretPosition(GetCaretPosition());
+
+#if wxRICHTEXT_USE_DYNAMIC_STYLES
+    if (GetUncombinedStyle(pos, attr))
+#else
+    if (GetStyle(pos, attr))
+#endif
     {
         SetDefaultStyle(attr);
         return true;
     }
+
+    return false;
+}
+
+/// Returns the first visible position in the current view
+long wxRichTextCtrl::GetFirstVisiblePosition() const
+{
+    wxRichTextLine* line = GetBuffer().GetLineAtYPosition(GetLogicalPoint(wxPoint(0, 0)).y);
+    if (line)
+        return line->GetAbsoluteRange().GetStart();
     else
-        return false;
+        return 0;
+}
+
+/// The adjusted caret position is the character position adjusted to take
+/// into account whether we're at the start of a paragraph, in which case
+/// style information should be taken from the next position, not current one.
+long wxRichTextCtrl::GetAdjustedCaretPosition(long caretPos) const
+{
+    wxRichTextParagraph* para = GetBuffer().GetParagraphAtPosition(caretPos+1);
+
+    if (para && (caretPos+1 == para->GetRange().GetStart()))
+        caretPos ++;
+    return caretPos;
+}
+
+/// Get/set the selection range in character positions. -1, -1 means no selection.
+/// The range is in API convention, i.e. a single character selection is denoted
+/// by (n, n+1)
+wxRichTextRange wxRichTextCtrl::GetSelectionRange() const
+{
+    wxRichTextRange range = GetInternalSelectionRange();
+    if (range != wxRichTextRange(-2,-2) && range != wxRichTextRange(-1,-1))
+        range.SetEnd(range.GetEnd() + 1);
+    return range;
+}
+
+void wxRichTextCtrl::SetSelectionRange(const wxRichTextRange& range)
+{
+    wxRichTextRange range1(range);
+    if (range1 != wxRichTextRange(-2,-2) && range1 != wxRichTextRange(-1,-1) )
+        range1.SetEnd(range1.GetEnd() - 1);
+
+    wxASSERT( range1.GetStart() > range1.GetEnd() );
+
+    SetInternalSelectionRange(range1);
 }
 
 #endif
     // wxUSE_RICHTEXT
-