#include "wx/filename.h"
#include "wx/dcbuffer.h"
#include "wx/arrimpl.cpp"
+#include "wx/fontenum.h"
// DLL options compatibility check:
#include "wx/app.h"
DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_RIGHT_CLICK)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_LEFT_DCLICK)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_RETURN)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACING)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACED)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_STYLESHEET_CHANGING)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_STYLESHEET_CHANGED)
-#if wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE
IMPLEMENT_CLASS( wxRichTextCtrl, wxControl )
-#else
-IMPLEMENT_CLASS( wxRichTextCtrl, wxScrolledWindow )
-#endif
IMPLEMENT_CLASS( wxRichTextEvent, wxNotifyEvent )
-#if wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE
BEGIN_EVENT_TABLE( wxRichTextCtrl, wxControl )
-#else
-BEGIN_EVENT_TABLE( wxRichTextCtrl, wxScrolledWindow )
-#endif
EVT_PAINT(wxRichTextCtrl::OnPaint)
EVT_ERASE_BACKGROUND(wxRichTextCtrl::OnEraseBackground)
EVT_IDLE(wxRichTextCtrl::OnIdle)
* wxRichTextCtrl
*/
+wxArrayString wxRichTextCtrl::sm_availableFontNames;
+
wxRichTextCtrl::wxRichTextCtrl()
-#if wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE
- : wxScrollHelper(this)
-#endif
+ : wxScrollHelper(this)
{
Init();
}
-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
+wxRichTextCtrl::wxRichTextCtrl(wxWindow* parent,
+ wxWindowID id,
+ const wxString& value,
+ const wxPoint& pos,
+ const wxSize& size,
+ long style)
+ : wxScrollHelper(this)
{
Init();
Create(parent, id, value, pos, size, style);
/// Creation
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
- ))
- return false;
-#else
- if (!wxScrolledWindow::Create(parent, id, pos, size, style|wxFULL_REPAINT_ON_RESIZE
- ))
+ if (!wxTextCtrlBase::Create(parent, id, pos, size,
+ style|wxFULL_REPAINT_ON_RESIZE))
return false;
-#endif
if (!GetFont().Ok())
{
SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
}
+ GetBuffer().Reset();
GetBuffer().SetRichTextCtrl(this);
+ if (style & wxTE_READONLY)
+ SetEditable(false);
+
wxTextAttrEx attributes;
attributes.SetFont(GetFont());
attributes.SetTextColour(*wxBLACK);
attributes.SetLineSpacing(10);
attributes.SetParagraphSpacingAfter(10);
attributes.SetParagraphSpacingBefore(0);
- attributes.SetFlags(wxTEXT_ATTR_ALL);
+
SetBasicStyle(attributes);
// The default attributes will be merged with base attributes, so
RecreateBuffer(size);
#endif
- SetCursor(wxCursor(wxCURSOR_IBEAM));
+ m_textCursor = wxCursor(wxCURSOR_IBEAM);
+ m_urlCursor = wxCursor(wxCURSOR_HAND);
+
+ SetCursor(m_textCursor);
if (!value.IsEmpty())
SetValue(value);
+ GetBuffer().AddEventHandler(this);
+
return true;
}
wxRichTextCtrl::~wxRichTextCtrl()
{
+ GetBuffer().RemoveEventHandler(this);
+
delete m_contextMenu;
}
/// Clear all text
void wxRichTextCtrl::Clear()
{
- m_buffer.Reset();
+ m_buffer.ResetAndClearCommands();
m_buffer.SetDirty(true);
m_caretPosition = -1;
m_caretPositionForDefaultStyle = -2;
SetupScrollbars();
Refresh(false);
}
- SendUpdateEvent();
+ SendTextUpdatedEvent();
}
/// Painting
// Paint the background
PaintBackground(dc);
- wxRegion dirtyRegion = GetUpdateRegion();
-
wxRect drawingArea(GetLogicalPoint(wxPoint(0, 0)), GetClientSize());
wxRect availableSpace(GetClientSize());
if (GetBuffer().GetDirty())
}
/// Left-up
-void wxRichTextCtrl::OnLeftUp(wxMouseEvent& WXUNUSED(event))
+void wxRichTextCtrl::OnLeftUp(wxMouseEvent& event)
{
if (m_dragging)
{
m_dragging = false;
if (GetCapture() == this)
ReleaseMouse();
+
+ // See if we clicked on a URL
+ wxClientDC dc(this);
+ PrepareDC(dc);
+ dc.SetFont(GetFont());
+
+ long position = 0;
+ wxPoint logicalPt = event.GetLogicalPosition(dc);
+ int hit = GetBuffer().HitTest(dc, logicalPt, position);
+
+ if (hit != wxRICHTEXT_HITTEST_NONE)
+ {
+ wxTextAttrEx attr;
+ if (GetStyle(position, attr))
+ {
+ if (attr.HasFlag(wxTEXT_ATTR_URL))
+ {
+ wxString urlTarget = attr.GetURL();
+ if (!urlTarget.IsEmpty())
+ {
+ wxMouseEvent mouseEvent(event);
+
+ long startPos = 0, endPos = 0;
+ wxRichTextObject* obj = GetBuffer().GetLeafObjectAtPosition(position);
+ if (obj)
+ {
+ startPos = obj->GetRange().GetStart();
+ endPos = obj->GetRange().GetEnd();
+ }
+
+ wxTextUrlEvent urlEvent(GetId(), mouseEvent, startPos, endPos);
+ InitCommandEvent(urlEvent);
+
+ urlEvent.SetString(urlTarget);
+
+ GetEventHandler()->ProcessEvent(urlEvent);
+ }
+ }
+ }
+ }
}
}
/// Left-click
void wxRichTextCtrl::OnMoveMouse(wxMouseEvent& event)
{
- if (!event.Dragging())
- {
- event.Skip();
- return;
- }
-
wxClientDC dc(this);
PrepareDC(dc);
dc.SetFont(GetFont());
long position = 0;
wxPoint logicalPt = event.GetLogicalPosition(dc);
int hit = GetBuffer().HitTest(dc, logicalPt, position);
+
+ // See if we need to change the cursor
+
+ {
+ if (hit != wxRICHTEXT_HITTEST_NONE)
+ {
+ wxTextAttrEx attr;
+ if (GetStyle(position, attr))
+ {
+ if (attr.HasFlag(wxTEXT_ATTR_URL))
+ {
+ if (GetCursor() != m_urlCursor)
+ SetCursor(m_urlCursor);
+ }
+ else if (!attr.HasFlag(wxTEXT_ATTR_URL))
+ {
+ if (GetCursor() != m_textCursor)
+ SetCursor(m_textCursor);
+ }
+ }
+ }
+ }
+
+ if (!event.Dragging())
+ {
+ event.Skip();
+ return;
+ }
if (m_dragging && hit != wxRICHTEXT_HITTEST_NONE)
{
DeleteSelectedContent(& newPos);
GetBuffer().InsertNewlineWithUndo(newPos+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE);
+ EndBatchUndo();
+ SetDefaultStyleToCursorStyle();
+
+ ScrollIntoView(m_caretPosition, WXK_RIGHT);
wxRichTextEvent cmdEvent(
wxEVT_COMMAND_RICHTEXT_RETURN,
GetId());
cmdEvent.SetEventObject(this);
cmdEvent.SetFlags(flags);
- GetEventHandler()->ProcessEvent(cmdEvent);
-
- EndBatchUndo();
- SetDefaultStyleToCursorStyle();
-
- ScrollIntoView(m_caretPosition, WXK_RIGHT);
+ if (!GetEventHandler()->ProcessEvent(cmdEvent))
+ {
+ // Generate conventional event
+ wxCommandEvent textEvent(wxEVT_COMMAND_TEXT_ENTER, GetId());
+ InitCommandEvent(textEvent);
+
+ GetEventHandler()->ProcessEvent(textEvent);
+ }
}
else if (event.GetKeyCode() == WXK_BACK)
{
EndBatchUndo();
- // Shouldn't this be in Do()?
if (GetLastPosition() == -1)
{
GetBuffer().Reset();
EndBatchUndo();
- // Shouldn't this be in Do()?
if (GetLastPosition() == -1)
{
GetBuffer().Reset();
event.Skip();
return;
}
-
+
default:
{
if (event.CmdDown() || event.AltDown())
return;
}
+ if (keycode == wxT('\t'))
+ {
+ // See if we need to promote or demote the selection or paragraph at the cursor
+ // position, instead of inserting a tab.
+ long pos = GetAdjustedCaretPosition(GetCaretPosition());
+ wxRichTextParagraph* para = GetBuffer().GetParagraphAtPosition(pos);
+ if (para && para->GetRange().GetStart() == pos && para->GetAttributes().HasListStyleName())
+ {
+ wxRichTextRange range;
+ if (HasSelection())
+ range = GetSelectionRange();
+ else
+ range = para->GetRange().FromInternal();
+
+ int promoteBy = event.ShiftDown() ? 1 : -1;
+
+ PromoteList(promoteBy, range, NULL);
+
+ return;
+ }
+ }
+
BeginBatchUndo(_("Insert Text"));
long newPos = m_caretPosition;
// file IO functions
// ----------------------------------------------------------------------------
-#if !wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE
-bool wxRichTextCtrl::LoadFile(const wxString& filename, int fileType)
-{
- 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);
PositionCaret();
SetupScrollbars(true);
Refresh(false);
- SendUpdateEvent();
+ SendTextUpdatedEvent();
if (success)
return true;
{
if (position < 0 || position > GetBuffer().GetRange().GetEnd())
return false;
-
+
wxRichTextParagraph* para = GetBuffer().GetParagraphAtPosition(position);
if (!para)
return false;
long positionStart = position;
long positionEnd = position;
-
+
for (positionStart = position; positionStart >= para->GetRange().GetStart(); positionStart --)
{
wxString text = GetBuffer().GetTextForRange(wxRichTextRange(positionStart, positionStart));
}
if (positionStart < para->GetRange().GetStart())
positionStart = para->GetRange().GetStart();
-
+
for (positionEnd = position; positionEnd < para->GetRange().GetEnd(); positionEnd ++)
{
wxString text = GetBuffer().GetTextForRange(wxRichTextRange(positionEnd, positionEnd));
}
if (positionEnd >= para->GetRange().GetEnd())
positionEnd = para->GetRange().GetEnd();
-
+
SetSelection(positionStart, positionEnd+1);
if (positionStart >= 0)
{
MoveCaret(positionStart-1, true);
- SetDefaultStyleToCursorStyle();
+ SetDefaultStyleToCursorStyle();
}
return true;
return GetRange(from, to);
}
-// do the window-specific processing after processing the update event
-#if !wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE
-void wxRichTextCtrl::DoUpdateWindowUI(wxUpdateUIEvent& event)
-{
- // call inherited
- wxWindowBase::DoUpdateWindowUI(event);
-
- // update text
- if ( event.GetSetText() )
- {
- if ( event.GetText() != GetValue() )
- SetValue(event.GetText());
- }
-}
-#endif // !wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE
-
// ----------------------------------------------------------------------------
// hit testing
// ----------------------------------------------------------------------------
return GetBuffer().GetTextForRange(wxRichTextRange(from, to-1));
}
-void wxRichTextCtrl::SetValue(const wxString& value)
+void wxRichTextCtrl::DoSetValue(const wxString& value, int flags)
{
Clear();
// edit controls mostly)
if ( (value.length() > 0x400) || (value != GetValue()) )
{
- DoWriteText(value, false /* not selection only */);
+ DoWriteText(value);
// for compatibility, don't move the cursor when doing SetValue()
SetInsertionPoint(0);
}
else // same text
{
- // still send an event for consistency
- SendUpdateEvent();
+ if ( flags & SetValue_SendEvent )
+ {
+ // still send an event for consistency
+ SendTextUpdatedEvent();
+ }
}
// we should reset the modified flag even if the value didn't really change
DoWriteText(value);
}
-void wxRichTextCtrl::DoWriteText(const wxString& value, bool WXUNUSED(selectionOnly))
+void wxRichTextCtrl::DoWriteText(const wxString& value, int flags)
{
wxString valueUnix = wxTextFile::Translate(value, wxTextFileType_Unix);
GetBuffer().InsertTextWithUndo(m_caretPosition+1, valueUnix, this);
+
+ if ( flags & SetValue_SendEvent )
+ SendTextUpdatedEvent();
}
void wxRichTextCtrl::AppendText(const wxString& text)
// Editing
// ----------------------------------------------------------------------------
-void wxRichTextCtrl::Replace(long WXUNUSED(from), long WXUNUSED(to), const wxString& value)
+void wxRichTextCtrl::Replace(long WXUNUSED(from), long WXUNUSED(to),
+ const wxString& value)
{
BeginBatchUndo(_("Replace"));
DeleteSelectedContent();
- DoWriteText(value, true /* selection only */);
+ DoWriteText(value, SetValue_SelectionOnly);
EndBatchUndo();
}
}
}
-// ----------------------------------------------------------------------------
-// text control event processing
-// ----------------------------------------------------------------------------
-
-bool wxRichTextCtrl::SendUpdateEvent()
-{
- wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId());
- InitCommandEvent(event);
-
- return GetEventHandler()->ProcessEvent(event);
-}
-
-void wxRichTextCtrl::InitCommandEvent(wxCommandEvent& event) const
-{
- event.SetEventObject((wxControlBase *)this); // const_cast
-
- switch ( m_clientDataType )
- {
- case wxClientData_Void:
- event.SetClientData(GetClientData());
- break;
-
- case wxClientData_Object:
- event.SetClientObject(GetClientObject());
- break;
-
- case wxClientData_None:
- // nothing to do
- ;
- }
-}
-
-
wxSize wxRichTextCtrl::DoGetBestSize() const
{
return wxSize(10, 10);
/// Set font, and also the buffer attributes
bool wxRichTextCtrl::SetFont(const wxFont& font)
{
-#if wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE
wxControl::SetFont(font);
-#else
- wxScrolledWindow::SetFont(font);
-#endif
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);
}
/// Apply a named style to the selection
-void wxRichTextCtrl::ApplyStyle(wxRichTextStyleDefinition* def)
+bool wxRichTextCtrl::ApplyStyle(wxRichTextStyleDefinition* def)
{
// Flags are defined within each definition, so only certain
// attributes are applied.
wxRichTextAttr attr(def->GetStyle());
-
+
int flags = wxRICHTEXT_SETSTYLE_WITH_UNDO|wxRICHTEXT_SETSTYLE_OPTIMIZE;
+ if (def->IsKindOf(CLASSINFO(wxRichTextListStyleDefinition)))
+ {
+ flags |= wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY;
+
+ wxRichTextRange range;
+
+ if (HasSelection())
+ range = GetSelectionRange();
+ else
+ {
+ long pos = GetAdjustedCaretPosition(GetCaretPosition());
+ range = wxRichTextRange(pos, pos+1);
+ }
+
+ return SetListStyle(range, (wxRichTextListStyleDefinition*) def, flags);
+ }
+
// Make sure the attr has the style name
if (def->IsKindOf(CLASSINFO(wxRichTextParagraphStyleDefinition)))
{
attr.SetParagraphStyleName(def->GetName());
-
+
// If applying a paragraph style, we only want the paragraph nodes to adopt these
- // attributes, and not the leaf nodes. This will allow the context (e.g. text)
+ // attributes, and not the leaf nodes. This will allow the content (e.g. text)
// to change its style independently.
flags |= wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY;
}
attr.SetCharacterStyleName(def->GetName());
if (HasSelection())
- SetStyleEx(GetSelectionRange(), attr, flags);
+ return SetStyleEx(GetSelectionRange(), attr, flags);
else
+ {
SetAndShowDefaultStyle(attr);
+ return true;
+ }
}
/// Apply the style sheet to the buffer, for example if the styles have changed.
SetInternalSelectionRange(range1);
}
+/// Set list style
+bool wxRichTextCtrl::SetListStyle(const wxRichTextRange& range, wxRichTextListStyleDefinition* def, int flags, int startFrom, int specifiedLevel)
+{
+ return GetBuffer().SetListStyle(range.ToInternal(), def, flags, startFrom, specifiedLevel);
+}
+
+bool wxRichTextCtrl::SetListStyle(const wxRichTextRange& range, const wxString& defName, int flags, int startFrom, int specifiedLevel)
+{
+ return GetBuffer().SetListStyle(range.ToInternal(), defName, flags, startFrom, specifiedLevel);
+}
+
+/// Clear list for given range
+bool wxRichTextCtrl::ClearListStyle(const wxRichTextRange& range, int flags)
+{
+ return GetBuffer().ClearListStyle(range.ToInternal(), flags);
+}
+
+/// Number/renumber any list elements in the given range
+bool wxRichTextCtrl::NumberList(const wxRichTextRange& range, wxRichTextListStyleDefinition* def, int flags, int startFrom, int specifiedLevel)
+{
+ return GetBuffer().NumberList(range.ToInternal(), def, flags, startFrom, specifiedLevel);
+}
+
+bool wxRichTextCtrl::NumberList(const wxRichTextRange& range, const wxString& defName, int flags, int startFrom, int specifiedLevel)
+{
+ return GetBuffer().NumberList(range.ToInternal(), defName, flags, startFrom, specifiedLevel);
+}
+
+/// Promote the list items within the given range. promoteBy can be a positive or negative number, e.g. 1 or -1
+bool wxRichTextCtrl::PromoteList(int promoteBy, const wxRichTextRange& range, wxRichTextListStyleDefinition* def, int flags, int specifiedLevel)
+{
+ return GetBuffer().PromoteList(promoteBy, range.ToInternal(), def, flags, specifiedLevel);
+}
+
+bool wxRichTextCtrl::PromoteList(int promoteBy, const wxRichTextRange& range, const wxString& defName, int flags, int specifiedLevel)
+{
+ return GetBuffer().PromoteList(promoteBy, range.ToInternal(), defName, flags, specifiedLevel);
+}
+
+const wxArrayString& wxRichTextCtrl::GetAvailableFontNames()
+{
+ if (sm_availableFontNames.GetCount() == 0)
+ {
+ sm_availableFontNames = wxFontEnumerator::GetFacenames();
+ sm_availableFontNames.Sort();
+ }
+ return sm_availableFontNames;
+}
+
+void wxRichTextCtrl::ClearAvailableFontNames()
+{
+ sm_availableFontNames.Clear();
+}
+
#endif
// wxUSE_RICHTEXT
-