From 2638ee292616f1238d7804f0d537a34cb374b98b Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 17 Mar 2024 03:46:11 +0300 Subject: [PATCH] Improved message edition with pre-selected text. --- .../chat_helpers/message_field.cpp | 25 +++++++++++++++++++ .../SourceFiles/chat_helpers/message_field.h | 4 +++ .../history/history_inner_widget.cpp | 12 ++++++++- .../SourceFiles/history/history_widget.cpp | 13 ++++------ Telegram/SourceFiles/history/history_widget.h | 5 ++-- .../history_view_compose_controls.cpp | 5 +++- .../controls/history_view_compose_controls.h | 2 +- .../history/view/history_view_list_widget.cpp | 5 ++++ .../history/view/history_view_list_widget.h | 2 ++ .../view/history_view_replies_section.cpp | 4 ++- .../view/history_view_scheduled_section.cpp | 4 ++- .../business/settings_shortcut_messages.cpp | 4 ++- 12 files changed, 69 insertions(+), 16 deletions(-) diff --git a/Telegram/SourceFiles/chat_helpers/message_field.cpp b/Telegram/SourceFiles/chat_helpers/message_field.cpp index 5715eea4576f5a..c5c04a43c9319f 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.cpp +++ b/Telegram/SourceFiles/chat_helpers/message_field.cpp @@ -1037,3 +1037,28 @@ base::unique_qptr PremiumRequiredSendRestriction( }); return result; } + +void SelectTextInFieldWithMargins( + not_null field, + const TextSelection &selection) { + if (selection.empty()) { + return; + } + auto textCursor = field->textCursor(); + // Try to set equal margins for top and bottom sides. + const auto charsCountInLine = field->width() + / field->st().font->width('W'); + const auto linesCount = (field->height() / field->st().font->height); + const auto selectedLines = (selection.to - selection.from) + / charsCountInLine; + constexpr auto kMinDiff = ushort(3); + if ((linesCount - selectedLines) > kMinDiff) { + textCursor.setPosition(selection.from + - charsCountInLine * ((linesCount - 1) / 2)); + field->setTextCursor(textCursor); + } + textCursor.setPosition(selection.from); + field->setTextCursor(textCursor); + textCursor.setPosition(selection.to, QTextCursor::KeepAnchor); + field->setTextCursor(textCursor); +} diff --git a/Telegram/SourceFiles/chat_helpers/message_field.h b/Telegram/SourceFiles/chat_helpers/message_field.h index a8f248e82fe189..0c9d8ff853fca6 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.h +++ b/Telegram/SourceFiles/chat_helpers/message_field.h @@ -154,3 +154,7 @@ class MessageLinksParser final : private QObject { QWidget *parent, not_null user, not_null controller); + +void SelectTextInFieldWithMargins( + not_null field, + const TextSelection &selection); diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 79c25f691b02e4..c5f201f5162d67 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -2131,7 +2131,17 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { if (editItem) { const auto editItemId = editItem->fullId(); _menu->addAction(tr::lng_context_edit_msg(tr::now), [=] { - _widget->editMessage(editItemId); + if (const auto item = session->data().message(editItemId)) { + auto it = _selected.find(item); + const auto selection = ((it != _selected.end()) + && (it->second != FullSelection)) + ? it->second + : TextSelection(); + if (!selection.empty()) { + clearSelected(true); + } + _widget->editMessage(item, selection); + } }, &st::menuIconEdit); } const auto pinItem = (item->canPin() && item->isPinned()) diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 8aa8f7332504fe..1bc4ac21fa636c 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -6606,7 +6606,7 @@ void HistoryWidget::keyPressEvent(QKeyEvent *e) { && _field->empty() && !_editMsgId && !_replyTo) { - editMessage(item); + editMessage(item, {}); return; } _scroll->keyPressEvent(e); @@ -7570,13 +7570,9 @@ void HistoryWidget::setReplyFieldsFromProcessing() { setInnerFocus(); } -void HistoryWidget::editMessage(FullMsgId itemId) { - if (const auto item = session().data().message(itemId)) { - editMessage(item); - } -} - -void HistoryWidget::editMessage(not_null item) { +void HistoryWidget::editMessage( + not_null item, + const TextSelection &selection) { if (_chooseTheme) { toggleChooseChatTheme(_peer); } else if (_voiceRecordBar->isActive()) { @@ -7625,6 +7621,7 @@ void HistoryWidget::editMessage(not_null item) { updateReplyToName(); updateControlsGeometry(); updateField(); + SelectTextInFieldWithMargins(_field, selection); _saveDraftText = true; _saveDraftStart = crl::now(); diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 4cbfd46afa7fd1..eafa19ac9d8a5e 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -195,8 +195,9 @@ class HistoryWidget final not_null item, TextWithEntities quote = {}, int quoteOffset = 0); - void editMessage(FullMsgId itemId); - void editMessage(not_null item); + void editMessage( + not_null item, + const TextSelection &selection); [[nodiscard]] FullReplyTo replyTo() const; bool lastForceReplyReplied(const FullMsgId &replyTo) const; diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp index 8fe8752c53a041..185073db11787c 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -2857,9 +2857,12 @@ void ComposeControls::updateHeight() { } } -void ComposeControls::editMessage(FullMsgId id) { +void ComposeControls::editMessage( + FullMsgId id, + const TextSelection &selection) { if (const auto item = session().data().message(id)) { editMessage(item); + SelectTextInFieldWithMargins(_field, selection); } } diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h index 779c8c2d877a11..b24e0213abcb81 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h @@ -198,7 +198,7 @@ class ComposeControls final { void showFinished(); void raisePanels(); - void editMessage(FullMsgId id); + void editMessage(FullMsgId id, const TextSelection &selection); void cancelEditMessage(); void maybeCancelEditMessage(); // Confirm if changed and cancel. diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 9c2f94086e643e..fb8d99130710be 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -2425,6 +2425,11 @@ SelectedItems ListWidget::getSelectedItems() const { return collectSelectedItems(); } +const TextSelection &ListWidget::getSelectedTextRange( + not_null item) const { + return _selectedTextRange; +} + int ListWidget::findItemIndexByY(int y) const { Expects(!_items.empty()); diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.h b/Telegram/SourceFiles/history/view/history_view_list_widget.h index 12e09accf0ae38..b68e689e9957fe 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.h @@ -248,6 +248,8 @@ class ListWidget final [[nodiscard]] TextForMimeData getSelectedText() const; [[nodiscard]] MessageIdsList getSelectedIds() const; [[nodiscard]] SelectedItems getSelectedItems() const; + [[nodiscard]] const TextSelection &getSelectedTextRange( + not_null item) const; void cancelSelection(); void selectItem(not_null item); void selectItemAsGroup(not_null item); diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index 7b8eb8765b3edc..9451bd556bea9b 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -316,7 +316,9 @@ RepliesWidget::RepliesWidget( if (const auto item = session().data().message(fullId)) { const auto media = item->media(); if (!media || media->webpage() || media->allowsEditCaption()) { - _composeControls->editMessage(fullId); + _composeControls->editMessage( + fullId, + _inner->getSelectedTextRange(item)); } } }, _inner->lifetime()); diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index 2a6328b38bab4c..59ee93ae994d04 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -172,7 +172,9 @@ ScheduledWidget::ScheduledWidget( if (const auto item = session().data().message(fullId)) { const auto media = item->media(); if (!media || media->webpage() || media->allowsEditCaption()) { - _composeControls->editMessage(fullId); + _composeControls->editMessage( + fullId, + _inner->getSelectedTextRange(item)); } } }, _inner->lifetime()); diff --git a/Telegram/SourceFiles/settings/business/settings_shortcut_messages.cpp b/Telegram/SourceFiles/settings/business/settings_shortcut_messages.cpp index e1fcec944d8650..9422c892c792a6 100644 --- a/Telegram/SourceFiles/settings/business/settings_shortcut_messages.cpp +++ b/Telegram/SourceFiles/settings/business/settings_shortcut_messages.cpp @@ -394,7 +394,9 @@ ShortcutMessages::ShortcutMessages( if (const auto item = _session->data().message(fullId)) { const auto media = item->media(); if (!media || media->webpage() || media->allowsEditCaption()) { - _composeControls->editMessage(fullId); + _composeControls->editMessage( + fullId, + _inner->getSelectedTextRange(item)); } } }, _inner->lifetime());