/////////////////////////////////////////////////////////////////////////////
-// 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"
-#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)
#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)
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
{
SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
}
-
+
GetBuffer().SetRichTextCtrl(this);
wxTextAttrEx attributes;
SetDefaultStyle(attributes);
SetBasicStyle(attributes);
- SetBackgroundColour(*wxWHITE);
+ 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;
}
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;
}
/// Call Freeze to prevent refresh
}
/// 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);
}
}
m_caretAtLineStart = false;
m_selectionRange.SetRange(-2, -2);
+ SetScrollbars(0, 0, 0, 0, 0, 0);
+
if (m_freezeCount == 0)
{
SetupScrollbars();
- Refresh();
+ Refresh(false);
}
SendUpdateEvent();
}
/// 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 drawingArea(GetLogicalPoint(wxPoint(0, 0)), GetClientSize());
- wxRect availableSpace(wxPoint(0, 0), GetClientSize());
- if (GetBuffer().GetDirty())
- {
- GetBuffer().Layout(dc, availableSpace, GetBuffer().GetRange(), 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(), GetSelectionRange(), drawingArea, 0 /* descent */, 0 /* flags */);
}
- GetBuffer().Draw(dc, GetBuffer().GetRange(), GetSelectionRange(), drawingArea, 0 /* descent */, 0 /* flags */);
+ if (GetCaret())
+ GetCaret()->Show();
+
+ PositionCaret();
}
// Empty implementation, to prevent flicker
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
wxClientDC dc(this);
PrepareDC(dc);
dc.SetFont(GetFont());
-
+
long position = 0;
int hit = GetBuffer().HitTest(dc, event.GetLogicalPosition(dc), position);
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 --;
}
wxClientDC dc(this);
PrepareDC(dc);
dc.SetFont(GetFont());
-
+
long position = 0;
wxPoint logicalPt = event.GetLogicalPosition(dc);
int hit = GetBuffer().HitTest(dc, logicalPt, position);
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 --;
}
if (m_caretPosition != position)
{
bool extendSel = ExtendSelection(m_caretPosition, position, wxRICHTEXT_SHIFT_DOWN);
-
+
MoveCaret(position, caretAtLineStart);
SetDefaultStyleToCursorStyle();
-
+
if (extendSel)
- Refresh();
+ Refresh(false);
}
}
}
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"));
EndBatchUndo();
SetDefaultStyleToCursorStyle();
+
+ ScrollIntoView(m_caretPosition, WXK_RIGHT);
}
else if (event.GetKeyCode() == WXK_BACK)
{
SetDefaultStyleToCursorStyle();
}
+ ScrollIntoView(m_caretPosition, WXK_LEFT);
}
else if (event.GetKeyCode() == WXK_DELETE)
{
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.
*/
-bool wxRichTextCtrl::Navigate(int keyCode, int flags)
+bool wxRichTextCtrl::KeyboardNavigate(int keyCode, int flags)
{
bool success = false;
- Freeze();
if (keyCode == WXK_RIGHT)
{
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);
}
SetDefaultStyleToCursorStyle();
}
- // Only refresh if something changed
- Thaw(success);
-
return success;
}
{
wxLogDebug(wxT("Strange selection range"));
}
-
+
return true;
}
else
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();
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();
startX = 0;
startY = startY * ppuY;
- int sx, sy;
+ int sx = 0, sy = 0;
GetVirtualSize(& sx, & sy);
sx = 0;
if (ppuY != 0)
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)
{
// 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;
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)
{
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
PositionCaret();
SetDefaultStyleToCursorStyle();
- if (!IsFrozen())
- Refresh();
+ if (extendSel)
+ Refresh(false);
return true;
}
else
- return false;
+ return false;
}
/// Move up
/// 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;
wxRichTextLine* lineObj = GetBuffer().GetLineForVisibleLineNumber(newLine);
if (lineObj)
- {
- pt.y = lineObj->GetAbsolutePosition().y + 2;
+ {
+ pt.y = lineObj->GetAbsolutePosition().y + 2;
}
else
return false;
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,
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
{
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
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;
}
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;
}
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;
}
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;
}
{
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
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
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;
}
}
// 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
{
{
// 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
{
{
// 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;
{
// 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)
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;
}
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);
+ }
+ 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;
// 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,
// 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);
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();
DiscardEdits();
SetInsertionPoint(0);
- Layout();
+ LayoutContent();
PositionCaret();
- Refresh();
+ SetupScrollbars(true);
+ Refresh(false);
SendUpdateEvent();
if (success)
else
{
wxLogError(_("File couldn't be loaded."));
-
+
return false;
}
}
/// Select none
void wxRichTextCtrl::SelectNone()
{
- SetSelection(-2, -2);
+ if (!(GetSelectionRange() == wxRichTextRange(-2, -2)))
+ SetSelection(-2, -2);
m_selectionAnchor = -2;
}
}
// 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
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;
}
// ----------------------------------------------------------------------------
wxImage image2 = image;
if (imageBlock.MakeImageBlock(image2, bitmapType))
return WriteImage(imageBlock);
- else
- return false;
+
+ return false;
}
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)
if (bitmap.Ok())
{
wxRichTextImageBlock imageBlock;
-
+
wxImage image = bitmap.ConvertToImage();
if (image.Ok() && imageBlock.MakeImageBlock(image, bitmapType))
return WriteImage(imageBlock);
- else
- return false;
}
+
return false;
}
GetBuffer().CopyToClipboard(range);
DeleteSelectedContent();
- Layout();
- Refresh();
+ LayoutContent();
+ Refresh(false);
}
}
if (CanPaste())
{
BeginBatchUndo(_("Paste"));
-
+
long newPos = m_caretPosition;
DeleteSelectedContent(& newPos);
-
+
GetBuffer().PasteFromClipboard(newPos);
EndBatchUndo();
{
m_selectionAnchor = from;
m_selectionRange.SetRange(from, to);
- if (!IsFrozen())
- Refresh();
+ Refresh(false);
PositionCaret();
}
from, // New caret position
this);
- Layout();
+ LayoutContent();
if (!IsFrozen())
- Refresh();
+ Refresh(false);
}
bool wxRichTextCtrl::IsModified() const
}
// ----------------------------------------------------------------------------
-// implemenation details
+// implementation details
// ----------------------------------------------------------------------------
-void wxRichTextCtrl::Command(wxCommandEvent & event)
+void wxRichTextCtrl::Command(wxCommandEvent& event)
{
SetValue(event.GetString());
GetEventHandler()->ProcessEvent(event);
return GetBuffer().SetStyle(wxRichTextRange(start, end), style);
}
+bool wxRichTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
+{
+ return GetBuffer().SetStyle(wxRichTextRange(start, end), wxTextAttrEx(style));
+}
+
bool wxRichTextCtrl::SetStyle(const wxRichTextRange& range, const wxRichTextAttr& style)
{
return GetBuffer().SetStyle(range, style);
return GetBuffer().SetDefaultStyle(style);
}
+bool wxRichTextCtrl::SetDefaultStyle(const wxTextAttr& style)
+{
+ return GetBuffer().SetDefaultStyle(wxTextAttrEx(style));
+}
+
const wxTextAttrEx& wxRichTextCtrl::GetDefaultStyleEx() const
{
return GetBuffer().GetDefaultStyle();
}
+const wxTextAttr& wxRichTextCtrl::GetDefaultStyle() const
+{
+ return GetBuffer().GetDefaultStyle();
+}
+
+bool wxRichTextCtrl::GetStyle(long position, wxTextAttr& style) const
+{
+ wxTextAttrEx attr;
+ if (GetBuffer().GetStyle(position, attr))
+ {
+ style = attr;
+ return true;
+ }
+ else
+ return false;
+}
+
bool wxRichTextCtrl::GetStyle(long position, wxTextAttrEx& style) const
{
return GetBuffer().GetStyle(position, style);
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);
}
/// 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);
/// 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());
+ }
}
}
{
wxClientDC dc(this);
dc.SetFont(GetFont());
-
+
PrepareDC(dc);
wxPoint pt;
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
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);
bool wxRichTextCtrl::MoveCaret(long pos, bool showAtLineStart)
{
if (GetBuffer().GetDirty())
- Layout();
+ LayoutContent();
if (pos <= GetBuffer().GetRange().GetEnd())
{
/// 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, GetBuffer().GetRange(), 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;
}
wxRichTextRange range = GetSelectionRange();
attr.SetFlags(wxTEXT_ATTR_FONT_WEIGHT);
attr.SetFontWeight(wxBOLD);
-
+
return HasCharacterAttributes(range, attr);
}
else
wxRichTextAttr attr;
attr.SetFlags(wxTEXT_ATTR_FONT_ITALIC);
attr.SetFontStyle(wxITALIC);
-
+
return HasCharacterAttributes(range, attr);
}
else
wxRichTextAttr attr;
attr.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE);
attr.SetFontUnderlined(true);
-
+
return HasCharacterAttributes(range, attr);
}
else
{
wxRichTextAttr attr;
attr.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE);
- attr.SetFontWeight(!IsSelectionUnderlined());
+ attr.SetFontUnderlined(!IsSelectionUnderlined());
if (HasSelection())
return SetStyle(GetSelectionRange(), attr);
wxRichTextRange range = GetSelectionRange();
wxRichTextAttr attr;
attr.SetAlignment(alignment);
-
+
return HasParagraphAttributes(range, attr);
}
else
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;
}
#endif
// wxUSE_RICHTEXT
-