]> git.saurik.com Git - wxWidgets.git/blobdiff - src/richtext/richtextctrl.cpp
fixed client<->window coords translations in DoMoveWindow and DoSetSize
[wxWidgets.git] / src / richtext / richtextctrl.cpp
index ea46d5f76d01cc27feeaa1dcdf4cd6a460ff9a9c..7143227cccd612088abb27eaa9d6454a2e0140ea 100644 (file)
@@ -1,5 +1,5 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        richtext/richeditctrl.cpp
+// Name:        src/richtext/richeditctrl.cpp
 // Purpose:     A rich edit control
 // Author:      Julian Smart
 // Modified by:
 #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/settings.h"
+    #include "wx/menu.h"
+    #include "wx/intl.h"
+    #include "wx/log.h"
+    #include "wx/stopwatch.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)
@@ -57,6 +63,7 @@ BEGIN_EVENT_TABLE( wxRichTextCtrl, wxScrolledWindow )
     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)
@@ -103,17 +110,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
@@ -151,13 +158,11 @@ bool wxRichTextCtrl::Create( wxWindow* parent, wxWindowID id, const wxPoint& pos
     // 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;
 }
 
@@ -182,6 +187,7 @@ void wxRichTextCtrl::Init()
     m_fullLayoutTime = 0;
     m_fullLayoutSavedPosition = 0;
     m_delayedLayoutThreshold = wxRICHTEXT_DEFAULT_DELAYED_LAYOUT_THRESHOLD;
+    m_caretPositionForDefaultStyle = -2;
 }
 
 /// Call Freeze to prevent refresh
@@ -191,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);
     }
 }
 
@@ -208,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();
 }
@@ -222,31 +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());
+        if (m_freezeCount > 0)
+            return;
 
-    // Paint the background
-    PaintBackground(dc);
+        dc.SetFont(GetFont());
 
-    wxRegion dirtyRegion = GetUpdateRegion();
+        // Paint the background
+        PaintBackground(dc);
 
-    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();
+        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 */);
     }
-    PositionCaret();
 
-    GetBuffer().Draw(dc, GetBuffer().GetRange(), GetSelectionRange(), drawingArea, 0 /* descent */, 0 /* flags */);
+    if (GetCaret())
+        GetCaret()->Show();
+
+    PositionCaret();
 }
 
 // Empty implementation, to prevent flicker
@@ -256,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
@@ -376,7 +402,7 @@ void wxRichTextCtrl::OnMoveMouse(wxMouseEvent& event)
             SetDefaultStyleToCursorStyle();
 
             if (extendSel)
-                Refresh();
+                Refresh(false);
         }
     }
 }
@@ -418,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;
+    }
+
+    // all the other keys modify the controls contents which shouldn't be
+    // possible if we're read-only
+    if ( !IsEditable() )
+    {
+        event.Skip();
+        return;
     }
-    else if (event.GetKeyCode() == WXK_RETURN)
+
+    if (event.GetKeyCode() == WXK_RETURN)
     {
         BeginBatchUndo(_("Insert Text"));
 
@@ -443,6 +477,8 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
 
         EndBatchUndo();
         SetDefaultStyleToCursorStyle();
+
+        ScrollIntoView(m_caretPosition, WXK_RIGHT);
     }
     else if (event.GetKeyCode() == WXK_BACK)
     {
@@ -472,6 +508,7 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
             SetDefaultStyleToCursorStyle();
         }
 
+        ScrollIntoView(m_caretPosition, WXK_LEFT);
     }
     else if (event.GetKeyCode() == WXK_DELETE)
     {
@@ -513,11 +550,8 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
         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.
@@ -571,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)
     {
@@ -604,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);
     }
@@ -633,9 +666,6 @@ bool wxRichTextCtrl::Navigate(int keyCode, int flags)
         SetDefaultStyleToCursorStyle();
     }
 
-    // Only refresh if something changed
-    Thaw(success);
-
     return success;
 }
 
@@ -687,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();
 
@@ -705,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();
 
@@ -763,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)
@@ -904,8 +964,8 @@ 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
@@ -933,8 +993,8 @@ bool wxRichTextCtrl::MoveLeft(int noPositions, int flags)
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (!IsFrozen())
-            Refresh();
+        if (extendSel)
+            Refresh(false);
         return true;
     }
     else
@@ -950,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;
@@ -1013,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
@@ -1035,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;
     }
 
@@ -1057,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;
     }
 
@@ -1081,15 +1147,16 @@ bool wxRichTextCtrl::MoveToLineEnd(int flags)
     {
         wxRichTextRange lineRange = line->GetAbsoluteRange();
         long newPos = lineRange.GetEnd();
-        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;
     }
 
@@ -1105,7 +1172,8 @@ bool wxRichTextCtrl::MoveToLineStart(int flags)
         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);
@@ -1114,8 +1182,8 @@ bool wxRichTextCtrl::MoveToLineStart(int flags)
         PositionCaret();
         SetDefaultStyleToCursorStyle();
 
-        if (!IsFrozen())
-            Refresh();
+        if (extendSel)
+            Refresh(false);
         return true;
     }
 
@@ -1127,15 +1195,16 @@ 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
@@ -1149,15 +1218,16 @@ 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
@@ -1189,15 +1259,16 @@ bool wxRichTextCtrl::PageDown(int noPages, int flags)
             {
                 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() != lineRange.GetStart());
                 PositionCaret();
                 SetDefaultStyleToCursorStyle();
 
-                if (!IsFrozen())
-                    Refresh();
+                if (extendSel)
+                    Refresh(false);
                 return true;
             }
         }
@@ -1287,15 +1358,16 @@ bool wxRichTextCtrl::WordLeft(int WXUNUSED(n), int flags)
     {
         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;
     }
 
@@ -1310,15 +1382,16 @@ bool wxRichTextCtrl::WordRight(int WXUNUSED(n), int flags)
     {
         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;
     }
 
@@ -1334,7 +1407,7 @@ void wxRichTextCtrl::OnSize(wxSizeEvent& event)
         m_fullLayoutRequired = true;
         m_fullLayoutTime = wxGetLocalTimeMillis();
         m_fullLayoutSavedPosition = GetFirstVisiblePosition();
-        Layout(true /* onlyVisibleRect */);
+        LayoutContent(true /* onlyVisibleRect */);
     }
     else
         GetBuffer().Invalidate(wxRICHTEXT_ALL);
@@ -1356,8 +1429,24 @@ void wxRichTextCtrl::OnIdle(wxIdleEvent& event)
         m_fullLayoutTime = 0;
         GetBuffer().Invalidate(wxRICHTEXT_ALL);
         ShowPosition(m_fullLayoutSavedPosition);
-        Refresh();
+        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();
 }
 
@@ -1375,19 +1464,20 @@ void wxRichTextCtrl::SetupScrollbars(bool atTop)
 
     // 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 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
@@ -1443,10 +1533,10 @@ bool wxRichTextCtrl::LoadFile(const wxString& filename, int type)
 
     DiscardEdits();
     SetInsertionPoint(0);
-    Layout();
+    LayoutContent();
     PositionCaret();
     SetupScrollbars(true);
-    Refresh();
+    Refresh(false);
     SendUpdateEvent();
 
     if (success)
@@ -1507,14 +1597,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;
 }
 
@@ -1527,17 +1618,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
@@ -1567,15 +1661,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;
 }
 
 // ----------------------------------------------------------------------------
@@ -1589,7 +1693,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)
@@ -1645,8 +1750,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)
@@ -1656,8 +1761,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)
@@ -1674,9 +1779,8 @@ bool wxRichTextCtrl::WriteImage(const wxBitmap& bitmap, int bitmapType)
         wxImage image = bitmap.ConvertToImage();
         if (image.Ok() && imageBlock.MakeImageBlock(image, bitmapType))
             return WriteImage(imageBlock);
-        else
-            return false;
     }
+
     return false;
 }
 
@@ -1708,8 +1812,8 @@ void wxRichTextCtrl::Cut()
         GetBuffer().CopyToClipboard(range);
 
         DeleteSelectedContent();
-        Layout();
-        Refresh();
+        LayoutContent();
+        Refresh(false);
     }
 }
 
@@ -1804,6 +1908,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
@@ -1822,7 +1928,7 @@ void wxRichTextCtrl::SetSelection(long from, long to)
     if ( (from == -1) && (to == -1) )
     {
         from = 0;
-        to = GetLastPosition();
+        to = GetLastPosition()+1;
     }
 
     DoSetSelection(from, to);
@@ -1831,9 +1937,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();
 }
 
@@ -1861,9 +1966,9 @@ void wxRichTextCtrl::Remove(long from, long to)
         from,                           // New caret position
         this);
 
-    Layout();
+    LayoutContent();
     if (!IsFrozen())
-        Refresh();
+        Refresh(false);
 }
 
 bool wxRichTextCtrl::IsModified() const
@@ -1878,6 +1983,7 @@ void wxRichTextCtrl::MarkDirty()
 
 void wxRichTextCtrl::DiscardEdits()
 {
+    m_caretPositionForDefaultStyle = -2;
     m_buffer.Modify(false);
     m_buffer.GetCommandProcessor()->ClearCommands();
 }
@@ -1952,10 +2058,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);
@@ -2105,12 +2211,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)
@@ -2118,17 +2229,39 @@ 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;
+    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);
 }
@@ -2171,14 +2304,21 @@ wxPoint wxRichTextCtrl::GetLogicalPoint(const wxPoint& ptPhysical) const
 /// 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());
+        }
     }
 }
 
@@ -2198,8 +2338,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
@@ -2228,7 +2368,7 @@ wxRichTextLine* wxRichTextCtrl::GetVisibleLineForCaretPosition(long caretPositio
 bool wxRichTextCtrl::MoveCaret(long pos, bool showAtLineStart)
 {
     if (GetBuffer().GetDirty())
-        Layout();
+        LayoutContent();
 
     if (pos <= GetBuffer().GetRange().GetEnd())
     {
@@ -2244,7 +2384,7 @@ 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 onlyVisibleRect)
+bool wxRichTextCtrl::LayoutContent(bool onlyVisibleRect)
 {
     if (GetBuffer().GetDirty() || onlyVisibleRect)
     {
@@ -2260,17 +2400,17 @@ bool wxRichTextCtrl::Layout(bool onlyVisibleRect)
             flags |= wxRICHTEXT_LAYOUT_SPECIFIED_RECT;
             availableSpace.SetPosition(GetLogicalPoint(wxPoint(0, 0)));
         }
-        
+
         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();
     }
@@ -2279,12 +2419,12 @@ bool wxRichTextCtrl::Layout(bool onlyVisibleRect)
 }
 
 /// 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);
 
@@ -2296,9 +2436,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;
         }
     }
@@ -2306,11 +2449,11 @@ 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);
@@ -2323,9 +2466,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;
         }
     }
@@ -2333,11 +2479,11 @@ 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);
@@ -2350,9 +2496,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();
         }
     }
@@ -2369,7 +2518,7 @@ bool wxRichTextCtrl::ApplyBoldToSelection()
     if (HasSelection())
         return SetStyle(GetSelectionRange(), attr);
     else
-        SetDefaultStyle(attr);
+        SetAndShowDefaultStyle(attr);
     return true;
 }
 
@@ -2383,7 +2532,7 @@ bool wxRichTextCtrl::ApplyItalicToSelection()
     if (HasSelection())
         return SetStyle(GetSelectionRange(), attr);
     else
-        SetDefaultStyle(attr);
+        SetAndShowDefaultStyle(attr);
     return true;
 }
 
@@ -2397,16 +2546,16 @@ bool wxRichTextCtrl::ApplyUnderlineToSelection()
     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);
 
@@ -2433,24 +2582,46 @@ 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);
+}
+
 /// 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 (GetStyle(pos, attr))
     {
         SetDefaultStyle(attr);
         return true;
     }
-    else
-        return false;
+
+    return false;
 }
 
 /// Returns the first visible position in the current view
@@ -2463,6 +2634,39 @@ long wxRichTextCtrl::GetFirstVisiblePosition() const
         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
-