X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/345c78ca5fa57ea6c7dc7e6a05496a8e82aa2b50..7be2a7af39888b264eb0c5787fb2914005633d1b:/src/richtext/richtextctrl.cpp diff --git a/src/richtext/richtextctrl.cpp b/src/richtext/richtextctrl.cpp index 9f90f65488..1b0a084f86 100644 --- a/src/richtext/richtextctrl.cpp +++ b/src/richtext/richtextctrl.cpp @@ -1130,82 +1130,8 @@ 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())) - { + if (!ProcessBackKey(event, flags)) 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) - { - if (event.CmdDown()) - { - long pos = wxRichTextCtrl::FindNextWordPosition(-1); - if (pos < newPos) - { - wxRichTextRange range(pos+1, newPos); - if (CanDeleteRange(* GetFocusObject(), range.FromInternal())) - { - GetFocusObject()->DeleteRangeWithUndo(range, this, & GetBuffer()); - deletions ++; - } - processed = true; - } - } - - if (!processed) - { - wxRichTextRange range(newPos, newPos); - if (CanDeleteRange(* GetFocusObject(), range.FromInternal())) - { - GetFocusObject()->DeleteRangeWithUndo(range, this, & GetBuffer()); - deletions ++; - } - } - } - - EndBatchUndo(); - - if (GetLastPosition() == -1) - { - GetFocusObject()->Reset(); - - m_caretPosition = -1; - PositionCaret(); - SetDefaultStyleToCursorStyle(); - } - - ScrollIntoView(m_caretPosition, WXK_LEFT); - - // Always send this event; wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED will be sent only if there is an actual deletion. - { - 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 event.Skip(); @@ -1248,6 +1174,14 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) else GetFocusObject()->InsertNewlineWithUndo(& GetBuffer(), newPos+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE|wxRICHTEXT_INSERT_INTERACTIVE); + // Automatically renumber list + bool isNumberedList = false; + wxRichTextRange numberedListRange = FindRangeForList(newPos+1, isNumberedList); + if (isNumberedList && numberedListRange != wxRichTextRange(-1, -1)) + { + NumberList(numberedListRange, NULL, wxRICHTEXT_SETSTYLE_RENUMBER|wxRICHTEXT_SETSTYLE_WITH_UNDO); + } + EndBatchUndo(); SetDefaultStyleToCursorStyle(); @@ -1273,77 +1207,7 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event) } else if (event.GetKeyCode() == WXK_BACK) { - 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) - { - if (event.CmdDown()) - { - long pos = wxRichTextCtrl::FindNextWordPosition(-1); - if (pos < newPos) - { - wxRichTextRange range(pos+1, newPos); - if (CanDeleteRange(* GetFocusObject(), range.FromInternal())) - { - GetFocusObject()->DeleteRangeWithUndo(range, this, & GetBuffer()); - deletions ++; - } - processed = true; - } - } - - if (!processed) - { - wxRichTextRange range(newPos, newPos); - if (CanDeleteRange(* GetFocusObject(), range.FromInternal())) - { - GetFocusObject()->DeleteRangeWithUndo(range, this, & GetBuffer()); - deletions ++; - } - } - } - - EndBatchUndo(); - - if (GetLastPosition() == -1) - { - GetFocusObject()->Reset(); - - m_caretPosition = -1; - PositionCaret(); - SetDefaultStyleToCursorStyle(); - } - - ScrollIntoView(m_caretPosition, WXK_LEFT); - - // Always send this event; wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED will be sent only if there is an actual deletion. - { - 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(); + ProcessBackKey(event, flags); } else if (event.GetKeyCode() == WXK_DELETE) { @@ -1530,6 +1394,122 @@ bool wxRichTextCtrl::ProcessMouseMovement(wxRichTextParagraphLayoutBox* containe return false; } +// Processes the back key +bool wxRichTextCtrl::ProcessBackKey(wxKeyEvent& event, int flags) +{ + if (!IsEditable()) + { + return false; + } + + if (HasSelection() && !CanDeleteRange(* GetFocusObject(), GetSelectionRange())) + { + return false; + } + + wxRichTextParagraph* para = GetFocusObject()->GetParagraphAtPosition(m_caretPosition, true); + + // If we're at the start of a list item with a bullet, let's 'delete' the bullet, i.e. + // make it a continuation paragraph. + if (!HasSelection() && para && ((m_caretPosition+1) == para->GetRange().GetStart()) && + para->GetAttributes().HasBulletStyle() && (para->GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_CONTINUATION) == 0) + { + wxRichTextParagraph* newPara = wxDynamicCast(para->Clone(), wxRichTextParagraph); + newPara->GetAttributes().SetBulletStyle(newPara->GetAttributes().GetBulletStyle() | wxTEXT_ATTR_BULLET_STYLE_CONTINUATION); + + wxRichTextAction* action = new wxRichTextAction(NULL, _("Remove Bullet"), wxRICHTEXT_CHANGE_STYLE, & GetBuffer(), GetFocusObject(), this); + action->SetRange(newPara->GetRange()); + action->SetPosition(GetCaretPosition()); + action->GetNewParagraphs().AppendChild(newPara); + // Also store the old ones for Undo + action->GetOldParagraphs().AppendChild(new wxRichTextParagraph(*para)); + + GetBuffer().Invalidate(para->GetRange()); + GetBuffer().SubmitAction(action); + + // Automatically renumber list + bool isNumberedList = false; + wxRichTextRange numberedListRange = FindRangeForList(m_caretPosition, isNumberedList); + if (isNumberedList && numberedListRange != wxRichTextRange(-1, -1)) + { + NumberList(numberedListRange, NULL, wxRICHTEXT_SETSTYLE_RENUMBER|wxRICHTEXT_SETSTYLE_WITH_UNDO); + } + + Update(); + } + else + { + 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) + { + if (event.CmdDown()) + { + long pos = wxRichTextCtrl::FindNextWordPosition(-1); + if (pos < newPos) + { + wxRichTextRange range(pos+1, newPos); + if (CanDeleteRange(* GetFocusObject(), range.FromInternal())) + { + GetFocusObject()->DeleteRangeWithUndo(range, this, & GetBuffer()); + deletions ++; + } + processed = true; + } + } + + if (!processed) + { + wxRichTextRange range(newPos, newPos); + if (CanDeleteRange(* GetFocusObject(), range.FromInternal())) + { + GetFocusObject()->DeleteRangeWithUndo(range, this, & GetBuffer()); + deletions ++; + } + } + } + + EndBatchUndo(); + + if (GetLastPosition() == -1) + { + GetFocusObject()->Reset(); + + m_caretPosition = -1; + PositionCaret(); + SetDefaultStyleToCursorStyle(); + } + + ScrollIntoView(m_caretPosition, WXK_LEFT); + + // Always send this event; wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED will be sent only if there is an actual deletion. + { + 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(); + } + + return true; +} + /// Delete content if there is a selection, e.g. when pressing a key. bool wxRichTextCtrl::DeleteSelectedContent(long* newPos) { @@ -1992,7 +1972,7 @@ bool wxRichTextCtrl::MoveRight(int noPositions, int flags) // we want to adjust the caret position such that it is positioned at the // start of the next line, rather than jumping past the first character of the // line. - if (noPositions == 1 && !extendSel) + if (noPositions == 1) MoveCaretForward(oldPos); else SetCaretPosition(newPos); @@ -2019,7 +1999,7 @@ bool wxRichTextCtrl::MoveLeft(int noPositions, int flags) if (!extendSel) SelectNone(); - if (noPositions == 1 && !extendSel) + if (noPositions == 1) MoveCaretBack(oldPos); else SetCaretPosition(newPos); @@ -2208,7 +2188,7 @@ bool wxRichTextCtrl::MoveToParagraphStart(int flags) if (!extendSel) SelectNone(); - SetCaretPosition(newPos); + SetCaretPosition(newPos, true); PositionCaret(); SetDefaultStyleToCursorStyle(); @@ -2663,6 +2643,8 @@ bool wxRichTextCtrl::RecreateBuffer(const wxSize& size) bool wxRichTextCtrl::DoLoadFile(const wxString& filename, int fileType) { + SetFocusObject(& GetBuffer(), true); + bool success = GetBuffer().LoadFile(filename, (wxRichTextFileType)fileType); if (success) m_filename = filename; @@ -3172,6 +3154,7 @@ void wxRichTextCtrl::SetInsertionPoint(long pos) SelectNone(); m_caretPosition = pos - 1; + m_caretAtLineStart = true; PositionCaret(); @@ -3894,7 +3877,7 @@ bool wxRichTextCtrl::LayoutContent(bool onlyVisibleRect) GetBuffer().Layout(dc, context, availableSpace, availableSpace, flags); GetBuffer().Invalidate(wxRICHTEXT_NONE); - if (!IsFrozen()) + if (!IsFrozen() && !onlyVisibleRect) SetupScrollbars(); } @@ -4342,6 +4325,61 @@ bool wxRichTextCtrl::PromoteList(int promoteBy, const wxRichTextRange& range, co return GetFocusObject()->PromoteList(promoteBy, range.ToInternal(), defName, flags, specifiedLevel); } +// Given a character position at which there is a list style, find the range +// encompassing the same list style by looking backwards and forwards. +wxRichTextRange wxRichTextCtrl::FindRangeForList(long pos, bool& isNumberedList) +{ + wxRichTextParagraphLayoutBox* focusObject = GetFocusObject(); + wxRichTextRange range = wxRichTextRange(-1, -1); + wxRichTextParagraph* para = focusObject->GetParagraphAtPosition(pos); + if (!para || !para->GetAttributes().HasListStyleName()) + return range; + else + { + wxString listStyle = para->GetAttributes().GetListStyleName(); + range = para->GetRange(); + + isNumberedList = para->GetAttributes().HasBulletNumber(); + + // Search back + wxRichTextObjectList::compatibility_iterator initialNode = focusObject->GetChildren().Find(para); + if (initialNode) + { + wxRichTextObjectList::compatibility_iterator startNode = initialNode->GetPrevious(); + while (startNode) + { + wxRichTextParagraph* p = wxDynamicCast(startNode->GetData(), wxRichTextParagraph); + if (p) + { + if (!p->GetAttributes().HasListStyleName() || p->GetAttributes().GetListStyleName() != listStyle) + break; + else + range.SetStart(p->GetRange().GetStart()); + } + + startNode = startNode->GetPrevious(); + } + + // Search forward + wxRichTextObjectList::compatibility_iterator endNode = initialNode->GetNext(); + while (endNode) + { + wxRichTextParagraph* p = wxDynamicCast(endNode->GetData(), wxRichTextParagraph); + if (p) + { + if (!p->GetAttributes().HasListStyleName() || p->GetAttributes().GetListStyleName() != listStyle) + break; + else + range.SetEnd(p->GetRange().GetEnd()); + } + + endNode = endNode->GetNext(); + } + } + } + return range; +} + /// Deletes the content in the given range bool wxRichTextCtrl::Delete(const wxRichTextRange& range) {