X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/805c8d92b92fc29beec5e226ecd48799a70aa005..246117d4440eeea80d965d96c63b7229912c1308:/src/richtext/richtextctrl.cpp diff --git a/src/richtext/richtextctrl.cpp b/src/richtext/richtextctrl.cpp index 68fd792f2c..d46d6c31dd 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" @@ -67,18 +68,30 @@ wxDEFINE_EVENT( wxEVT_COMMAND_RICHTEXT_BUFFER_RESET, wxRichTextEvent ); * 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,7 +130,8 @@ 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 @@ -196,6 +212,8 @@ 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) { + style |= wxVSCROLL; + if (!wxTextCtrlBase::Create(parent, id, pos, size, style|wxFULL_REPAINT_ON_RESIZE, validator, name)) @@ -271,6 +289,17 @@ bool wxRichTextCtrl::Create( wxWindow* parent, wxWindowID id, const wxString& va 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; } @@ -380,6 +409,9 @@ void wxRichTextCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) dc.DestroyClippingRegion(); + // Other user defined painting after everything else (i.e. all text) is painted + PaintAboveContent(dc); + #if wxRICHTEXT_USE_OWN_CARET if (GetCaret()->IsVisible()) { @@ -674,23 +706,7 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) if (event.GetEventType() == wxEVT_KEY_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) + if (event.IsKeyInCategory(WXK_CATEGORY_NAVIGATION)) { KeyboardNavigate(event.GetKeyCode(), flags); return; @@ -766,7 +782,6 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) case WXK_NUMPAD_END: case WXK_NUMPAD_BEGIN: case WXK_NUMPAD_INSERT: - case WXK_NUMPAD_DELETE: case WXK_WINDOWS_LEFT: { return; @@ -951,7 +966,7 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) } } - if (!processed) + if (!processed && newPos < (GetLastPosition()-1)) GetBuffer().DeleteRangeWithUndo(wxRichTextRange(newPos+1, newPos+1), this); } @@ -992,7 +1007,8 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) #ifdef __WXMAC__ if (event.CmdDown()) #else - if (event.CmdDown() || event.AltDown()) + // Fixes AltGr+key with European input languages on Windows + if ((event.CmdDown() && !event.AltDown()) || (event.AltDown() && !event.CmdDown())) #endif { event.Skip(); @@ -1066,7 +1082,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) @@ -2046,7 +2070,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 @@ -2161,8 +2185,7 @@ wxRichTextRange wxRichTextCtrl::AddImage(const wxImage& image) void wxRichTextCtrl::SelectAll() { - SetSelection(0, GetLastPosition()+1); - m_selectionAnchor = -1; + SetSelection(-1, -1); } /// Select none @@ -2502,6 +2525,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; @@ -2514,6 +2544,8 @@ void wxRichTextCtrl::SetInsertionPoint(long pos) m_caretPosition = pos - 1; PositionCaret(); + + SetDefaultStyleToCursorStyle(); } void wxRichTextCtrl::SetInsertionPointEnd() @@ -2561,11 +2593,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(); @@ -2573,10 +2600,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-1); RefreshForSelectionChange(oldSelection, m_selectionRange); PositionCaret(); @@ -2788,7 +2815,8 @@ void wxRichTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event) void wxRichTextCtrl::OnSelectAll(wxCommandEvent& WXUNUSED(event)) { - SelectAll(); + if (GetLastPosition() > 0) + SelectAll(); } void wxRichTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent& event) @@ -2804,20 +2832,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; } @@ -3232,9 +3248,12 @@ bool wxRichTextCtrl::ApplyStyle(wxRichTextStyleDefinition* def) return SetListStyle(range, (wxRichTextListStyleDefinition*) def, flags); } + bool isPara = false; + // Make sure the attr has the style name if (def->IsKindOf(CLASSINFO(wxRichTextParagraphStyleDefinition))) { + isPara = true; attr.SetParagraphStyleName(def->GetName()); // If applying a paragraph style, we only want the paragraph nodes to adopt these @@ -3249,9 +3268,28 @@ bool wxRichTextCtrl::ApplyStyle(wxRichTextStyleDefinition* def) return SetStyleEx(GetSelectionRange(), attr, flags); else { - wxRichTextAttr current = GetDefaultStyleEx(); - current.Apply(attr); + wxTextAttr current = GetDefaultStyleEx(); + wxTextAttr defaultStyle(attr); + if (isPara) + { + // Don't apply extra character styles since they are already implied + // in the paragraph style + defaultStyle.SetFlags(defaultStyle.GetFlags() & ~wxTEXT_ATTR_CHARACTER); + } + current.Apply(defaultStyle); SetAndShowDefaultStyle(current); + + // If it's a paragraph style, we want to apply the style to the + // current paragraph even if we didn't select any text. + if (isPara) + { + long pos = GetAdjustedCaretPosition(GetCaretPosition()); + wxRichTextParagraph* para = GetBuffer().GetParagraphAtPosition(pos); + if (para) + { + return SetStyleEx(para->GetRange().FromInternal(), attr, flags); + } + } return true; } } @@ -3339,13 +3377,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 @@ -3482,10 +3514,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(); } // ---------------------------------------------------------------------------- @@ -3494,11 +3529,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(); } @@ -3575,17 +3618,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