X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/590a0f8bcb889dc4e99ce26a378c02cbf57b9bdb..5f2f8e027e2acc56416aa2c64736e33b3f1174f8:/src/richtext/richtextctrl.cpp?ds=sidebyside diff --git a/src/richtext/richtextctrl.cpp b/src/richtext/richtextctrl.cpp index 626cd1357a..e8eff5d801 100644 --- a/src/richtext/richtextctrl.cpp +++ b/src/richtext/richtextctrl.cpp @@ -356,6 +356,7 @@ void wxRichTextCtrl::Init() m_selectionAnchorObject = NULL; m_selectionState = wxRichTextCtrlSelectionState_Normal; m_editable = true; + m_verticalScrollbarEnabled = true; m_caretAtLineStart = false; m_dragging = false; #if wxUSE_DRAG_AND_DROP @@ -445,9 +446,10 @@ void wxRichTextCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) drawingArea.SetPosition(GetLogicalPoint(drawingArea.GetPosition())); wxRect availableSpace(GetClientSize()); + wxRichTextDrawingContext context(& GetBuffer()); if (GetBuffer().IsDirty()) { - GetBuffer().Layout(dc, availableSpace, availableSpace, wxRICHTEXT_FIXED_WIDTH|wxRICHTEXT_VARIABLE_HEIGHT); + GetBuffer().Layout(dc, context, availableSpace, availableSpace, wxRICHTEXT_FIXED_WIDTH|wxRICHTEXT_VARIABLE_HEIGHT); GetBuffer().Invalidate(wxRICHTEXT_NONE); SetupScrollbars(); } @@ -464,7 +466,7 @@ void wxRichTextCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) if ((GetExtraStyle() & wxRICHTEXT_EX_NO_GUIDELINES) == 0) flags |= wxRICHTEXT_DRAW_GUIDELINES; - GetBuffer().Draw(dc, GetBuffer().GetOwnRange(), GetSelection(), drawingArea, 0 /* descent */, flags); + GetBuffer().Draw(dc, context, GetBuffer().GetOwnRange(), GetSelection(), drawingArea, 0 /* descent */, flags); dc.DestroyClippingRegion(); @@ -573,7 +575,8 @@ void wxRichTextCtrl::OnLeftClick(wxMouseEvent& event) long position = 0; wxRichTextObject* hitObj = NULL; wxRichTextObject* contextObj = NULL; - int hit = GetBuffer().HitTest(dc, event.GetLogicalPosition(dc), position, & hitObj, & contextObj); + wxRichTextDrawingContext context(& GetBuffer()); + int hit = GetBuffer().HitTest(dc, context, event.GetLogicalPosition(dc), position, & hitObj, & contextObj); #if wxUSE_DRAG_AND_DROP // If there's no selection, or we're not inside it, this isn't an attempt to initiate Drag'n'Drop @@ -639,8 +642,9 @@ void wxRichTextCtrl::OnLeftUp(wxMouseEvent& event) wxPoint logicalPt = event.GetLogicalPosition(dc); wxRichTextObject* hitObj = NULL; wxRichTextObject* contextObj = NULL; + wxRichTextDrawingContext context(& GetBuffer()); // Only get objects at this level, not nested, because otherwise we couldn't swipe text at a single level. - int hit = GetFocusObject()->HitTest(dc, logicalPt, position, & hitObj, & contextObj, wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS); + int hit = GetFocusObject()->HitTest(dc, context, logicalPt, position, & hitObj, & contextObj, wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS); #if wxUSE_DRAG_AND_DROP if (m_preDrag) @@ -652,7 +656,7 @@ void wxRichTextCtrl::OnLeftUp(wxMouseEvent& event) long position = 0; wxRichTextObject* hitObj = NULL; wxRichTextObject* contextObj = NULL; - int hit = GetBuffer().HitTest(dc, event.GetLogicalPosition(dc), position, & hitObj, & contextObj); + int hit = GetBuffer().HitTest(dc, context, event.GetLogicalPosition(dc), position, & hitObj, & contextObj); wxRichTextParagraphLayoutBox* oldFocusObject = GetFocusObject(); wxRichTextParagraphLayoutBox* container = wxDynamicCast(contextObj, wxRichTextParagraphLayoutBox); if (container && container != GetFocusObject() && container->AcceptsFocus()) @@ -823,7 +827,8 @@ void wxRichTextCtrl::OnMoveMouse(wxMouseEvent& event) flags = wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS; container = GetFocusObject(); } - int hit = container->HitTest(dc, logicalPt, position, & hitObj, & contextObj, flags); + wxRichTextDrawingContext context(& GetBuffer()); + int hit = container->HitTest(dc, context, logicalPt, position, & hitObj, & contextObj, flags); // See if we need to change the cursor @@ -857,7 +862,7 @@ void wxRichTextCtrl::OnMoveMouse(wxMouseEvent& event) // Check for dragging across multiple containers long position2 = 0; wxRichTextObject* hitObj2 = NULL, *contextObj2 = NULL; - int hit2 = GetBuffer().HitTest(dc, logicalPt, position2, & hitObj2, & contextObj2, 0); + int hit2 = GetBuffer().HitTest(dc, context, logicalPt, position2, & hitObj2, & contextObj2, 0); if (hit2 != wxRICHTEXT_HITTEST_NONE && !(hit2 & wxRICHTEXT_HITTEST_OUTSIDE) && hitObj2 && hitObj != hitObj2) { // See if we can find a common ancestor @@ -945,7 +950,8 @@ void wxRichTextCtrl::OnRightClick(wxMouseEvent& event) wxPoint logicalPt = event.GetLogicalPosition(dc); wxRichTextObject* hitObj = NULL; wxRichTextObject* contextObj = NULL; - int hit = GetFocusObject()->HitTest(dc, logicalPt, position, & hitObj, & contextObj); + wxRichTextDrawingContext context(& GetBuffer()); + int hit = GetFocusObject()->HitTest(dc, context, logicalPt, position, & hitObj, & contextObj); if (hitObj && hitObj->GetContainer() != GetFocusObject()) { @@ -1107,12 +1113,26 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) // Must process this before translation, otherwise it's translated into a WXK_DELETE event. if (event.CmdDown() && event.GetKeyCode() == WXK_BACK) { + if (!IsEditable()) + { + return; + } + + if (HasSelection() && !CanDeleteRange(* GetFocusObject(), GetSelectionRange())) + { + return; + } + BeginBatchUndo(_("Delete Text")); long newPos = m_caretPosition; bool processed = DeleteSelectedContent(& newPos); + int deletions = 0; + if (processed) + deletions ++; + // 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) @@ -1122,13 +1142,25 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) long pos = wxRichTextCtrl::FindNextWordPosition(-1); if (pos < newPos) { - GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(pos+1, newPos), this, & GetBuffer()); + wxRichTextRange range(pos+1, newPos); + if (CanDeleteRange(* GetFocusObject(), range.FromInternal())) + { + GetFocusObject()->DeleteRangeWithUndo(range, this, & GetBuffer()); + deletions ++; + } processed = true; } } if (!processed) - GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(newPos, newPos), this, & GetBuffer()); + { + wxRichTextRange range(newPos, newPos); + if (CanDeleteRange(* GetFocusObject(), range.FromInternal())) + { + GetFocusObject()->DeleteRangeWithUndo(range, this, & GetBuffer()); + deletions ++; + } + } } EndBatchUndo(); @@ -1144,14 +1176,18 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) ScrollIntoView(m_caretPosition, WXK_LEFT); - wxRichTextEvent cmdEvent( - wxEVT_COMMAND_RICHTEXT_DELETE, - GetId()); - cmdEvent.SetEventObject(this); - cmdEvent.SetFlags(flags); - cmdEvent.SetPosition(m_caretPosition+1); - cmdEvent.SetContainer(GetFocusObject()); - GetEventHandler()->ProcessEvent(cmdEvent); + // Always send this event; wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED will be sent only if there is an actual deletion. + //if (deletions > 0) + { + wxRichTextEvent cmdEvent( + wxEVT_COMMAND_RICHTEXT_DELETE, + GetId()); + cmdEvent.SetEventObject(this); + cmdEvent.SetFlags(flags); + cmdEvent.SetPosition(m_caretPosition+1); + cmdEvent.SetContainer(GetFocusObject()); + GetEventHandler()->ProcessEvent(cmdEvent); + } Update(); } @@ -1171,10 +1207,18 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) if (event.GetKeyCode() == WXK_RETURN) { - BeginBatchUndo(_("Insert Text")); + if (!CanInsertContent(* GetFocusObject(), m_caretPosition+1)) + return; long newPos = m_caretPosition; + if (HasSelection() && !CanDeleteRange(* GetFocusObject(), GetSelectionRange())) + { + return; + } + + BeginBatchUndo(_("Insert Text")); + DeleteSelectedContent(& newPos); if (event.ShiftDown()) @@ -1213,12 +1257,21 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) } else if (event.GetKeyCode() == WXK_BACK) { - BeginBatchUndo(_("Delete Text")); - long newPos = m_caretPosition; + if (HasSelection() && !CanDeleteRange(* GetFocusObject(), GetSelectionRange())) + { + return; + } + + BeginBatchUndo(_("Delete Text")); + bool processed = DeleteSelectedContent(& newPos); + int deletions = 0; + if (processed) + deletions ++; + // 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) @@ -1228,13 +1281,25 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) long pos = wxRichTextCtrl::FindNextWordPosition(-1); if (pos < newPos) { - GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(pos+1, newPos), this, & GetBuffer()); + wxRichTextRange range(pos+1, newPos); + if (CanDeleteRange(* GetFocusObject(), range.FromInternal())) + { + GetFocusObject()->DeleteRangeWithUndo(range, this, & GetBuffer()); + deletions ++; + } processed = true; } } if (!processed) - GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(newPos, newPos), this, & GetBuffer()); + { + wxRichTextRange range(newPos, newPos); + if (CanDeleteRange(* GetFocusObject(), range.FromInternal())) + { + GetFocusObject()->DeleteRangeWithUndo(range, this, & GetBuffer()); + deletions ++; + } + } } EndBatchUndo(); @@ -1250,25 +1315,38 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) ScrollIntoView(m_caretPosition, WXK_LEFT); - wxRichTextEvent cmdEvent( - wxEVT_COMMAND_RICHTEXT_DELETE, - GetId()); - cmdEvent.SetEventObject(this); - cmdEvent.SetFlags(flags); - cmdEvent.SetPosition(m_caretPosition+1); - cmdEvent.SetContainer(GetFocusObject()); - GetEventHandler()->ProcessEvent(cmdEvent); + // Always send this event; wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED will be sent only if there is an actual deletion. + //if (deletions > 0) + { + wxRichTextEvent cmdEvent( + wxEVT_COMMAND_RICHTEXT_DELETE, + GetId()); + cmdEvent.SetEventObject(this); + cmdEvent.SetFlags(flags); + cmdEvent.SetPosition(m_caretPosition+1); + cmdEvent.SetContainer(GetFocusObject()); + GetEventHandler()->ProcessEvent(cmdEvent); + } Update(); } else if (event.GetKeyCode() == WXK_DELETE) { - BeginBatchUndo(_("Delete Text")); - long newPos = m_caretPosition; + if (HasSelection() && !CanDeleteRange(* GetFocusObject(), GetSelectionRange())) + { + return; + } + + BeginBatchUndo(_("Delete Text")); + bool processed = DeleteSelectedContent(& newPos); + int deletions = 0; + if (processed) + deletions ++; + // Submit range in character positions, which are greater than caret positions, if (newPos < GetFocusObject()->GetOwnRange().GetEnd()+1) { @@ -1277,13 +1355,25 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) long pos = wxRichTextCtrl::FindNextWordPosition(1); if (pos != -1 && (pos > newPos)) { - GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(newPos+1, pos), this, & GetBuffer()); + wxRichTextRange range(newPos+1, pos); + if (CanDeleteRange(* GetFocusObject(), range.FromInternal())) + { + GetFocusObject()->DeleteRangeWithUndo(range, this, & GetBuffer()); + deletions ++; + } processed = true; } } if (!processed && newPos < (GetLastPosition()-1)) - GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(newPos+1, newPos+1), this, & GetBuffer()); + { + wxRichTextRange range(newPos+1, newPos+1); + if (CanDeleteRange(* GetFocusObject(), range.FromInternal())) + { + GetFocusObject()->DeleteRangeWithUndo(range, this, & GetBuffer()); + deletions ++; + } + } } EndBatchUndo(); @@ -1299,14 +1389,18 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) ScrollIntoView(m_caretPosition, WXK_LEFT); - wxRichTextEvent cmdEvent( - wxEVT_COMMAND_RICHTEXT_DELETE, - GetId()); - cmdEvent.SetEventObject(this); - cmdEvent.SetFlags(flags); - cmdEvent.SetPosition(m_caretPosition+1); - cmdEvent.SetContainer(GetFocusObject()); - GetEventHandler()->ProcessEvent(cmdEvent); + // Always send this event; wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED will be sent only if there is an actual deletion. + //if (deletions > 0) + { + wxRichTextEvent cmdEvent( + wxEVT_COMMAND_RICHTEXT_DELETE, + GetId()); + cmdEvent.SetEventObject(this); + cmdEvent.SetFlags(flags); + cmdEvent.SetPosition(m_caretPosition+1); + cmdEvent.SetContainer(GetFocusObject()); + GetEventHandler()->ProcessEvent(cmdEvent); + } Update(); } @@ -1371,6 +1465,12 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) } } + if (!CanInsertContent(* GetFocusObject(), m_caretPosition+1)) + return; + + if (HasSelection() && !CanDeleteRange(* GetFocusObject(), GetSelectionRange())) + return; + BeginBatchUndo(_("Insert Text")); long newPos = m_caretPosition; @@ -1397,7 +1497,7 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) } } -bool wxRichTextCtrl::ProcessMouseMovement(wxRichTextParagraphLayoutBox* container, wxRichTextObject* obj, long position, const wxPoint& pos) +bool wxRichTextCtrl::ProcessMouseMovement(wxRichTextParagraphLayoutBox* container, wxRichTextObject* WXUNUSED(obj), long position, const wxPoint& WXUNUSED(pos)) { wxRichTextAttr attr; if (container && GetStyle(position, attr, container)) @@ -2020,7 +2120,8 @@ bool wxRichTextCtrl::MoveDown(int noLines, int flags) wxRichTextObject* hitObj = NULL; wxRichTextObject* contextObj = NULL; - int hitTest = container->HitTest(dc, pt, newPos, & hitObj, & contextObj, hitTestFlags); + wxRichTextDrawingContext context(& GetBuffer()); + int hitTest = container->HitTest(dc, context, pt, newPos, & hitObj, & contextObj, hitTestFlags); if (hitObj && ((hitTest & wxRICHTEXT_HITTEST_NONE) == 0) && @@ -2458,7 +2559,7 @@ void wxRichTextCtrl::SetupScrollbars(bool atTop) if (IsFrozen()) return; - if (GetBuffer().IsEmpty()) + if (GetBuffer().IsEmpty() || !m_verticalScrollbarEnabled) { SetScrollbars(0, 0, 0, 0, 0, 0); return; @@ -2734,7 +2835,8 @@ wxRichTextCtrl::HitTest(const wxPoint& pt, wxRichTextObject* hitObj = NULL; wxRichTextObject* contextObj = NULL; - int hit = ((wxRichTextCtrl*)this)->GetFocusObject()->HitTest(dc, pt2, *pos, & hitObj, & contextObj, wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS); + wxRichTextDrawingContext context((wxRichTextBuffer*) & GetBuffer()); + int hit = ((wxRichTextCtrl*)this)->GetFocusObject()->HitTest(dc, context, pt2, *pos, & hitObj, & contextObj, wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS); if ((hit & wxRICHTEXT_HITTEST_BEFORE) && (hit & wxRICHTEXT_HITTEST_OUTSIDE)) return wxTE_HT_BEFORE; @@ -2756,7 +2858,8 @@ wxRichTextCtrl::FindContainerAtPoint(const wxPoint pt, long& position, int& hit, wxPoint logicalPt = GetLogicalPoint(pt); wxRichTextObject* contextObj = NULL; - hit = GetBuffer().HitTest(dc, logicalPt, position, &hitObj, &contextObj, flags); + wxRichTextDrawingContext context(& GetBuffer()); + hit = GetBuffer().HitTest(dc, context, logicalPt, position, &hitObj, &contextObj, flags); wxRichTextParagraphLayoutBox* container = wxDynamicCast(contextObj, wxRichTextParagraphLayoutBox); return container; @@ -3009,12 +3112,12 @@ bool wxRichTextCtrl::CanCopy() const bool wxRichTextCtrl::CanCut() const { - return HasSelection() && IsEditable(); + return CanDeleteSelection(); } bool wxRichTextCtrl::CanPaste() const { - if ( !IsEditable() ) + if ( !IsEditable() || !GetFocusObject() || !CanInsertContent(* GetFocusObject(), m_caretPosition+1)) return false; return GetBuffer().CanPasteFromClipboard(); @@ -3022,7 +3125,7 @@ bool wxRichTextCtrl::CanPaste() const bool wxRichTextCtrl::CanDeleteSelection() const { - return HasSelection() && IsEditable(); + return HasSelection() && IsEditable() && CanDeleteRange(* GetFocusObject(), GetSelectionRange()); } @@ -3390,7 +3493,8 @@ int wxRichTextCtrl::PrepareContextMenu(wxMenu* menu, const wxPoint& pt, bool add if (pt != wxDefaultPosition) { wxPoint logicalPt = GetLogicalPoint(ScreenToClient(pt)); - int hit = GetBuffer().HitTest(dc, logicalPt, position, & hitObj, & contextObj); + wxRichTextDrawingContext context(& GetBuffer()); + int hit = GetBuffer().HitTest(dc, context, logicalPt, position, & hitObj, & contextObj); if (hit == wxRICHTEXT_HITTEST_ON || hit == wxRICHTEXT_HITTEST_BEFORE || hit == wxRICHTEXT_HITTEST_AFTER) { @@ -3678,7 +3782,8 @@ bool wxRichTextCtrl::GetCaretPositionForIndex(long position, wxRect& rect, wxRic if (!container) container = GetFocusObject(); - if (container->FindPosition(dc, position, pt, & height, m_caretAtLineStart)) + wxRichTextDrawingContext context(& GetBuffer()); + if (container->FindPosition(dc, context, position, pt, & height, m_caretAtLineStart)) { // Caret height can't be zero if (height == 0) @@ -3758,9 +3863,10 @@ bool wxRichTextCtrl::LayoutContent(bool onlyVisibleRect) PrepareDC(dc); + wxRichTextDrawingContext context(& GetBuffer()); GetBuffer().Defragment(); GetBuffer().UpdateRanges(); // If items were deleted, ranges need recalculation - GetBuffer().Layout(dc, availableSpace, availableSpace, flags); + GetBuffer().Layout(dc, context, availableSpace, availableSpace, flags); GetBuffer().Invalidate(wxRICHTEXT_NONE); if (!IsFrozen()) @@ -4448,6 +4554,22 @@ bool wxRichTextDropSource::GiveFeedback(wxDragResult WXUNUSED(effect)) } #endif // wxUSE_DRAG_AND_DROP +bool wxRichTextCtrl::CanDeleteRange(wxRichTextParagraphLayoutBox& WXUNUSED(container), const wxRichTextRange& WXUNUSED(range)) const +{ + return true; +} + +bool wxRichTextCtrl::CanInsertContent(wxRichTextParagraphLayoutBox& WXUNUSED(container), long WXUNUSED(pos)) const +{ + return true; +} + +void wxRichTextCtrl::EnableVerticalScrollbar(bool enable) +{ + m_verticalScrollbarEnabled = enable; + SetupScrollbars(); +} + #if wxRICHTEXT_USE_OWN_CARET