/* This file is part of Telegram Desktop, the official desktop version of Telegram messaging app, see https://telegram.org Telegram Desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. In addition, as a special exception, the copyright holders give permission to link the code of portions of this program with the OpenSSL library. Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #include "chat_helpers/bot_keyboard.h" #include "styles/style_widgets.h" #include "styles/style_history.h" BotKeyboard::BotKeyboard(QWidget *parent) : TWidget(parent) , _st(&st::botKbButton) { setGeometry(0, 0, _st->margin, st::botKbScroll.deltat); _height = st::botKbScroll.deltat; setMouseTracking(true); } void BotKeyboard::paintEvent(QPaintEvent *e) { Painter p(this); auto clip = e->rect(); p.fillRect(clip, st::historyComposeAreaBg); if (_impl) { int x = rtl() ? st::botKbScroll.width : _st->margin; p.translate(x, st::botKbScroll.deltat); _impl->paint(p, width(), clip.translated(-x, -st::botKbScroll.deltat), getms()); } } void BotKeyboard::Style::startPaint(Painter &p) const { p.setPen(st::botKbColor); p.setFont(st::botKbStyle.font); } const style::TextStyle &BotKeyboard::Style::textStyle() const { return st::botKbStyle; } void BotKeyboard::Style::repaint(not_null item) const { _parent->update(); } int BotKeyboard::Style::buttonRadius() const { return st::buttonRadius; } void BotKeyboard::Style::paintButtonBg(Painter &p, const QRect &rect, float64 howMuchOver) const { App::roundRect(p, rect, st::botKbBg, BotKeyboardCorners); } void BotKeyboard::Style::paintButtonIcon(Painter &p, const QRect &rect, int outerWidth, HistoryMessageReplyMarkup::Button::Type type) const { // Buttons with icons should not appear here. } void BotKeyboard::Style::paintButtonLoading(Painter &p, const QRect &rect) const { // Buttons with loading progress should not appear here. } int BotKeyboard::Style::minButtonWidth(HistoryMessageReplyMarkup::Button::Type type) const { int result = 2 * buttonPadding(); return result; } void BotKeyboard::mousePressEvent(QMouseEvent *e) { _lastMousePos = e->globalPos(); updateSelected(); ClickHandler::pressed(); } void BotKeyboard::mouseMoveEvent(QMouseEvent *e) { _lastMousePos = e->globalPos(); updateSelected(); } void BotKeyboard::mouseReleaseEvent(QMouseEvent *e) { _lastMousePos = e->globalPos(); updateSelected(); if (ClickHandlerPtr activated = ClickHandler::unpressed()) { App::activateClickHandler(activated, e->button()); } } void BotKeyboard::enterEventHook(QEvent *e) { _lastMousePos = QCursor::pos(); updateSelected(); } void BotKeyboard::leaveEventHook(QEvent *e) { clearSelection(); } bool BotKeyboard::moderateKeyActivate(int key) { if (auto item = App::histItemById(_wasForMsgId)) { if (auto markup = item->Get()) { if (key >= Qt::Key_1 && key <= Qt::Key_9) { int index = (key - Qt::Key_1); if (!markup->rows.isEmpty() && index >= 0 && index < markup->rows.front().size()) { App::activateBotCommand(item, 0, index); return true; } } else if (key == Qt::Key_Q) { if (auto user = item->history()->peer->asUser()) { if (user->botInfo && item->from() == user) { App::sendBotCommand(user, user, qsl("/translate")); return true; } } } } } return false; } void BotKeyboard::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { if (!_impl) return; _impl->clickHandlerActiveChanged(p, active); } void BotKeyboard::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) { if (!_impl) return; _impl->clickHandlerPressedChanged(p, pressed); } bool BotKeyboard::updateMarkup(HistoryItem *to, bool force) { if (!to || !to->definesReplyKeyboard()) { if (_wasForMsgId.msg) { _maximizeSize = _singleUse = _forceReply = false; _wasForMsgId = FullMsgId(); _impl = nullptr; return true; } return false; } if (_wasForMsgId == FullMsgId(to->channelId(), to->id) && !force) { return false; } _wasForMsgId = FullMsgId(to->channelId(), to->id); auto markupFlags = to->replyKeyboardFlags(); _forceReply = markupFlags & MTPDreplyKeyboardMarkup_ClientFlag::f_force_reply; _maximizeSize = !(markupFlags & MTPDreplyKeyboardMarkup::Flag::f_resize); _singleUse = _forceReply || (markupFlags & MTPDreplyKeyboardMarkup::Flag::f_single_use); _impl = nullptr; if (auto markup = to->Get()) { if (!markup->rows.isEmpty()) { _impl.reset(new ReplyKeyboard(to, std::make_unique