X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/addcf76c65f61c5955652615b4acbf06a0aec621..2028c33ab5a39a12bd410ac953731a56ad6377ba:/src/richtext/richtextctrl.cpp?ds=sidebyside diff --git a/src/richtext/richtextctrl.cpp b/src/richtext/richtextctrl.cpp index b3395fe20b..be2bc269ee 100644 --- a/src/richtext/richtextctrl.cpp +++ b/src/richtext/richtextctrl.cpp @@ -26,6 +26,7 @@ #include "wx/settings.h" #endif +#include "wx/timer.h" #include "wx/textfile.h" #include "wx/ffile.h" #include "wx/filename.h" @@ -38,24 +39,24 @@ #include "wx/app.h" WX_CHECK_BUILD_OPTIONS("wxRichTextCtrl") -DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_LEFT_CLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_MIDDLE_CLICK) -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_CHARACTER) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_DELETE) - -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) - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_CONTENT_INSERTED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_STYLE_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_SELECTION_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_BUFFER_RESET) +wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_LEFT_CLICK, wxRichTextEvent ); +wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_MIDDLE_CLICK, wxRichTextEvent ); +wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_RIGHT_CLICK, wxRichTextEvent ); +wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_LEFT_DCLICK, wxRichTextEvent ); +wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_RETURN, wxRichTextEvent ); +wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_CHARACTER, wxRichTextEvent ); +wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_DELETE, wxRichTextEvent ); + +wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACING, wxRichTextEvent ); +wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACED, wxRichTextEvent ); +wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_STYLESHEET_CHANGING, wxRichTextEvent ); +wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_STYLESHEET_CHANGED, wxRichTextEvent ); + +wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_CONTENT_INSERTED, wxRichTextEvent ); +wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED, wxRichTextEvent ); +wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_STYLE_CHANGED, wxRichTextEvent ); +wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_SELECTION_CHANGED, wxRichTextEvent ); +wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_BUFFER_RESET, wxRichTextEvent ); #if wxRICHTEXT_USE_OWN_CARET @@ -67,18 +68,30 @@ DEFINE_EVENT_TYPE(wxEVT_COMMAND_RICHTEXT_BUFFER_RESET) * wxRICHTEXT_USE_OWN_CARET is set in richtextbuffer.h. */ +class wxRichTextCaret; +class wxRichTextCaretTimer: public wxTimer +{ + public: + wxRichTextCaretTimer(wxRichTextCaret* caret) + { + m_caret = caret; + } + virtual void Notify(); + wxRichTextCaret* m_caret; +}; + class wxRichTextCaret: public wxCaret { public: // ctors // ----- // default - use Create() - wxRichTextCaret() { Init(); } + wxRichTextCaret(): m_timer(this) { Init(); } // creates a block caret associated with the given window wxRichTextCaret(wxRichTextCtrl *window, int width, int height) - : wxCaret(window, width, height) { Init(); m_richTextCtrl = window; } + : wxCaret(window, width, height), m_timer(this) { Init(); m_richTextCtrl = window; } wxRichTextCaret(wxRichTextCtrl *window, const wxSize& size) - : wxCaret(window, size) { Init(); m_richTextCtrl = window; } + : wxCaret(window, size), m_timer(this) { Init(); m_richTextCtrl = window; } virtual ~wxRichTextCaret(); @@ -99,6 +112,8 @@ public: bool GetNeedsUpdate() const { return m_needsUpdate; } void SetNeedsUpdate(bool needsUpdate = true ) { m_needsUpdate = needsUpdate; } + void Notify(); + protected: virtual void DoShow(); virtual void DoHide(); @@ -115,16 +130,17 @@ private: m_yOld; bool m_hasFocus; // true => our window has focus bool m_needsUpdate; // must be repositioned - + bool m_flashOn; + wxRichTextCaretTimer m_timer; wxRichTextCtrl* m_richTextCtrl; }; #endif -IMPLEMENT_CLASS( wxRichTextCtrl, wxControl ) +IMPLEMENT_DYNAMIC_CLASS( wxRichTextCtrl, wxTextCtrlBase ) -IMPLEMENT_CLASS( wxRichTextEvent, wxNotifyEvent ) +IMPLEMENT_DYNAMIC_CLASS( wxRichTextEvent, wxNotifyEvent ) -BEGIN_EVENT_TABLE( wxRichTextCtrl, wxControl ) +BEGIN_EVENT_TABLE( wxRichTextCtrl, wxTextCtrlBase ) EVT_PAINT(wxRichTextCtrl::OnPaint) EVT_ERASE_BACKGROUND(wxRichTextCtrl::OnEraseBackground) EVT_IDLE(wxRichTextCtrl::OnIdle) @@ -136,6 +152,7 @@ BEGIN_EVENT_TABLE( wxRichTextCtrl, wxControl ) EVT_MIDDLE_DOWN(wxRichTextCtrl::OnMiddleClick) EVT_LEFT_DCLICK(wxRichTextCtrl::OnLeftDClick) EVT_CHAR(wxRichTextCtrl::OnChar) + EVT_KEY_DOWN(wxRichTextCtrl::OnChar) EVT_SIZE(wxRichTextCtrl::OnSize) EVT_SET_FOCUS(wxRichTextCtrl::OnSetFocus) EVT_KILL_FOCUS(wxRichTextCtrl::OnKillFocus) @@ -195,7 +212,9 @@ wxRichTextCtrl::wxRichTextCtrl(wxWindow* parent, bool wxRichTextCtrl::Create( wxWindow* parent, wxWindowID id, const wxString& value, const wxPoint& pos, const wxSize& size, long style, const wxValidator& validator, const wxString& name) { - if (!wxControl::Create(parent, id, pos, size, + style |= wxVSCROLL; + + if (!wxTextCtrlBase::Create(parent, id, pos, size, style|wxFULL_REPAINT_ON_RESIZE, validator, name)) return false; @@ -205,6 +224,9 @@ bool wxRichTextCtrl::Create( wxWindow* parent, wxWindowID id, const wxString& va SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); } + // No physical scrolling, so we can preserve margins + EnableScrolling(false, false); + if (style & wxTE_READONLY) SetEditable(false); @@ -216,8 +238,6 @@ bool wxRichTextCtrl::Create( wxWindow* parent, wxWindowID id, const wxString& va attributes.SetLineSpacing(10); attributes.SetParagraphSpacingAfter(10); attributes.SetParagraphSpacingBefore(0); - attributes.SetTextEffects(0); - attributes.SetTextEffectFlags(wxTEXT_ATTR_EFFECT_STRIKETHROUGH|wxTEXT_ATTR_EFFECT_CAPITALS); SetBasicStyle(attributes); @@ -257,16 +277,29 @@ bool wxRichTextCtrl::Create( wxWindow* parent, wxWindowID id, const wxString& va GetBuffer().AddEventHandler(this); // Accelerators - wxAcceleratorEntry entries[4]; + wxAcceleratorEntry entries[6]; entries[0].Set(wxACCEL_CMD, (int) 'C', wxID_COPY); entries[1].Set(wxACCEL_CMD, (int) 'X', wxID_CUT); entries[2].Set(wxACCEL_CMD, (int) 'V', wxID_PASTE); entries[3].Set(wxACCEL_CMD, (int) 'A', wxID_SELECTALL); + entries[4].Set(wxACCEL_CMD, (int) 'Z', wxID_UNDO); + entries[5].Set(wxACCEL_CMD, (int) 'Y', wxID_REDO); - wxAcceleratorTable accel(4, entries); + wxAcceleratorTable accel(6, entries); SetAcceleratorTable(accel); + m_contextMenu = new wxMenu; + m_contextMenu->Append(wxID_UNDO, _("&Undo")); + m_contextMenu->Append(wxID_REDO, _("&Redo")); + m_contextMenu->AppendSeparator(); + m_contextMenu->Append(wxID_CUT, _("Cu&t")); + m_contextMenu->Append(wxID_COPY, _("&Copy")); + m_contextMenu->Append(wxID_PASTE, _("&Paste")); + m_contextMenu->Append(wxID_CLEAR, _("&Delete")); + m_contextMenu->AppendSeparator(); + m_contextMenu->Append(wxID_SELECTALL, _("Select &All")); + return true; } @@ -301,7 +334,8 @@ void wxRichTextCtrl::DoThaw() LayoutContent(); else SetupScrollbars(); - Refresh(false); + + wxWindow::DoThaw(); } /// Clear all text @@ -363,7 +397,18 @@ void wxRichTextCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) SetupScrollbars(); } + wxRect clipRect(availableSpace); + clipRect.x += GetBuffer().GetLeftMargin(); + clipRect.y += GetBuffer().GetTopMargin(); + clipRect.width -= (GetBuffer().GetLeftMargin() + GetBuffer().GetRightMargin()); + clipRect.height -= (GetBuffer().GetTopMargin() + GetBuffer().GetBottomMargin()); + clipRect.SetPosition(GetLogicalPoint(clipRect.GetPosition())); + dc.SetClippingRegion(clipRect); + GetBuffer().Draw(dc, GetBuffer().GetRange(), GetInternalSelectionRange(), drawingArea, 0 /* descent */, 0 /* flags */); + + dc.DestroyClippingRegion(); + #if wxRICHTEXT_USE_OWN_CARET if (GetCaret()->IsVisible()) { @@ -458,6 +503,7 @@ void wxRichTextCtrl::OnLeftClick(wxMouseEvent& event) long oldCaretPos = m_caretPosition; MoveCaret(position, caretAtLineStart); + SetDefaultStyleToCursorStyle(); if (event.ShiftDown()) { @@ -596,6 +642,7 @@ void wxRichTextCtrl::OnMoveMouse(wxMouseEvent& event) ExtendSelection(m_caretPosition, position, wxRICHTEXT_SHIFT_DOWN); MoveCaret(position, caretAtLineStart); + SetDefaultStyleToCursorStyle(); } } } @@ -654,25 +701,146 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) if (event.AltDown()) flags |= wxRICHTEXT_ALT_DOWN; - if (event.GetKeyCode() == WXK_LEFT || - event.GetKeyCode() == WXK_RIGHT || - event.GetKeyCode() == WXK_UP || - event.GetKeyCode() == WXK_DOWN || - event.GetKeyCode() == WXK_HOME || - event.GetKeyCode() == WXK_PAGEUP || - event.GetKeyCode() == WXK_PAGEDOWN || - event.GetKeyCode() == WXK_END || - - event.GetKeyCode() == WXK_NUMPAD_LEFT || - event.GetKeyCode() == WXK_NUMPAD_RIGHT || - event.GetKeyCode() == WXK_NUMPAD_UP || - event.GetKeyCode() == WXK_NUMPAD_DOWN || - event.GetKeyCode() == WXK_NUMPAD_HOME || - event.GetKeyCode() == WXK_NUMPAD_PAGEUP || - event.GetKeyCode() == WXK_NUMPAD_PAGEDOWN || - event.GetKeyCode() == WXK_NUMPAD_END) - { - KeyboardNavigate(event.GetKeyCode(), flags); + if (event.GetEventType() == wxEVT_KEY_DOWN) + { + if (event.IsKeyInCategory(WXK_CATEGORY_NAVIGATION)) + { + KeyboardNavigate(event.GetKeyCode(), flags); + return; + } + + long keycode = event.GetKeyCode(); + switch ( keycode ) + { + case WXK_ESCAPE: + case WXK_START: + case WXK_LBUTTON: + case WXK_RBUTTON: + case WXK_CANCEL: + case WXK_MBUTTON: + case WXK_CLEAR: + case WXK_SHIFT: + case WXK_ALT: + case WXK_CONTROL: + case WXK_MENU: + case WXK_PAUSE: + case WXK_CAPITAL: + case WXK_END: + case WXK_HOME: + case WXK_LEFT: + case WXK_UP: + case WXK_RIGHT: + case WXK_DOWN: + case WXK_SELECT: + case WXK_PRINT: + case WXK_EXECUTE: + case WXK_SNAPSHOT: + case WXK_INSERT: + case WXK_HELP: + case WXK_F1: + case WXK_F2: + case WXK_F3: + case WXK_F4: + case WXK_F5: + case WXK_F6: + case WXK_F7: + case WXK_F8: + case WXK_F9: + case WXK_F10: + case WXK_F11: + case WXK_F12: + case WXK_F13: + case WXK_F14: + case WXK_F15: + case WXK_F16: + case WXK_F17: + case WXK_F18: + case WXK_F19: + case WXK_F20: + case WXK_F21: + case WXK_F22: + case WXK_F23: + case WXK_F24: + case WXK_NUMLOCK: + case WXK_SCROLL: + case WXK_PAGEUP: + case WXK_PAGEDOWN: + case WXK_NUMPAD_F1: + case WXK_NUMPAD_F2: + case WXK_NUMPAD_F3: + case WXK_NUMPAD_F4: + case WXK_NUMPAD_HOME: + case WXK_NUMPAD_LEFT: + case WXK_NUMPAD_UP: + case WXK_NUMPAD_RIGHT: + case WXK_NUMPAD_DOWN: + case WXK_NUMPAD_PAGEUP: + case WXK_NUMPAD_PAGEDOWN: + case WXK_NUMPAD_END: + case WXK_NUMPAD_BEGIN: + case WXK_NUMPAD_INSERT: + case WXK_WINDOWS_LEFT: + { + return; + } + default: + { + } + } + + // Must process this before translation, otherwise it's translated into a WXK_DELETE event. + if (event.CmdDown() && event.GetKeyCode() == WXK_BACK) + { + BeginBatchUndo(_("Delete Text")); + + long newPos = m_caretPosition; + + bool processed = DeleteSelectedContent(& newPos); + + // Submit range in character positions, which are greater than caret positions, + // so subtract 1 for deleted character and add 1 for conversion to character position. + if (newPos > -1) + { + if (event.CmdDown()) + { + long pos = wxRichTextCtrl::FindNextWordPosition(-1); + if (pos < newPos) + { + GetBuffer().DeleteRangeWithUndo(wxRichTextRange(pos+1, newPos), this); + processed = true; + } + } + + if (!processed) + GetBuffer().DeleteRangeWithUndo(wxRichTextRange(newPos, newPos), this); + } + + EndBatchUndo(); + + if (GetLastPosition() == -1) + { + GetBuffer().Reset(); + + m_caretPosition = -1; + PositionCaret(); + SetDefaultStyleToCursorStyle(); + } + + ScrollIntoView(m_caretPosition, WXK_LEFT); + + wxRichTextEvent cmdEvent( + wxEVT_COMMAND_RICHTEXT_DELETE, + GetId()); + cmdEvent.SetEventObject(this); + cmdEvent.SetFlags(flags); + cmdEvent.SetPosition(m_caretPosition+1); + GetEventHandler()->ProcessEvent(cmdEvent); + + Update(); + } + else + event.Skip(); + return; } @@ -686,7 +854,6 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) if (event.GetKeyCode() == WXK_RETURN) { - SetDefaultStyleToCursorStyle(); BeginBatchUndo(_("Insert Text")); long newPos = m_caretPosition; @@ -698,11 +865,14 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) wxString text; text = wxRichTextLineBreakChar; GetBuffer().InsertTextWithUndo(newPos+1, text, this); + m_caretAtLineStart = true; + PositionCaret(); } else GetBuffer().InsertNewlineWithUndo(newPos+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE|wxRICHTEXT_INSERT_INTERACTIVE); EndBatchUndo(); + SetDefaultStyleToCursorStyle(); ScrollIntoView(m_caretPosition, WXK_RIGHT); @@ -727,26 +897,27 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) { BeginBatchUndo(_("Delete Text")); + long newPos = m_caretPosition; + + bool processed = DeleteSelectedContent(& newPos); + // Submit range in character positions, which are greater than caret positions, // so subtract 1 for deleted character and add 1 for conversion to character position. - if (m_caretPosition > -1 && !HasSelection()) + if (newPos > -1) { - bool processed = false; if (event.CmdDown()) { long pos = wxRichTextCtrl::FindNextWordPosition(-1); - if (pos != -1 && (pos < m_caretPosition)) + if (pos < newPos) { - GetBuffer().DeleteRangeWithUndo(wxRichTextRange(pos+1, m_caretPosition), this); + GetBuffer().DeleteRangeWithUndo(wxRichTextRange(pos+1, newPos), this); processed = true; } } if (!processed) - GetBuffer().DeleteRangeWithUndo(wxRichTextRange(m_caretPosition, m_caretPosition), this); + GetBuffer().DeleteRangeWithUndo(wxRichTextRange(newPos, newPos), this); } - else - DeleteSelectedContent(); EndBatchUndo(); @@ -756,6 +927,7 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) m_caretPosition = -1; PositionCaret(); + SetDefaultStyleToCursorStyle(); } ScrollIntoView(m_caretPosition, WXK_LEFT); @@ -774,13 +946,26 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) { BeginBatchUndo(_("Delete Text")); + long newPos = m_caretPosition; + + bool processed = DeleteSelectedContent(& newPos); + // Submit range in character positions, which are greater than caret positions, - if (m_caretPosition < GetBuffer().GetRange().GetEnd()+1 && !HasSelection()) + if (newPos < GetBuffer().GetRange().GetEnd()+1) { - GetBuffer().DeleteRangeWithUndo(wxRichTextRange(m_caretPosition+1, m_caretPosition+1), this); + if (event.CmdDown()) + { + long pos = wxRichTextCtrl::FindNextWordPosition(1); + if (pos != -1 && (pos > newPos)) + { + GetBuffer().DeleteRangeWithUndo(wxRichTextRange(newPos+1, pos), this); + processed = true; + } + } + + if (!processed && newPos < (GetLastPosition()-1)) + GetBuffer().DeleteRangeWithUndo(wxRichTextRange(newPos+1, newPos+1), this); } - else - DeleteSelectedContent(); EndBatchUndo(); @@ -790,6 +975,7 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) m_caretPosition = -1; PositionCaret(); + SetDefaultStyleToCursorStyle(); } wxRichTextEvent cmdEvent( @@ -808,100 +994,6 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) switch ( keycode ) { case WXK_ESCAPE: - case WXK_DELETE: - case WXK_START: - case WXK_LBUTTON: - case WXK_RBUTTON: - case WXK_CANCEL: - case WXK_MBUTTON: - case WXK_CLEAR: - case WXK_SHIFT: - case WXK_ALT: - case WXK_CONTROL: - case WXK_MENU: - case WXK_PAUSE: - case WXK_CAPITAL: - case WXK_END: - case WXK_HOME: - case WXK_LEFT: - case WXK_UP: - case WXK_RIGHT: - case WXK_DOWN: - case WXK_SELECT: - case WXK_PRINT: - case WXK_EXECUTE: - case WXK_SNAPSHOT: - case WXK_INSERT: - case WXK_HELP: - case WXK_NUMPAD0: - case WXK_NUMPAD1: - case WXK_NUMPAD2: - case WXK_NUMPAD3: - case WXK_NUMPAD4: - case WXK_NUMPAD5: - case WXK_NUMPAD6: - case WXK_NUMPAD7: - case WXK_NUMPAD8: - case WXK_NUMPAD9: - case WXK_MULTIPLY: - case WXK_ADD: - case WXK_SEPARATOR: - case WXK_SUBTRACT: - case WXK_DECIMAL: - case WXK_DIVIDE: - case WXK_F1: - case WXK_F2: - case WXK_F3: - case WXK_F4: - case WXK_F5: - case WXK_F6: - case WXK_F7: - case WXK_F8: - case WXK_F9: - case WXK_F10: - case WXK_F11: - case WXK_F12: - case WXK_F13: - case WXK_F14: - case WXK_F15: - case WXK_F16: - case WXK_F17: - case WXK_F18: - case WXK_F19: - case WXK_F20: - case WXK_F21: - case WXK_F22: - case WXK_F23: - case WXK_F24: - case WXK_NUMLOCK: - case WXK_SCROLL: - case WXK_PAGEUP: - case WXK_PAGEDOWN: - case WXK_NUMPAD_SPACE: - case WXK_NUMPAD_TAB: - case WXK_NUMPAD_ENTER: - case WXK_NUMPAD_F1: - case WXK_NUMPAD_F2: - case WXK_NUMPAD_F3: - case WXK_NUMPAD_F4: - case WXK_NUMPAD_HOME: - case WXK_NUMPAD_LEFT: - case WXK_NUMPAD_UP: - case WXK_NUMPAD_RIGHT: - case WXK_NUMPAD_DOWN: - case WXK_NUMPAD_PAGEUP: - case WXK_NUMPAD_PAGEDOWN: - case WXK_NUMPAD_END: - case WXK_NUMPAD_BEGIN: - case WXK_NUMPAD_INSERT: - case WXK_NUMPAD_DELETE: - case WXK_NUMPAD_EQUAL: - case WXK_NUMPAD_MULTIPLY: - case WXK_NUMPAD_ADD: - case WXK_NUMPAD_SEPARATOR: - case WXK_NUMPAD_SUBTRACT: - case WXK_NUMPAD_DECIMAL: - case WXK_WINDOWS_LEFT: { event.Skip(); return; @@ -909,7 +1001,12 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) default: { - if (event.CmdDown() || event.AltDown()) +#ifdef __WXMAC__ + if (event.CmdDown()) +#else + // Fixes AltGr+key with European input languages on Windows + if ((event.CmdDown() && !event.AltDown()) || (event.AltDown() && !event.CmdDown())) +#endif { event.Skip(); return; @@ -951,7 +1048,6 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) } } - SetDefaultStyleToCursorStyle(); BeginBatchUndo(_("Insert Text")); long newPos = m_caretPosition; @@ -966,6 +1062,7 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) EndBatchUndo(); + SetDefaultStyleToCursorStyle(); ScrollIntoView(m_caretPosition, WXK_RIGHT); GetEventHandler()->ProcessEvent(cmdEvent); @@ -982,7 +1079,15 @@ bool wxRichTextCtrl::DeleteSelectedContent(long* newPos) if (HasSelection()) { long pos = m_selectionRange.GetStart(); - GetBuffer().DeleteRangeWithUndo(m_selectionRange, this); + wxRichTextRange range = m_selectionRange; + + // SelectAll causes more to be selected than doing it interactively, + // and causes a new paragraph to be inserted. So for multiline buffers, + // don't delete the final position. + if (range.GetEnd() == GetLastPosition() && GetNumberOfLines() > 0) + range.SetEnd(range.GetEnd()-1); + + GetBuffer().DeleteRangeWithUndo(range, this); m_selectionRange.SetRange(-2, -2); if (newPos) @@ -1082,6 +1187,7 @@ bool wxRichTextCtrl::KeyboardNavigate(int keyCode, int flags) if (success) { ScrollIntoView(m_caretPosition, keyCode); + SetDefaultStyleToCursorStyle(); } return success; @@ -1092,6 +1198,9 @@ bool wxRichTextCtrl::ExtendSelection(long oldPos, long newPos, int flags) { if (flags & wxRICHTEXT_SHIFT_DOWN) { + if (oldPos == newPos) + return false; + wxRichTextRange oldSelection = m_selectionRange; // If not currently selecting, start selecting @@ -1110,6 +1219,8 @@ bool wxRichTextCtrl::ExtendSelection(long oldPos, long newPos, int flags) // the end. if (newPos > m_selectionAnchor) m_selectionRange.SetRange(m_selectionAnchor+1, newPos); + else if (newPos == m_selectionAnchor) + m_selectionRange = wxRichTextRange(-2, -2); else m_selectionRange.SetRange(newPos+1, m_selectionAnchor); } @@ -1155,6 +1266,27 @@ bool wxRichTextCtrl::ScrollIntoView(long position, int keyCode) bool scrolled = false; wxSize clientSize = GetClientSize(); + clientSize.y -= GetBuffer().GetBottomMargin(); + + if (GetWindowStyle() & wxRE_CENTRE_CARET) + { + int y = rect.y - GetClientSize().y/2; + int yUnits = (int) (0.5 + ((float) y)/(float) ppuY); + if (y >= 0 && (y + clientSize.y) < GetBuffer().GetCachedSize().y) + { + if (startYUnits != yUnits) + { + SetScrollbars(ppuX, ppuY, sxUnits, syUnits, 0, yUnits); + scrolled = true; + } +#if !wxRICHTEXT_USE_OWN_CARET + if (scrolled) +#endif + PositionCaret(); + + return scrolled; + } + } // Going down if (keyCode == WXK_DOWN || keyCode == WXK_NUMPAD_DOWN || @@ -1179,11 +1311,11 @@ bool wxRichTextCtrl::ScrollIntoView(long position, int keyCode) scrolled = true; } } - else if (rect.y < startY) + else if (rect.y < (startY + GetBuffer().GetTopMargin())) { // Make it scroll so this item is at the top // of the window - int y = rect.y ; + int y = rect.y - GetBuffer().GetTopMargin(); int yUnits = (int) (0.5 + ((float) y)/(float) ppuY); if (startYUnits != yUnits) @@ -1199,11 +1331,11 @@ bool wxRichTextCtrl::ScrollIntoView(long position, int keyCode) keyCode == WXK_HOME || keyCode == WXK_NUMPAD_HOME || keyCode == WXK_PAGEUP || keyCode == WXK_NUMPAD_PAGEUP ) { - if (rect.y < startY) + if (rect.y < (startY + GetBuffer().GetBottomMargin())) { // Make it scroll so this item is at the top // of the window - int y = rect.y ; + int y = rect.y - GetBuffer().GetTopMargin(); int yUnits = (int) (0.5 + ((float) y)/(float) ppuY); if (startYUnits != yUnits) @@ -1257,8 +1389,9 @@ bool wxRichTextCtrl::IsPositionVisible(long pos) const wxRect rect = line->GetRect(); wxSize clientSize = GetClientSize(); + clientSize.y -= GetBuffer().GetBottomMargin(); - return (rect.GetBottom() > startY) && (rect.GetTop() < (startY + clientSize.y)); + return (rect.GetBottom() > (startY + GetBuffer().GetTopMargin())) && (rect.GetTop() < (startY + clientSize.y)); } void wxRichTextCtrl::SetCaretPosition(long position, bool showAtLineStart) @@ -1303,11 +1436,13 @@ void wxRichTextCtrl::MoveCaretForward(long oldPosition) m_caretPosition = oldPosition; m_caretAtLineStart = true; } + SetDefaultStyleToCursorStyle(); return; } } } m_caretPosition ++; + SetDefaultStyleToCursorStyle(); } /// Move caret one visual step backward: this may mean setting a flag @@ -1351,11 +1486,13 @@ void wxRichTextCtrl::MoveCaretBack(long oldPosition) // to the previous character position. m_caretPosition = oldPosition - 1; } + SetDefaultStyleToCursorStyle(); return; } } } m_caretPosition --; + SetDefaultStyleToCursorStyle(); } /// Move right @@ -1383,6 +1520,7 @@ bool wxRichTextCtrl::MoveRight(int noPositions, int flags) SetCaretPosition(newPos); PositionCaret(); + SetDefaultStyleToCursorStyle(); return true; } @@ -1409,6 +1547,7 @@ bool wxRichTextCtrl::MoveLeft(int noPositions, int flags) SetCaretPosition(newPos); PositionCaret(); + SetDefaultStyleToCursorStyle(); return true; } @@ -1497,6 +1636,7 @@ bool wxRichTextCtrl::MoveDown(int noLines, int flags) SetCaretPosition(newPos, caretLineStart); PositionCaret(); + SetDefaultStyleToCursorStyle(); return true; } @@ -1517,6 +1657,7 @@ bool wxRichTextCtrl::MoveToParagraphEnd(int flags) SetCaretPosition(newPos); PositionCaret(); + SetDefaultStyleToCursorStyle(); return true; } @@ -1537,6 +1678,7 @@ bool wxRichTextCtrl::MoveToParagraphStart(int flags) SetCaretPosition(newPos); PositionCaret(); + SetDefaultStyleToCursorStyle(); return true; } @@ -1559,6 +1701,7 @@ bool wxRichTextCtrl::MoveToLineEnd(int flags) SetCaretPosition(newPos); PositionCaret(); + SetDefaultStyleToCursorStyle(); return true; } @@ -1583,6 +1726,7 @@ bool wxRichTextCtrl::MoveToLineStart(int flags) SetCaretPosition(newPos, para->GetRange().GetStart() != lineRange.GetStart()); PositionCaret(); + SetDefaultStyleToCursorStyle(); return true; } @@ -1601,6 +1745,7 @@ bool wxRichTextCtrl::MoveHome(int flags) SetCaretPosition(-1); PositionCaret(); + SetDefaultStyleToCursorStyle(); return true; } @@ -1621,6 +1766,7 @@ bool wxRichTextCtrl::MoveEnd(int flags) SetCaretPosition(endPos); PositionCaret(); + SetDefaultStyleToCursorStyle(); return true; } @@ -1659,6 +1805,7 @@ bool wxRichTextCtrl::PageDown(int noPages, int flags) SetCaretPosition(pos, para->GetRange().GetStart() != lineRange.GetStart()); PositionCaret(); + SetDefaultStyleToCursorStyle(); return true; } @@ -1775,6 +1922,7 @@ bool wxRichTextCtrl::WordLeft(int WXUNUSED(n), int flags) SetCaretPosition(pos, para->GetRange().GetStart() != pos); PositionCaret(); + SetDefaultStyleToCursorStyle(); return true; } @@ -1796,6 +1944,7 @@ bool wxRichTextCtrl::WordRight(int WXUNUSED(n), int flags) SetCaretPosition(pos, para->GetRange().GetStart() != pos); PositionCaret(); + SetDefaultStyleToCursorStyle(); return true; } @@ -1890,7 +2039,7 @@ void wxRichTextCtrl::SetupScrollbars(bool atTop) int pixelsPerUnit = 5; wxSize clientSize = GetClientSize(); - int maxHeight = GetBuffer().GetCachedSize().y; + int maxHeight = GetBuffer().GetCachedSize().y + GetBuffer().GetTopMargin(); // Round up so we have at least maxHeight pixels int unitsY = (int) (((float)maxHeight/(float)pixelsPerUnit) + 0.5); @@ -1918,7 +2067,7 @@ void wxRichTextCtrl::SetupScrollbars(bool atTop) return; // Don't set scrollbars if there were none before, and there will be none now. - if (oldPPUY != 0 && (oldVirtualSizeY < clientSize.y) && (unitsY*pixelsPerUnit < clientSize.y)) + if (oldPPUY != 0 && (oldVirtualSizeY*oldPPUY < clientSize.y) && (unitsY*pixelsPerUnit < clientSize.y)) return; // Move to previous scroll position if @@ -1969,7 +2118,7 @@ bool wxRichTextCtrl::RecreateBuffer(const wxSize& size) bool wxRichTextCtrl::DoLoadFile(const wxString& filename, int fileType) { - bool success = GetBuffer().LoadFile(filename, fileType); + bool success = GetBuffer().LoadFile(filename, (wxRichTextFileType)fileType); if (success) m_filename = filename; @@ -1993,7 +2142,7 @@ bool wxRichTextCtrl::DoLoadFile(const wxString& filename, int fileType) bool wxRichTextCtrl::DoSaveFile(const wxString& filename, int fileType) { - if (GetBuffer().SaveFile(filename, fileType)) + if (GetBuffer().SaveFile(filename, (wxRichTextFileType)fileType)) { m_filename = filename; @@ -2033,8 +2182,7 @@ wxRichTextRange wxRichTextCtrl::AddImage(const wxImage& image) void wxRichTextCtrl::SelectAll() { - SetSelection(0, GetLastPosition()+1); - m_selectionAnchor = -1; + SetSelection(-1, -1); } /// Select none @@ -2104,6 +2252,7 @@ bool wxRichTextCtrl::SelectWord(long position) if (positionStart >= 0) { MoveCaret(positionStart-1, true); + SetDefaultStyleToCursorStyle(); } return true; @@ -2165,7 +2314,7 @@ wxRichTextCtrl::HitTest(const wxPoint& pt, // set/get the controls text // ---------------------------------------------------------------------------- -wxString wxRichTextCtrl::GetValue() const +wxString wxRichTextCtrl::DoGetValue() const { return GetBuffer().GetText(); } @@ -2221,7 +2370,6 @@ void wxRichTextCtrl::DoWriteText(const wxString& value, int flags) { wxString valueUnix = wxTextFile::Translate(value, wxTextFileType_Unix); - SetDefaultStyleToCursorStyle(); GetBuffer().InsertTextWithUndo(m_caretPosition+1, valueUnix, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE); if ( flags & SetValue_SendEvent ) @@ -2236,7 +2384,7 @@ void wxRichTextCtrl::AppendText(const wxString& text) } /// Write an image at the current insertion point -bool wxRichTextCtrl::WriteImage(const wxImage& image, int bitmapType) +bool wxRichTextCtrl::WriteImage(const wxImage& image, wxBitmapType bitmapType) { wxRichTextImageBlock imageBlock; @@ -2247,7 +2395,7 @@ bool wxRichTextCtrl::WriteImage(const wxImage& image, int bitmapType) return false; } -bool wxRichTextCtrl::WriteImage(const wxString& filename, int bitmapType) +bool wxRichTextCtrl::WriteImage(const wxString& filename, wxBitmapType bitmapType) { wxRichTextImageBlock imageBlock; @@ -2263,7 +2411,7 @@ bool wxRichTextCtrl::WriteImage(const wxRichTextImageBlock& imageBlock) return GetBuffer().InsertImageWithUndo(m_caretPosition+1, imageBlock, this); } -bool wxRichTextCtrl::WriteImage(const wxBitmap& bitmap, int bitmapType) +bool wxRichTextCtrl::WriteImage(const wxBitmap& bitmap, wxBitmapType bitmapType) { if (bitmap.Ok()) { @@ -2280,7 +2428,7 @@ bool wxRichTextCtrl::WriteImage(const wxBitmap& bitmap, int bitmapType) /// Insert a newline (actually paragraph) at the current insertion point. bool wxRichTextCtrl::Newline() { - return GetBuffer().InsertNewlineWithUndo(m_caretPosition+1, this); + return GetBuffer().InsertNewlineWithUndo(m_caretPosition+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE); } /// Insert a line break at the current insertion point. @@ -2321,7 +2469,6 @@ void wxRichTextCtrl::Paste() { if (CanPaste()) { - SetDefaultStyleToCursorStyle(); BeginBatchUndo(_("Paste")); long newPos = m_caretPosition; @@ -2375,6 +2522,13 @@ bool wxRichTextCtrl::CanDeleteSelection() const // Accessors // ---------------------------------------------------------------------------- +void wxRichTextCtrl::SetContextMenu(wxMenu* menu) +{ + if (m_contextMenu && m_contextMenu != menu) + delete m_contextMenu; + m_contextMenu = menu; +} + void wxRichTextCtrl::SetEditable(bool editable) { m_editable = editable; @@ -2387,6 +2541,8 @@ void wxRichTextCtrl::SetInsertionPoint(long pos) m_caretPosition = pos - 1; PositionCaret(); + + SetDefaultStyleToCursorStyle(); } void wxRichTextCtrl::SetInsertionPointEnd() @@ -2434,11 +2590,6 @@ void wxRichTextCtrl::SetSelection(long from, long to) to = GetLastPosition()+1; } - DoSetSelection(from, to); -} - -void wxRichTextCtrl::DoSetSelection(long from, long to, bool WXUNUSED(scrollCaret)) -{ if (from == to) { SelectNone(); @@ -2446,10 +2597,10 @@ void wxRichTextCtrl::DoSetSelection(long from, long to, bool WXUNUSED(scrollCare else { wxRichTextRange oldSelection = m_selectionRange; - m_selectionAnchor = from; + m_selectionAnchor = from-1; m_selectionRange.SetRange(from, to-1); - if (from > -2) - m_caretPosition = from-1; + + m_caretPosition = wxMax(-1, to-2); RefreshForSelectionChange(oldSelection, m_selectionRange); PositionCaret(); @@ -2661,7 +2812,8 @@ void wxRichTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event) void wxRichTextCtrl::OnSelectAll(wxCommandEvent& WXUNUSED(event)) { - SelectAll(); + if (GetLastPosition() > 0) + SelectAll(); } void wxRichTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent& event) @@ -2677,20 +2829,8 @@ void wxRichTextCtrl::OnContextMenu(wxContextMenuEvent& event) return; } - if (!m_contextMenu) - { - m_contextMenu = new wxMenu; - m_contextMenu->Append(wxID_UNDO, _("&Undo")); - m_contextMenu->Append(wxID_REDO, _("&Redo")); - m_contextMenu->AppendSeparator(); - m_contextMenu->Append(wxID_CUT, _("Cu&t")); - m_contextMenu->Append(wxID_COPY, _("&Copy")); - m_contextMenu->Append(wxID_PASTE, _("&Paste")); - m_contextMenu->Append(wxID_CLEAR, _("&Delete")); - m_contextMenu->AppendSeparator(); - m_contextMenu->Append(wxID_SELECTALL, _("Select &All")); - } - PopupMenu(m_contextMenu); + if (m_contextMenu) + PopupMenu(m_contextMenu); return; } @@ -2743,7 +2883,7 @@ bool wxRichTextCtrl::GetUncombinedStyle(long position, wxTextAttr& style) /// Set font, and also the buffer attributes bool wxRichTextCtrl::SetFont(const wxFont& font) { - wxControl::SetFont(font); + wxTextCtrlBase::SetFont(font); wxTextAttr attr = GetBuffer().GetAttributes(); attr.SetFont(font); @@ -2792,6 +2932,12 @@ void wxRichTextCtrl::PositionCaret() GetCaret()->Hide(); if (GetCaret()->GetSize() != newSz) GetCaret()->SetSize(newSz); + + int halfSize = newSz.y/2; + // If the caret is beyond the margin, hide it by moving it out of the way + if (((pt.y + halfSize) < GetBuffer().GetTopMargin()) || ((pt.y + halfSize) > (GetClientSize().y - GetBuffer().GetBottomMargin()))) + pt.y = -200; + GetCaret()->Move(pt); GetCaret()->Show(); } @@ -2906,7 +3052,7 @@ bool wxRichTextCtrl::IsSelectionBold() wxTextAttr attr; wxRichTextRange range = GetSelectionRange(); attr.SetFlags(wxTEXT_ATTR_FONT_WEIGHT); - attr.SetFontWeight(wxBOLD); + attr.SetFontWeight(wxFONTWEIGHT_BOLD); return HasCharacterAttributes(range, attr); } @@ -2922,7 +3068,7 @@ bool wxRichTextCtrl::IsSelectionBold() { if (IsDefaultStyleShowing()) wxRichTextApplyStyle(attr, GetDefaultStyleEx()); - return attr.GetFontWeight() == wxBOLD; + return attr.GetFontWeight() == wxFONTWEIGHT_BOLD; } } return false; @@ -2936,7 +3082,7 @@ bool wxRichTextCtrl::IsSelectionItalics() wxRichTextRange range = GetSelectionRange(); wxTextAttr attr; attr.SetFlags(wxTEXT_ATTR_FONT_ITALIC); - attr.SetFontStyle(wxITALIC); + attr.SetFontStyle(wxFONTSTYLE_ITALIC); return HasCharacterAttributes(range, attr); } @@ -2952,7 +3098,7 @@ bool wxRichTextCtrl::IsSelectionItalics() { if (IsDefaultStyleShowing()) wxRichTextApplyStyle(attr, GetDefaultStyleEx()); - return attr.GetFontStyle() == wxITALIC; + return attr.GetFontStyle() == wxFONTSTYLE_ITALIC; } } return false; @@ -2993,7 +3139,7 @@ bool wxRichTextCtrl::ApplyBoldToSelection() { wxTextAttr attr; attr.SetFlags(wxTEXT_ATTR_FONT_WEIGHT); - attr.SetFontWeight(IsSelectionBold() ? wxNORMAL : wxBOLD); + attr.SetFontWeight(IsSelectionBold() ? wxFONTWEIGHT_NORMAL : wxFONTWEIGHT_BOLD); if (HasSelection()) return SetStyleEx(GetSelectionRange(), attr, wxRICHTEXT_SETSTYLE_WITH_UNDO|wxRICHTEXT_SETSTYLE_OPTIMIZE|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY); @@ -3011,7 +3157,7 @@ bool wxRichTextCtrl::ApplyItalicToSelection() { wxTextAttr attr; attr.SetFlags(wxTEXT_ATTR_FONT_ITALIC); - attr.SetFontStyle(IsSelectionItalics() ? wxNORMAL : wxITALIC); + attr.SetFontStyle(IsSelectionItalics() ? wxFONTSTYLE_NORMAL : wxFONTSTYLE_ITALIC); if (HasSelection()) return SetStyleEx(GetSelectionRange(), attr, wxRICHTEXT_SETSTYLE_WITH_UNDO|wxRICHTEXT_SETSTYLE_OPTIMIZE|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY); @@ -3206,13 +3352,7 @@ wxRichTextRange wxRichTextCtrl::GetSelectionRange() const 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); + SetSelection(range.GetStart(), range.GetEnd()); } /// Set list style @@ -3349,10 +3489,13 @@ void wxRichTextCaret::Init() m_yOld = -1; m_richTextCtrl = NULL; m_needsUpdate = false; + m_flashOn = true; } wxRichTextCaret::~wxRichTextCaret() { + if (m_timer.IsRunning()) + m_timer.Stop(); } // ---------------------------------------------------------------------------- @@ -3361,11 +3504,19 @@ wxRichTextCaret::~wxRichTextCaret() void wxRichTextCaret::DoShow() { + m_flashOn = true; + + if (!m_timer.IsRunning()) + m_timer.Start(GetBlinkTime()); + Refresh(); } void wxRichTextCaret::DoHide() { + if (m_timer.IsRunning()) + m_timer.Stop(); + Refresh(); } @@ -3442,17 +3593,25 @@ void wxRichTextCaret::DoDraw(wxDC *dc) dc->SetBrush(*(m_hasFocus ? wxBLACK_BRUSH : wxTRANSPARENT_BRUSH)); dc->SetPen(*wxBLACK_PEN); - // VZ: unfortunately, the rectangle comes out a pixel smaller when this is - // done under wxGTK - no idea why - //dc->SetLogicalFunction(wxINVERT); - wxPoint pt(m_x, m_y); if (m_richTextCtrl) { pt = m_richTextCtrl->GetLogicalPoint(pt); } - dc->DrawRectangle(pt.x, pt.y, m_width, m_height); + if (IsVisible() && m_flashOn) + dc->DrawRectangle(pt.x, pt.y, m_width, m_height); +} + +void wxRichTextCaret::Notify() +{ + m_flashOn = !m_flashOn; + Refresh(); +} + +void wxRichTextCaretTimer::Notify() +{ + m_caret->Notify(); } #endif // wxRICHTEXT_USE_OWN_CARET