"Fossies" - the Fresh Open Source Software Archive 
Member "tdesktop-2.6.1/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp" (24 Feb 2021, 7696 Bytes) of package /linux/misc/tdesktop-2.6.1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "bot_keyboard.cpp" see the
Fossies "Dox" file reference documentation.
1 /*
2 This file is part of Telegram Desktop,
3 the official desktop application for the Telegram messaging service.
4
5 For license and copyright information please follow this link:
6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
7 */
8 #include "chat_helpers/bot_keyboard.h"
9
10 #include "history/history.h"
11 #include "history/history_item_components.h"
12 #include "data/data_user.h"
13 #include "data/data_session.h"
14 #include "main/main_session.h"
15 #include "ui/cached_round_corners.h"
16 #include "facades.h"
17 #include "styles/style_widgets.h"
18 #include "styles/style_chat.h"
19
20 namespace {
21
22 class Style : public ReplyKeyboard::Style {
23 public:
24 Style(
25 not_null<BotKeyboard*> parent,
26 const style::BotKeyboardButton &st);
27
28 int buttonRadius() const override;
29
30 void startPaint(Painter &p) const override;
31 const style::TextStyle &textStyle() const override;
32 void repaint(not_null<const HistoryItem*> item) const override;
33
34 protected:
35 void paintButtonBg(
36 Painter &p,
37 const QRect &rect,
38 float64 howMuchOver) const override;
39 void paintButtonIcon(
40 Painter &p,
41 const QRect &rect,
42 int outerWidth,
43 HistoryMessageMarkupButton::Type type) const override;
44 void paintButtonLoading(Painter &p, const QRect &rect) const override;
45 int minButtonWidth(HistoryMessageMarkupButton::Type type) const override;
46
47 private:
48 not_null<BotKeyboard*> _parent;
49
50 };
51
52 Style::Style(
53 not_null<BotKeyboard*> parent,
54 const style::BotKeyboardButton &st)
55 : ReplyKeyboard::Style(st), _parent(parent) {
56 }
57
58 void Style::startPaint(Painter &p) const {
59 p.setPen(st::botKbColor);
60 p.setFont(st::botKbStyle.font);
61 }
62
63 const style::TextStyle &Style::textStyle() const {
64 return st::botKbStyle;
65 }
66
67 void Style::repaint(not_null<const HistoryItem*> item) const {
68 _parent->update();
69 }
70
71 int Style::buttonRadius() const {
72 return st::roundRadiusSmall;
73 }
74
75 void Style::paintButtonBg(
76 Painter &p,
77 const QRect &rect,
78 float64 howMuchOver) const {
79 Ui::FillRoundRect(p, rect, st::botKbBg, Ui::BotKeyboardCorners);
80 }
81
82 void Style::paintButtonIcon(
83 Painter &p,
84 const QRect &rect,
85 int outerWidth,
86 HistoryMessageMarkupButton::Type type) const {
87 // Buttons with icons should not appear here.
88 }
89
90 void Style::paintButtonLoading(Painter &p, const QRect &rect) const {
91 // Buttons with loading progress should not appear here.
92 }
93
94 int Style::minButtonWidth(HistoryMessageMarkupButton::Type type) const {
95 int result = 2 * buttonPadding();
96 return result;
97 }
98
99 } // namespace
100
101 BotKeyboard::BotKeyboard(not_null<Main::Session*> session, QWidget *parent)
102 : TWidget(parent)
103 , _session(session)
104 , _st(&st::botKbButton) {
105 setGeometry(0, 0, _st->margin, st::botKbScroll.deltat);
106 _height = st::botKbScroll.deltat;
107 setMouseTracking(true);
108 }
109
110 void BotKeyboard::paintEvent(QPaintEvent *e) {
111 Painter p(this);
112
113 auto clip = e->rect();
114 p.fillRect(clip, st::historyComposeAreaBg);
115
116 if (_impl) {
117 int x = rtl() ? st::botKbScroll.width : _st->margin;
118 p.translate(x, st::botKbScroll.deltat);
119 _impl->paint(p, width(), clip.translated(-x, -st::botKbScroll.deltat));
120 }
121 }
122
123 void BotKeyboard::mousePressEvent(QMouseEvent *e) {
124 _lastMousePos = e->globalPos();
125 updateSelected();
126
127 ClickHandler::pressed();
128 }
129
130 void BotKeyboard::mouseMoveEvent(QMouseEvent *e) {
131 _lastMousePos = e->globalPos();
132 updateSelected();
133 }
134
135 void BotKeyboard::mouseReleaseEvent(QMouseEvent *e) {
136 _lastMousePos = e->globalPos();
137 updateSelected();
138
139 if (ClickHandlerPtr activated = ClickHandler::unpressed()) {
140 ActivateClickHandler(window(), activated, e->button());
141 }
142 }
143
144 void BotKeyboard::enterEventHook(QEvent *e) {
145 _lastMousePos = QCursor::pos();
146 updateSelected();
147 }
148
149 void BotKeyboard::leaveEventHook(QEvent *e) {
150 clearSelection();
151 }
152
153 bool BotKeyboard::moderateKeyActivate(int key) {
154 if (const auto item = _session->data().message(_wasForMsgId)) {
155 if (const auto markup = item->Get<HistoryMessageReplyMarkup>()) {
156 if (key >= Qt::Key_1 && key <= Qt::Key_9) {
157 const auto index = int(key - Qt::Key_1);
158 if (!markup->rows.empty()
159 && index >= 0
160 && index < int(markup->rows.front().size())) {
161 App::activateBotCommand(item, 0, index);
162 return true;
163 }
164 } else if (const auto user = item->history()->peer->asUser()) {
165 if (user->isBot() && item->from() == user) {
166 if (key == Qt::Key_Q) {
167 App::sendBotCommand(user, user, qsl("/translate"));
168 } else if (key == Qt::Key_W) {
169 App::sendBotCommand(user, user, qsl("/eng"));
170 }
171 return true;
172 }
173 }
174 }
175 }
176 return false;
177 }
178
179 void BotKeyboard::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
180 if (!_impl) return;
181 _impl->clickHandlerActiveChanged(p, active);
182 }
183
184 void BotKeyboard::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) {
185 if (!_impl) return;
186 _impl->clickHandlerPressedChanged(p, pressed);
187 }
188
189 bool BotKeyboard::updateMarkup(HistoryItem *to, bool force) {
190 if (!to || !to->definesReplyKeyboard()) {
191 if (_wasForMsgId.msg) {
192 _maximizeSize = _singleUse = _forceReply = false;
193 _wasForMsgId = FullMsgId();
194 _impl = nullptr;
195 return true;
196 }
197 return false;
198 }
199
200 if (_wasForMsgId == FullMsgId(to->channelId(), to->id) && !force) {
201 return false;
202 }
203
204 _wasForMsgId = FullMsgId(to->channelId(), to->id);
205
206 auto markupFlags = to->replyKeyboardFlags();
207 _forceReply = markupFlags & MTPDreplyKeyboardMarkup_ClientFlag::f_force_reply;
208 _maximizeSize = !(markupFlags & MTPDreplyKeyboardMarkup::Flag::f_resize);
209 _singleUse = _forceReply || (markupFlags & MTPDreplyKeyboardMarkup::Flag::f_single_use);
210
211 _impl = nullptr;
212 if (auto markup = to->Get<HistoryMessageReplyMarkup>()) {
213 if (!markup->rows.empty()) {
214 _impl = std::make_unique<ReplyKeyboard>(
215 to,
216 std::make_unique<Style>(this, *_st));
217 }
218 }
219
220 resizeToWidth(width(), _maxOuterHeight);
221
222 return true;
223 }
224
225 bool BotKeyboard::hasMarkup() const {
226 return _impl != nullptr;
227 }
228
229 bool BotKeyboard::forceReply() const {
230 return _forceReply;
231 }
232
233 int BotKeyboard::resizeGetHeight(int newWidth) {
234 updateStyle(newWidth);
235 _height = st::botKbScroll.deltat + st::botKbScroll.deltab + (_impl ? _impl->naturalHeight() : 0);
236 if (_maximizeSize) {
237 accumulate_max(_height, _maxOuterHeight);
238 }
239 if (_impl) {
240 int implWidth = newWidth - _st->margin - st::botKbScroll.width;
241 int implHeight = _height - (st::botKbScroll.deltat + st::botKbScroll.deltab);
242 _impl->resize(implWidth, implHeight);
243 }
244 return _height;
245 }
246
247 bool BotKeyboard::maximizeSize() const {
248 return _maximizeSize;
249 }
250
251 bool BotKeyboard::singleUse() const {
252 return _singleUse;
253 }
254
255 void BotKeyboard::updateStyle(int newWidth) {
256 if (!_impl) return;
257
258 int implWidth = newWidth - st::botKbButton.margin - st::botKbScroll.width;
259 _st = _impl->isEnoughSpace(implWidth, st::botKbButton) ? &st::botKbButton : &st::botKbTinyButton;
260
261 _impl->setStyle(std::make_unique<Style>(this, *_st));
262 }
263
264 void BotKeyboard::clearSelection() {
265 if (_impl) {
266 if (ClickHandler::setActive(ClickHandlerPtr(), this)) {
267 Ui::Tooltip::Hide();
268 setCursor(style::cur_default);
269 }
270 }
271 }
272
273 QPoint BotKeyboard::tooltipPos() const {
274 return _lastMousePos;
275 }
276
277 bool BotKeyboard::tooltipWindowActive() const {
278 return Ui::AppInFocus() && Ui::InFocusChain(window());
279 }
280
281 QString BotKeyboard::tooltipText() const {
282 if (ClickHandlerPtr lnk = ClickHandler::getActive()) {
283 return lnk->tooltip();
284 }
285 return QString();
286 }
287
288 void BotKeyboard::updateSelected() {
289 Ui::Tooltip::Show(1000, this);
290
291 if (!_impl) return;
292
293 auto p = mapFromGlobal(_lastMousePos);
294 auto x = rtl() ? st::botKbScroll.width : _st->margin;
295
296 auto link = _impl->getLink(p - QPoint(x, _st->margin));
297 if (ClickHandler::setActive(link, this)) {
298 Ui::Tooltip::Hide();
299 setCursor(link ? style::cur_pointer : style::cur_default);
300 }
301 }
302
303 BotKeyboard::~BotKeyboard() = default;