From 0110a6277611b4997564527009e209e53c39ef61 Mon Sep 17 00:00:00 2001 From: John Preston Date: Sat, 9 Apr 2016 15:02:50 +0400 Subject: [PATCH] Inline bot cancel button added. It replaces Send button when the user is editing an inline bot query. First cancel clears the inline bot request, second one clears the field entirely. Escape key acts the same as cancel. --- Telegram/Resources/style.txt | 5 + Telegram/SourceFiles/dropdown.cpp | 2 +- Telegram/SourceFiles/historywidget.cpp | 222 ++++++++++++++--------- Telegram/SourceFiles/historywidget.h | 25 ++- Telegram/SourceFiles/mainwidget.cpp | 11 +- Telegram/SourceFiles/mainwidget.h | 22 +-- Telegram/SourceFiles/ui/flatbutton.cpp | 16 +- Telegram/SourceFiles/ui/flattextarea.cpp | 58 +++--- Telegram/SourceFiles/ui/flattextarea.h | 38 +++- 9 files changed, 246 insertions(+), 153 deletions(-) diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt index 917c77ca16..5fd98d4b20 100644 --- a/Telegram/Resources/style.txt +++ b/Telegram/Resources/style.txt @@ -1489,6 +1489,11 @@ replyCancel: iconedButton(btnDefIconed) { width: 49px; height: 49px; } +inlineBotCancel: iconedButton(replyCancel) { + height: 46px; + iconPos: point(-1px, 16px); // < 0 means draw in the center of the button + downIconPos: point(-1px, 17px); +} forwardIcon: sprite(368px, 197px, 24px, 24px); historyScroll: flatScroll(scrollDef) { diff --git a/Telegram/SourceFiles/dropdown.cpp b/Telegram/SourceFiles/dropdown.cpp index c66d6a7844..8e9537bfdf 100644 --- a/Telegram/SourceFiles/dropdown.cpp +++ b/Telegram/SourceFiles/dropdown.cpp @@ -3655,7 +3655,7 @@ void EmojiPan::inlineBotChanged() { if (_inlineRequestId) MTP::cancel(_inlineRequestId); _inlineRequestId = 0; _inlineQuery = _inlineNextQuery = _inlineNextOffset = QString(); - _inlineBot = 0; + _inlineBot = nullptr; for (InlineCache::const_iterator i = _inlineCache.cbegin(), e = _inlineCache.cend(); i != e; ++i) { delete i.value(); } diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index a254613614..454e62234c 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -2816,7 +2816,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent) connect(&_attachMention, SIGNAL(chosen(QString)), this, SLOT(onMentionHashtagOrBotCommandInsert(QString))); connect(&_attachMention, SIGNAL(stickerSelected(DocumentData*)), this, SLOT(onStickerSend(DocumentData*))); _field.installEventFilter(&_attachMention); - _field.setCtrlEnterSubmit(cCtrlEnter()); + updateFieldSubmitSettings(); _field.hide(); _send.hide(); @@ -2884,28 +2884,31 @@ void HistoryWidget::onMentionHashtagOrBotCommandInsert(QString str) { } void HistoryWidget::updateInlineBotQuery() { - UserData *bot = _inlineBot; - bool start = false; - QString inlineBotUsername(_inlineBotUsername); - QString query = _field.getInlineBotQuery(_inlineBot, _inlineBotUsername); + UserData *bot = nullptr; + QString inlineBotUsername; + QString query = _field.getInlineBotQuery(&bot, &inlineBotUsername); if (inlineBotUsername != _inlineBotUsername) { + _inlineBotUsername = inlineBotUsername; if (_inlineBotResolveRequestId) { // Notify::inlineBotRequesting(false); MTP::cancel(_inlineBotResolveRequestId); _inlineBotResolveRequestId = 0; } - if (_inlineBot == LookingUpInlineBot) { + if (bot == LookingUpInlineBot) { + _inlineBot = LookingUpInlineBot; // Notify::inlineBotRequesting(true); _inlineBotResolveRequestId = MTP::send(MTPcontacts_ResolveUsername(MTP_string(_inlineBotUsername)), rpcDone(&HistoryWidget::inlineBotResolveDone), rpcFail(&HistoryWidget::inlineBotResolveFail, _inlineBotUsername)); return; } - } else if (_inlineBot == LookingUpInlineBot) { + } else if (bot == LookingUpInlineBot) { + _inlineBot = LookingUpInlineBot; return; } - if (_inlineBot) { + if (bot) { if (_inlineBot != bot) { - updateFieldPlaceholder(); + _inlineBot = bot; + inlineBotChanged(); } if (_inlineBot->username == cInlineGifBotUsername() && query.isEmpty()) { _emojiPan.clearInlineBot(); @@ -2916,12 +2919,7 @@ void HistoryWidget::updateInlineBotQuery() { _attachMention.hideStart(); } } else { - if (_inlineBot != bot) { - updateFieldPlaceholder(); - _field.finishPlaceholder(); - } - _emojiPan.clearInlineBot(); - onCheckMentionDropdown(); + clearInlineBot(); } } @@ -3531,7 +3529,7 @@ void HistoryWidget::fastShowAtEnd(History *h) { void HistoryWidget::applyDraft(bool parseLinks) { HistoryDraft *draft = _history ? _history->draft() : nullptr; if (!draft) { - setFieldText(QString()); + clearFieldText(); _field.setFocus(); _editMsgId = _replyToId = 0; return; @@ -3672,11 +3670,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re _scroll.takeWidget(); updateTopBarSelection(); - if (_inlineBot) { - _inlineBot = nullptr; - _emojiPan.clearInlineBot(); - updateFieldPlaceholder(); - } + clearInlineBot(); _showAtMsgId = showAtMsgId; _histInited = false; @@ -3776,7 +3770,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re onBotStart(); } } else { - setFieldText(QString()); + clearFieldText(); doneShow(); } @@ -3815,8 +3809,14 @@ void HistoryWidget::updateAfterDrag() { if (_list) _list->dragActionUpdate(QCursor::pos()); } -void HistoryWidget::ctrlEnterSubmitUpdated() { - _field.setCtrlEnterSubmit(cCtrlEnter()); +void HistoryWidget::updateFieldSubmitSettings() { + FlatTextarea::SubmitSettings settings = FlatTextarea::SubmitSettings::Enter; + if (_inlineBotCancel) { + settings = FlatTextarea::SubmitSettings::None; + } else if (cCtrlEnter()) { + settings = FlatTextarea::SubmitSettings::CtrlEnter; + } + _field.setSubmitSettings(settings); } void HistoryWidget::updateNotifySettings() { @@ -3943,6 +3943,7 @@ void HistoryWidget::updateControlsVisibility() { _scroll.hide(); _kbScroll.hide(); _send.hide(); + if (_inlineBotCancel) _inlineBotCancel->hide(); _unblock.hide(); _botStart.hide(); _joinChannel.hide(); @@ -4010,6 +4011,7 @@ void HistoryWidget::updateControlsVisibility() { _kbShown = false; _attachMention.hide(); _send.hide(); + if (_inlineBotCancel) _inlineBotCancel->hide(); _botStart.hide(); _attachDocument.hide(); _attachPhoto.hide(); @@ -4044,6 +4046,7 @@ void HistoryWidget::updateControlsVisibility() { } _kbShown = false; _send.hide(); + if (_inlineBotCancel) _inlineBotCancel->hide(); _field.hide(); _attachEmoji.hide(); _kbShow.hide(); @@ -4064,7 +4067,12 @@ void HistoryWidget::updateControlsVisibility() { _send.hide(); mouseMoveEvent(0); } else { - _send.show(); + if (_inlineBotCancel) { + _inlineBotCancel->show(); + _send.hide(); + } else { + _send.show(); + } _a_record.stop(); _inRecord = _inField = false; a_recordOver = anim::fvalue(0, 0); @@ -4146,6 +4154,7 @@ void HistoryWidget::updateControlsVisibility() { } else { _attachMention.hide(); _send.hide(); + if (_inlineBotCancel) _inlineBotCancel->hide(); _unblock.hide(); _botStart.hide(); _joinChannel.hide(); @@ -4630,6 +4639,15 @@ void HistoryWidget::preloadHistoryIfNeeded() { } } +void HistoryWidget::onInlineBotCancel() { + QString text = _field.getLastText(); + if (text.size() > _inlineBotUsername.size() + 2) { + setFieldText('@' + _inlineBotUsername + ' ', TextUpdateEventsSaveDraft, false); + } else { + clearFieldText(TextUpdateEventsSaveDraft, false); + } +} + void HistoryWidget::onWindowVisibleChanged() { QTimer::singleShot(0, this, SLOT(preloadHistoryIfNeeded())); } @@ -4746,7 +4764,7 @@ void HistoryWidget::onSend(bool ctrlShiftEnter, MsgId replyTo) { App::main()->sendMessage(_history, _field.getLastText(), replyTo, _broadcast.checked(), _silent.checked(), webPageId); - setFieldText(QString()); + clearFieldText(); _saveDraftText = true; _saveDraftStart = getms(); onDraftSave(); @@ -4971,6 +4989,7 @@ void HistoryWidget::animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTo _field.hide(); _fieldBarCancel.hide(); _send.hide(); + if (_inlineBotCancel) _inlineBotCancel->hide(); _unblock.hide(); _botStart.hide(); _joinChannel.hide(); @@ -5341,7 +5360,7 @@ bool HistoryWidget::insertBotCommand(const QString &cmd, bool specialGif) { QString text = _field.getLastText(); if (specialGif) { if (text.trimmed() == '@' + cInlineGifBotUsername() && text.at(0) == '@') { - setFieldText(QString(), TextUpdateEventsSaveDraft, false); + clearFieldText(TextUpdateEventsSaveDraft, false); } } else { QRegularExpressionMatch m = QRegularExpression(qsl("^/[A-Za-z_0-9]{0,64}(@[A-Za-z_0-9]{0,32})?(\\s|$)")).match(text); @@ -5481,8 +5500,7 @@ bool HistoryWidget::inlineBotResolveFail(QString name, const RPCError &error) { _inlineBotResolveRequestId = 0; // Notify::inlineBotRequesting(false); if (name == _inlineBotUsername) { - _inlineBot = nullptr; - onCheckMentionDropdown(); + clearInlineBot(); } return true; } @@ -5654,7 +5672,6 @@ void HistoryWidget::onKbToggle(bool manual) { void HistoryWidget::onCmdStart() { setFieldText(qsl("/")); - _field.moveCursor(QTextCursor::End); } void HistoryWidget::contextMenuEvent(QContextMenuEvent *e) { @@ -5816,35 +5833,92 @@ void HistoryWidget::updateOnlineDisplayTimer() { App::main()->updateOnlineDisplayIn(minIn * 1000); } -void HistoryWidget::onFieldResize() { - int32 maxKeyboardHeight = int(st::maxFieldHeight) - _field.height(); +void HistoryWidget::moveFieldControls() { + int w = width(), h = height(), right = w, bottom = h, keyboardHeight = 0; + int maxKeyboardHeight = int(st::maxFieldHeight) - _field.height(); _keyboard.resizeToWidth(width(), maxKeyboardHeight); - - int32 kbh = 0; if (_kbShown) { - kbh = qMin(_keyboard.height(), maxKeyboardHeight); - _kbScroll.setGeometry(0, height() - kbh, width(), kbh); + keyboardHeight = qMin(_keyboard.height(), maxKeyboardHeight); + bottom -= keyboardHeight; + _kbScroll.setGeometry(0, bottom, w, keyboardHeight); } - _field.move(_attachDocument.x() + _attachDocument.width(), height() - kbh - _field.height() - st::sendPadding); - _fieldBarCancel.move(width() - _fieldBarCancel.width(), _field.y() - st::sendPadding - _fieldBarCancel.height()); - _attachDocument.move(0, height() - kbh - _attachDocument.height()); - _attachPhoto.move(_attachDocument.x(), _attachDocument.y()); - _botStart.setGeometry(0, _attachDocument.y(), width(), _botStart.height()); - _unblock.setGeometry(0, _attachDocument.y(), width(), _unblock.height()); - _joinChannel.setGeometry(0, _attachDocument.y(), width(), _joinChannel.height()); - _muteUnmute.setGeometry(0, _attachDocument.y(), width(), _muteUnmute.height()); - _send.move(width() - _send.width(), _attachDocument.y()); - _broadcast.move(_send.x() - _broadcast.width(), height() - kbh - _broadcast.height()); - _attachEmoji.move((hasBroadcastToggle() ? _broadcast.x() : _send.x()) - _attachEmoji.width(), height() - kbh - _attachEmoji.height()); - _kbShow.move(_attachEmoji.x() - _kbShow.width(), height() - kbh - _kbShow.height()); - _kbHide.move(_attachEmoji.x(), _attachEmoji.y()); - _cmdStart.move(_attachEmoji.x() - _cmdStart.width(), height() - kbh - _cmdStart.height()); - _silent.move(_attachEmoji.x() - _silent.width(), height() - kbh - _silent.height()); +// _attachType ----------------------------------------------------------- _emojiPan --------- _fieldBarCancel +// (_attachDocument|_attachPhoto) _field (_silent|_cmdStart|_kbShow) (_kbHide|_attachEmoji) [_broadcast] _send +// (_botStart|_unblock|_joinChannel|_muteUnmute) + int buttonsBottom = bottom - _attachDocument.height(); + _attachDocument.move(0, buttonsBottom); + _attachPhoto.move(0, buttonsBottom); + _field.move(_attachDocument.width(), bottom - _field.height() - st::sendPadding); + _send.move(right - _send.width(), buttonsBottom); + if (_inlineBotCancel) _inlineBotCancel->move(_send.pos()); + right -= _send.width(); + _broadcast.move(right - _broadcast.width(), buttonsBottom); + if (hasBroadcastToggle()) right -= _broadcast.width(); + _attachEmoji.move(right - _attachEmoji.width(), buttonsBottom); + _kbHide.move(right - _kbHide.width(), buttonsBottom); + right -= _attachEmoji.width(); + _kbShow.move(right - _kbShow.width(), buttonsBottom); + _cmdStart.move(right - _cmdStart.width(), buttonsBottom); + _silent.move(right - _silent.width(), buttonsBottom); + + right = w; + _fieldBarCancel.move(right - _fieldBarCancel.width(), _field.y() - st::sendPadding - _fieldBarCancel.height()); _attachType.move(0, _attachDocument.y() - _attachType.height()); _emojiPan.moveBottom(_attachEmoji.y()); + _botStart.setGeometry(0, bottom - _botStart.height(), w, _botStart.height()); + _unblock.setGeometry(0, bottom - _unblock.height(), w, _unblock.height()); + _joinChannel.setGeometry(0, bottom - _joinChannel.height(), w, _joinChannel.height()); + _muteUnmute.setGeometry(0, bottom - _muteUnmute.height(), w, _muteUnmute.height()); +} + +void HistoryWidget::updateFieldSize() { + bool kbShowShown = _history && !_kbShown && _keyboard.hasMarkup(); + int fieldWidth = width() - _attachDocument.width(); + fieldWidth -= _send.width(); + fieldWidth -= _attachEmoji.width(); + if (kbShowShown) fieldWidth -= _kbShow.width(); + if (_cmdStartShown) fieldWidth -= _cmdStart.width(); + if (hasBroadcastToggle()) fieldWidth -= _broadcast.width(); + if (hasSilentToggle()) fieldWidth -= _silent.width(); + + if (_field.width() != fieldWidth) { + _field.resize(fieldWidth, _field.height()); + } else { + moveFieldControls(); + } +} + +void HistoryWidget::clearInlineBot() { + if (_inlineBot) { + _inlineBot = nullptr; + inlineBotChanged(); + _field.finishPlaceholder(); + } + _emojiPan.clearInlineBot(); + onCheckMentionDropdown(); +} + +void HistoryWidget::inlineBotChanged() { + bool isInlineBot = _inlineBot && (_inlineBot != LookingUpInlineBot); + if (isInlineBot && !_inlineBotCancel) { + _inlineBotCancel = MakeUnique(this, st::inlineBotCancel); + connect(_inlineBotCancel.data(), SIGNAL(clicked()), this, SLOT(onInlineBotCancel())); + _inlineBotCancel->setGeometry(_send.geometry()); + updateFieldSubmitSettings(); + updateControlsVisibility(); + } else if (!isInlineBot && _inlineBotCancel) { + _inlineBotCancel.clear(); + updateFieldSubmitSettings(); + updateControlsVisibility(); + } + updateFieldPlaceholder(); +} + +void HistoryWidget::onFieldResize() { + moveFieldControls(); updateListSize(); updateField(); } @@ -5996,7 +6070,7 @@ void HistoryWidget::confirmSendFile(const FileLoadResultPtr &file, bool ctrlShif void HistoryWidget::cancelSendFile(const FileLoadResultPtr &file) { if (_confirmWithTextId && file->id == _confirmWithTextId) { - setFieldText(QString()); + clearFieldText(); _confirmWithTextId = 0; } if (!file->originalText.isEmpty()) { @@ -6017,7 +6091,7 @@ void HistoryWidget::confirmShareContact(const QString &phone, const QString &fna void HistoryWidget::cancelShareContact() { if (_confirmWithTextId == 0xFFFFFFFFFFFFFFFFL) { - setFieldText(QString()); + clearFieldText(); _confirmWithTextId = 0; } } @@ -6331,15 +6405,7 @@ void HistoryWidget::notify_handlePendingHistoryUpdate() { void HistoryWidget::resizeEvent(QResizeEvent *e) { _reportSpamPanel.resize(width(), _reportSpamPanel.height()); - int32 maxKeyboardHeight = int(st::maxFieldHeight) - _field.height(); - _keyboard.resizeToWidth(width(), maxKeyboardHeight); - - int32 kbh = 0; - if (_kbShown) { - kbh = qMin(_keyboard.height(), maxKeyboardHeight); - _kbScroll.setGeometry(0, height() - kbh, width(), kbh); - } - _field.move(_attachDocument.x() + _attachDocument.width(), height() - kbh - _field.height() - st::sendPadding); + moveFieldControls(); if (_pinnedBar) { if (_scroll.y() != st::replyHeight) { @@ -6355,32 +6421,13 @@ void HistoryWidget::resizeEvent(QResizeEvent *e) { _attachMention.setBoundings(_scroll.geometry()); } - _attachDocument.move(0, height() - kbh - _attachDocument.height()); - _attachPhoto.move(_attachDocument.x(), _attachDocument.y()); - - _fieldBarCancel.move(width() - _fieldBarCancel.width(), _field.y() - st::sendPadding - _fieldBarCancel.height()); updateListSize(false, false, { ScrollChangeAdd, App::main() ? App::main()->contentScrollAddToY() : 0 }); - bool kbShowShown = _history && !_kbShown && _keyboard.hasMarkup(); - _field.resize(width() - _send.width() - _attachDocument.width() - _attachEmoji.width() - (kbShowShown ? _kbShow.width() : 0) - (_cmdStartShown ? _cmdStart.width() : 0) - (hasBroadcastToggle() ? _broadcast.width() : 0) - (hasSilentToggle() ? _silent.width() : 0), _field.height()); + updateFieldSize(); _toHistoryEnd.move((width() - _toHistoryEnd.width()) / 2, _scroll.y() + _scroll.height() - _toHistoryEnd.height() - st::historyToEndSkip); updateCollapseCommentsVisibility(); - _send.move(width() - _send.width(), _attachDocument.y()); - _botStart.setGeometry(0, _attachDocument.y(), width(), _botStart.height()); - _unblock.setGeometry(0, _attachDocument.y(), width(), _unblock.height()); - _joinChannel.setGeometry(0, _attachDocument.y(), width(), _joinChannel.height()); - _muteUnmute.setGeometry(0, _attachDocument.y(), width(), _muteUnmute.height()); - _broadcast.move(_send.x() - _broadcast.width(), height() - kbh - _broadcast.height()); - _attachEmoji.move((hasBroadcastToggle() ? _broadcast.x() : _send.x()) - _attachEmoji.width(), height() - kbh - _attachEmoji.height()); - _kbShow.move(_attachEmoji.x() - _kbShow.width(), height() - kbh - _kbShow.height()); - _kbHide.move(_attachEmoji.x(), _attachEmoji.y()); - _cmdStart.move(_attachEmoji.x() - _cmdStart.width(), height() - kbh - _cmdStart.height()); - _silent.move(_attachEmoji.x() - _silent.width(), height() - kbh - _silent.height()); - - _attachType.move(0, _attachDocument.y() - _attachType.height()); - _emojiPan.moveBottom(_attachEmoji.y()); _emojiPan.setMaxHeight(height() - st::dropdownDef.padding.top() - st::dropdownDef.padding.bottom() - _attachEmoji.height()); switch (_attachDrag) { @@ -6904,7 +6951,7 @@ void HistoryWidget::onInlineResultSend(InlineBots::Result *result, UserData *bot App::historyRegRandom(randomId, newId); - setFieldText(QString()); + clearFieldText(); _saveDraftText = true; _saveDraftStart = getms(); onDraftSave(); @@ -7079,7 +7126,7 @@ void HistoryWidget::sendExistingDocument(DocumentData *doc, const QString &capti App::historyRegRandom(randomId, newId); if (_attachMention.stickersShown()) { - setFieldText(QString()); + clearFieldText(); _saveDraftText = true; _saveDraftStart = getms(); onDraftSave(); @@ -7142,10 +7189,11 @@ void HistoryWidget::sendExistingPhoto(PhotoData *photo, const QString &caption) void HistoryWidget::setFieldText(const QString &text, int32 textUpdateEventsFlags, bool clearUndoHistory) { _textUpdateEventsFlags = textUpdateEventsFlags; _field.setTextFast(text, clearUndoHistory); + _field.moveCursor(QTextCursor::End); _textUpdateEventsFlags = TextUpdateEventsSaveDraft | TextUpdateEventsSendTyping; _previewCancelled = false; - _previewData = 0; + _previewData = nullptr; if (_previewRequest) { MTP::cancel(_previewRequest); _previewRequest = 0; @@ -7554,8 +7602,8 @@ void HistoryWidget::updatePreview() { } void HistoryWidget::onCancel() { - if (_inlineBot && _field.getLastText().startsWith('@' + _inlineBot->username + ' ')) { - setFieldText(QString(), TextUpdateEventsSaveDraft, false); + if (_inlineBotCancel) { + onInlineBotCancel(); } else if (!_attachMention.isHidden()) { _attachMention.hideStart(); } else { diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index e314c6e268..1544d2b122 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -270,11 +270,9 @@ public: bool hasSendText() const; public slots: - void onEmojiInsert(EmojiPtr emoji); signals: - void focused(); private: @@ -490,13 +488,9 @@ enum TextUpdateEventsFlags { namespace InlineBots { namespace Layout { - class ItemBase; - } // namespace Layout - class Result; - } // namespace InlineBots class HistoryWidget : public TWidget, public RPCSender { @@ -653,7 +647,7 @@ public: void updateCollapseCommentsVisibility(); void updateAfterDrag(); - void ctrlEnterSubmitUpdated(); + void updateFieldSubmitSettings(); void setInnerFocus(); bool canSendMessages(PeerData *peer) const; @@ -813,8 +807,20 @@ public slots: // in the scroll area and preloads history if needed void preloadHistoryIfNeeded(); +private slots: + + void onInlineBotCancel(); + private: + // Updates position of controls around the message field, + // like send button, emoji button and others. + void moveFieldControls(); + void updateFieldSize(); + + void clearInlineBot(); + void inlineBotChanged(); + MsgId _replyToId = 0; Text _replyToName; int _replyToNameVersion = 0; @@ -950,6 +956,9 @@ private: void writeDrafts(HistoryDraft **msgDraft, HistoryEditDraft **editDraft); void writeDrafts(History *history); void setFieldText(const QString &text, int32 textUpdateEventsFlags = 0, bool clearUndoHistory = true); + void clearFieldText(int32 textUpdateEventsFlags = 0, bool clearUndoHistory = true) { + setFieldText(QString()); + } QStringList getMediasFromMime(const QMimeData *d); @@ -998,9 +1007,11 @@ private: CollapseButton _collapseComments; MentionsDropdown _attachMention; + UserData *_inlineBot = nullptr; QString _inlineBotUsername; mtpRequestId _inlineBotResolveRequestId = 0; + UniquePointer _inlineBotCancel; void inlineBotResolveDone(const MTPcontacts_ResolvedPeer &result); bool inlineBotResolveFail(QString name, const RPCError &error); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index b4243bda62..89dd46e24d 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -723,6 +723,15 @@ void MainWidget::onFilesOrForwardDrop(const PeerId &peer, const QMimeData *data) } } +void MainWidget::rpcClear() { + history.rpcClear(); + dialogs.rpcClear(); + if (profile) profile->rpcClear(); + if (overview) overview->rpcClear(); + if (_api) _api->rpcClear(); + RPCSender::rpcClear(); +} + QPixmap MainWidget::grabInner() { if (overview && !overview->isHidden()) { return myGrab(overview); @@ -2306,7 +2315,7 @@ void MainWidget::updateAfterDrag() { } void MainWidget::ctrlEnterSubmitUpdated() { - history.ctrlEnterSubmitUpdated(); + history.updateFieldSubmitSettings(); } void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, bool back) { diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 0098355d54..a2cf9d6ecf 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -20,17 +20,24 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once +#include "apiwrap.h" #include "dialogswidget.h" #include "historywidget.h" #include "profilewidget.h" #include "overviewwidget.h" #include "playerwidget.h" -#include "apiwrap.h" class Window; struct DialogRow; + +class ApiWrap; class MainWidget; class ConfirmBox; +class DialogsWidget; +class HistoryWidget; +class ProfileWidget; +class OverviewWidget; +class PlayerWidget; class TopBarWidget : public TWidget { Q_OBJECT @@ -433,14 +440,7 @@ public: QPixmap grabTopBar(); QPixmap grabInner(); - void rpcClear() override { - history.rpcClear(); - dialogs.rpcClear(); - if (profile) profile->rpcClear(); - if (overview) overview->rpcClear(); - if (_api) _api->rpcClear(); - RPCSender::rpcClear(); - } + void rpcClear() override; bool isItemVisible(HistoryItem *item); @@ -620,8 +620,8 @@ private: DialogsWidget dialogs; HistoryWidget history; - ProfileWidget *profile = nullptr; - OverviewWidget *overview = nullptr; + ProfileWidget* profile = nullptr; + OverviewWidget* overview = nullptr; PlayerWidget _player; TopBarWidget _topBar; ConfirmBox *_forwardConfirm = nullptr; // for single column layout diff --git a/Telegram/SourceFiles/ui/flatbutton.cpp b/Telegram/SourceFiles/ui/flatbutton.cpp index a2facf8880..7079c2cb6a 100644 --- a/Telegram/SourceFiles/ui/flatbutton.cpp +++ b/Telegram/SourceFiles/ui/flatbutton.cpp @@ -241,7 +241,7 @@ void IconedButton::onStateChange(int oldState, ButtonStateChangeSource source) { } void IconedButton::paintEvent(QPaintEvent *e) { - QPainter p(this); + Painter p(this); p.setOpacity(_opacity); @@ -256,10 +256,16 @@ void IconedButton::paintEvent(QPaintEvent *e) { const QPoint &t((_state & StateDown) ? _st.downTextPos : _st.textPos); p.drawText(t.x(), t.y() + _st.font->ascent, _text); } - const QRect &i((_state & StateDown) ? _st.downIcon : _st.icon); - if (i.width()) { - const QPoint &t((_state & StateDown) ? _st.downIconPos : _st.iconPos); - p.drawPixmap(t, App::sprite(), i); + const style::sprite &i((_state & StateDown) ? _st.downIcon : _st.icon); + if (i.pxWidth()) { + QPoint t((_state & StateDown) ? _st.downIconPos : _st.iconPos); + if (t.x() < 0) { + t.setX((width() - i.pxWidth()) / 2); + } + if (t.y() < 0) { + t.setY((height() - i.pxHeight()) / 2); + } + p.drawSprite(t, i); } } diff --git a/Telegram/SourceFiles/ui/flattextarea.cpp b/Telegram/SourceFiles/ui/flattextarea.cpp index efe8bcdfd8..89a729e1e6 100644 --- a/Telegram/SourceFiles/ui/flattextarea.cpp +++ b/Telegram/SourceFiles/ui/flattextarea.cpp @@ -25,27 +25,13 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "window.h" FlatTextarea::FlatTextarea(QWidget *parent, const style::flatTextarea &st, const QString &pholder, const QString &v) : QTextEdit(parent) -, _minHeight(-1) -, _maxHeight(-1) -, _maxLength(-1) -, _ctrlEnterSubmit(true) , _oldtext(v) -, _phAfter(0) , _phVisible(!v.length()) , a_phLeft(_phVisible ? 0 : st.phShift) , a_phAlpha(_phVisible ? 1 : 0) , a_phColor(st.phColor->c) , _a_appearance(animation(this, &FlatTextarea::step_appearance)) -, _st(st) -, _undoAvailable(false) -, _redoAvailable(false) -, _inDrop(false) -, _inHeightCheck(false) -, _fakeMargin(0) -, _touchPress(false) -, _touchRightButton(false) -, _touchMove(false) -, _correcting(false) { +, _st(st) { setAcceptRichText(false); resize(_st.width, _st.font->height); @@ -270,7 +256,10 @@ EmojiPtr FlatTextarea::getSingleEmoji() const { return 0; } -QString FlatTextarea::getInlineBotQuery(UserData *&inlineBot, QString &inlineBotUsername) const { +QString FlatTextarea::getInlineBotQuery(UserData **outInlineBot, QString *outInlineBotUsername) const { + t_assert(outInlineBot != nullptr); + t_assert(outInlineBotUsername != nullptr); + const QString &text(getLastText()); int32 inlineUsernameStart = 1, inlineUsernameLength = 0, size = text.size(); @@ -288,23 +277,23 @@ QString FlatTextarea::getInlineBotQuery(UserData *&inlineBot, QString &inlineBot } if (inlineUsernameLength && inlineUsernameStart + inlineUsernameLength < text.size() && text.at(inlineUsernameStart + inlineUsernameLength).isSpace()) { QStringRef username = text.midRef(inlineUsernameStart, inlineUsernameLength); - if (username != inlineBotUsername) { - inlineBotUsername = username.toString(); - PeerData *peer = App::peerByName(inlineBotUsername); + if (username != *outInlineBotUsername) { + *outInlineBotUsername = username.toString(); + PeerData *peer = App::peerByName(*outInlineBotUsername); if (peer) { if (peer->isUser()) { - inlineBot = peer->asUser(); + *outInlineBot = peer->asUser(); } else { - inlineBot = 0; + *outInlineBot = nullptr; } } else { - inlineBot = LookingUpInlineBot; + *outInlineBot = LookingUpInlineBot; } } - if (inlineBot == LookingUpInlineBot) return QString(); + if (*outInlineBot == LookingUpInlineBot) return QString(); - if (inlineBot && (!inlineBot->botInfo || inlineBot->botInfo->inlinePlaceholder.isEmpty())) { - inlineBot = 0; + if (*outInlineBot && (!(*outInlineBot)->botInfo || (*outInlineBot)->botInfo->inlinePlaceholder.isEmpty())) { + *outInlineBot = nullptr; } else { return text.mid(inlineUsernameStart + inlineUsernameLength + 1); } @@ -313,8 +302,8 @@ QString FlatTextarea::getInlineBotQuery(UserData *&inlineBot, QString &inlineBot } } if (inlineUsernameLength < 3) { - inlineBot = 0; - inlineBotUsername = QString(); + *outInlineBot = nullptr; + *outInlineBotUsername = QString(); } return QString(); } @@ -945,14 +934,21 @@ QMimeData *FlatTextarea::createMimeDataFromSelection() const { return result; } -void FlatTextarea::setCtrlEnterSubmit(bool ctrlEnterSubmit) { - _ctrlEnterSubmit = ctrlEnterSubmit; +void FlatTextarea::setSubmitSettings(SubmitSettings settings) { + _submitSettings = settings; } void FlatTextarea::keyPressEvent(QKeyEvent *e) { bool shift = e->modifiers().testFlag(Qt::ShiftModifier); bool macmeta = (cPlatform() == dbipMac || cPlatform() == dbipMacOld) && e->modifiers().testFlag(Qt::ControlModifier) && !e->modifiers().testFlag(Qt::MetaModifier) && !e->modifiers().testFlag(Qt::AltModifier); - bool ctrl = e->modifiers().testFlag(Qt::ControlModifier) || e->modifiers().testFlag(Qt::MetaModifier), ctrlGood = (ctrl && _ctrlEnterSubmit) || (!ctrl && !shift && !_ctrlEnterSubmit) || (ctrl && shift); + bool ctrl = e->modifiers().testFlag(Qt::ControlModifier) || e->modifiers().testFlag(Qt::MetaModifier); + bool enterSubmit = (ctrl && shift); + if (ctrl && _submitSettings != SubmitSettings::None && _submitSettings != SubmitSettings::Enter) { + enterSubmit = true; + } + if (!ctrl && _submitSettings != SubmitSettings::None && _submitSettings != SubmitSettings::CtrlEnter) { + enterSubmit = true; + } bool enter = (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return); if (macmeta && e->key() == Qt::Key_Backspace) { @@ -960,7 +956,7 @@ void FlatTextarea::keyPressEvent(QKeyEvent *e) { start.movePosition(QTextCursor::StartOfLine); tc.setPosition(start.position(), QTextCursor::KeepAnchor); tc.removeSelectedText(); - } else if (enter && ctrlGood) { + } else if (enter && enterSubmit) { emit submitted(ctrl && shift); } else if (e->key() == Qt::Key_Escape) { emit cancelled(); diff --git a/Telegram/SourceFiles/ui/flattextarea.h b/Telegram/SourceFiles/ui/flattextarea.h index cd3c476361..2a115107ae 100644 --- a/Telegram/SourceFiles/ui/flattextarea.h +++ b/Telegram/SourceFiles/ui/flattextarea.h @@ -67,7 +67,12 @@ public: EmojiPtr getSingleEmoji() const; QString getMentionHashtagBotCommandPart(bool &start) const; - QString getInlineBotQuery(UserData *&contextBot, QString &contextBotUsername) const; + + // Get the current inline bot and request string for it. + // The *outInlineBot can be filled by LookingUpInlineBot shared ptr. + // In that case the caller should lookup the bot by *outInlineBotUsername. + QString getInlineBotQuery(UserData **outInlineBot, QString *outInlineBotUsername) const; + void removeSingleEmoji(); bool hasText() const; @@ -80,7 +85,14 @@ public: void insertFromMimeData(const QMimeData *source); QMimeData *createMimeDataFromSelection() const; - void setCtrlEnterSubmit(bool ctrlEnterSubmit); + + enum class SubmitSettings { + None, + Enter, + CtrlEnter, + Both, + }; + void setSubmitSettings(SubmitSettings settings); void setTextFast(const QString &text, bool clearUndoHistory = true); @@ -123,12 +135,13 @@ private: void processDocumentContentsChange(int position, int charsAdded); bool heightAutoupdated(); - int32 _minHeight, _maxHeight; // < 0 - no autosize - int32 _maxLength; - bool _ctrlEnterSubmit; + int _minHeight = -1; // < 0 - no autosize + int _maxHeight = -1; + int _maxLength = -1; + SubmitSettings _submitSettings = SubmitSettings::Enter; QString _ph, _phelided, _oldtext; - int32 _phAfter; + int _phAfter = 0; bool _phVisible; anim::ivalue a_phLeft; anim::fvalue a_phAlpha; @@ -137,15 +150,20 @@ private: style::flatTextarea _st; - bool _undoAvailable, _redoAvailable, _inDrop, _inHeightCheck; + bool _undoAvailable = false; + bool _redoAvailable = false; + bool _inDrop = false; + bool _inHeightCheck = false; - int32 _fakeMargin; + int _fakeMargin = 0; QTimer _touchTimer; - bool _touchPress, _touchRightButton, _touchMove; + bool _touchPress = false; + bool _touchRightButton = false; + bool _touchMove = false; QPoint _touchStart; - bool _correcting; + bool _correcting = false; typedef QPair LinkRange; typedef QList LinkRanges;