mirror of
https://github.com/kotatogram/kotatogram-desktop
synced 2025-08-31 06:35:14 +00:00
Move some classes to separate modules.
MessageField, BotKeyboard, HistoryInner from historywidget.
This commit is contained in:
248
Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp
Normal file
248
Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp
Normal file
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
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(const HistoryItem *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<HistoryMessageReplyMarkup>()) {
|
||||
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<HistoryMessageReplyMarkup>()) {
|
||||
if (!markup->rows.isEmpty()) {
|
||||
_impl.reset(new ReplyKeyboard(to, std::make_unique<Style>(this, *_st)));
|
||||
}
|
||||
}
|
||||
|
||||
resizeToWidth(width(), _maxOuterHeight);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BotKeyboard::hasMarkup() const {
|
||||
return _impl != nullptr;
|
||||
}
|
||||
|
||||
bool BotKeyboard::forceReply() const {
|
||||
return _forceReply;
|
||||
}
|
||||
|
||||
int BotKeyboard::resizeGetHeight(int newWidth) {
|
||||
updateStyle(newWidth);
|
||||
_height = st::botKbScroll.deltat + st::botKbScroll.deltab + (_impl ? _impl->naturalHeight() : 0);
|
||||
if (_maximizeSize) {
|
||||
accumulate_max(_height, _maxOuterHeight);
|
||||
}
|
||||
if (_impl) {
|
||||
int implWidth = newWidth - _st->margin - st::botKbScroll.width;
|
||||
int implHeight = _height - (st::botKbScroll.deltat + st::botKbScroll.deltab);
|
||||
_impl->resize(implWidth, implHeight);
|
||||
}
|
||||
return _height;
|
||||
}
|
||||
|
||||
bool BotKeyboard::maximizeSize() const {
|
||||
return _maximizeSize;
|
||||
}
|
||||
|
||||
bool BotKeyboard::singleUse() const {
|
||||
return _singleUse;
|
||||
}
|
||||
|
||||
void BotKeyboard::updateStyle(int newWidth) {
|
||||
if (!_impl) return;
|
||||
|
||||
int implWidth = newWidth - st::botKbButton.margin - st::botKbScroll.width;
|
||||
_st = _impl->isEnoughSpace(implWidth, st::botKbButton) ? &st::botKbButton : &st::botKbTinyButton;
|
||||
|
||||
_impl->setStyle(std::make_unique<Style>(this, *_st));
|
||||
}
|
||||
|
||||
void BotKeyboard::clearSelection() {
|
||||
if (_impl) {
|
||||
if (ClickHandler::setActive(ClickHandlerPtr(), this)) {
|
||||
Ui::Tooltip::Hide();
|
||||
setCursor(style::cur_default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QPoint BotKeyboard::tooltipPos() const {
|
||||
return _lastMousePos;
|
||||
}
|
||||
|
||||
QString BotKeyboard::tooltipText() const {
|
||||
if (ClickHandlerPtr lnk = ClickHandler::getActive()) {
|
||||
return lnk->tooltip();
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
void BotKeyboard::updateSelected() {
|
||||
Ui::Tooltip::Show(1000, this);
|
||||
|
||||
if (!_impl) return;
|
||||
|
||||
QPoint p(mapFromGlobal(_lastMousePos));
|
||||
int x = rtl() ? st::botKbScroll.width : _st->margin;
|
||||
|
||||
auto link = _impl->getState(p.x() - x, p.y() - _st->margin);
|
||||
if (ClickHandler::setActive(link, this)) {
|
||||
Ui::Tooltip::Hide();
|
||||
setCursor(link ? style::cur_pointer : style::cur_default);
|
||||
}
|
||||
}
|
109
Telegram/SourceFiles/chat_helpers/bot_keyboard.h
Normal file
109
Telegram/SourceFiles/chat_helpers/bot_keyboard.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ui/widgets/tooltip.h"
|
||||
|
||||
class BotKeyboard : public TWidget, public Ui::AbstractTooltipShower, public ClickHandlerHost {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
BotKeyboard(QWidget *parent);
|
||||
|
||||
bool moderateKeyActivate(int index);
|
||||
|
||||
// With force=true the markup is updated even if it is
|
||||
// already shown for the passed history item.
|
||||
bool updateMarkup(HistoryItem *last, bool force = false);
|
||||
bool hasMarkup() const;
|
||||
bool forceReply() const;
|
||||
|
||||
void step_selected(TimeMs ms, bool timer);
|
||||
void resizeToWidth(int newWidth, int maxOuterHeight) {
|
||||
_maxOuterHeight = maxOuterHeight;
|
||||
return TWidget::resizeToWidth(newWidth);
|
||||
}
|
||||
|
||||
bool maximizeSize() const;
|
||||
bool singleUse() const;
|
||||
|
||||
FullMsgId forMsgId() const {
|
||||
return _wasForMsgId;
|
||||
}
|
||||
|
||||
// AbstractTooltipShower interface
|
||||
QString tooltipText() const override;
|
||||
QPoint tooltipPos() const override;
|
||||
|
||||
// ClickHandlerHost interface
|
||||
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
||||
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
|
||||
|
||||
protected:
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
void enterEventHook(QEvent *e) override;
|
||||
void leaveEventHook(QEvent *e) override;
|
||||
|
||||
private:
|
||||
void updateSelected();
|
||||
|
||||
void updateStyle(int newWidth);
|
||||
void clearSelection();
|
||||
|
||||
FullMsgId _wasForMsgId;
|
||||
int _height = 0;
|
||||
int _maxOuterHeight = 0;
|
||||
bool _maximizeSize = false;
|
||||
bool _singleUse = false;
|
||||
bool _forceReply = false;
|
||||
|
||||
QPoint _lastMousePos;
|
||||
std::unique_ptr<ReplyKeyboard> _impl;
|
||||
|
||||
class Style : public ReplyKeyboard::Style {
|
||||
public:
|
||||
Style(BotKeyboard *parent, const style::BotKeyboardButton &st) : ReplyKeyboard::Style(st), _parent(parent) {
|
||||
}
|
||||
|
||||
int buttonRadius() const override;
|
||||
|
||||
void startPaint(Painter &p) const override;
|
||||
const style::TextStyle &textStyle() const override;
|
||||
void repaint(const HistoryItem *item) const override;
|
||||
|
||||
protected:
|
||||
void paintButtonBg(Painter &p, const QRect &rect, float64 howMuchOver) const override;
|
||||
void paintButtonIcon(Painter &p, const QRect &rect, int outerWidth, HistoryMessageReplyMarkup::Button::Type type) const override;
|
||||
void paintButtonLoading(Painter &p, const QRect &rect) const override;
|
||||
int minButtonWidth(HistoryMessageReplyMarkup::Button::Type type) const override;
|
||||
|
||||
private:
|
||||
BotKeyboard *_parent;
|
||||
|
||||
};
|
||||
const style::BotKeyboardButton *_st = nullptr;
|
||||
|
||||
};
|
152
Telegram/SourceFiles/chat_helpers/message_field.cpp
Normal file
152
Telegram/SourceFiles/chat_helpers/message_field.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
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/message_field.h"
|
||||
|
||||
#include "historywidget.h"
|
||||
#include "base/qthelp_regex.h"
|
||||
#include "styles/style_history.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "mainwindow.h"
|
||||
#include "auth_session.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// For mention tags save and validate userId, ignore tags for different userId.
|
||||
class FieldTagMimeProcessor : public Ui::FlatTextarea::TagMimeProcessor {
|
||||
public:
|
||||
QString mimeTagFromTag(const QString &tagId) override {
|
||||
return ConvertTagToMimeTag(tagId);
|
||||
}
|
||||
|
||||
QString tagFromMimeTag(const QString &mimeTag) override {
|
||||
if (mimeTag.startsWith(qstr("mention://"))) {
|
||||
auto match = QRegularExpression(":(\\d+)$").match(mimeTag);
|
||||
if (!match.hasMatch() || match.capturedRef(1).toInt() != AuthSession::CurrentUserId()) {
|
||||
return QString();
|
||||
}
|
||||
return mimeTag.mid(0, mimeTag.size() - match.capturedLength());
|
||||
}
|
||||
return mimeTag;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
QString ConvertTagToMimeTag(const QString &tagId) {
|
||||
if (tagId.startsWith(qstr("mention://"))) {
|
||||
return tagId + ':' + QString::number(AuthSession::CurrentUserId());
|
||||
}
|
||||
return tagId;
|
||||
}
|
||||
|
||||
EntitiesInText ConvertTextTagsToEntities(const TextWithTags::Tags &tags) {
|
||||
EntitiesInText result;
|
||||
if (tags.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result.reserve(tags.size());
|
||||
auto mentionStart = qstr("mention://user.");
|
||||
for_const (auto &tag, tags) {
|
||||
if (tag.id.startsWith(mentionStart)) {
|
||||
if (auto match = qthelp::regex_match("^(\\d+\\.\\d+)(/|$)", tag.id.midRef(mentionStart.size()))) {
|
||||
result.push_back(EntityInText(EntityInTextMentionName, tag.offset, tag.length, match->captured(1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
TextWithTags::Tags ConvertEntitiesToTextTags(const EntitiesInText &entities) {
|
||||
TextWithTags::Tags result;
|
||||
if (entities.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result.reserve(entities.size());
|
||||
for_const (auto &entity, entities) {
|
||||
if (entity.type() == EntityInTextMentionName) {
|
||||
auto match = QRegularExpression("^(\\d+\\.\\d+)$").match(entity.data());
|
||||
if (match.hasMatch()) {
|
||||
result.push_back({ entity.offset(), entity.length(), qstr("mention://user.") + entity.data() });
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
MessageField::MessageField(QWidget *parent, gsl::not_null<Window::Controller*> controller, const style::FlatTextarea &st, const QString &ph, const QString &val) : Ui::FlatTextarea(parent, st, ph, val)
|
||||
, _controller(controller) {
|
||||
setMinHeight(st::historySendSize.height() - 2 * st::historySendPadding);
|
||||
setMaxHeight(st::historyComposeFieldMaxHeight);
|
||||
|
||||
setTagMimeProcessor(std::make_unique<FieldTagMimeProcessor>());
|
||||
}
|
||||
|
||||
bool MessageField::hasSendText() const {
|
||||
auto &text = getTextWithTags().text;
|
||||
for (auto *ch = text.constData(), *e = ch + text.size(); ch != e; ++ch) {
|
||||
auto code = ch->unicode();
|
||||
if (code != ' ' && code != '\n' && code != '\r' && !chReplacedBySpace(code)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MessageField::onEmojiInsert(EmojiPtr emoji) {
|
||||
if (isHidden()) return;
|
||||
insertEmoji(emoji, textCursor());
|
||||
}
|
||||
|
||||
void MessageField::dropEvent(QDropEvent *e) {
|
||||
FlatTextarea::dropEvent(e);
|
||||
if (e->isAccepted()) {
|
||||
_controller->window()->activateWindow();
|
||||
}
|
||||
}
|
||||
|
||||
bool MessageField::canInsertFromMimeData(const QMimeData *source) const {
|
||||
if (source->hasUrls()) {
|
||||
int32 files = 0;
|
||||
for (int32 i = 0; i < source->urls().size(); ++i) {
|
||||
if (source->urls().at(i).isLocalFile()) {
|
||||
++files;
|
||||
}
|
||||
}
|
||||
if (files > 1) return false; // multiple confirm with "compressed" checkbox
|
||||
}
|
||||
if (source->hasImage()) return true;
|
||||
return FlatTextarea::canInsertFromMimeData(source);
|
||||
}
|
||||
|
||||
void MessageField::insertFromMimeData(const QMimeData *source) {
|
||||
if (_insertFromMimeDataHook && _insertFromMimeDataHook(source)) {
|
||||
return;
|
||||
}
|
||||
FlatTextarea::insertFromMimeData(source);
|
||||
}
|
||||
|
||||
void MessageField::focusInEvent(QFocusEvent *e) {
|
||||
FlatTextarea::focusInEvent(e);
|
||||
emit focused();
|
||||
}
|
63
Telegram/SourceFiles/chat_helpers/message_field.h
Normal file
63
Telegram/SourceFiles/chat_helpers/message_field.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
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
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ui/widgets/input_fields.h"
|
||||
|
||||
class HistoryWidget;
|
||||
namespace Window {
|
||||
class Controller;
|
||||
} // namespace Window
|
||||
|
||||
QString ConvertTagToMimeTag(const QString &tagId);
|
||||
|
||||
EntitiesInText ConvertTextTagsToEntities(const TextWithTags::Tags &tags);
|
||||
TextWithTags::Tags ConvertEntitiesToTextTags(const EntitiesInText &entities);
|
||||
|
||||
class MessageField final : public Ui::FlatTextarea {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MessageField(QWidget *parent, gsl::not_null<Window::Controller*> controller, const style::FlatTextarea &st, const QString &ph = QString(), const QString &val = QString());
|
||||
|
||||
bool hasSendText() const;
|
||||
|
||||
void setInsertFromMimeDataHook(base::lambda<bool(const QMimeData *data)> hook) {
|
||||
_insertFromMimeDataHook = std::move(hook);
|
||||
}
|
||||
|
||||
public slots:
|
||||
void onEmojiInsert(EmojiPtr emoji);
|
||||
|
||||
signals:
|
||||
void focused();
|
||||
|
||||
protected:
|
||||
void focusInEvent(QFocusEvent *e) override;
|
||||
void dropEvent(QDropEvent *e) override;
|
||||
bool canInsertFromMimeData(const QMimeData *source) const override;
|
||||
void insertFromMimeData(const QMimeData *source) override;
|
||||
|
||||
private:
|
||||
gsl::not_null<Window::Controller*> _controller;
|
||||
base::lambda<bool(const QMimeData *data)> _insertFromMimeDataHook;
|
||||
|
||||
};
|
Reference in New Issue
Block a user