mirror of https://github.com/procxx/kepka.git
Moved History[Media] classes to history_media_types module.
This commit is contained in:
parent
d277b0d4bb
commit
538ffb9727
Binary file not shown.
Before Width: | Height: | Size: 177 KiB After Width: | Height: | Size: 177 KiB |
Binary file not shown.
Before Width: | Height: | Size: 241 KiB After Width: | Height: | Size: 241 KiB |
|
@ -1232,7 +1232,7 @@ introErrLabelTextStyle: textStyle(defaultTextStyle) {
|
||||||
|
|
||||||
mediaPadding: margins(0px, 0px, 0px, 0px);//1px, 1px, 1px, 1px);//2px, 2px, 2px, 2px);
|
mediaPadding: margins(0px, 0px, 0px, 0px);//1px, 1px, 1px, 1px);//2px, 2px, 2px, 2px);
|
||||||
mediaCaptionSkip: 5px;
|
mediaCaptionSkip: 5px;
|
||||||
mediaHeaderSkip: 5px;
|
mediaInBubbleSkip: 5px;
|
||||||
mediaThumbSize: 48px;
|
mediaThumbSize: 48px;
|
||||||
mediaNameTop: 3px;
|
mediaNameTop: 3px;
|
||||||
mediaDetailsShift: 3px;
|
mediaDetailsShift: 3px;
|
||||||
|
@ -2285,7 +2285,6 @@ webPageLeft: 10px;
|
||||||
webPageBar: 2px;
|
webPageBar: 2px;
|
||||||
webPageTitleFont: semiboldFont;
|
webPageTitleFont: semiboldFont;
|
||||||
webPageDescriptionFont: normalFont;
|
webPageDescriptionFont: normalFont;
|
||||||
webPagePhotoSkip: 5px;
|
|
||||||
webPagePhotoSize: 100px;
|
webPagePhotoSize: 100px;
|
||||||
webPagePhotoDelta: 8px;
|
webPagePhotoDelta: 8px;
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "data/data_abstract_structure.h"
|
#include "data/data_abstract_structure.h"
|
||||||
#include "history/history_service_layout.h"
|
#include "history/history_service_layout.h"
|
||||||
#include "history/history_location_manager.h"
|
#include "history/history_location_manager.h"
|
||||||
|
#include "history/history_media_types.h"
|
||||||
#include "media/media_audio.h"
|
#include "media/media_audio.h"
|
||||||
#include "inline_bots/inline_bot_layout_item.h"
|
#include "inline_bots/inline_bot_layout_item.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
|
@ -1523,7 +1524,7 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
GameData *feedGame(const MTPDgame &game, GameData *convert) {
|
GameData *feedGame(const MTPDgame &game, GameData *convert) {
|
||||||
return App::gameSet(game.vid.v, convert, game.vaccess_hash.v, qs(game.vshort_name), qs(game.vtitle), qs(game.vdescription), qs(game.vurl), App::feedPhoto(game.vphoto), game.has_document() ? App::feedDocument(game.vdocument) : nullptr);
|
return App::gameSet(game.vid.v, convert, game.vaccess_hash.v, qs(game.vshort_name), qs(game.vtitle), qs(game.vdescription), App::feedPhoto(game.vphoto), game.has_document() ? App::feedDocument(game.vdocument) : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
UserData *curUser() {
|
UserData *curUser() {
|
||||||
|
@ -1847,7 +1848,7 @@ namespace {
|
||||||
return i.value();
|
return i.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
GameData *gameSet(const GameId &game, GameData *convert, const uint64 &accessHash, const QString &shortName, const QString &title, const QString &description, const QString &url, PhotoData *photo, DocumentData *document) {
|
GameData *gameSet(const GameId &game, GameData *convert, const uint64 &accessHash, const QString &shortName, const QString &title, const QString &description, PhotoData *photo, DocumentData *document) {
|
||||||
if (convert) {
|
if (convert) {
|
||||||
if (convert->id != game) {
|
if (convert->id != game) {
|
||||||
auto i = gamesData.find(convert->id);
|
auto i = gamesData.find(convert->id);
|
||||||
|
@ -1856,12 +1857,11 @@ namespace {
|
||||||
}
|
}
|
||||||
convert->id = game;
|
convert->id = game;
|
||||||
}
|
}
|
||||||
if (convert->url.isEmpty() && !url.isEmpty()) {
|
if (convert->shortName.isEmpty() && !shortName.isEmpty()) {
|
||||||
convert->accessHash = accessHash;
|
convert->accessHash = accessHash;
|
||||||
convert->shortName = shortName;
|
convert->shortName = shortName;
|
||||||
convert->title = title;
|
convert->title = title;
|
||||||
convert->description = description;
|
convert->description = description;
|
||||||
convert->url = url;
|
|
||||||
convert->photo = photo;
|
convert->photo = photo;
|
||||||
convert->document = document;
|
convert->document = document;
|
||||||
if (App::main()) App::main()->gameUpdated(convert);
|
if (App::main()) App::main()->gameUpdated(convert);
|
||||||
|
@ -1873,18 +1873,17 @@ namespace {
|
||||||
if (convert) {
|
if (convert) {
|
||||||
result = convert;
|
result = convert;
|
||||||
} else {
|
} else {
|
||||||
result = new GameData(game, accessHash, shortName, title, description, url, photo, document);
|
result = new GameData(game, accessHash, shortName, title, description, photo, document);
|
||||||
}
|
}
|
||||||
gamesData.insert(game, result);
|
gamesData.insert(game, result);
|
||||||
} else {
|
} else {
|
||||||
result = i.value();
|
result = i.value();
|
||||||
if (result != convert) {
|
if (result != convert) {
|
||||||
if (result->url.isEmpty() && !url.isEmpty()) {
|
if (result->shortName.isEmpty() && !shortName.isEmpty()) {
|
||||||
result->accessHash = accessHash;
|
result->accessHash = accessHash;
|
||||||
result->shortName = shortName;
|
result->shortName = shortName;
|
||||||
result->title = title;
|
result->title = title;
|
||||||
result->description = description;
|
result->description = description;
|
||||||
result->url = url;
|
|
||||||
result->photo = photo;
|
result->photo = photo;
|
||||||
result->document = document;
|
result->document = document;
|
||||||
if (App::main()) App::main()->gameUpdated(result);
|
if (App::main()) App::main()->gameUpdated(result);
|
||||||
|
|
|
@ -44,6 +44,9 @@ using GifItems = QHash<Media::Clip::Reader*, HistoryItem*>;
|
||||||
using PhotosData = QHash<PhotoId, PhotoData*>;
|
using PhotosData = QHash<PhotoId, PhotoData*>;
|
||||||
using DocumentsData = QHash<DocumentId, DocumentData*>;
|
using DocumentsData = QHash<DocumentId, DocumentData*>;
|
||||||
|
|
||||||
|
struct LocationCoords;
|
||||||
|
struct LocationData;
|
||||||
|
|
||||||
namespace App {
|
namespace App {
|
||||||
AppClass *app();
|
AppClass *app();
|
||||||
MainWindow *wnd();
|
MainWindow *wnd();
|
||||||
|
@ -154,7 +157,7 @@ namespace App {
|
||||||
WebPageData *webPage(const WebPageId &webPage);
|
WebPageData *webPage(const WebPageId &webPage);
|
||||||
WebPageData *webPageSet(const WebPageId &webPage, WebPageData *convert, const QString &type, const QString &url, const QString &displayUrl, const QString &siteName, const QString &title, const QString &description, PhotoData *photo, DocumentData *doc, int32 duration, const QString &author, int32 pendingTill);
|
WebPageData *webPageSet(const WebPageId &webPage, WebPageData *convert, const QString &type, const QString &url, const QString &displayUrl, const QString &siteName, const QString &title, const QString &description, PhotoData *photo, DocumentData *doc, int32 duration, const QString &author, int32 pendingTill);
|
||||||
GameData *game(const GameId &game);
|
GameData *game(const GameId &game);
|
||||||
GameData *gameSet(const GameId &game, GameData *convert, const uint64 &accessHash, const QString &shortName, const QString &title, const QString &description, const QString &url, PhotoData *photo, DocumentData *doc);
|
GameData *gameSet(const GameId &game, GameData *convert, const uint64 &accessHash, const QString &shortName, const QString &title, const QString &description, PhotoData *photo, DocumentData *doc);
|
||||||
LocationData *location(const LocationCoords &coords);
|
LocationData *location(const LocationCoords &coords);
|
||||||
void forgetMedia();
|
void forgetMedia();
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "photosendbox.h"
|
#include "photosendbox.h"
|
||||||
|
#include "history/history_media_types.h"
|
||||||
|
|
||||||
PhotoSendBox::PhotoSendBox(const FileLoadResultPtr &file) : AbstractBox(st::boxWideWidth)
|
PhotoSendBox::PhotoSendBox(const FileLoadResultPtr &file) : AbstractBox(st::boxWideWidth)
|
||||||
, _file(file)
|
, _file(file)
|
||||||
|
|
|
@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "history.h"
|
#include "history.h"
|
||||||
|
|
||||||
|
#include "history/history_media_types.h"
|
||||||
#include "dialogs/dialogs_indexed_list.h"
|
#include "dialogs/dialogs_indexed_list.h"
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
#include "data/data_drafts.h"
|
#include "data/data_drafts.h"
|
||||||
|
|
|
@ -28,84 +28,64 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
#include "fileuploader.h"
|
#include "fileuploader.h"
|
||||||
|
|
||||||
class ReplyMarkupClickHandler : public LeftButtonClickHandler {
|
ReplyMarkupClickHandler::ReplyMarkupClickHandler(const HistoryItem *item, int row, int col)
|
||||||
public:
|
: _itemId(item->fullId())
|
||||||
ReplyMarkupClickHandler(const HistoryItem *item, int row, int col) : _itemId(item->fullId()), _row(row), _col(col) {
|
, _row(row)
|
||||||
}
|
, _col(col) {
|
||||||
|
}
|
||||||
|
|
||||||
QString tooltip() const override {
|
// Copy to clipboard support.
|
||||||
return _fullDisplayed ? QString() : buttonText();
|
void ReplyMarkupClickHandler::copyToClipboard() const {
|
||||||
|
if (auto button = getButton()) {
|
||||||
|
if (button->type == HistoryMessageReplyMarkup::Button::Type::Url) {
|
||||||
|
auto url = QString::fromUtf8(button->data);
|
||||||
|
if (!url.isEmpty()) {
|
||||||
|
QApplication::clipboard()->setText(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void setFullDisplayed(bool full) {
|
QString ReplyMarkupClickHandler::copyToClipboardContextItemText() const {
|
||||||
_fullDisplayed = full;
|
if (auto button = getButton()) {
|
||||||
|
if (button->type == HistoryMessageReplyMarkup::Button::Type::Url) {
|
||||||
|
return lang(lng_context_copy_link);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
// Copy to clipboard support.
|
// Finds the corresponding button in the items markup struct.
|
||||||
void copyToClipboard() const override {
|
// If the button is not found it returns nullptr.
|
||||||
if (auto button = getButton()) {
|
// Note: it is possible that we will point to the different button
|
||||||
if (button->type == HistoryMessageReplyMarkup::Button::Type::Url) {
|
// than the one was used when constructing the handler, but not a big deal.
|
||||||
auto url = QString::fromUtf8(button->data);
|
const HistoryMessageReplyMarkup::Button *ReplyMarkupClickHandler::getButton() const {
|
||||||
if (!url.isEmpty()) {
|
if (auto item = App::histItemById(_itemId)) {
|
||||||
QApplication::clipboard()->setText(url);
|
if (auto markup = item->Get<HistoryMessageReplyMarkup>()) {
|
||||||
|
if (_row < markup->rows.size()) {
|
||||||
|
auto &row = markup->rows.at(_row);
|
||||||
|
if (_col < row.size()) {
|
||||||
|
return &row.at(_col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QString copyToClipboardContextItemText() const override {
|
return nullptr;
|
||||||
if (auto button = getButton()) {
|
}
|
||||||
if (button->type == HistoryMessageReplyMarkup::Button::Type::Url) {
|
|
||||||
return lang(lng_context_copy_link);
|
void ReplyMarkupClickHandler::onClickImpl() const {
|
||||||
}
|
if (auto item = App::histItemById(_itemId)) {
|
||||||
}
|
App::activateBotCommand(item, _row, _col);
|
||||||
return QString();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Finds the corresponding button in the items markup struct.
|
// Returns the full text of the corresponding button.
|
||||||
// If the button is not found it returns nullptr.
|
QString ReplyMarkupClickHandler::buttonText() const {
|
||||||
// Note: it is possible that we will point to the different button
|
if (auto button = getButton()) {
|
||||||
// than the one was used when constructing the handler, but not a big deal.
|
return button->text;
|
||||||
const HistoryMessageReplyMarkup::Button *getButton() const {
|
|
||||||
if (auto item = App::histItemById(_itemId)) {
|
|
||||||
if (auto markup = item->Get<HistoryMessageReplyMarkup>()) {
|
|
||||||
if (_row < markup->rows.size()) {
|
|
||||||
auto &row = markup->rows.at(_row);
|
|
||||||
if (_col < row.size()) {
|
|
||||||
return &row.at(_col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
return QString();
|
||||||
// We hold only FullMsgId, not HistoryItem*, because all click handlers
|
}
|
||||||
// are activated async and the item may be already destroyed.
|
|
||||||
void setMessageId(const FullMsgId &msgId) {
|
|
||||||
_itemId = msgId;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void onClickImpl() const override {
|
|
||||||
if (auto item = App::histItemById(_itemId)) {
|
|
||||||
App::activateBotCommand(item, _row, _col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
FullMsgId _itemId;
|
|
||||||
int _row, _col;
|
|
||||||
bool _fullDisplayed = true;
|
|
||||||
|
|
||||||
// Returns the full text of the corresponding button.
|
|
||||||
QString buttonText() const {
|
|
||||||
if (auto button = getButton()) {
|
|
||||||
return button->text;
|
|
||||||
}
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
ReplyKeyboard::ReplyKeyboard(const HistoryItem *item, StylePtr &&s)
|
ReplyKeyboard::ReplyKeyboard(const HistoryItem *item, StylePtr &&s)
|
||||||
: _item(item)
|
: _item(item)
|
||||||
|
|
|
@ -230,7 +230,47 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ReplyMarkupClickHandler;
|
class ReplyMarkupClickHandler : public LeftButtonClickHandler {
|
||||||
|
public:
|
||||||
|
ReplyMarkupClickHandler(const HistoryItem *item, int row, int col);
|
||||||
|
|
||||||
|
QString tooltip() const override {
|
||||||
|
return _fullDisplayed ? QString() : buttonText();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setFullDisplayed(bool full) {
|
||||||
|
_fullDisplayed = full;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy to clipboard support.
|
||||||
|
void copyToClipboard() const override;
|
||||||
|
QString copyToClipboardContextItemText() const override;
|
||||||
|
|
||||||
|
// Finds the corresponding button in the items markup struct.
|
||||||
|
// If the button is not found it returns nullptr.
|
||||||
|
// Note: it is possible that we will point to the different button
|
||||||
|
// than the one was used when constructing the handler, but not a big deal.
|
||||||
|
const HistoryMessageReplyMarkup::Button *getButton() const;
|
||||||
|
|
||||||
|
// We hold only FullMsgId, not HistoryItem*, because all click handlers
|
||||||
|
// are activated async and the item may be already destroyed.
|
||||||
|
void setMessageId(const FullMsgId &msgId) {
|
||||||
|
_itemId = msgId;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onClickImpl() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
FullMsgId _itemId;
|
||||||
|
int _row, _col;
|
||||||
|
bool _fullDisplayed = true;
|
||||||
|
|
||||||
|
// Returns the full text of the corresponding button.
|
||||||
|
QString buttonText() const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class ReplyKeyboard {
|
class ReplyKeyboard {
|
||||||
private:
|
private:
|
||||||
struct Button;
|
struct Button;
|
||||||
|
|
|
@ -20,38 +20,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
void historyInitMedia();
|
enum class MediaInBubbleState {
|
||||||
|
None,
|
||||||
class RadialAnimation {
|
Top,
|
||||||
public:
|
Middle,
|
||||||
RadialAnimation(AnimationCallbacks &&callbacks);
|
Bottom,
|
||||||
|
|
||||||
float64 opacity() const {
|
|
||||||
return _opacity;
|
|
||||||
}
|
|
||||||
bool animating() const {
|
|
||||||
return _animation.animating();
|
|
||||||
}
|
|
||||||
|
|
||||||
void start(float64 prg);
|
|
||||||
void update(float64 prg, bool finished, uint64 ms);
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
void step(uint64 ms);
|
|
||||||
void step() {
|
|
||||||
step(getms());
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw(Painter &p, const QRect &inner, int32 thickness, const style::color &color);
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint64 _firstStart = 0;
|
|
||||||
uint64 _lastStart = 0;
|
|
||||||
uint64 _lastTime = 0;
|
|
||||||
float64 _opacity = 0.;
|
|
||||||
anim::ivalue a_arcEnd, a_arcStart;
|
|
||||||
Animation _animation;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class HistoryMedia : public HistoryElement {
|
class HistoryMedia : public HistoryElement {
|
||||||
|
@ -67,7 +40,10 @@ public:
|
||||||
|
|
||||||
// Returns text with link-start and link-end commands for service-color highlighting.
|
// Returns text with link-start and link-end commands for service-color highlighting.
|
||||||
// Example: "[link1-start]You:[link1-end] [link1-start]Photo,[link1-end] caption text"
|
// Example: "[link1-start]You:[link1-end] [link1-start]Photo,[link1-end] caption text"
|
||||||
virtual QString inDialogsText() const;
|
virtual QString inDialogsText() const {
|
||||||
|
auto result = notificationText();
|
||||||
|
return result.isEmpty() ? QString() : textcmdLink(1, textClean(result));
|
||||||
|
}
|
||||||
virtual TextWithEntities selectedText(TextSelection selection) const = 0;
|
virtual TextWithEntities selectedText(TextSelection selection) const = 0;
|
||||||
|
|
||||||
bool hasPoint(int x, int y) const {
|
bool hasPoint(int x, int y) const {
|
||||||
|
@ -177,881 +153,22 @@ public:
|
||||||
return _width;
|
return _width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setInBubbleState(MediaInBubbleState state) {
|
||||||
|
_inBubbleState = state;
|
||||||
|
}
|
||||||
|
MediaInBubbleState inBubbleState() const {
|
||||||
|
return _inBubbleState;
|
||||||
|
}
|
||||||
|
bool isBubbleTop() const {
|
||||||
|
return (_inBubbleState == MediaInBubbleState::Top) || (_inBubbleState == MediaInBubbleState::None);
|
||||||
|
}
|
||||||
|
bool isBubbleBottom() const {
|
||||||
|
return (_inBubbleState == MediaInBubbleState::Bottom) || (_inBubbleState == MediaInBubbleState::None);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
HistoryItem *_parent;
|
HistoryItem *_parent;
|
||||||
int _width = 0;
|
int _width = 0;
|
||||||
|
MediaInBubbleState _inBubbleState = MediaInBubbleState::None;
|
||||||
};
|
|
||||||
|
|
||||||
class HistoryFileMedia : public HistoryMedia {
|
|
||||||
public:
|
|
||||||
using HistoryMedia::HistoryMedia;
|
|
||||||
|
|
||||||
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
|
|
||||||
return p == _openl || p == _savel || p == _cancell;
|
|
||||||
}
|
|
||||||
bool dragItemByHandler(const ClickHandlerPtr &p) const override {
|
|
||||||
return p == _openl || p == _savel || p == _cancell;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
|
||||||
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
|
|
||||||
|
|
||||||
~HistoryFileMedia();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
ClickHandlerPtr _openl, _savel, _cancell;
|
|
||||||
void setLinks(ClickHandlerPtr &&openl, ClickHandlerPtr &&savel, ClickHandlerPtr &&cancell);
|
|
||||||
void setDocumentLinks(DocumentData *document, bool inlinegif = false) {
|
|
||||||
ClickHandlerPtr open, save;
|
|
||||||
if (inlinegif) {
|
|
||||||
open.reset(new GifOpenClickHandler(document));
|
|
||||||
} else {
|
|
||||||
open.reset(new DocumentOpenClickHandler(document));
|
|
||||||
}
|
|
||||||
if (inlinegif) {
|
|
||||||
save.reset(new GifOpenClickHandler(document));
|
|
||||||
} else if (document->voice()) {
|
|
||||||
save.reset(new DocumentOpenClickHandler(document));
|
|
||||||
} else {
|
|
||||||
save.reset(new DocumentSaveClickHandler(document));
|
|
||||||
}
|
|
||||||
setLinks(std_::move(open), std_::move(save), MakeShared<DocumentCancelClickHandler>(document));
|
|
||||||
}
|
|
||||||
|
|
||||||
// >= 0 will contain download / upload string, _statusSize = loaded bytes
|
|
||||||
// < 0 will contain played string, _statusSize = -(seconds + 1) played
|
|
||||||
// 0x7FFFFFF0 will contain status for not yet downloaded file
|
|
||||||
// 0x7FFFFFF1 will contain status for already downloaded file
|
|
||||||
// 0x7FFFFFF2 will contain status for failed to download / upload file
|
|
||||||
mutable int32 _statusSize;
|
|
||||||
mutable QString _statusText;
|
|
||||||
|
|
||||||
// duration = -1 - no duration, duration = -2 - "GIF" duration
|
|
||||||
void setStatusSize(int32 newSize, int32 fullSize, int32 duration, qint64 realDuration) const;
|
|
||||||
|
|
||||||
void step_thumbOver(float64 ms, bool timer);
|
|
||||||
void step_radial(uint64 ms, bool timer);
|
|
||||||
|
|
||||||
void ensureAnimation() const;
|
|
||||||
void checkAnimationFinished();
|
|
||||||
|
|
||||||
bool isRadialAnimation(uint64 ms) const {
|
|
||||||
if (!_animation || !_animation->radial.animating()) return false;
|
|
||||||
|
|
||||||
_animation->radial.step(ms);
|
|
||||||
return _animation && _animation->radial.animating();
|
|
||||||
}
|
|
||||||
bool isThumbAnimation(uint64 ms) const {
|
|
||||||
if (!_animation || !_animation->_a_thumbOver.animating()) return false;
|
|
||||||
|
|
||||||
_animation->_a_thumbOver.step(ms);
|
|
||||||
return _animation && _animation->_a_thumbOver.animating();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual float64 dataProgress() const = 0;
|
|
||||||
virtual bool dataFinished() const = 0;
|
|
||||||
virtual bool dataLoaded() const = 0;
|
|
||||||
|
|
||||||
struct AnimationData {
|
|
||||||
AnimationData(AnimationCallbacks &&thumbOverCallbacks, AnimationCallbacks &&radialCallbacks) : a_thumbOver(0, 0)
|
|
||||||
, _a_thumbOver(std_::move(thumbOverCallbacks))
|
|
||||||
, radial(std_::move(radialCallbacks)) {
|
|
||||||
}
|
|
||||||
anim::fvalue a_thumbOver;
|
|
||||||
Animation _a_thumbOver;
|
|
||||||
|
|
||||||
RadialAnimation radial;
|
|
||||||
};
|
|
||||||
mutable AnimationData *_animation = nullptr;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class HistoryPhoto : public HistoryFileMedia {
|
|
||||||
public:
|
|
||||||
HistoryPhoto(HistoryItem *parent, PhotoData *photo, const QString &caption);
|
|
||||||
HistoryPhoto(HistoryItem *parent, PeerData *chat, const MTPDphoto &photo, int width);
|
|
||||||
HistoryPhoto(HistoryItem *parent, const HistoryPhoto &other);
|
|
||||||
|
|
||||||
void init();
|
|
||||||
HistoryMediaType type() const override {
|
|
||||||
return MediaTypePhoto;
|
|
||||||
}
|
|
||||||
HistoryPhoto *clone(HistoryItem *newParent) const override {
|
|
||||||
return new HistoryPhoto(newParent, *this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void initDimensions() override;
|
|
||||||
int resizeGetHeight(int width) override;
|
|
||||||
|
|
||||||
void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
|
|
||||||
HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
|
|
||||||
|
|
||||||
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override {
|
|
||||||
return _caption.adjustSelection(selection, type);
|
|
||||||
}
|
|
||||||
bool hasTextForCopy() const override {
|
|
||||||
return !_caption.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString notificationText() const override;
|
|
||||||
QString inDialogsText() const override;
|
|
||||||
TextWithEntities selectedText(TextSelection selection) const override;
|
|
||||||
|
|
||||||
PhotoData *photo() const {
|
|
||||||
return _data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateSentMedia(const MTPMessageMedia &media) override;
|
|
||||||
bool needReSetInlineResultMedia(const MTPMessageMedia &media) override;
|
|
||||||
|
|
||||||
void attachToParent() override;
|
|
||||||
void detachFromParent() override;
|
|
||||||
|
|
||||||
bool hasReplyPreview() const override {
|
|
||||||
return !_data->thumb->isNull();
|
|
||||||
}
|
|
||||||
ImagePtr replyPreview() override;
|
|
||||||
|
|
||||||
TextWithEntities getCaption() const override {
|
|
||||||
return _caption.originalTextWithEntities();
|
|
||||||
}
|
|
||||||
bool needsBubble() const override {
|
|
||||||
if (!_caption.isEmpty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (_parent->viaBot()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return (_parent->Has<HistoryMessageForwarded>() || _parent->Has<HistoryMessageReply>());
|
|
||||||
}
|
|
||||||
bool customInfoLayout() const override {
|
|
||||||
return _caption.isEmpty();
|
|
||||||
}
|
|
||||||
bool hideFromName() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
float64 dataProgress() const override {
|
|
||||||
return _data->progress();
|
|
||||||
}
|
|
||||||
bool dataFinished() const override {
|
|
||||||
return !_data->loading() && !_data->uploading();
|
|
||||||
}
|
|
||||||
bool dataLoaded() const override {
|
|
||||||
return _data->loaded();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
PhotoData *_data;
|
|
||||||
int16 _pixw = 1;
|
|
||||||
int16 _pixh = 1;
|
|
||||||
Text _caption;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class HistoryVideo : public HistoryFileMedia {
|
|
||||||
public:
|
|
||||||
HistoryVideo(HistoryItem *parent, DocumentData *document, const QString &caption);
|
|
||||||
HistoryVideo(HistoryItem *parent, const HistoryVideo &other);
|
|
||||||
HistoryMediaType type() const override {
|
|
||||||
return MediaTypeVideo;
|
|
||||||
}
|
|
||||||
HistoryVideo *clone(HistoryItem *newParent) const override {
|
|
||||||
return new HistoryVideo(newParent, *this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void initDimensions() override;
|
|
||||||
int resizeGetHeight(int width) override;
|
|
||||||
|
|
||||||
void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
|
|
||||||
HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
|
|
||||||
|
|
||||||
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override {
|
|
||||||
return _caption.adjustSelection(selection, type);
|
|
||||||
}
|
|
||||||
bool hasTextForCopy() const override {
|
|
||||||
return !_caption.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString notificationText() const override;
|
|
||||||
QString inDialogsText() const override;
|
|
||||||
TextWithEntities selectedText(TextSelection selection) const override;
|
|
||||||
|
|
||||||
DocumentData *getDocument() override {
|
|
||||||
return _data;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool uploading() const override {
|
|
||||||
return _data->uploading();
|
|
||||||
}
|
|
||||||
|
|
||||||
void attachToParent() override;
|
|
||||||
void detachFromParent() override;
|
|
||||||
|
|
||||||
bool needReSetInlineResultMedia(const MTPMessageMedia &media) override;
|
|
||||||
|
|
||||||
bool hasReplyPreview() const override {
|
|
||||||
return !_data->thumb->isNull();
|
|
||||||
}
|
|
||||||
ImagePtr replyPreview() override;
|
|
||||||
|
|
||||||
TextWithEntities getCaption() const override {
|
|
||||||
return _caption.originalTextWithEntities();
|
|
||||||
}
|
|
||||||
bool needsBubble() const override {
|
|
||||||
if (!_caption.isEmpty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (_parent->viaBot()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return (_parent->Has<HistoryMessageForwarded>() || _parent->Has<HistoryMessageReply>());
|
|
||||||
}
|
|
||||||
bool customInfoLayout() const override {
|
|
||||||
return _caption.isEmpty();
|
|
||||||
}
|
|
||||||
bool hideFromName() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
float64 dataProgress() const override {
|
|
||||||
return _data->progress();
|
|
||||||
}
|
|
||||||
bool dataFinished() const override {
|
|
||||||
return !_data->loading() && !_data->uploading();
|
|
||||||
}
|
|
||||||
bool dataLoaded() const override {
|
|
||||||
return _data->loaded();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
DocumentData *_data;
|
|
||||||
int32 _thumbw;
|
|
||||||
Text _caption;
|
|
||||||
|
|
||||||
void setStatusSize(int32 newSize) const;
|
|
||||||
void updateStatusText() const;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct HistoryDocumentThumbed : public BaseComponent<HistoryDocumentThumbed> {
|
|
||||||
ClickHandlerPtr _linksavel, _linkcancell;
|
|
||||||
int _thumbw = 0;
|
|
||||||
|
|
||||||
mutable int _linkw = 0;
|
|
||||||
mutable QString _link;
|
|
||||||
};
|
|
||||||
struct HistoryDocumentCaptioned : public BaseComponent<HistoryDocumentCaptioned> {
|
|
||||||
Text _caption = { int(st::msgFileMinWidth) - st::msgPadding.left() - st::msgPadding.right() };
|
|
||||||
};
|
|
||||||
struct HistoryDocumentNamed : public BaseComponent<HistoryDocumentNamed> {
|
|
||||||
QString _name;
|
|
||||||
int _namew = 0;
|
|
||||||
};
|
|
||||||
class HistoryDocument;
|
|
||||||
struct HistoryDocumentVoicePlayback {
|
|
||||||
HistoryDocumentVoicePlayback(const HistoryDocument *that);
|
|
||||||
|
|
||||||
int32 _position;
|
|
||||||
anim::fvalue a_progress;
|
|
||||||
Animation _a_progress;
|
|
||||||
};
|
|
||||||
struct HistoryDocumentVoice : public BaseComponent<HistoryDocumentVoice> {
|
|
||||||
HistoryDocumentVoice &operator=(HistoryDocumentVoice &&other) {
|
|
||||||
std::swap(_playback, other._playback);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
~HistoryDocumentVoice() {
|
|
||||||
deleteAndMark(_playback);
|
|
||||||
}
|
|
||||||
void ensurePlayback(const HistoryDocument *interfaces) const;
|
|
||||||
void checkPlaybackFinished() const;
|
|
||||||
mutable HistoryDocumentVoicePlayback *_playback = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HistoryDocument : public HistoryFileMedia, public Composer {
|
|
||||||
public:
|
|
||||||
HistoryDocument(HistoryItem *parent, DocumentData *document, const QString &caption);
|
|
||||||
HistoryDocument(HistoryItem *parent, const HistoryDocument &other);
|
|
||||||
HistoryMediaType type() const override {
|
|
||||||
return _data->voice() ? MediaTypeVoiceFile : (_data->song() ? MediaTypeMusicFile : MediaTypeFile);
|
|
||||||
}
|
|
||||||
HistoryDocument *clone(HistoryItem *newParent) const override {
|
|
||||||
return new HistoryDocument(newParent, *this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void initDimensions() override;
|
|
||||||
int resizeGetHeight(int width) override;
|
|
||||||
|
|
||||||
void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
|
|
||||||
HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
|
|
||||||
|
|
||||||
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override {
|
|
||||||
if (auto captioned = Get<HistoryDocumentCaptioned>()) {
|
|
||||||
return captioned->_caption.adjustSelection(selection, type);
|
|
||||||
}
|
|
||||||
return selection;
|
|
||||||
}
|
|
||||||
bool hasTextForCopy() const override {
|
|
||||||
return Has<HistoryDocumentCaptioned>();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString notificationText() const override;
|
|
||||||
QString inDialogsText() const override;
|
|
||||||
TextWithEntities selectedText(TextSelection selection) const override;
|
|
||||||
|
|
||||||
bool uploading() const override {
|
|
||||||
return _data->uploading();
|
|
||||||
}
|
|
||||||
|
|
||||||
DocumentData *getDocument() override {
|
|
||||||
return _data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void attachToParent() override;
|
|
||||||
void detachFromParent() override;
|
|
||||||
|
|
||||||
void updateSentMedia(const MTPMessageMedia &media) override;
|
|
||||||
bool needReSetInlineResultMedia(const MTPMessageMedia &media) override;
|
|
||||||
|
|
||||||
bool hasReplyPreview() const override {
|
|
||||||
return !_data->thumb->isNull();
|
|
||||||
}
|
|
||||||
ImagePtr replyPreview() override;
|
|
||||||
|
|
||||||
TextWithEntities getCaption() const override {
|
|
||||||
if (const HistoryDocumentCaptioned *captioned = Get<HistoryDocumentCaptioned>()) {
|
|
||||||
return captioned->_caption.originalTextWithEntities();
|
|
||||||
}
|
|
||||||
return TextWithEntities();
|
|
||||||
}
|
|
||||||
bool needsBubble() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool customInfoLayout() const override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
QMargins bubbleMargins() const override {
|
|
||||||
return Get<HistoryDocumentThumbed>() ? QMargins(st::msgFileThumbPadding.left(), st::msgFileThumbPadding.top(), st::msgFileThumbPadding.left(), st::msgFileThumbPadding.bottom()) : st::msgPadding;
|
|
||||||
}
|
|
||||||
bool hideForwardedFrom() const override {
|
|
||||||
return _data->song();
|
|
||||||
}
|
|
||||||
|
|
||||||
void step_voiceProgress(float64 ms, bool timer);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
float64 dataProgress() const override {
|
|
||||||
return _data->progress();
|
|
||||||
}
|
|
||||||
bool dataFinished() const override {
|
|
||||||
return !_data->loading() && !_data->uploading();
|
|
||||||
}
|
|
||||||
bool dataLoaded() const override {
|
|
||||||
return _data->loaded();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void createComponents(bool caption);
|
|
||||||
|
|
||||||
void setStatusSize(int32 newSize, qint64 realDuration = 0) const;
|
|
||||||
bool updateStatusText() const; // returns showPause
|
|
||||||
|
|
||||||
// Callback is a void(const QString &, const QString &, const Text &) functor.
|
|
||||||
// It will be called as callback(attachType, attachFileName, attachCaption).
|
|
||||||
template <typename Callback>
|
|
||||||
void buildStringRepresentation(Callback callback) const;
|
|
||||||
|
|
||||||
DocumentData *_data;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class HistoryGif : public HistoryFileMedia {
|
|
||||||
public:
|
|
||||||
HistoryGif(HistoryItem *parent, DocumentData *document, const QString &caption);
|
|
||||||
HistoryGif(HistoryItem *parent, const HistoryGif &other);
|
|
||||||
HistoryMediaType type() const override {
|
|
||||||
return MediaTypeGif;
|
|
||||||
}
|
|
||||||
HistoryGif *clone(HistoryItem *newParent) const override {
|
|
||||||
return new HistoryGif(newParent, *this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void initDimensions() override;
|
|
||||||
int resizeGetHeight(int width) override;
|
|
||||||
|
|
||||||
void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
|
|
||||||
HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
|
|
||||||
|
|
||||||
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override {
|
|
||||||
return _caption.adjustSelection(selection, type);
|
|
||||||
}
|
|
||||||
bool hasTextForCopy() const override {
|
|
||||||
return !_caption.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString notificationText() const override;
|
|
||||||
QString inDialogsText() const override;
|
|
||||||
TextWithEntities selectedText(TextSelection selection) const override;
|
|
||||||
|
|
||||||
bool uploading() const override {
|
|
||||||
return _data->uploading();
|
|
||||||
}
|
|
||||||
|
|
||||||
DocumentData *getDocument() override {
|
|
||||||
return _data;
|
|
||||||
}
|
|
||||||
Media::Clip::Reader *getClipReader() override {
|
|
||||||
return gif();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool playInline(bool autoplay) override;
|
|
||||||
void stopInline() override;
|
|
||||||
|
|
||||||
void attachToParent() override;
|
|
||||||
void detachFromParent() override;
|
|
||||||
|
|
||||||
void updateSentMedia(const MTPMessageMedia &media) override;
|
|
||||||
bool needReSetInlineResultMedia(const MTPMessageMedia &media) override;
|
|
||||||
|
|
||||||
bool hasReplyPreview() const override {
|
|
||||||
return !_data->thumb->isNull();
|
|
||||||
}
|
|
||||||
ImagePtr replyPreview() override;
|
|
||||||
|
|
||||||
TextWithEntities getCaption() const override {
|
|
||||||
return _caption.originalTextWithEntities();
|
|
||||||
}
|
|
||||||
bool needsBubble() const override {
|
|
||||||
if (!_caption.isEmpty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (_parent->viaBot()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return (_parent->Has<HistoryMessageForwarded>() || _parent->Has<HistoryMessageReply>());
|
|
||||||
}
|
|
||||||
bool customInfoLayout() const override {
|
|
||||||
return _caption.isEmpty();
|
|
||||||
}
|
|
||||||
bool hideFromName() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
~HistoryGif();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
float64 dataProgress() const override;
|
|
||||||
bool dataFinished() const override;
|
|
||||||
bool dataLoaded() const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
DocumentData *_data;
|
|
||||||
int32 _thumbw, _thumbh;
|
|
||||||
Text _caption;
|
|
||||||
|
|
||||||
Media::Clip::Reader *_gif;
|
|
||||||
Media::Clip::Reader *gif() {
|
|
||||||
return (_gif == Media::Clip::BadReader) ? nullptr : _gif;
|
|
||||||
}
|
|
||||||
const Media::Clip::Reader *gif() const {
|
|
||||||
return (_gif == Media::Clip::BadReader) ? nullptr : _gif;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setStatusSize(int32 newSize) const;
|
|
||||||
void updateStatusText() const;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class HistorySticker : public HistoryMedia {
|
|
||||||
public:
|
|
||||||
HistorySticker(HistoryItem *parent, DocumentData *document);
|
|
||||||
HistoryMediaType type() const override {
|
|
||||||
return MediaTypeSticker;
|
|
||||||
}
|
|
||||||
HistorySticker *clone(HistoryItem *newParent) const override {
|
|
||||||
return new HistorySticker(newParent, _data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void initDimensions() override;
|
|
||||||
int resizeGetHeight(int width) override;
|
|
||||||
|
|
||||||
void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
|
|
||||||
HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
|
|
||||||
|
|
||||||
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool dragItem() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool dragItemByHandler(const ClickHandlerPtr &p) const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString notificationText() const override;
|
|
||||||
TextWithEntities selectedText(TextSelection selection) const override;
|
|
||||||
|
|
||||||
DocumentData *getDocument() override {
|
|
||||||
return _data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void attachToParent() override;
|
|
||||||
void detachFromParent() override;
|
|
||||||
|
|
||||||
void updateSentMedia(const MTPMessageMedia &media) override;
|
|
||||||
bool needReSetInlineResultMedia(const MTPMessageMedia &media) override;
|
|
||||||
|
|
||||||
bool needsBubble() const override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool customInfoLayout() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int additionalWidth(const HistoryMessageVia *via, const HistoryMessageReply *reply) const;
|
|
||||||
int additionalWidth() const {
|
|
||||||
return additionalWidth(_parent->Get<HistoryMessageVia>(), _parent->Get<HistoryMessageReply>());
|
|
||||||
}
|
|
||||||
QString toString() const;
|
|
||||||
|
|
||||||
int16 _pixw, _pixh;
|
|
||||||
ClickHandlerPtr _packLink;
|
|
||||||
DocumentData *_data;
|
|
||||||
QString _emoji;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class SendMessageClickHandler : public PeerClickHandler {
|
|
||||||
public:
|
|
||||||
using PeerClickHandler::PeerClickHandler;
|
|
||||||
protected:
|
|
||||||
void onClickImpl() const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AddContactClickHandler : public MessageClickHandler {
|
|
||||||
public:
|
|
||||||
using MessageClickHandler::MessageClickHandler;
|
|
||||||
protected:
|
|
||||||
void onClickImpl() const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HistoryContact : public HistoryMedia {
|
|
||||||
public:
|
|
||||||
HistoryContact(HistoryItem *parent, int32 userId, const QString &first, const QString &last, const QString &phone);
|
|
||||||
HistoryMediaType type() const override {
|
|
||||||
return MediaTypeContact;
|
|
||||||
}
|
|
||||||
HistoryContact *clone(HistoryItem *newParent) const override {
|
|
||||||
return new HistoryContact(newParent, _userId, _fname, _lname, _phone);
|
|
||||||
}
|
|
||||||
|
|
||||||
void initDimensions() override;
|
|
||||||
|
|
||||||
void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
|
|
||||||
HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
|
|
||||||
|
|
||||||
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool dragItemByHandler(const ClickHandlerPtr &p) const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString notificationText() const override;
|
|
||||||
TextWithEntities selectedText(TextSelection selection) const override;
|
|
||||||
|
|
||||||
void attachToParent() override;
|
|
||||||
void detachFromParent() override;
|
|
||||||
|
|
||||||
void updateSentMedia(const MTPMessageMedia &media) override;
|
|
||||||
|
|
||||||
bool needsBubble() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool customInfoLayout() const override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString &fname() const {
|
|
||||||
return _fname;
|
|
||||||
}
|
|
||||||
const QString &lname() const {
|
|
||||||
return _lname;
|
|
||||||
}
|
|
||||||
const QString &phone() const {
|
|
||||||
return _phone;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
int32 _userId;
|
|
||||||
UserData *_contact;
|
|
||||||
|
|
||||||
int32 _phonew;
|
|
||||||
QString _fname, _lname, _phone;
|
|
||||||
Text _name;
|
|
||||||
|
|
||||||
ClickHandlerPtr _linkl;
|
|
||||||
int32 _linkw;
|
|
||||||
QString _link;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HistoryWebPage : public HistoryMedia {
|
|
||||||
public:
|
|
||||||
HistoryWebPage(HistoryItem *parent, WebPageData *data);
|
|
||||||
HistoryWebPage(HistoryItem *parent, const HistoryWebPage &other);
|
|
||||||
HistoryMediaType type() const override {
|
|
||||||
return MediaTypeWebPage;
|
|
||||||
}
|
|
||||||
HistoryWebPage *clone(HistoryItem *newParent) const override {
|
|
||||||
return new HistoryWebPage(newParent, *this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void initDimensions() override;
|
|
||||||
int resizeGetHeight(int width) override;
|
|
||||||
|
|
||||||
void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
|
|
||||||
HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
|
|
||||||
|
|
||||||
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override;
|
|
||||||
bool hasTextForCopy() const override {
|
|
||||||
return false; // we do not add _title and _description in FullSelection text copy.
|
|
||||||
}
|
|
||||||
|
|
||||||
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
|
|
||||||
return _attach && _attach->toggleSelectionByHandlerClick(p);
|
|
||||||
}
|
|
||||||
bool dragItemByHandler(const ClickHandlerPtr &p) const override {
|
|
||||||
return _attach && _attach->dragItemByHandler(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextWithEntities selectedText(TextSelection selection) const override;
|
|
||||||
|
|
||||||
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
|
||||||
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
|
|
||||||
|
|
||||||
bool isDisplayed() const override {
|
|
||||||
return !_data->pendingTill;
|
|
||||||
}
|
|
||||||
DocumentData *getDocument() override {
|
|
||||||
return _attach ? _attach->getDocument() : 0;
|
|
||||||
}
|
|
||||||
Media::Clip::Reader *getClipReader() override {
|
|
||||||
return _attach ? _attach->getClipReader() : 0;
|
|
||||||
}
|
|
||||||
bool playInline(bool autoplay) override {
|
|
||||||
return _attach ? _attach->playInline(autoplay) : false;
|
|
||||||
}
|
|
||||||
void stopInline() override {
|
|
||||||
if (_attach) _attach->stopInline();
|
|
||||||
}
|
|
||||||
|
|
||||||
void attachToParent() override;
|
|
||||||
void detachFromParent() override;
|
|
||||||
|
|
||||||
bool hasReplyPreview() const override {
|
|
||||||
return (_data->photo && !_data->photo->thumb->isNull()) || (_data->document && !_data->document->thumb->isNull());
|
|
||||||
}
|
|
||||||
ImagePtr replyPreview() override;
|
|
||||||
|
|
||||||
WebPageData *webpage() {
|
|
||||||
return _data;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool needsBubble() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool customInfoLayout() const override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
HistoryMedia *attach() const {
|
|
||||||
return _attach.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
TextSelection toDescriptionSelection(TextSelection selection) const {
|
|
||||||
return internal::unshiftSelection(selection, _title);
|
|
||||||
}
|
|
||||||
TextSelection fromDescriptionSelection(TextSelection selection) const {
|
|
||||||
return internal::shiftSelection(selection, _title);
|
|
||||||
}
|
|
||||||
|
|
||||||
WebPageData *_data;
|
|
||||||
ClickHandlerPtr _openl;
|
|
||||||
std_::unique_ptr<HistoryMedia> _attach;
|
|
||||||
|
|
||||||
bool _asArticle = false;
|
|
||||||
int32 _titleLines, _descriptionLines;
|
|
||||||
|
|
||||||
Text _title, _description;
|
|
||||||
int32 _siteNameWidth = 0;
|
|
||||||
|
|
||||||
QString _duration;
|
|
||||||
int32 _durationWidth = 0;
|
|
||||||
|
|
||||||
int16 _pixw = 0;
|
|
||||||
int16 _pixh = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HistoryGame : public HistoryMedia {
|
|
||||||
public:
|
|
||||||
HistoryGame(HistoryItem *parent, GameData *data);
|
|
||||||
HistoryGame(HistoryItem *parent, const HistoryGame &other);
|
|
||||||
HistoryMediaType type() const override {
|
|
||||||
return MediaTypeGame;
|
|
||||||
}
|
|
||||||
HistoryGame *clone(HistoryItem *newParent) const override {
|
|
||||||
return new HistoryGame(newParent, *this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void initDimensions() override;
|
|
||||||
int resizeGetHeight(int width) override;
|
|
||||||
|
|
||||||
void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
|
|
||||||
HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
|
|
||||||
|
|
||||||
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override;
|
|
||||||
bool isAboveMessage() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool hasTextForCopy() const override {
|
|
||||||
return false; // we do not add _title and _description in FullSelection text copy.
|
|
||||||
}
|
|
||||||
|
|
||||||
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
|
|
||||||
return _attach && _attach->toggleSelectionByHandlerClick(p);
|
|
||||||
}
|
|
||||||
bool dragItemByHandler(const ClickHandlerPtr &p) const override {
|
|
||||||
return _attach && _attach->dragItemByHandler(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextWithEntities selectedText(TextSelection selection) const override;
|
|
||||||
|
|
||||||
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
|
||||||
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
|
|
||||||
|
|
||||||
DocumentData *getDocument() override {
|
|
||||||
return _attach ? _attach->getDocument() : nullptr;
|
|
||||||
}
|
|
||||||
Media::Clip::Reader *getClipReader() override {
|
|
||||||
return _attach ? _attach->getClipReader() : nullptr;
|
|
||||||
}
|
|
||||||
bool playInline(bool autoplay) override {
|
|
||||||
return _attach ? _attach->playInline(autoplay) : false;
|
|
||||||
}
|
|
||||||
void stopInline() override {
|
|
||||||
if (_attach) _attach->stopInline();
|
|
||||||
}
|
|
||||||
|
|
||||||
void attachToParent() override;
|
|
||||||
void detachFromParent() override;
|
|
||||||
|
|
||||||
bool hasReplyPreview() const override {
|
|
||||||
return (_data->photo && !_data->photo->thumb->isNull()) || (_data->document && !_data->document->thumb->isNull());
|
|
||||||
}
|
|
||||||
ImagePtr replyPreview() override;
|
|
||||||
|
|
||||||
GameData *game() {
|
|
||||||
return _data;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool needsBubble() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool customInfoLayout() const override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
HistoryMedia *attach() const {
|
|
||||||
return _attach.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
TextSelection toDescriptionSelection(TextSelection selection) const {
|
|
||||||
return internal::unshiftSelection(selection, _title);
|
|
||||||
}
|
|
||||||
TextSelection fromDescriptionSelection(TextSelection selection) const {
|
|
||||||
return internal::shiftSelection(selection, _title);
|
|
||||||
}
|
|
||||||
|
|
||||||
GameData *_data;
|
|
||||||
ClickHandlerPtr _openl;
|
|
||||||
std_::unique_ptr<HistoryMedia> _attach;
|
|
||||||
|
|
||||||
int32 _titleLines, _descriptionLines;
|
|
||||||
|
|
||||||
Text _title, _description;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct LocationCoords;
|
|
||||||
struct LocationData;
|
|
||||||
|
|
||||||
class HistoryLocation : public HistoryMedia {
|
|
||||||
public:
|
|
||||||
HistoryLocation(HistoryItem *parent, const LocationCoords &coords, const QString &title = QString(), const QString &description = QString());
|
|
||||||
HistoryLocation(HistoryItem *parent, const HistoryLocation &other);
|
|
||||||
HistoryMediaType type() const override {
|
|
||||||
return MediaTypeLocation;
|
|
||||||
}
|
|
||||||
HistoryLocation *clone(HistoryItem *newParent) const override {
|
|
||||||
return new HistoryLocation(newParent, *this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void initDimensions() override;
|
|
||||||
int resizeGetHeight(int32 width) override;
|
|
||||||
|
|
||||||
void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
|
|
||||||
HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
|
|
||||||
|
|
||||||
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override;
|
|
||||||
bool hasTextForCopy() const override {
|
|
||||||
return !_title.isEmpty() || !_description.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
|
|
||||||
return p == _link;
|
|
||||||
}
|
|
||||||
bool dragItemByHandler(const ClickHandlerPtr &p) const override {
|
|
||||||
return p == _link;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString notificationText() const override;
|
|
||||||
QString inDialogsText() const override;
|
|
||||||
TextWithEntities selectedText(TextSelection selection) const override;
|
|
||||||
|
|
||||||
bool needsBubble() const override {
|
|
||||||
if (!_title.isEmpty() || !_description.isEmpty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (_parent->viaBot()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return (_parent->Has<HistoryMessageForwarded>() || _parent->Has<HistoryMessageReply>());
|
|
||||||
}
|
|
||||||
bool customInfoLayout() const override {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
TextSelection toDescriptionSelection(TextSelection selection) const {
|
|
||||||
return internal::unshiftSelection(selection, _title);
|
|
||||||
}
|
|
||||||
TextSelection fromDescriptionSelection(TextSelection selection) const {
|
|
||||||
return internal::shiftSelection(selection, _title);
|
|
||||||
}
|
|
||||||
|
|
||||||
LocationData *_data;
|
|
||||||
Text _title, _description;
|
|
||||||
ClickHandlerPtr _link;
|
|
||||||
|
|
||||||
int32 fullWidth() const;
|
|
||||||
int32 fullHeight() const;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,7 +19,7 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "history/history_media.h"
|
#include "history/history_media_types.h"
|
||||||
|
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
|
@ -86,81 +86,6 @@ void historyInitMedia() {
|
||||||
initTextOptions();
|
initTextOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
RadialAnimation::RadialAnimation(AnimationCallbacks &&callbacks)
|
|
||||||
: a_arcEnd(0, 0)
|
|
||||||
, a_arcStart(0, FullArcLength)
|
|
||||||
, _animation(std_::move(callbacks)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void RadialAnimation::start(float64 prg) {
|
|
||||||
_firstStart = _lastStart = _lastTime = getms();
|
|
||||||
int32 iprg = qRound(qMax(prg, 0.0001) * AlmostFullArcLength), iprgstrict = qRound(prg * AlmostFullArcLength);
|
|
||||||
a_arcEnd = anim::ivalue(iprgstrict, iprg);
|
|
||||||
_animation.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RadialAnimation::update(float64 prg, bool finished, uint64 ms) {
|
|
||||||
int32 iprg = qRound(qMax(prg, 0.0001) * AlmostFullArcLength);
|
|
||||||
if (iprg != a_arcEnd.to()) {
|
|
||||||
a_arcEnd.start(iprg);
|
|
||||||
_lastStart = _lastTime;
|
|
||||||
}
|
|
||||||
_lastTime = ms;
|
|
||||||
|
|
||||||
float64 dt = float64(ms - _lastStart), fulldt = float64(ms - _firstStart);
|
|
||||||
_opacity = qMin(fulldt / st::radialDuration, 1.);
|
|
||||||
if (!finished) {
|
|
||||||
a_arcEnd.update(1. - (st::radialDuration / (st::radialDuration + dt)), anim::linear);
|
|
||||||
} else if (dt >= st::radialDuration) {
|
|
||||||
a_arcEnd.update(1, anim::linear);
|
|
||||||
stop();
|
|
||||||
} else {
|
|
||||||
float64 r = dt / st::radialDuration;
|
|
||||||
a_arcEnd.update(r, anim::linear);
|
|
||||||
_opacity *= 1 - r;
|
|
||||||
}
|
|
||||||
float64 fromstart = fulldt / st::radialPeriod;
|
|
||||||
a_arcStart.update(fromstart - std::floor(fromstart), anim::linear);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RadialAnimation::stop() {
|
|
||||||
_firstStart = _lastStart = _lastTime = 0;
|
|
||||||
a_arcEnd = anim::ivalue(0, 0);
|
|
||||||
_animation.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RadialAnimation::step(uint64 ms) {
|
|
||||||
_animation.step(ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RadialAnimation::draw(Painter &p, const QRect &inner, int32 thickness, const style::color &color) {
|
|
||||||
float64 o = p.opacity();
|
|
||||||
p.setOpacity(o * _opacity);
|
|
||||||
|
|
||||||
QPen pen(color->p), was(p.pen());
|
|
||||||
pen.setWidth(thickness);
|
|
||||||
p.setPen(pen);
|
|
||||||
|
|
||||||
int32 len = MinArcLength + a_arcEnd.current();
|
|
||||||
int32 from = QuarterArcLength - a_arcStart.current() - len;
|
|
||||||
if (rtl()) {
|
|
||||||
from = QuarterArcLength - (from - QuarterArcLength) - len;
|
|
||||||
if (from < 0) from += FullArcLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
|
||||||
p.drawArc(inner, from, len);
|
|
||||||
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
|
|
||||||
|
|
||||||
p.setPen(was);
|
|
||||||
p.setOpacity(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString HistoryMedia::inDialogsText() const {
|
|
||||||
auto result = notificationText();
|
|
||||||
return result.isEmpty() ? QString() : textcmdLink(1, textClean(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
int32 documentMaxStatusWidth(DocumentData *document) {
|
int32 documentMaxStatusWidth(DocumentData *document) {
|
||||||
|
@ -371,7 +296,11 @@ void HistoryPhoto::initDimensions() {
|
||||||
_maxw += st::mediaPadding.left() + st::mediaPadding.right();
|
_maxw += st::mediaPadding.left() + st::mediaPadding.right();
|
||||||
_minh += st::mediaPadding.top() + st::mediaPadding.bottom();
|
_minh += st::mediaPadding.top() + st::mediaPadding.bottom();
|
||||||
if (!_caption.isEmpty()) {
|
if (!_caption.isEmpty()) {
|
||||||
_minh += st::mediaCaptionSkip + _caption.countHeight(maxActualWidth - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom();
|
auto captionw = maxActualWidth - st::msgPadding.left() - st::msgPadding.right();
|
||||||
|
_minh += st::mediaCaptionSkip + _caption.countHeight(captionw);
|
||||||
|
if (isBubbleBottom()) {
|
||||||
|
_minh += st::msgPadding.bottom();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -417,7 +346,10 @@ int HistoryPhoto::resizeGetHeight(int width) {
|
||||||
_height += st::mediaPadding.top() + st::mediaPadding.bottom();
|
_height += st::mediaPadding.top() + st::mediaPadding.bottom();
|
||||||
if (!_caption.isEmpty()) {
|
if (!_caption.isEmpty()) {
|
||||||
int captionw = _width - st::msgPadding.left() - st::msgPadding.right();
|
int captionw = _width - st::msgPadding.left() - st::msgPadding.right();
|
||||||
_height += st::mediaCaptionSkip + _caption.countHeight(captionw) + st::msgPadding.bottom();
|
_height += st::mediaCaptionSkip + _caption.countHeight(captionw);
|
||||||
|
if (isBubbleBottom()) {
|
||||||
|
_height += st::msgPadding.bottom();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _height;
|
return _height;
|
||||||
|
@ -425,7 +357,6 @@ int HistoryPhoto::resizeGetHeight(int width) {
|
||||||
|
|
||||||
void HistoryPhoto::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const {
|
void HistoryPhoto::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const {
|
||||||
if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return;
|
if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return;
|
||||||
p.fillRect(QRect(0, 0, _width, _height), QColor(128, 255, 128));
|
|
||||||
|
|
||||||
_data->automaticLoad(_parent);
|
_data->automaticLoad(_parent);
|
||||||
bool selected = (selection == FullSelection);
|
bool selected = (selection == FullSelection);
|
||||||
|
@ -453,7 +384,10 @@ void HistoryPhoto::draw(Painter &p, const QRect &r, TextSelection selection, uin
|
||||||
width -= st::mediaPadding.left() + st::mediaPadding.right();
|
width -= st::mediaPadding.left() + st::mediaPadding.right();
|
||||||
height -= skipy + st::mediaPadding.bottom();
|
height -= skipy + st::mediaPadding.bottom();
|
||||||
if (!_caption.isEmpty()) {
|
if (!_caption.isEmpty()) {
|
||||||
height -= st::mediaCaptionSkip + _caption.countHeight(captionw) + st::msgPadding.bottom();
|
height -= st::mediaCaptionSkip + _caption.countHeight(captionw);
|
||||||
|
if (isBubbleBottom()) {
|
||||||
|
height -= st::msgPadding.bottom();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
App::roundShadow(p, 0, 0, width, height, selected ? st::msgInShadowSelected : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners);
|
App::roundShadow(p, 0, 0, width, height, selected ? st::msgInShadowSelected : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners);
|
||||||
|
@ -470,7 +404,8 @@ void HistoryPhoto::draw(Painter &p, const QRect &r, TextSelection selection, uin
|
||||||
QRect rthumb(rtlrect(skipx, skipy, width, height, _width));
|
QRect rthumb(rtlrect(skipx, skipy, width, height, _width));
|
||||||
p.drawPixmap(rthumb.topLeft(), pix);
|
p.drawPixmap(rthumb.topLeft(), pix);
|
||||||
if (selected) {
|
if (selected) {
|
||||||
App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, SelectedOverlayLargeCorners);
|
auto overlayCorners = inWebPage ? SelectedOverlaySmallCorners : SelectedOverlayLargeCorners;
|
||||||
|
App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, overlayCorners);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notChild && (radial || (!loaded && !_data->loading()))) {
|
if (notChild && (radial || (!loaded && !_data->loading()))) {
|
||||||
|
@ -540,7 +475,10 @@ HistoryTextState HistoryPhoto::getState(int x, int y, HistoryStateRequest reques
|
||||||
skipy = st::mediaPadding.top();
|
skipy = st::mediaPadding.top();
|
||||||
if (!_caption.isEmpty()) {
|
if (!_caption.isEmpty()) {
|
||||||
int captionw = width - st::msgPadding.left() - st::msgPadding.right();
|
int captionw = width - st::msgPadding.left() - st::msgPadding.right();
|
||||||
height -= _caption.countHeight(captionw) + st::msgPadding.bottom();
|
height -= _caption.countHeight(captionw);
|
||||||
|
if (isBubbleBottom()) {
|
||||||
|
height -= st::msgPadding.bottom();
|
||||||
|
}
|
||||||
if (x >= st::msgPadding.left() && y >= height && x < st::msgPadding.left() + captionw && y < _height) {
|
if (x >= st::msgPadding.left() && y >= height && x < st::msgPadding.left() + captionw && y < _height) {
|
||||||
result = _caption.getState(x - st::msgPadding.left(), y - height, captionw, request.forText());
|
result = _caption.getState(x - st::msgPadding.left(), y - height, captionw, request.forText());
|
||||||
return result;
|
return result;
|
||||||
|
@ -712,7 +650,11 @@ void HistoryVideo::initDimensions() {
|
||||||
_maxw += st::mediaPadding.left() + st::mediaPadding.right();
|
_maxw += st::mediaPadding.left() + st::mediaPadding.right();
|
||||||
_minh += st::mediaPadding.top() + st::mediaPadding.bottom();
|
_minh += st::mediaPadding.top() + st::mediaPadding.bottom();
|
||||||
if (!_caption.isEmpty()) {
|
if (!_caption.isEmpty()) {
|
||||||
_minh += st::mediaCaptionSkip + _caption.countHeight(_maxw - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom();
|
auto captionw = _maxw - st::msgPadding.left() - st::msgPadding.right();
|
||||||
|
_minh += st::mediaCaptionSkip + _caption.countHeight(captionw);
|
||||||
|
if (isBubbleBottom()) {
|
||||||
|
_minh += st::msgPadding.bottom();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -750,7 +692,10 @@ int HistoryVideo::resizeGetHeight(int width) {
|
||||||
_height += st::mediaPadding.top() + st::mediaPadding.bottom();
|
_height += st::mediaPadding.top() + st::mediaPadding.bottom();
|
||||||
if (!_caption.isEmpty()) {
|
if (!_caption.isEmpty()) {
|
||||||
int captionw = _width - st::msgPadding.left() - st::msgPadding.right();
|
int captionw = _width - st::msgPadding.left() - st::msgPadding.right();
|
||||||
_height += st::mediaCaptionSkip + _caption.countHeight(captionw) + st::msgPadding.bottom();
|
_height += st::mediaCaptionSkip + _caption.countHeight(captionw);
|
||||||
|
if (isBubbleBottom()) {
|
||||||
|
_height += st::msgPadding.bottom();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _height;
|
return _height;
|
||||||
|
@ -785,16 +730,22 @@ void HistoryVideo::draw(Painter &p, const QRect &r, TextSelection selection, uin
|
||||||
width -= st::mediaPadding.left() + st::mediaPadding.right();
|
width -= st::mediaPadding.left() + st::mediaPadding.right();
|
||||||
height -= skipy + st::mediaPadding.bottom();
|
height -= skipy + st::mediaPadding.bottom();
|
||||||
if (!_caption.isEmpty()) {
|
if (!_caption.isEmpty()) {
|
||||||
height -= st::mediaCaptionSkip + _caption.countHeight(captionw) + st::msgPadding.bottom();
|
height -= st::mediaCaptionSkip + _caption.countHeight(captionw);
|
||||||
|
if (isBubbleBottom()) {
|
||||||
|
height -= st::msgPadding.bottom();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
App::roundShadow(p, 0, 0, width, height, selected ? st::msgInShadowSelected : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners);
|
App::roundShadow(p, 0, 0, width, height, selected ? st::msgInShadowSelected : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto inWebPage = (_parent->getMedia() != this);
|
||||||
|
auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large;
|
||||||
QRect rthumb(rtlrect(skipx, skipy, width, height, _width));
|
QRect rthumb(rtlrect(skipx, skipy, width, height, _width));
|
||||||
p.drawPixmap(rthumb.topLeft(), _data->thumb->pixBlurredSingle(ImageRoundRadius::Large, _thumbw, 0, width, height));
|
p.drawPixmap(rthumb.topLeft(), _data->thumb->pixBlurredSingle(roundRadius, _thumbw, 0, width, height));
|
||||||
if (selected) {
|
if (selected) {
|
||||||
App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, SelectedOverlayLargeCorners);
|
auto overlayCorners = inWebPage ? SelectedOverlaySmallCorners : SelectedOverlayLargeCorners;
|
||||||
|
App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, overlayCorners);
|
||||||
}
|
}
|
||||||
|
|
||||||
QRect inner(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
|
QRect inner(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
|
||||||
|
@ -866,8 +817,11 @@ HistoryTextState HistoryVideo::getState(int x, int y, HistoryStateRequest reques
|
||||||
skipx = st::mediaPadding.left();
|
skipx = st::mediaPadding.left();
|
||||||
skipy = st::mediaPadding.top();
|
skipy = st::mediaPadding.top();
|
||||||
if (!_caption.isEmpty()) {
|
if (!_caption.isEmpty()) {
|
||||||
int32 captionw = width - st::msgPadding.left() - st::msgPadding.right();
|
auto captionw = width - st::msgPadding.left() - st::msgPadding.right();
|
||||||
height -= _caption.countHeight(captionw) + st::msgPadding.bottom();
|
height -= _caption.countHeight(captionw);
|
||||||
|
if (isBubbleBottom()) {
|
||||||
|
height -= st::msgPadding.bottom();
|
||||||
|
}
|
||||||
if (x >= st::msgPadding.left() && y >= height && x < st::msgPadding.left() + captionw && y < _height) {
|
if (x >= st::msgPadding.left() && y >= height && x < st::msgPadding.left() + captionw && y < _height) {
|
||||||
result = _caption.getState(x - st::msgPadding.left(), y - height, captionw, request.forText());
|
result = _caption.getState(x - st::msgPadding.left(), y - height, captionw, request.forText());
|
||||||
}
|
}
|
||||||
|
@ -1077,7 +1031,11 @@ void HistoryDocument::initDimensions() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (captioned) {
|
if (captioned) {
|
||||||
_minh += captioned->_caption.countHeight(_maxw - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom();
|
auto captionw = _maxw - st::msgPadding.left() - st::msgPadding.right();
|
||||||
|
_minh += captioned->_caption.countHeight(captionw);
|
||||||
|
if (isBubbleBottom()) {
|
||||||
|
_minh += st::msgPadding.bottom();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
_height = _minh;
|
_height = _minh;
|
||||||
}
|
}
|
||||||
|
@ -1095,7 +1053,11 @@ int HistoryDocument::resizeGetHeight(int width) {
|
||||||
} else {
|
} else {
|
||||||
_height = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom();
|
_height = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom();
|
||||||
}
|
}
|
||||||
_height += captioned->_caption.countHeight(_width - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom();
|
auto captionw = _width - st::msgPadding.left() - st::msgPadding.right();
|
||||||
|
_height += captioned->_caption.countHeight(captionw);
|
||||||
|
if (isBubbleBottom()) {
|
||||||
|
_height += st::msgPadding.bottom();
|
||||||
|
}
|
||||||
|
|
||||||
return _height;
|
return _height;
|
||||||
}
|
}
|
||||||
|
@ -1129,11 +1091,14 @@ void HistoryDocument::draw(Painter &p, const QRect &r, TextSelection selection,
|
||||||
linktop = st::msgFileThumbLinkTop;
|
linktop = st::msgFileThumbLinkTop;
|
||||||
bottom = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom();
|
bottom = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom();
|
||||||
|
|
||||||
|
auto inWebPage = (_parent->getMedia() != this);
|
||||||
|
auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large;
|
||||||
QRect rthumb(rtlrect(st::msgFileThumbPadding.left(), st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, _width));
|
QRect rthumb(rtlrect(st::msgFileThumbPadding.left(), st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, _width));
|
||||||
QPixmap thumb = loaded ? _data->thumb->pixSingle(ImageRoundRadius::Large, thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize) : _data->thumb->pixBlurredSingle(ImageRoundRadius::Small, thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize);
|
QPixmap thumb = loaded ? _data->thumb->pixSingle(roundRadius, thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize) : _data->thumb->pixBlurredSingle(ImageRoundRadius::Small, thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize);
|
||||||
p.drawPixmap(rthumb.topLeft(), thumb);
|
p.drawPixmap(rthumb.topLeft(), thumb);
|
||||||
if (selected) {
|
if (selected) {
|
||||||
App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, SelectedOverlayLargeCorners);
|
auto overlayCorners = inWebPage ? SelectedOverlaySmallCorners : SelectedOverlayLargeCorners;
|
||||||
|
App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, overlayCorners);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (radial || (!loaded && !_data->loading())) {
|
if (radial || (!loaded && !_data->loading())) {
|
||||||
|
@ -1366,7 +1331,11 @@ HistoryTextState HistoryDocument::getState(int x, int y, HistoryStateRequest req
|
||||||
result = captioned->_caption.getState(x - st::msgPadding.left(), y - bottom, _width - st::msgPadding.left() - st::msgPadding.right(), request.forText());
|
result = captioned->_caption.getState(x - st::msgPadding.left(), y - bottom, _width - st::msgPadding.left() - st::msgPadding.right(), request.forText());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
height -= captioned->_caption.countHeight(_width - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom();
|
auto captionw = _width - st::msgPadding.left() - st::msgPadding.right();
|
||||||
|
height -= captioned->_caption.countHeight(captionw);
|
||||||
|
if (isBubbleBottom()) {
|
||||||
|
height -= st::msgPadding.bottom();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (x >= 0 && y >= 0 && x < _width && y < height && !_data->loading() && !_data->uploading() && _data->isValid()) {
|
if (x >= 0 && y >= 0 && x < _width && y < height && !_data->loading() && !_data->uploading() && _data->isValid()) {
|
||||||
result.link = _openl;
|
result.link = _openl;
|
||||||
|
@ -1628,7 +1597,11 @@ void HistoryGif::initDimensions() {
|
||||||
_maxw += st::mediaPadding.left() + st::mediaPadding.right();
|
_maxw += st::mediaPadding.left() + st::mediaPadding.right();
|
||||||
_minh += st::mediaPadding.top() + st::mediaPadding.bottom();
|
_minh += st::mediaPadding.top() + st::mediaPadding.bottom();
|
||||||
if (!_caption.isEmpty()) {
|
if (!_caption.isEmpty()) {
|
||||||
_minh += st::mediaCaptionSkip + _caption.countHeight(_maxw - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom();
|
auto captionw = _maxw - st::msgPadding.left() - st::msgPadding.right();
|
||||||
|
_minh += st::mediaCaptionSkip + _caption.countHeight(captionw);
|
||||||
|
if (isBubbleBottom()) {
|
||||||
|
_minh += st::msgPadding.bottom();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1685,7 +1658,11 @@ int HistoryGif::resizeGetHeight(int width) {
|
||||||
_width += st::mediaPadding.left() + st::mediaPadding.right();
|
_width += st::mediaPadding.left() + st::mediaPadding.right();
|
||||||
_height += st::mediaPadding.top() + st::mediaPadding.bottom();
|
_height += st::mediaPadding.top() + st::mediaPadding.bottom();
|
||||||
if (!_caption.isEmpty()) {
|
if (!_caption.isEmpty()) {
|
||||||
_height += st::mediaCaptionSkip + _caption.countHeight(_width - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom();
|
auto captionw = _width - st::msgPadding.left() - st::msgPadding.right();
|
||||||
|
_height += st::mediaCaptionSkip + _caption.countHeight(captionw);
|
||||||
|
if (isBubbleBottom()) {
|
||||||
|
_height += st::msgPadding.bottom();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1729,7 +1706,10 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, uint6
|
||||||
width -= st::mediaPadding.left() + st::mediaPadding.right();
|
width -= st::mediaPadding.left() + st::mediaPadding.right();
|
||||||
height -= skipy + st::mediaPadding.bottom();
|
height -= skipy + st::mediaPadding.bottom();
|
||||||
if (!_caption.isEmpty()) {
|
if (!_caption.isEmpty()) {
|
||||||
height -= st::mediaCaptionSkip + _caption.countHeight(captionw) + st::msgPadding.bottom();
|
height -= st::mediaCaptionSkip + _caption.countHeight(captionw);
|
||||||
|
if (isBubbleBottom()) {
|
||||||
|
height -= st::msgPadding.bottom();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
App::roundShadow(p, 0, 0, width, _height, selected ? st::msgInShadowSelected : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners);
|
App::roundShadow(p, 0, 0, width, _height, selected ? st::msgInShadowSelected : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners);
|
||||||
|
@ -1740,10 +1720,14 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, uint6
|
||||||
if (animating) {
|
if (animating) {
|
||||||
p.drawPixmap(rthumb.topLeft(), _gif->current(_thumbw, _thumbh, width, height, (Ui::isLayerShown() || Ui::isMediaViewShown() || Ui::isInlineItemBeingChosen()) ? 0 : ms));
|
p.drawPixmap(rthumb.topLeft(), _gif->current(_thumbw, _thumbh, width, height, (Ui::isLayerShown() || Ui::isMediaViewShown() || Ui::isInlineItemBeingChosen()) ? 0 : ms));
|
||||||
} else {
|
} else {
|
||||||
p.drawPixmap(rthumb.topLeft(), _data->thumb->pixBlurredSingle(ImageRoundRadius::Large, _thumbw, _thumbh, width, height));
|
auto inWebPage = (_parent->getMedia() != this);
|
||||||
|
auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large;
|
||||||
|
p.drawPixmap(rthumb.topLeft(), _data->thumb->pixBlurredSingle(roundRadius, _thumbw, _thumbh, width, height));
|
||||||
}
|
}
|
||||||
if (selected) {
|
if (selected) {
|
||||||
App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, SelectedOverlayLargeCorners);
|
auto inWebPage = (_parent->getMedia() != this);
|
||||||
|
auto overlayCorners = inWebPage ? SelectedOverlaySmallCorners : SelectedOverlayLargeCorners;
|
||||||
|
App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, overlayCorners);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (radial || (!_gif && ((!loaded && !_data->loading()) || !cAutoPlayGif())) || (_gif == Media::Clip::BadReader)) {
|
if (radial || (!_gif && ((!loaded && !_data->loading()) || !cAutoPlayGif())) || (_gif == Media::Clip::BadReader)) {
|
||||||
|
@ -1817,8 +1801,11 @@ HistoryTextState HistoryGif::getState(int x, int y, HistoryStateRequest request)
|
||||||
skipx = st::mediaPadding.left();
|
skipx = st::mediaPadding.left();
|
||||||
skipy = st::mediaPadding.top();
|
skipy = st::mediaPadding.top();
|
||||||
if (!_caption.isEmpty()) {
|
if (!_caption.isEmpty()) {
|
||||||
int32 captionw = width - st::msgPadding.left() - st::msgPadding.right();
|
auto captionw = width - st::msgPadding.left() - st::msgPadding.right();
|
||||||
height -= _caption.countHeight(captionw) + st::msgPadding.bottom();
|
height -= _caption.countHeight(captionw);
|
||||||
|
if (isBubbleBottom()) {
|
||||||
|
height -= st::msgPadding.bottom();
|
||||||
|
}
|
||||||
if (x >= st::msgPadding.left() && y >= height && x < st::msgPadding.left() + captionw && y < _height) {
|
if (x >= st::msgPadding.left() && y >= height && x < st::msgPadding.left() + captionw && y < _height) {
|
||||||
result = _caption.getState(x - st::msgPadding.left(), y - height, captionw, request.forText());
|
result = _caption.getState(x - st::msgPadding.left(), y - height, captionw, request.forText());
|
||||||
return result;
|
return result;
|
||||||
|
@ -2547,25 +2534,31 @@ void HistoryWebPage::initDimensions() {
|
||||||
|
|
||||||
if (_siteNameWidth) {
|
if (_siteNameWidth) {
|
||||||
if (_title.isEmpty() && _description.isEmpty()) {
|
if (_title.isEmpty() && _description.isEmpty()) {
|
||||||
_maxw = qMax(_maxw, int32(_siteNameWidth + _parent->skipBlockWidth()));
|
accumulate_max(_maxw, _siteNameWidth + _parent->skipBlockWidth());
|
||||||
} else {
|
} else {
|
||||||
_maxw = qMax(_maxw, int32(_siteNameWidth + articlePhotoMaxWidth));
|
accumulate_max(_maxw, _siteNameWidth + articlePhotoMaxWidth);
|
||||||
}
|
}
|
||||||
_minh += _lineHeight;
|
_minh += _lineHeight;
|
||||||
}
|
}
|
||||||
if (!_title.isEmpty()) {
|
if (!_title.isEmpty()) {
|
||||||
_maxw = qMax(_maxw, int32(_title.maxWidth() + articlePhotoMaxWidth));
|
accumulate_max(_maxw, _title.maxWidth() + articlePhotoMaxWidth);
|
||||||
_minh += titleMinHeight;
|
_minh += titleMinHeight;
|
||||||
}
|
}
|
||||||
if (!_description.isEmpty()) {
|
if (!_description.isEmpty()) {
|
||||||
_maxw = qMax(_maxw, int32(_description.maxWidth() + articlePhotoMaxWidth));
|
accumulate_max(_maxw, _description.maxWidth() + articlePhotoMaxWidth);
|
||||||
_minh += descriptionMinHeight;
|
_minh += descriptionMinHeight;
|
||||||
}
|
}
|
||||||
if (_attach) {
|
if (_attach) {
|
||||||
if (_minh) _minh += st::webPagePhotoSkip;
|
auto attachAtTop = !_siteNameWidth && _title.isEmpty() && _description.isEmpty();
|
||||||
|
if (!attachAtTop) _minh += st::mediaInBubbleSkip;
|
||||||
|
|
||||||
_attach->initDimensions();
|
_attach->initDimensions();
|
||||||
QMargins bubble(_attach->bubbleMargins());
|
QMargins bubble(_attach->bubbleMargins());
|
||||||
_maxw = qMax(_maxw, int32(_attach->maxWidth() - bubble.left() - bubble.top() + (_attach->customInfoLayout() ? skipBlockWidth : 0)));
|
auto maxMediaWidth = _attach->maxWidth() - bubble.left() - bubble.right();
|
||||||
|
if (isBubbleBottom() && _attach->customInfoLayout()) {
|
||||||
|
maxMediaWidth += skipBlockWidth;
|
||||||
|
}
|
||||||
|
accumulate_max(_maxw, maxMediaWidth);
|
||||||
_minh += _attach->minHeight() - bubble.top() - bubble.bottom();
|
_minh += _attach->minHeight() - bubble.top() - bubble.bottom();
|
||||||
}
|
}
|
||||||
if (_data->type == WebPageVideo && _data->duration) {
|
if (_data->type == WebPageVideo && _data->duration) {
|
||||||
|
@ -2573,10 +2566,11 @@ void HistoryWebPage::initDimensions() {
|
||||||
_durationWidth = st::msgDateFont->width(_duration);
|
_durationWidth = st::msgDateFont->width(_duration);
|
||||||
}
|
}
|
||||||
_maxw += st::msgPadding.left() + st::webPageLeft + st::msgPadding.right();
|
_maxw += st::msgPadding.left() + st::webPageLeft + st::msgPadding.right();
|
||||||
_minh += st::msgPadding.bottom();
|
auto padding = inBubblePadding();
|
||||||
|
_minh += padding.top() + padding.bottom();
|
||||||
|
|
||||||
if (_asArticle) {
|
if (_asArticle) {
|
||||||
_minh = resizeGetHeight(_maxw); // hack
|
_minh = resizeGetHeight(_maxw);
|
||||||
// _minh += st::msgDateFont->height;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2625,7 +2619,7 @@ int HistoryWebPage::resizeGetHeight(int width) {
|
||||||
|
|
||||||
_pixh -= _lineHeight;
|
_pixh -= _lineHeight;
|
||||||
} while (_pixh > _lineHeight);
|
} while (_pixh > _lineHeight);
|
||||||
_height += st::msgDateFont->height;
|
_height += bottomInfoPadding();
|
||||||
} else {
|
} else {
|
||||||
_height = siteNameHeight;
|
_height = siteNameHeight;
|
||||||
|
|
||||||
|
@ -2653,18 +2647,20 @@ int HistoryWebPage::resizeGetHeight(int width) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_attach) {
|
if (_attach) {
|
||||||
if (_height) _height += st::webPagePhotoSkip;
|
auto attachAtTop = !_siteNameWidth && !_titleLines && !_descriptionLines;
|
||||||
|
if (!attachAtTop) _height += st::mediaInBubbleSkip;
|
||||||
|
|
||||||
QMargins bubble(_attach->bubbleMargins());
|
QMargins bubble(_attach->bubbleMargins());
|
||||||
|
|
||||||
_attach->resizeGetHeight(width + bubble.left() + bubble.right());
|
_attach->resizeGetHeight(width + bubble.left() + bubble.right());
|
||||||
_height += _attach->height() - bubble.top() - bubble.bottom();
|
_height += _attach->height() - bubble.top() - bubble.bottom();
|
||||||
if (_attach->customInfoLayout() && _attach->currentWidth() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) {
|
if (isBubbleBottom() && _attach->customInfoLayout() && _attach->currentWidth() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) {
|
||||||
_height += st::msgDateFont->height;
|
_height += bottomInfoPadding();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_height += st::msgPadding.bottom();
|
auto padding = inBubblePadding();
|
||||||
|
_height += padding.top() + padding.bottom();
|
||||||
|
|
||||||
return _height;
|
return _height;
|
||||||
}
|
}
|
||||||
|
@ -2680,14 +2676,16 @@ void HistoryWebPage::draw(Painter &p, const QRect &r, TextSelection selection, u
|
||||||
style::color semibold = (selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg));
|
style::color semibold = (selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg));
|
||||||
style::color regular = (selected ? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected) : (outbg ? st::msgOutDateFg : st::msgInDateFg));
|
style::color regular = (selected ? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected) : (outbg ? st::msgOutDateFg : st::msgInDateFg));
|
||||||
|
|
||||||
int32 lshift = st::msgPadding.left() + st::webPageLeft, rshift = st::msgPadding.right(), bshift = st::msgPadding.bottom();
|
|
||||||
width -= lshift + rshift;
|
|
||||||
QMargins bubble(_attach ? _attach->bubbleMargins() : QMargins());
|
QMargins bubble(_attach ? _attach->bubbleMargins() : QMargins());
|
||||||
if (_asArticle || (_attach && _attach->customInfoLayout() && _attach->currentWidth() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right())) {
|
auto padding = inBubblePadding();
|
||||||
bshift += st::msgDateFont->height;
|
auto tshift = padding.top();
|
||||||
|
auto bshift = padding.bottom();
|
||||||
|
if (_asArticle || (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->currentWidth() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right())) {
|
||||||
|
bshift += bottomInfoPadding();
|
||||||
}
|
}
|
||||||
|
width -= padding.left() + padding.right();
|
||||||
|
|
||||||
QRect bar(rtlrect(st::msgPadding.left(), 0, st::webPageBar, _height - bshift, _width));
|
QRect bar(rtlrect(st::msgPadding.left(), tshift, st::webPageBar, _height - tshift - bshift, _width));
|
||||||
p.fillRect(bar, barfg);
|
p.fillRect(bar, barfg);
|
||||||
|
|
||||||
if (_asArticle) {
|
if (_asArticle) {
|
||||||
|
@ -2707,17 +2705,16 @@ void HistoryWebPage::draw(Painter &p, const QRect &r, TextSelection selection, u
|
||||||
} else {
|
} else {
|
||||||
pix = _data->photo->thumb->pixBlurredSingle(ImageRoundRadius::Small, pixw, pixh, pw, ph);
|
pix = _data->photo->thumb->pixBlurredSingle(ImageRoundRadius::Small, pixw, pixh, pw, ph);
|
||||||
}
|
}
|
||||||
p.drawPixmapLeft(lshift + width - pw, 0, _width, pix);
|
p.drawPixmapLeft(padding.left() + width - pw, 0, _width, pix);
|
||||||
if (selected) {
|
if (selected) {
|
||||||
App::roundRect(p, rtlrect(lshift + width - pw, 0, pw, _pixh, _width), textstyleCurrent()->selectOverlay, SelectedOverlaySmallCorners);
|
App::roundRect(p, rtlrect(padding.left() + width - pw, 0, pw, _pixh, _width), textstyleCurrent()->selectOverlay, SelectedOverlaySmallCorners);
|
||||||
}
|
}
|
||||||
width -= pw + st::webPagePhotoDelta;
|
width -= pw + st::webPagePhotoDelta;
|
||||||
}
|
}
|
||||||
int32 tshift = 0;
|
|
||||||
if (_siteNameWidth) {
|
if (_siteNameWidth) {
|
||||||
p.setFont(st::webPageTitleFont);
|
p.setFont(st::webPageTitleFont);
|
||||||
p.setPen(semibold);
|
p.setPen(semibold);
|
||||||
p.drawTextLeft(lshift, tshift, _width, (width >= _siteNameWidth) ? _data->siteName : st::webPageTitleFont->elided(_data->siteName, width));
|
p.drawTextLeft(padding.left(), tshift, _width, (width >= _siteNameWidth) ? _data->siteName : st::webPageTitleFont->elided(_data->siteName, width));
|
||||||
tshift += _lineHeight;
|
tshift += _lineHeight;
|
||||||
}
|
}
|
||||||
if (_titleLines) {
|
if (_titleLines) {
|
||||||
|
@ -2726,7 +2723,7 @@ void HistoryWebPage::draw(Painter &p, const QRect &r, TextSelection selection, u
|
||||||
if (_title.hasSkipBlock()) {
|
if (_title.hasSkipBlock()) {
|
||||||
endskip = _parent->skipBlockWidth();
|
endskip = _parent->skipBlockWidth();
|
||||||
}
|
}
|
||||||
_title.drawLeftElided(p, lshift, tshift, width, _width, _titleLines, style::al_left, 0, -1, endskip, false, selection);
|
_title.drawLeftElided(p, padding.left(), tshift, width, _width, _titleLines, style::al_left, 0, -1, endskip, false, selection);
|
||||||
tshift += _titleLines * _lineHeight;
|
tshift += _titleLines * _lineHeight;
|
||||||
}
|
}
|
||||||
if (_descriptionLines) {
|
if (_descriptionLines) {
|
||||||
|
@ -2735,16 +2732,17 @@ void HistoryWebPage::draw(Painter &p, const QRect &r, TextSelection selection, u
|
||||||
if (_description.hasSkipBlock()) {
|
if (_description.hasSkipBlock()) {
|
||||||
endskip = _parent->skipBlockWidth();
|
endskip = _parent->skipBlockWidth();
|
||||||
}
|
}
|
||||||
_description.drawLeftElided(p, lshift, tshift, width, _width, _descriptionLines, style::al_left, 0, -1, endskip, false, toDescriptionSelection(selection));
|
_description.drawLeftElided(p, padding.left(), tshift, width, _width, _descriptionLines, style::al_left, 0, -1, endskip, false, toDescriptionSelection(selection));
|
||||||
tshift += _descriptionLines * _lineHeight;
|
tshift += _descriptionLines * _lineHeight;
|
||||||
}
|
}
|
||||||
if (_attach) {
|
if (_attach) {
|
||||||
if (tshift) tshift += st::webPagePhotoSkip;
|
auto attachAtTop = !_siteNameWidth && !_titleLines && !_descriptionLines;
|
||||||
|
if (!attachAtTop) tshift += st::mediaInBubbleSkip;
|
||||||
|
|
||||||
int32 attachLeft = lshift - bubble.left(), attachTop = tshift - bubble.top();
|
auto attachLeft = padding.left() - bubble.left();
|
||||||
|
auto attachTop = tshift - bubble.top();
|
||||||
if (rtl()) attachLeft = _width - attachLeft - _attach->currentWidth();
|
if (rtl()) attachLeft = _width - attachLeft - _attach->currentWidth();
|
||||||
|
|
||||||
p.save();
|
|
||||||
p.translate(attachLeft, attachTop);
|
p.translate(attachLeft, attachTop);
|
||||||
|
|
||||||
auto attachSelection = selected ? FullSelection : TextSelection { 0, 0 };
|
auto attachSelection = selected ? FullSelection : TextSelection { 0, 0 };
|
||||||
|
@ -2771,7 +2769,7 @@ void HistoryWebPage::draw(Painter &p, const QRect &r, TextSelection selection, u
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p.restore();
|
p.translate(-attachLeft, -attachTop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2781,22 +2779,24 @@ HistoryTextState HistoryWebPage::getState(int x, int y, HistoryStateRequest requ
|
||||||
if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result;
|
if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result;
|
||||||
int32 skipx = 0, skipy = 0, width = _width, height = _height;
|
int32 skipx = 0, skipy = 0, width = _width, height = _height;
|
||||||
|
|
||||||
int32 lshift = st::msgPadding.left() + st::webPageLeft, rshift = st::msgPadding.right(), bshift = st::msgPadding.bottom();
|
|
||||||
width -= lshift + rshift;
|
|
||||||
QMargins bubble(_attach ? _attach->bubbleMargins() : QMargins());
|
QMargins bubble(_attach ? _attach->bubbleMargins() : QMargins());
|
||||||
if (_asArticle || (_attach && _attach->customInfoLayout() && _attach->currentWidth() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right())) {
|
auto padding = inBubblePadding();
|
||||||
bshift += st::msgDateFont->height;
|
auto tshift = padding.top();
|
||||||
|
auto bshift = padding.bottom();
|
||||||
|
if (_asArticle || (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->currentWidth() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right())) {
|
||||||
|
bshift += bottomInfoPadding();
|
||||||
}
|
}
|
||||||
|
width -= padding.left() + padding.right();
|
||||||
|
|
||||||
bool inThumb = false;
|
bool inThumb = false;
|
||||||
if (_asArticle) {
|
if (_asArticle) {
|
||||||
int32 pw = qMax(_pixw, int16(_lineHeight));
|
int32 pw = qMax(_pixw, int16(_lineHeight));
|
||||||
if (rtlrect(lshift + width - pw, 0, pw, _pixh, _width).contains(x, y)) {
|
if (rtlrect(padding.left() + width - pw, 0, pw, _pixh, _width).contains(x, y)) {
|
||||||
inThumb = true;
|
inThumb = true;
|
||||||
}
|
}
|
||||||
width -= pw + st::webPagePhotoDelta;
|
width -= pw + st::webPagePhotoDelta;
|
||||||
}
|
}
|
||||||
int tshift = 0, symbolAdd = 0;
|
int symbolAdd = 0;
|
||||||
if (_siteNameWidth) {
|
if (_siteNameWidth) {
|
||||||
tshift += _lineHeight;
|
tshift += _lineHeight;
|
||||||
}
|
}
|
||||||
|
@ -2804,7 +2804,7 @@ HistoryTextState HistoryWebPage::getState(int x, int y, HistoryStateRequest requ
|
||||||
if (y >= tshift && y < tshift + _titleLines * _lineHeight) {
|
if (y >= tshift && y < tshift + _titleLines * _lineHeight) {
|
||||||
Text::StateRequestElided titleRequest = request.forText();
|
Text::StateRequestElided titleRequest = request.forText();
|
||||||
titleRequest.lines = _titleLines;
|
titleRequest.lines = _titleLines;
|
||||||
result = _title.getStateElidedLeft(x - lshift, y - tshift, width, _width, titleRequest);
|
result = _title.getStateElidedLeft(x - padding.left(), y - tshift, width, _width, titleRequest);
|
||||||
} else if (y >= tshift + _titleLines * _lineHeight) {
|
} else if (y >= tshift + _titleLines * _lineHeight) {
|
||||||
symbolAdd += _title.length();
|
symbolAdd += _title.length();
|
||||||
}
|
}
|
||||||
|
@ -2814,7 +2814,7 @@ HistoryTextState HistoryWebPage::getState(int x, int y, HistoryStateRequest requ
|
||||||
if (y >= tshift && y < tshift + _descriptionLines * _lineHeight) {
|
if (y >= tshift && y < tshift + _descriptionLines * _lineHeight) {
|
||||||
Text::StateRequestElided descriptionRequest = request.forText();
|
Text::StateRequestElided descriptionRequest = request.forText();
|
||||||
descriptionRequest.lines = _descriptionLines;
|
descriptionRequest.lines = _descriptionLines;
|
||||||
result = _description.getStateElidedLeft(x - lshift, y - tshift, width, _width, descriptionRequest);
|
result = _description.getStateElidedLeft(x - padding.left(), y - tshift, width, _width, descriptionRequest);
|
||||||
} else if (y >= tshift + _descriptionLines * _lineHeight) {
|
} else if (y >= tshift + _descriptionLines * _lineHeight) {
|
||||||
symbolAdd += _description.length();
|
symbolAdd += _description.length();
|
||||||
}
|
}
|
||||||
|
@ -2823,10 +2823,12 @@ HistoryTextState HistoryWebPage::getState(int x, int y, HistoryStateRequest requ
|
||||||
if (inThumb) {
|
if (inThumb) {
|
||||||
result.link = _openl;
|
result.link = _openl;
|
||||||
} else if (_attach) {
|
} else if (_attach) {
|
||||||
if (tshift) tshift += st::webPagePhotoSkip;
|
auto attachAtTop = !_siteNameWidth && !_titleLines && !_descriptionLines;
|
||||||
|
if (!attachAtTop) tshift += st::mediaInBubbleSkip;
|
||||||
|
|
||||||
if (x >= lshift && x < lshift + width && y >= tshift && y < _height - st::msgPadding.bottom()) {
|
if (x >= padding.left() && x < padding.left() + width && y >= tshift && y < _height - bshift) {
|
||||||
int32 attachLeft = lshift - bubble.left(), attachTop = tshift - bubble.top();
|
auto attachLeft = padding.left() - bubble.left();
|
||||||
|
auto attachTop = tshift - bubble.top();
|
||||||
if (rtl()) attachLeft = _width - attachLeft - _attach->currentWidth();
|
if (rtl()) attachLeft = _width - attachLeft - _attach->currentWidth();
|
||||||
result = _attach->getState(x - attachLeft, y - attachTop, request);
|
result = _attach->getState(x - attachLeft, y - attachTop, request);
|
||||||
|
|
||||||
|
@ -2901,6 +2903,28 @@ ImagePtr HistoryWebPage::replyPreview() {
|
||||||
return _attach ? _attach->replyPreview() : (_data->photo ? _data->photo->makeReplyPreview() : ImagePtr());
|
return _attach ? _attach->replyPreview() : (_data->photo ? _data->photo->makeReplyPreview() : ImagePtr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QMargins HistoryWebPage::inBubblePadding() const {
|
||||||
|
auto lshift = st::msgPadding.left() + st::webPageLeft;
|
||||||
|
auto rshift = st::msgPadding.right();
|
||||||
|
auto bshift = isBubbleBottom() ? st::msgPadding.left() : st::mediaInBubbleSkip;
|
||||||
|
auto tshift = isBubbleTop() ? st::msgPadding.left() : st::mediaInBubbleSkip;
|
||||||
|
return QMargins(lshift, tshift, rshift, bshift);
|
||||||
|
}
|
||||||
|
|
||||||
|
int HistoryWebPage::bottomInfoPadding() const {
|
||||||
|
if (!isBubbleBottom()) return 0;
|
||||||
|
|
||||||
|
auto result = st::msgDateFont->height;
|
||||||
|
|
||||||
|
// we use padding greater than st::msgPadding.bottom() in the
|
||||||
|
// bottom of the bubble so that the left line looks pretty.
|
||||||
|
// but if we have bottom skip because of the info display
|
||||||
|
// we don't need that additional padding so we replace it
|
||||||
|
// back with st::msgPadding.bottom() instead of left().
|
||||||
|
result += st::msgPadding.bottom() - st::msgPadding.left();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
HistoryGame::HistoryGame(HistoryItem *parent, GameData *data) : HistoryMedia(parent)
|
HistoryGame::HistoryGame(HistoryItem *parent, GameData *data) : HistoryMedia(parent)
|
||||||
, _data(data)
|
, _data(data)
|
||||||
, _title(st::msgMinWidth - st::webPageLeft)
|
, _title(st::msgMinWidth - st::webPageLeft)
|
||||||
|
@ -2917,7 +2941,7 @@ HistoryGame::HistoryGame(HistoryItem *parent, const HistoryGame &other) : Histor
|
||||||
void HistoryGame::initDimensions() {
|
void HistoryGame::initDimensions() {
|
||||||
if (!_lineHeight) _lineHeight = qMax(st::webPageTitleFont->height, st::webPageDescriptionFont->height);
|
if (!_lineHeight) _lineHeight = qMax(st::webPageTitleFont->height, st::webPageDescriptionFont->height);
|
||||||
|
|
||||||
if (!_openl && !_data->url.isEmpty()) _openl.reset(new UrlClickHandler(_data->url, true));
|
if (!_openl) _openl.reset(new ReplyMarkupClickHandler(_parent, 0, 0));
|
||||||
|
|
||||||
auto title = _data->title;
|
auto title = _data->title;
|
||||||
|
|
||||||
|
@ -2960,36 +2984,44 @@ void HistoryGame::initDimensions() {
|
||||||
int32 l = st::msgPadding.left() + st::webPageLeft, r = st::msgPadding.right();
|
int32 l = st::msgPadding.left() + st::webPageLeft, r = st::msgPadding.right();
|
||||||
int32 skipBlockWidth = _parent->skipBlockWidth();
|
int32 skipBlockWidth = _parent->skipBlockWidth();
|
||||||
_maxw = skipBlockWidth;
|
_maxw = skipBlockWidth;
|
||||||
_minh = st::msgPadding.top();
|
_minh = 0;
|
||||||
|
|
||||||
int32 titleMinHeight = _title.isEmpty() ? 0 : _lineHeight;
|
int32 titleMinHeight = _title.isEmpty() ? 0 : _lineHeight;
|
||||||
int32 descMaxLines = (4 + (titleMinHeight ? 0 : 1));
|
int32 descMaxLines = (4 + (titleMinHeight ? 0 : 1));
|
||||||
int32 descriptionMinHeight = _description.isEmpty() ? 0 : qMin(_description.minHeight(), descMaxLines * _lineHeight);
|
int32 descriptionMinHeight = _description.isEmpty() ? 0 : qMin(_description.minHeight(), descMaxLines * _lineHeight);
|
||||||
|
|
||||||
if (!_title.isEmpty()) {
|
if (!_title.isEmpty()) {
|
||||||
_maxw = qMax(_maxw, int32(_title.maxWidth()));
|
accumulate_max(_maxw, _title.maxWidth());
|
||||||
_minh += titleMinHeight;
|
_minh += titleMinHeight;
|
||||||
}
|
}
|
||||||
if (!_description.isEmpty()) {
|
if (!_description.isEmpty()) {
|
||||||
_maxw = qMax(_maxw, int32(_description.maxWidth()));
|
accumulate_max(_maxw, _description.maxWidth());
|
||||||
_minh += descriptionMinHeight;
|
_minh += descriptionMinHeight;
|
||||||
}
|
}
|
||||||
if (_attach) {
|
if (_attach) {
|
||||||
if (_minh) _minh += st::webPagePhotoSkip;
|
auto attachAtTop = !_titleLines && !_descriptionLines;
|
||||||
|
if (!attachAtTop) _minh += st::mediaInBubbleSkip;
|
||||||
|
|
||||||
_attach->initDimensions();
|
_attach->initDimensions();
|
||||||
QMargins bubble(_attach->bubbleMargins());
|
QMargins bubble(_attach->bubbleMargins());
|
||||||
_maxw = qMax(_maxw, int32(_attach->maxWidth() - bubble.left() - bubble.top()));
|
auto maxMediaWidth = _attach->maxWidth() - bubble.left() - bubble.right();
|
||||||
|
if (isBubbleBottom() && _attach->customInfoLayout()) {
|
||||||
|
maxMediaWidth += skipBlockWidth;
|
||||||
|
}
|
||||||
|
accumulate_max(_maxw, maxMediaWidth);
|
||||||
_minh += _attach->minHeight() - bubble.top() - bubble.bottom();
|
_minh += _attach->minHeight() - bubble.top() - bubble.bottom();
|
||||||
}
|
}
|
||||||
_maxw += st::msgPadding.left() + st::webPageLeft + st::msgPadding.right();
|
_maxw += st::msgPadding.left() + st::webPageLeft + st::msgPadding.right();
|
||||||
|
auto padding = inBubblePadding();
|
||||||
|
_minh += padding.top() + padding.bottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
int HistoryGame::resizeGetHeight(int width) {
|
int HistoryGame::resizeGetHeight(int width) {
|
||||||
_width = qMin(width, _maxw);
|
_width = qMin(width, _maxw);
|
||||||
width -= st::msgPadding.left() + st::webPageLeft + st::msgPadding.right();
|
width -= st::msgPadding.left() + st::webPageLeft + st::msgPadding.right();
|
||||||
|
|
||||||
int32 linesMax = 5;
|
int linesMax = 5;
|
||||||
_height = st::msgPadding.top();
|
_height = 0;
|
||||||
if (_title.isEmpty()) {
|
if (_title.isEmpty()) {
|
||||||
_titleLines = 0;
|
_titleLines = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -3014,13 +3046,19 @@ int HistoryGame::resizeGetHeight(int width) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_attach) {
|
if (_attach) {
|
||||||
if (_height) _height += st::webPagePhotoSkip;
|
auto attachAtTop = !_titleLines && !_descriptionLines;
|
||||||
|
if (!attachAtTop) _height += st::mediaInBubbleSkip;
|
||||||
|
|
||||||
QMargins bubble(_attach->bubbleMargins());
|
QMargins bubble(_attach->bubbleMargins());
|
||||||
|
|
||||||
_attach->resizeGetHeight(width + bubble.left() + bubble.right());
|
_attach->resizeGetHeight(width + bubble.left() + bubble.right());
|
||||||
_height += _attach->height() - bubble.top() - bubble.bottom();
|
_height += _attach->height() - bubble.top() - bubble.bottom();
|
||||||
|
if (isBubbleBottom() && _attach->customInfoLayout() && _attach->currentWidth() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) {
|
||||||
|
_height += bottomInfoPadding();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
auto padding = inBubblePadding();
|
||||||
|
_height += padding.top() + padding.bottom();
|
||||||
|
|
||||||
return _height;
|
return _height;
|
||||||
}
|
}
|
||||||
|
@ -3036,21 +3074,25 @@ void HistoryGame::draw(Painter &p, const QRect &r, TextSelection selection, uint
|
||||||
style::color semibold = (selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg));
|
style::color semibold = (selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg));
|
||||||
style::color regular = (selected ? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected) : (outbg ? st::msgOutDateFg : st::msgInDateFg));
|
style::color regular = (selected ? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected) : (outbg ? st::msgOutDateFg : st::msgInDateFg));
|
||||||
|
|
||||||
int32 lshift = st::msgPadding.left() + st::webPageLeft, rshift = st::msgPadding.right(), bshift = 0;
|
|
||||||
width -= lshift + rshift;
|
|
||||||
QMargins bubble(_attach ? _attach->bubbleMargins() : QMargins());
|
QMargins bubble(_attach ? _attach->bubbleMargins() : QMargins());
|
||||||
|
auto padding = inBubblePadding();
|
||||||
|
auto tshift = padding.top();
|
||||||
|
auto bshift = padding.bottom();
|
||||||
|
if (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->currentWidth() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) {
|
||||||
|
bshift += bottomInfoPadding();
|
||||||
|
}
|
||||||
|
width -= padding.left() + padding.right();
|
||||||
|
|
||||||
QRect bar(rtlrect(st::msgPadding.left(), st::msgPadding.top(), st::webPageBar, _height - bshift, _width));
|
QRect bar(rtlrect(st::msgPadding.left(), tshift, st::webPageBar, _height - tshift - bshift, _width));
|
||||||
p.fillRect(bar, barfg);
|
p.fillRect(bar, barfg);
|
||||||
|
|
||||||
int32 tshift = st::msgPadding.top();
|
|
||||||
if (_titleLines) {
|
if (_titleLines) {
|
||||||
p.setPen(st::black);
|
p.setPen(st::black);
|
||||||
int32 endskip = 0;
|
int32 endskip = 0;
|
||||||
if (_title.hasSkipBlock()) {
|
if (_title.hasSkipBlock()) {
|
||||||
endskip = _parent->skipBlockWidth();
|
endskip = _parent->skipBlockWidth();
|
||||||
}
|
}
|
||||||
_title.drawLeftElided(p, lshift, tshift, width, _width, _titleLines, style::al_left, 0, -1, endskip, false, selection);
|
_title.drawLeftElided(p, padding.left(), tshift, width, _width, _titleLines, style::al_left, 0, -1, endskip, false, selection);
|
||||||
tshift += _titleLines * _lineHeight;
|
tshift += _titleLines * _lineHeight;
|
||||||
}
|
}
|
||||||
if (_descriptionLines) {
|
if (_descriptionLines) {
|
||||||
|
@ -3059,13 +3101,15 @@ void HistoryGame::draw(Painter &p, const QRect &r, TextSelection selection, uint
|
||||||
if (_description.hasSkipBlock()) {
|
if (_description.hasSkipBlock()) {
|
||||||
endskip = _parent->skipBlockWidth();
|
endskip = _parent->skipBlockWidth();
|
||||||
}
|
}
|
||||||
_description.drawLeftElided(p, lshift, tshift, width, _width, _descriptionLines, style::al_left, 0, -1, endskip, false, toDescriptionSelection(selection));
|
_description.drawLeftElided(p, padding.left(), tshift, width, _width, _descriptionLines, style::al_left, 0, -1, endskip, false, toDescriptionSelection(selection));
|
||||||
tshift += _descriptionLines * _lineHeight;
|
tshift += _descriptionLines * _lineHeight;
|
||||||
}
|
}
|
||||||
if (_attach) {
|
if (_attach) {
|
||||||
if (tshift) tshift += st::webPagePhotoSkip;
|
auto attachAtTop = !_titleLines && !_descriptionLines;
|
||||||
|
if (!attachAtTop) tshift += st::mediaInBubbleSkip;
|
||||||
|
|
||||||
int32 attachLeft = lshift - bubble.left(), attachTop = tshift - bubble.top();
|
auto attachLeft = padding.left() - bubble.left();
|
||||||
|
auto attachTop = tshift - bubble.top();
|
||||||
if (rtl()) attachLeft = _width - attachLeft - _attach->currentWidth();
|
if (rtl()) attachLeft = _width - attachLeft - _attach->currentWidth();
|
||||||
|
|
||||||
auto attachSelection = selected ? FullSelection : TextSelection { 0, 0 };
|
auto attachSelection = selected ? FullSelection : TextSelection { 0, 0 };
|
||||||
|
@ -3082,17 +3126,22 @@ HistoryTextState HistoryGame::getState(int x, int y, HistoryStateRequest request
|
||||||
if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result;
|
if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result;
|
||||||
int32 width = _width, height = _height;
|
int32 width = _width, height = _height;
|
||||||
|
|
||||||
int32 lshift = st::msgPadding.left() + st::webPageLeft, rshift = st::msgPadding.right(), bshift = 0;
|
|
||||||
width -= lshift + rshift;
|
|
||||||
QMargins bubble(_attach ? _attach->bubbleMargins() : QMargins());
|
QMargins bubble(_attach ? _attach->bubbleMargins() : QMargins());
|
||||||
|
auto padding = inBubblePadding();
|
||||||
|
auto tshift = padding.top();
|
||||||
|
auto bshift = padding.bottom();
|
||||||
|
if (isBubbleBottom() && _attach && _attach->customInfoLayout() && _attach->currentWidth() + _parent->skipBlockWidth() > width + bubble.left() + bubble.right()) {
|
||||||
|
bshift += bottomInfoPadding();
|
||||||
|
}
|
||||||
|
width -= padding.left() + padding.right();
|
||||||
|
|
||||||
bool inThumb = false;
|
bool inThumb = false;
|
||||||
int tshift = st::msgPadding.top(), symbolAdd = 0;
|
int symbolAdd = 0;
|
||||||
if (_titleLines) {
|
if (_titleLines) {
|
||||||
if (y >= tshift && y < tshift + _titleLines * _lineHeight) {
|
if (y >= tshift && y < tshift + _titleLines * _lineHeight) {
|
||||||
Text::StateRequestElided titleRequest = request.forText();
|
Text::StateRequestElided titleRequest = request.forText();
|
||||||
titleRequest.lines = _titleLines;
|
titleRequest.lines = _titleLines;
|
||||||
result = _title.getStateElidedLeft(x - lshift, y - tshift, width, _width, titleRequest);
|
result = _title.getStateElidedLeft(x - padding.left(), y - tshift, width, _width, titleRequest);
|
||||||
} else if (y >= tshift + _titleLines * _lineHeight) {
|
} else if (y >= tshift + _titleLines * _lineHeight) {
|
||||||
symbolAdd += _title.length();
|
symbolAdd += _title.length();
|
||||||
}
|
}
|
||||||
|
@ -3102,7 +3151,7 @@ HistoryTextState HistoryGame::getState(int x, int y, HistoryStateRequest request
|
||||||
if (y >= tshift && y < tshift + _descriptionLines * _lineHeight) {
|
if (y >= tshift && y < tshift + _descriptionLines * _lineHeight) {
|
||||||
Text::StateRequestElided descriptionRequest = request.forText();
|
Text::StateRequestElided descriptionRequest = request.forText();
|
||||||
descriptionRequest.lines = _descriptionLines;
|
descriptionRequest.lines = _descriptionLines;
|
||||||
result = _description.getStateElidedLeft(x - lshift, y - tshift, width, _width, descriptionRequest);
|
result = _description.getStateElidedLeft(x - padding.left(), y - tshift, width, _width, descriptionRequest);
|
||||||
} else if (y >= tshift + _descriptionLines * _lineHeight) {
|
} else if (y >= tshift + _descriptionLines * _lineHeight) {
|
||||||
symbolAdd += _description.length();
|
symbolAdd += _description.length();
|
||||||
}
|
}
|
||||||
|
@ -3111,9 +3160,14 @@ HistoryTextState HistoryGame::getState(int x, int y, HistoryStateRequest request
|
||||||
if (inThumb) {
|
if (inThumb) {
|
||||||
result.link = _openl;
|
result.link = _openl;
|
||||||
} else if (_attach) {
|
} else if (_attach) {
|
||||||
if (tshift) tshift += st::webPagePhotoSkip;
|
auto attachAtTop = !_titleLines && !_descriptionLines;
|
||||||
|
if (!attachAtTop) tshift += st::mediaInBubbleSkip;
|
||||||
|
|
||||||
if (x >= lshift && x < lshift + width && y >= tshift && y < _height) {
|
auto attachLeft = padding.left() - bubble.left();
|
||||||
|
auto attachTop = tshift - bubble.top();
|
||||||
|
if (rtl()) attachLeft = _width - attachLeft - _attach->currentWidth();
|
||||||
|
|
||||||
|
if (x >= attachLeft && x < attachLeft + _attach->currentWidth() && y >= tshift && y < _height - bshift) {
|
||||||
result.link = _openl;
|
result.link = _openl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3177,6 +3231,28 @@ ImagePtr HistoryGame::replyPreview() {
|
||||||
return _attach ? _attach->replyPreview() : (_data->photo ? _data->photo->makeReplyPreview() : ImagePtr());
|
return _attach ? _attach->replyPreview() : (_data->photo ? _data->photo->makeReplyPreview() : ImagePtr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QMargins HistoryGame::inBubblePadding() const {
|
||||||
|
auto lshift = st::msgPadding.left() + st::webPageLeft;
|
||||||
|
auto rshift = st::msgPadding.right();
|
||||||
|
auto bshift = isBubbleBottom() ? st::msgPadding.left() : st::mediaInBubbleSkip;
|
||||||
|
auto tshift = isBubbleTop() ? st::msgPadding.left() : st::mediaInBubbleSkip;
|
||||||
|
return QMargins(lshift, tshift, rshift, bshift);
|
||||||
|
}
|
||||||
|
|
||||||
|
int HistoryGame::bottomInfoPadding() const {
|
||||||
|
if (!isBubbleBottom()) return 0;
|
||||||
|
|
||||||
|
auto result = st::msgDateFont->height;
|
||||||
|
|
||||||
|
// we use padding greater than st::msgPadding.bottom() in the
|
||||||
|
// bottom of the bubble so that the left line looks pretty.
|
||||||
|
// but if we have bottom skip because of the info display
|
||||||
|
// we don't need that additional padding so we replace it
|
||||||
|
// back with st::msgPadding.bottom() instead of left().
|
||||||
|
result += st::msgPadding.bottom() - st::msgPadding.left();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
HistoryLocation::HistoryLocation(HistoryItem *parent, const LocationCoords &coords, const QString &title, const QString &description) : HistoryMedia(parent)
|
HistoryLocation::HistoryLocation(HistoryItem *parent, const LocationCoords &coords, const QString &title, const QString &description) : HistoryMedia(parent)
|
||||||
, _data(App::location(coords))
|
, _data(App::location(coords))
|
||||||
, _title(st::msgMinWidth)
|
, _title(st::msgMinWidth)
|
||||||
|
@ -3220,8 +3296,8 @@ void HistoryLocation::initDimensions() {
|
||||||
}
|
}
|
||||||
_minh += st::mediaPadding.top() + st::mediaPadding.bottom();
|
_minh += st::mediaPadding.top() + st::mediaPadding.bottom();
|
||||||
if (!_title.isEmpty() || !_description.isEmpty()) {
|
if (!_title.isEmpty() || !_description.isEmpty()) {
|
||||||
_minh += st::webPagePhotoSkip;
|
_minh += st::mediaInBubbleSkip;
|
||||||
if (!_parent->Has<HistoryMessageForwarded>() && !_parent->Has<HistoryMessageReply>()) {
|
if (isBubbleTop()) {
|
||||||
_minh += st::msgPadding.top();
|
_minh += st::msgPadding.top();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3260,8 +3336,8 @@ int HistoryLocation::resizeGetHeight(int width) {
|
||||||
_height += qMin(_description.countHeight(_width - st::msgPadding.left() - st::msgPadding.right()), st::webPageDescriptionFont->height * 3);
|
_height += qMin(_description.countHeight(_width - st::msgPadding.left() - st::msgPadding.right()), st::webPageDescriptionFont->height * 3);
|
||||||
}
|
}
|
||||||
if (!_title.isEmpty() || !_description.isEmpty()) {
|
if (!_title.isEmpty() || !_description.isEmpty()) {
|
||||||
_height += st::webPagePhotoSkip;
|
_height += st::mediaInBubbleSkip;
|
||||||
if (!_parent->Has<HistoryMessageForwarded>() && !_parent->Has<HistoryMessageReply>()) {
|
if (isBubbleTop()) {
|
||||||
_height += st::msgPadding.top();
|
_height += st::msgPadding.top();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3281,7 +3357,7 @@ void HistoryLocation::draw(Painter &p, const QRect &r, TextSelection selection,
|
||||||
skipy = st::mediaPadding.top();
|
skipy = st::mediaPadding.top();
|
||||||
|
|
||||||
if (!_title.isEmpty() || !_description.isEmpty()) {
|
if (!_title.isEmpty() || !_description.isEmpty()) {
|
||||||
if (!_parent->Has<HistoryMessageForwarded>() && !_parent->Has<HistoryMessageReply>()) {
|
if (isBubbleTop()) {
|
||||||
skipy += st::msgPadding.top();
|
skipy += st::msgPadding.top();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3299,7 +3375,7 @@ void HistoryLocation::draw(Painter &p, const QRect &r, TextSelection selection,
|
||||||
skipy += qMin(_description.countHeight(textw), 3 * st::webPageDescriptionFont->height);
|
skipy += qMin(_description.countHeight(textw), 3 * st::webPageDescriptionFont->height);
|
||||||
}
|
}
|
||||||
if (!_title.isEmpty() || !_description.isEmpty()) {
|
if (!_title.isEmpty() || !_description.isEmpty()) {
|
||||||
skipy += st::webPagePhotoSkip;
|
skipy += st::mediaInBubbleSkip;
|
||||||
}
|
}
|
||||||
height -= skipy + st::mediaPadding.bottom();
|
height -= skipy + st::mediaPadding.bottom();
|
||||||
} else {
|
} else {
|
||||||
|
@ -3347,7 +3423,7 @@ HistoryTextState HistoryLocation::getState(int x, int y, HistoryStateRequest req
|
||||||
skipy = st::mediaPadding.top();
|
skipy = st::mediaPadding.top();
|
||||||
|
|
||||||
if (!_title.isEmpty() || !_description.isEmpty()) {
|
if (!_title.isEmpty() || !_description.isEmpty()) {
|
||||||
if (!_parent->Has<HistoryMessageForwarded>() && !_parent->Has<HistoryMessageReply>()) {
|
if (isBubbleTop()) {
|
||||||
skipy += st::msgPadding.top();
|
skipy += st::msgPadding.top();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3375,7 +3451,7 @@ HistoryTextState HistoryLocation::getState(int x, int y, HistoryStateRequest req
|
||||||
skipy += descriptionh;
|
skipy += descriptionh;
|
||||||
}
|
}
|
||||||
if (!_title.isEmpty() || !_description.isEmpty()) {
|
if (!_title.isEmpty() || !_description.isEmpty()) {
|
||||||
skipy += st::webPagePhotoSkip;
|
skipy += st::mediaInBubbleSkip;
|
||||||
}
|
}
|
||||||
height -= skipy + st::mediaPadding.bottom();
|
height -= skipy + st::mediaPadding.bottom();
|
||||||
}
|
}
|
|
@ -0,0 +1,906 @@
|
||||||
|
/*
|
||||||
|
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-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ui/effects/radial_animation.h"
|
||||||
|
|
||||||
|
void historyInitMedia();
|
||||||
|
|
||||||
|
class HistoryFileMedia : public HistoryMedia {
|
||||||
|
public:
|
||||||
|
using HistoryMedia::HistoryMedia;
|
||||||
|
|
||||||
|
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
|
||||||
|
return p == _openl || p == _savel || p == _cancell;
|
||||||
|
}
|
||||||
|
bool dragItemByHandler(const ClickHandlerPtr &p) const override {
|
||||||
|
return p == _openl || p == _savel || p == _cancell;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
||||||
|
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
|
||||||
|
|
||||||
|
~HistoryFileMedia();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ClickHandlerPtr _openl, _savel, _cancell;
|
||||||
|
void setLinks(ClickHandlerPtr &&openl, ClickHandlerPtr &&savel, ClickHandlerPtr &&cancell);
|
||||||
|
void setDocumentLinks(DocumentData *document, bool inlinegif = false) {
|
||||||
|
ClickHandlerPtr open, save;
|
||||||
|
if (inlinegif) {
|
||||||
|
open.reset(new GifOpenClickHandler(document));
|
||||||
|
} else {
|
||||||
|
open.reset(new DocumentOpenClickHandler(document));
|
||||||
|
}
|
||||||
|
if (inlinegif) {
|
||||||
|
save.reset(new GifOpenClickHandler(document));
|
||||||
|
} else if (document->voice()) {
|
||||||
|
save.reset(new DocumentOpenClickHandler(document));
|
||||||
|
} else {
|
||||||
|
save.reset(new DocumentSaveClickHandler(document));
|
||||||
|
}
|
||||||
|
setLinks(std_::move(open), std_::move(save), MakeShared<DocumentCancelClickHandler>(document));
|
||||||
|
}
|
||||||
|
|
||||||
|
// >= 0 will contain download / upload string, _statusSize = loaded bytes
|
||||||
|
// < 0 will contain played string, _statusSize = -(seconds + 1) played
|
||||||
|
// 0x7FFFFFF0 will contain status for not yet downloaded file
|
||||||
|
// 0x7FFFFFF1 will contain status for already downloaded file
|
||||||
|
// 0x7FFFFFF2 will contain status for failed to download / upload file
|
||||||
|
mutable int32 _statusSize;
|
||||||
|
mutable QString _statusText;
|
||||||
|
|
||||||
|
// duration = -1 - no duration, duration = -2 - "GIF" duration
|
||||||
|
void setStatusSize(int32 newSize, int32 fullSize, int32 duration, qint64 realDuration) const;
|
||||||
|
|
||||||
|
void step_thumbOver(float64 ms, bool timer);
|
||||||
|
void step_radial(uint64 ms, bool timer);
|
||||||
|
|
||||||
|
void ensureAnimation() const;
|
||||||
|
void checkAnimationFinished();
|
||||||
|
|
||||||
|
bool isRadialAnimation(uint64 ms) const {
|
||||||
|
if (!_animation || !_animation->radial.animating()) return false;
|
||||||
|
|
||||||
|
_animation->radial.step(ms);
|
||||||
|
return _animation && _animation->radial.animating();
|
||||||
|
}
|
||||||
|
bool isThumbAnimation(uint64 ms) const {
|
||||||
|
if (!_animation || !_animation->_a_thumbOver.animating()) return false;
|
||||||
|
|
||||||
|
_animation->_a_thumbOver.step(ms);
|
||||||
|
return _animation && _animation->_a_thumbOver.animating();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual float64 dataProgress() const = 0;
|
||||||
|
virtual bool dataFinished() const = 0;
|
||||||
|
virtual bool dataLoaded() const = 0;
|
||||||
|
|
||||||
|
struct AnimationData {
|
||||||
|
AnimationData(AnimationCallbacks &&thumbOverCallbacks, AnimationCallbacks &&radialCallbacks) : a_thumbOver(0, 0)
|
||||||
|
, _a_thumbOver(std_::move(thumbOverCallbacks))
|
||||||
|
, radial(std_::move(radialCallbacks)) {
|
||||||
|
}
|
||||||
|
anim::fvalue a_thumbOver;
|
||||||
|
Animation _a_thumbOver;
|
||||||
|
|
||||||
|
Ui::RadialAnimation radial;
|
||||||
|
};
|
||||||
|
mutable AnimationData *_animation = nullptr;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class HistoryPhoto : public HistoryFileMedia {
|
||||||
|
public:
|
||||||
|
HistoryPhoto(HistoryItem *parent, PhotoData *photo, const QString &caption);
|
||||||
|
HistoryPhoto(HistoryItem *parent, PeerData *chat, const MTPDphoto &photo, int width);
|
||||||
|
HistoryPhoto(HistoryItem *parent, const HistoryPhoto &other);
|
||||||
|
|
||||||
|
void init();
|
||||||
|
HistoryMediaType type() const override {
|
||||||
|
return MediaTypePhoto;
|
||||||
|
}
|
||||||
|
HistoryPhoto *clone(HistoryItem *newParent) const override {
|
||||||
|
return new HistoryPhoto(newParent, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initDimensions() override;
|
||||||
|
int resizeGetHeight(int width) override;
|
||||||
|
|
||||||
|
void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
|
||||||
|
HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
|
||||||
|
|
||||||
|
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override {
|
||||||
|
return _caption.adjustSelection(selection, type);
|
||||||
|
}
|
||||||
|
bool hasTextForCopy() const override {
|
||||||
|
return !_caption.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString notificationText() const override;
|
||||||
|
QString inDialogsText() const override;
|
||||||
|
TextWithEntities selectedText(TextSelection selection) const override;
|
||||||
|
|
||||||
|
PhotoData *photo() const {
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateSentMedia(const MTPMessageMedia &media) override;
|
||||||
|
bool needReSetInlineResultMedia(const MTPMessageMedia &media) override;
|
||||||
|
|
||||||
|
void attachToParent() override;
|
||||||
|
void detachFromParent() override;
|
||||||
|
|
||||||
|
bool hasReplyPreview() const override {
|
||||||
|
return !_data->thumb->isNull();
|
||||||
|
}
|
||||||
|
ImagePtr replyPreview() override;
|
||||||
|
|
||||||
|
TextWithEntities getCaption() const override {
|
||||||
|
return _caption.originalTextWithEntities();
|
||||||
|
}
|
||||||
|
bool needsBubble() const override {
|
||||||
|
if (!_caption.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (_parent->viaBot()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return (_parent->Has<HistoryMessageForwarded>() || _parent->Has<HistoryMessageReply>());
|
||||||
|
}
|
||||||
|
bool customInfoLayout() const override {
|
||||||
|
return _caption.isEmpty();
|
||||||
|
}
|
||||||
|
bool hideFromName() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
float64 dataProgress() const override {
|
||||||
|
return _data->progress();
|
||||||
|
}
|
||||||
|
bool dataFinished() const override {
|
||||||
|
return !_data->loading() && !_data->uploading();
|
||||||
|
}
|
||||||
|
bool dataLoaded() const override {
|
||||||
|
return _data->loaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
PhotoData *_data;
|
||||||
|
int16 _pixw = 1;
|
||||||
|
int16 _pixh = 1;
|
||||||
|
Text _caption;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class HistoryVideo : public HistoryFileMedia {
|
||||||
|
public:
|
||||||
|
HistoryVideo(HistoryItem *parent, DocumentData *document, const QString &caption);
|
||||||
|
HistoryVideo(HistoryItem *parent, const HistoryVideo &other);
|
||||||
|
HistoryMediaType type() const override {
|
||||||
|
return MediaTypeVideo;
|
||||||
|
}
|
||||||
|
HistoryVideo *clone(HistoryItem *newParent) const override {
|
||||||
|
return new HistoryVideo(newParent, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initDimensions() override;
|
||||||
|
int resizeGetHeight(int width) override;
|
||||||
|
|
||||||
|
void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
|
||||||
|
HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
|
||||||
|
|
||||||
|
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override {
|
||||||
|
return _caption.adjustSelection(selection, type);
|
||||||
|
}
|
||||||
|
bool hasTextForCopy() const override {
|
||||||
|
return !_caption.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString notificationText() const override;
|
||||||
|
QString inDialogsText() const override;
|
||||||
|
TextWithEntities selectedText(TextSelection selection) const override;
|
||||||
|
|
||||||
|
DocumentData *getDocument() override {
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uploading() const override {
|
||||||
|
return _data->uploading();
|
||||||
|
}
|
||||||
|
|
||||||
|
void attachToParent() override;
|
||||||
|
void detachFromParent() override;
|
||||||
|
|
||||||
|
bool needReSetInlineResultMedia(const MTPMessageMedia &media) override;
|
||||||
|
|
||||||
|
bool hasReplyPreview() const override {
|
||||||
|
return !_data->thumb->isNull();
|
||||||
|
}
|
||||||
|
ImagePtr replyPreview() override;
|
||||||
|
|
||||||
|
TextWithEntities getCaption() const override {
|
||||||
|
return _caption.originalTextWithEntities();
|
||||||
|
}
|
||||||
|
bool needsBubble() const override {
|
||||||
|
if (!_caption.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (_parent->viaBot()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return (_parent->Has<HistoryMessageForwarded>() || _parent->Has<HistoryMessageReply>());
|
||||||
|
}
|
||||||
|
bool customInfoLayout() const override {
|
||||||
|
return _caption.isEmpty();
|
||||||
|
}
|
||||||
|
bool hideFromName() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
float64 dataProgress() const override {
|
||||||
|
return _data->progress();
|
||||||
|
}
|
||||||
|
bool dataFinished() const override {
|
||||||
|
return !_data->loading() && !_data->uploading();
|
||||||
|
}
|
||||||
|
bool dataLoaded() const override {
|
||||||
|
return _data->loaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
DocumentData *_data;
|
||||||
|
int32 _thumbw;
|
||||||
|
Text _caption;
|
||||||
|
|
||||||
|
void setStatusSize(int32 newSize) const;
|
||||||
|
void updateStatusText() const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HistoryDocumentThumbed : public BaseComponent<HistoryDocumentThumbed> {
|
||||||
|
ClickHandlerPtr _linksavel, _linkcancell;
|
||||||
|
int _thumbw = 0;
|
||||||
|
|
||||||
|
mutable int _linkw = 0;
|
||||||
|
mutable QString _link;
|
||||||
|
};
|
||||||
|
struct HistoryDocumentCaptioned : public BaseComponent<HistoryDocumentCaptioned> {
|
||||||
|
Text _caption = { int(st::msgFileMinWidth) - st::msgPadding.left() - st::msgPadding.right() };
|
||||||
|
};
|
||||||
|
struct HistoryDocumentNamed : public BaseComponent<HistoryDocumentNamed> {
|
||||||
|
QString _name;
|
||||||
|
int _namew = 0;
|
||||||
|
};
|
||||||
|
class HistoryDocument;
|
||||||
|
struct HistoryDocumentVoicePlayback {
|
||||||
|
HistoryDocumentVoicePlayback(const HistoryDocument *that);
|
||||||
|
|
||||||
|
int32 _position;
|
||||||
|
anim::fvalue a_progress;
|
||||||
|
Animation _a_progress;
|
||||||
|
};
|
||||||
|
struct HistoryDocumentVoice : public BaseComponent<HistoryDocumentVoice> {
|
||||||
|
HistoryDocumentVoice &operator=(HistoryDocumentVoice &&other) {
|
||||||
|
std::swap(_playback, other._playback);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
~HistoryDocumentVoice() {
|
||||||
|
deleteAndMark(_playback);
|
||||||
|
}
|
||||||
|
void ensurePlayback(const HistoryDocument *interfaces) const;
|
||||||
|
void checkPlaybackFinished() const;
|
||||||
|
mutable HistoryDocumentVoicePlayback *_playback = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class HistoryDocument : public HistoryFileMedia, public Composer {
|
||||||
|
public:
|
||||||
|
HistoryDocument(HistoryItem *parent, DocumentData *document, const QString &caption);
|
||||||
|
HistoryDocument(HistoryItem *parent, const HistoryDocument &other);
|
||||||
|
HistoryMediaType type() const override {
|
||||||
|
return _data->voice() ? MediaTypeVoiceFile : (_data->song() ? MediaTypeMusicFile : MediaTypeFile);
|
||||||
|
}
|
||||||
|
HistoryDocument *clone(HistoryItem *newParent) const override {
|
||||||
|
return new HistoryDocument(newParent, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initDimensions() override;
|
||||||
|
int resizeGetHeight(int width) override;
|
||||||
|
|
||||||
|
void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
|
||||||
|
HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
|
||||||
|
|
||||||
|
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override {
|
||||||
|
if (auto captioned = Get<HistoryDocumentCaptioned>()) {
|
||||||
|
return captioned->_caption.adjustSelection(selection, type);
|
||||||
|
}
|
||||||
|
return selection;
|
||||||
|
}
|
||||||
|
bool hasTextForCopy() const override {
|
||||||
|
return Has<HistoryDocumentCaptioned>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString notificationText() const override;
|
||||||
|
QString inDialogsText() const override;
|
||||||
|
TextWithEntities selectedText(TextSelection selection) const override;
|
||||||
|
|
||||||
|
bool uploading() const override {
|
||||||
|
return _data->uploading();
|
||||||
|
}
|
||||||
|
|
||||||
|
DocumentData *getDocument() override {
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void attachToParent() override;
|
||||||
|
void detachFromParent() override;
|
||||||
|
|
||||||
|
void updateSentMedia(const MTPMessageMedia &media) override;
|
||||||
|
bool needReSetInlineResultMedia(const MTPMessageMedia &media) override;
|
||||||
|
|
||||||
|
bool hasReplyPreview() const override {
|
||||||
|
return !_data->thumb->isNull();
|
||||||
|
}
|
||||||
|
ImagePtr replyPreview() override;
|
||||||
|
|
||||||
|
TextWithEntities getCaption() const override {
|
||||||
|
if (const HistoryDocumentCaptioned *captioned = Get<HistoryDocumentCaptioned>()) {
|
||||||
|
return captioned->_caption.originalTextWithEntities();
|
||||||
|
}
|
||||||
|
return TextWithEntities();
|
||||||
|
}
|
||||||
|
bool needsBubble() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool customInfoLayout() const override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QMargins bubbleMargins() const override {
|
||||||
|
return Get<HistoryDocumentThumbed>() ? QMargins(st::msgFileThumbPadding.left(), st::msgFileThumbPadding.top(), st::msgFileThumbPadding.left(), st::msgFileThumbPadding.bottom()) : st::msgPadding;
|
||||||
|
}
|
||||||
|
bool hideForwardedFrom() const override {
|
||||||
|
return _data->song();
|
||||||
|
}
|
||||||
|
|
||||||
|
void step_voiceProgress(float64 ms, bool timer);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
float64 dataProgress() const override {
|
||||||
|
return _data->progress();
|
||||||
|
}
|
||||||
|
bool dataFinished() const override {
|
||||||
|
return !_data->loading() && !_data->uploading();
|
||||||
|
}
|
||||||
|
bool dataLoaded() const override {
|
||||||
|
return _data->loaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void createComponents(bool caption);
|
||||||
|
|
||||||
|
void setStatusSize(int32 newSize, qint64 realDuration = 0) const;
|
||||||
|
bool updateStatusText() const; // returns showPause
|
||||||
|
|
||||||
|
// Callback is a void(const QString &, const QString &, const Text &) functor.
|
||||||
|
// It will be called as callback(attachType, attachFileName, attachCaption).
|
||||||
|
template <typename Callback>
|
||||||
|
void buildStringRepresentation(Callback callback) const;
|
||||||
|
|
||||||
|
DocumentData *_data;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class HistoryGif : public HistoryFileMedia {
|
||||||
|
public:
|
||||||
|
HistoryGif(HistoryItem *parent, DocumentData *document, const QString &caption);
|
||||||
|
HistoryGif(HistoryItem *parent, const HistoryGif &other);
|
||||||
|
HistoryMediaType type() const override {
|
||||||
|
return MediaTypeGif;
|
||||||
|
}
|
||||||
|
HistoryGif *clone(HistoryItem *newParent) const override {
|
||||||
|
return new HistoryGif(newParent, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initDimensions() override;
|
||||||
|
int resizeGetHeight(int width) override;
|
||||||
|
|
||||||
|
void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
|
||||||
|
HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
|
||||||
|
|
||||||
|
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override {
|
||||||
|
return _caption.adjustSelection(selection, type);
|
||||||
|
}
|
||||||
|
bool hasTextForCopy() const override {
|
||||||
|
return !_caption.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString notificationText() const override;
|
||||||
|
QString inDialogsText() const override;
|
||||||
|
TextWithEntities selectedText(TextSelection selection) const override;
|
||||||
|
|
||||||
|
bool uploading() const override {
|
||||||
|
return _data->uploading();
|
||||||
|
}
|
||||||
|
|
||||||
|
DocumentData *getDocument() override {
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
Media::Clip::Reader *getClipReader() override {
|
||||||
|
return gif();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool playInline(bool autoplay) override;
|
||||||
|
void stopInline() override;
|
||||||
|
|
||||||
|
void attachToParent() override;
|
||||||
|
void detachFromParent() override;
|
||||||
|
|
||||||
|
void updateSentMedia(const MTPMessageMedia &media) override;
|
||||||
|
bool needReSetInlineResultMedia(const MTPMessageMedia &media) override;
|
||||||
|
|
||||||
|
bool hasReplyPreview() const override {
|
||||||
|
return !_data->thumb->isNull();
|
||||||
|
}
|
||||||
|
ImagePtr replyPreview() override;
|
||||||
|
|
||||||
|
TextWithEntities getCaption() const override {
|
||||||
|
return _caption.originalTextWithEntities();
|
||||||
|
}
|
||||||
|
bool needsBubble() const override {
|
||||||
|
if (!_caption.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (_parent->viaBot()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return (_parent->Has<HistoryMessageForwarded>() || _parent->Has<HistoryMessageReply>());
|
||||||
|
}
|
||||||
|
bool customInfoLayout() const override {
|
||||||
|
return _caption.isEmpty();
|
||||||
|
}
|
||||||
|
bool hideFromName() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
~HistoryGif();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
float64 dataProgress() const override;
|
||||||
|
bool dataFinished() const override;
|
||||||
|
bool dataLoaded() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
DocumentData *_data;
|
||||||
|
int32 _thumbw, _thumbh;
|
||||||
|
Text _caption;
|
||||||
|
|
||||||
|
Media::Clip::Reader *_gif;
|
||||||
|
Media::Clip::Reader *gif() {
|
||||||
|
return (_gif == Media::Clip::BadReader) ? nullptr : _gif;
|
||||||
|
}
|
||||||
|
const Media::Clip::Reader *gif() const {
|
||||||
|
return (_gif == Media::Clip::BadReader) ? nullptr : _gif;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setStatusSize(int32 newSize) const;
|
||||||
|
void updateStatusText() const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class HistorySticker : public HistoryMedia {
|
||||||
|
public:
|
||||||
|
HistorySticker(HistoryItem *parent, DocumentData *document);
|
||||||
|
HistoryMediaType type() const override {
|
||||||
|
return MediaTypeSticker;
|
||||||
|
}
|
||||||
|
HistorySticker *clone(HistoryItem *newParent) const override {
|
||||||
|
return new HistorySticker(newParent, _data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initDimensions() override;
|
||||||
|
int resizeGetHeight(int width) override;
|
||||||
|
|
||||||
|
void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
|
||||||
|
HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
|
||||||
|
|
||||||
|
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool dragItem() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool dragItemByHandler(const ClickHandlerPtr &p) const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString notificationText() const override;
|
||||||
|
TextWithEntities selectedText(TextSelection selection) const override;
|
||||||
|
|
||||||
|
DocumentData *getDocument() override {
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void attachToParent() override;
|
||||||
|
void detachFromParent() override;
|
||||||
|
|
||||||
|
void updateSentMedia(const MTPMessageMedia &media) override;
|
||||||
|
bool needReSetInlineResultMedia(const MTPMessageMedia &media) override;
|
||||||
|
|
||||||
|
bool needsBubble() const override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool customInfoLayout() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int additionalWidth(const HistoryMessageVia *via, const HistoryMessageReply *reply) const;
|
||||||
|
int additionalWidth() const {
|
||||||
|
return additionalWidth(_parent->Get<HistoryMessageVia>(), _parent->Get<HistoryMessageReply>());
|
||||||
|
}
|
||||||
|
QString toString() const;
|
||||||
|
|
||||||
|
int16 _pixw, _pixh;
|
||||||
|
ClickHandlerPtr _packLink;
|
||||||
|
DocumentData *_data;
|
||||||
|
QString _emoji;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class HistoryContact : public HistoryMedia {
|
||||||
|
public:
|
||||||
|
HistoryContact(HistoryItem *parent, int32 userId, const QString &first, const QString &last, const QString &phone);
|
||||||
|
HistoryMediaType type() const override {
|
||||||
|
return MediaTypeContact;
|
||||||
|
}
|
||||||
|
HistoryContact *clone(HistoryItem *newParent) const override {
|
||||||
|
return new HistoryContact(newParent, _userId, _fname, _lname, _phone);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initDimensions() override;
|
||||||
|
|
||||||
|
void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
|
||||||
|
HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
|
||||||
|
|
||||||
|
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool dragItemByHandler(const ClickHandlerPtr &p) const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString notificationText() const override;
|
||||||
|
TextWithEntities selectedText(TextSelection selection) const override;
|
||||||
|
|
||||||
|
void attachToParent() override;
|
||||||
|
void detachFromParent() override;
|
||||||
|
|
||||||
|
void updateSentMedia(const MTPMessageMedia &media) override;
|
||||||
|
|
||||||
|
bool needsBubble() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool customInfoLayout() const override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString &fname() const {
|
||||||
|
return _fname;
|
||||||
|
}
|
||||||
|
const QString &lname() const {
|
||||||
|
return _lname;
|
||||||
|
}
|
||||||
|
const QString &phone() const {
|
||||||
|
return _phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
int32 _userId;
|
||||||
|
UserData *_contact;
|
||||||
|
|
||||||
|
int32 _phonew;
|
||||||
|
QString _fname, _lname, _phone;
|
||||||
|
Text _name;
|
||||||
|
|
||||||
|
ClickHandlerPtr _linkl;
|
||||||
|
int32 _linkw;
|
||||||
|
QString _link;
|
||||||
|
};
|
||||||
|
|
||||||
|
class HistoryWebPage : public HistoryMedia {
|
||||||
|
public:
|
||||||
|
HistoryWebPage(HistoryItem *parent, WebPageData *data);
|
||||||
|
HistoryWebPage(HistoryItem *parent, const HistoryWebPage &other);
|
||||||
|
HistoryMediaType type() const override {
|
||||||
|
return MediaTypeWebPage;
|
||||||
|
}
|
||||||
|
HistoryWebPage *clone(HistoryItem *newParent) const override {
|
||||||
|
return new HistoryWebPage(newParent, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initDimensions() override;
|
||||||
|
int resizeGetHeight(int width) override;
|
||||||
|
|
||||||
|
void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
|
||||||
|
HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
|
||||||
|
|
||||||
|
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override;
|
||||||
|
bool hasTextForCopy() const override {
|
||||||
|
return false; // we do not add _title and _description in FullSelection text copy.
|
||||||
|
}
|
||||||
|
|
||||||
|
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
|
||||||
|
return _attach && _attach->toggleSelectionByHandlerClick(p);
|
||||||
|
}
|
||||||
|
bool dragItemByHandler(const ClickHandlerPtr &p) const override {
|
||||||
|
return _attach && _attach->dragItemByHandler(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextWithEntities selectedText(TextSelection selection) const override;
|
||||||
|
|
||||||
|
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
||||||
|
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
|
||||||
|
|
||||||
|
bool isDisplayed() const override {
|
||||||
|
return !_data->pendingTill;
|
||||||
|
}
|
||||||
|
DocumentData *getDocument() override {
|
||||||
|
return _attach ? _attach->getDocument() : 0;
|
||||||
|
}
|
||||||
|
Media::Clip::Reader *getClipReader() override {
|
||||||
|
return _attach ? _attach->getClipReader() : 0;
|
||||||
|
}
|
||||||
|
bool playInline(bool autoplay) override {
|
||||||
|
return _attach ? _attach->playInline(autoplay) : false;
|
||||||
|
}
|
||||||
|
void stopInline() override {
|
||||||
|
if (_attach) _attach->stopInline();
|
||||||
|
}
|
||||||
|
|
||||||
|
void attachToParent() override;
|
||||||
|
void detachFromParent() override;
|
||||||
|
|
||||||
|
bool hasReplyPreview() const override {
|
||||||
|
return (_data->photo && !_data->photo->thumb->isNull()) || (_data->document && !_data->document->thumb->isNull());
|
||||||
|
}
|
||||||
|
ImagePtr replyPreview() override;
|
||||||
|
|
||||||
|
WebPageData *webpage() {
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool needsBubble() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool customInfoLayout() const override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryMedia *attach() const {
|
||||||
|
return _attach.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TextSelection toDescriptionSelection(TextSelection selection) const {
|
||||||
|
return internal::unshiftSelection(selection, _title);
|
||||||
|
}
|
||||||
|
TextSelection fromDescriptionSelection(TextSelection selection) const {
|
||||||
|
return internal::shiftSelection(selection, _title);
|
||||||
|
}
|
||||||
|
QMargins inBubblePadding() const;
|
||||||
|
int bottomInfoPadding() const;
|
||||||
|
|
||||||
|
WebPageData *_data;
|
||||||
|
ClickHandlerPtr _openl;
|
||||||
|
std_::unique_ptr<HistoryMedia> _attach;
|
||||||
|
|
||||||
|
bool _asArticle = false;
|
||||||
|
int32 _titleLines, _descriptionLines;
|
||||||
|
|
||||||
|
Text _title, _description;
|
||||||
|
int32 _siteNameWidth = 0;
|
||||||
|
|
||||||
|
QString _duration;
|
||||||
|
int32 _durationWidth = 0;
|
||||||
|
|
||||||
|
int16 _pixw = 0;
|
||||||
|
int16 _pixh = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class HistoryGame : public HistoryMedia {
|
||||||
|
public:
|
||||||
|
HistoryGame(HistoryItem *parent, GameData *data);
|
||||||
|
HistoryGame(HistoryItem *parent, const HistoryGame &other);
|
||||||
|
HistoryMediaType type() const override {
|
||||||
|
return MediaTypeGame;
|
||||||
|
}
|
||||||
|
HistoryGame *clone(HistoryItem *newParent) const override {
|
||||||
|
return new HistoryGame(newParent, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initDimensions() override;
|
||||||
|
int resizeGetHeight(int width) override;
|
||||||
|
|
||||||
|
void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
|
||||||
|
HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
|
||||||
|
|
||||||
|
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override;
|
||||||
|
bool isAboveMessage() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool hasTextForCopy() const override {
|
||||||
|
return false; // we do not add _title and _description in FullSelection text copy.
|
||||||
|
}
|
||||||
|
|
||||||
|
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
|
||||||
|
return _attach && _attach->toggleSelectionByHandlerClick(p);
|
||||||
|
}
|
||||||
|
bool dragItemByHandler(const ClickHandlerPtr &p) const override {
|
||||||
|
return _attach && _attach->dragItemByHandler(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextWithEntities selectedText(TextSelection selection) const override;
|
||||||
|
|
||||||
|
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
||||||
|
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
|
||||||
|
|
||||||
|
DocumentData *getDocument() override {
|
||||||
|
return _attach ? _attach->getDocument() : nullptr;
|
||||||
|
}
|
||||||
|
Media::Clip::Reader *getClipReader() override {
|
||||||
|
return _attach ? _attach->getClipReader() : nullptr;
|
||||||
|
}
|
||||||
|
bool playInline(bool autoplay) override {
|
||||||
|
return _attach ? _attach->playInline(autoplay) : false;
|
||||||
|
}
|
||||||
|
void stopInline() override {
|
||||||
|
if (_attach) _attach->stopInline();
|
||||||
|
}
|
||||||
|
|
||||||
|
void attachToParent() override;
|
||||||
|
void detachFromParent() override;
|
||||||
|
|
||||||
|
bool hasReplyPreview() const override {
|
||||||
|
return (_data->photo && !_data->photo->thumb->isNull()) || (_data->document && !_data->document->thumb->isNull());
|
||||||
|
}
|
||||||
|
ImagePtr replyPreview() override;
|
||||||
|
|
||||||
|
GameData *game() {
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool needsBubble() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool customInfoLayout() const override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryMedia *attach() const {
|
||||||
|
return _attach.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TextSelection toDescriptionSelection(TextSelection selection) const {
|
||||||
|
return internal::unshiftSelection(selection, _title);
|
||||||
|
}
|
||||||
|
TextSelection fromDescriptionSelection(TextSelection selection) const {
|
||||||
|
return internal::shiftSelection(selection, _title);
|
||||||
|
}
|
||||||
|
QMargins inBubblePadding() const;
|
||||||
|
int bottomInfoPadding() const;
|
||||||
|
|
||||||
|
GameData *_data;
|
||||||
|
ClickHandlerPtr _openl;
|
||||||
|
std_::unique_ptr<HistoryMedia> _attach;
|
||||||
|
|
||||||
|
int32 _titleLines, _descriptionLines;
|
||||||
|
|
||||||
|
Text _title, _description;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LocationCoords;
|
||||||
|
struct LocationData;
|
||||||
|
|
||||||
|
class HistoryLocation : public HistoryMedia {
|
||||||
|
public:
|
||||||
|
HistoryLocation(HistoryItem *parent, const LocationCoords &coords, const QString &title = QString(), const QString &description = QString());
|
||||||
|
HistoryLocation(HistoryItem *parent, const HistoryLocation &other);
|
||||||
|
HistoryMediaType type() const override {
|
||||||
|
return MediaTypeLocation;
|
||||||
|
}
|
||||||
|
HistoryLocation *clone(HistoryItem *newParent) const override {
|
||||||
|
return new HistoryLocation(newParent, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initDimensions() override;
|
||||||
|
int resizeGetHeight(int32 width) override;
|
||||||
|
|
||||||
|
void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
|
||||||
|
HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
|
||||||
|
|
||||||
|
TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override;
|
||||||
|
bool hasTextForCopy() const override {
|
||||||
|
return !_title.isEmpty() || !_description.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
|
||||||
|
return p == _link;
|
||||||
|
}
|
||||||
|
bool dragItemByHandler(const ClickHandlerPtr &p) const override {
|
||||||
|
return p == _link;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString notificationText() const override;
|
||||||
|
QString inDialogsText() const override;
|
||||||
|
TextWithEntities selectedText(TextSelection selection) const override;
|
||||||
|
|
||||||
|
bool needsBubble() const override {
|
||||||
|
if (!_title.isEmpty() || !_description.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (_parent->viaBot()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return (_parent->Has<HistoryMessageForwarded>() || _parent->Has<HistoryMessageReply>());
|
||||||
|
}
|
||||||
|
bool customInfoLayout() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TextSelection toDescriptionSelection(TextSelection selection) const {
|
||||||
|
return internal::unshiftSelection(selection, _title);
|
||||||
|
}
|
||||||
|
TextSelection fromDescriptionSelection(TextSelection selection) const {
|
||||||
|
return internal::shiftSelection(selection, _title);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocationData *_data;
|
||||||
|
Text _title, _description;
|
||||||
|
ClickHandlerPtr _link;
|
||||||
|
|
||||||
|
int32 fullWidth() const;
|
||||||
|
int32 fullHeight() const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class SendMessageClickHandler : public PeerClickHandler {
|
||||||
|
public:
|
||||||
|
using PeerClickHandler::PeerClickHandler;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onClickImpl() const override;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class AddContactClickHandler : public MessageClickHandler {
|
||||||
|
public:
|
||||||
|
using MessageClickHandler::MessageClickHandler;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onClickImpl() const override;
|
||||||
|
|
||||||
|
};
|
|
@ -27,6 +27,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "history/history_location_manager.h"
|
#include "history/history_location_manager.h"
|
||||||
#include "history/history_service_layout.h"
|
#include "history/history_service_layout.h"
|
||||||
|
#include "history/history_media_types.h"
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -476,6 +477,39 @@ void HistoryMessage::createComponentsHelper(MTPDmessage::Flags flags, MsgId repl
|
||||||
createComponents(config);
|
createComponents(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HistoryMessage::updateMediaInBubbleState() {
|
||||||
|
if (!_media) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!drawBubble()) {
|
||||||
|
_media->setInBubbleState(MediaInBubbleState::None);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasSomethingAbove = displayFromName() || displayForwardedFrom() || Has<HistoryMessageVia>();
|
||||||
|
bool hasSomethingBelow = false;
|
||||||
|
if (!emptyText()) {
|
||||||
|
if (_media->isAboveMessage()) {
|
||||||
|
hasSomethingBelow = true;
|
||||||
|
} else {
|
||||||
|
hasSomethingAbove = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto computeState = [hasSomethingAbove, hasSomethingBelow] {
|
||||||
|
if (hasSomethingAbove) {
|
||||||
|
if (hasSomethingBelow) {
|
||||||
|
return MediaInBubbleState::Middle;
|
||||||
|
}
|
||||||
|
return MediaInBubbleState::Bottom;
|
||||||
|
} else if (hasSomethingBelow) {
|
||||||
|
return MediaInBubbleState::Top;
|
||||||
|
}
|
||||||
|
return MediaInBubbleState::None;
|
||||||
|
};
|
||||||
|
_media->setInBubbleState(computeState());
|
||||||
|
}
|
||||||
|
|
||||||
bool HistoryMessage::displayEditedBadge(bool hasViaBot) const {
|
bool HistoryMessage::displayEditedBadge(bool hasViaBot) const {
|
||||||
if (!(_flags & MTPDmessage::Flag::f_edit_date)) {
|
if (!(_flags & MTPDmessage::Flag::f_edit_date)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -658,6 +692,8 @@ void HistoryMessage::initDimensions() {
|
||||||
if (reply) {
|
if (reply) {
|
||||||
reply->updateName();
|
reply->updateName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateMediaInBubbleState();
|
||||||
if (drawBubble()) {
|
if (drawBubble()) {
|
||||||
auto fwd = Get<HistoryMessageForwarded>();
|
auto fwd = Get<HistoryMessageForwarded>();
|
||||||
auto via = Get<HistoryMessageVia>();
|
auto via = Get<HistoryMessageVia>();
|
||||||
|
@ -665,9 +701,11 @@ void HistoryMessage::initDimensions() {
|
||||||
fwd->create(via);
|
fwd->create(via);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto mediaDisplayed = false;
|
||||||
if (_media) {
|
if (_media) {
|
||||||
|
mediaDisplayed = _media->isDisplayed();
|
||||||
_media->initDimensions();
|
_media->initDimensions();
|
||||||
if (_media->isDisplayed() && !_media->isAboveMessage()) {
|
if (mediaDisplayed && _media->isBubbleBottom()) {
|
||||||
if (_text.hasSkipBlock()) {
|
if (_text.hasSkipBlock()) {
|
||||||
_text.removeSkipBlock();
|
_text.removeSkipBlock();
|
||||||
_textWidth = -1;
|
_textWidth = -1;
|
||||||
|
@ -681,19 +719,21 @@ void HistoryMessage::initDimensions() {
|
||||||
}
|
}
|
||||||
|
|
||||||
_maxw = plainMaxWidth();
|
_maxw = plainMaxWidth();
|
||||||
if (emptyText()) {
|
_minh = emptyText() ? 0 : _text.minHeight();
|
||||||
_minh = 0;
|
if (mediaDisplayed) {
|
||||||
} else {
|
if (!_media->isBubbleTop()) {
|
||||||
_minh = st::msgPadding.top() + _text.minHeight() + st::msgPadding.bottom();
|
_minh += st::msgPadding.top() + st::mediaInBubbleSkip;
|
||||||
}
|
}
|
||||||
if (_media && _media->isDisplayed()) {
|
if (!_media->isBubbleBottom()) {
|
||||||
int32 maxw = _media->maxWidth();
|
_minh += st::msgPadding.bottom() + st::mediaInBubbleSkip;
|
||||||
|
}
|
||||||
|
auto maxw = _media->maxWidth();
|
||||||
if (maxw > _maxw) _maxw = maxw;
|
if (maxw > _maxw) _maxw = maxw;
|
||||||
_minh += _media->minHeight();
|
_minh += _media->minHeight();
|
||||||
}
|
} else {
|
||||||
if (!_media) {
|
_minh += st::msgPadding.top() + st::msgPadding.bottom();
|
||||||
if (displayFromName()) {
|
if (displayFromName()) {
|
||||||
int32 namew = st::msgPadding.left() + author()->nameText.maxWidth() + st::msgPadding.right();
|
auto namew = st::msgPadding.left() + author()->nameText.maxWidth() + st::msgPadding.right();
|
||||||
if (via && !fwd) {
|
if (via && !fwd) {
|
||||||
namew += st::msgServiceFont->spacew + via->_maxWidth;
|
namew += st::msgServiceFont->spacew + via->_maxWidth;
|
||||||
}
|
}
|
||||||
|
@ -704,7 +744,7 @@ void HistoryMessage::initDimensions() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fwd) {
|
if (fwd) {
|
||||||
int32 _namew = st::msgPadding.left() + fwd->_text.maxWidth() + st::msgPadding.right();
|
auto _namew = st::msgPadding.left() + fwd->_text.maxWidth() + st::msgPadding.right();
|
||||||
if (via) {
|
if (via) {
|
||||||
_namew += st::msgServiceFont->spacew + via->_maxWidth;
|
_namew += st::msgServiceFont->spacew + via->_maxWidth;
|
||||||
}
|
}
|
||||||
|
@ -1029,19 +1069,19 @@ void HistoryMessage::drawInfo(Painter &p, int32 right, int32 bottom, int32 width
|
||||||
int32 infoRight = right, infoBottom = bottom;
|
int32 infoRight = right, infoBottom = bottom;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case InfoDisplayDefault:
|
case InfoDisplayDefault:
|
||||||
infoRight -= st::msgPadding.right() - st::msgDateDelta.x();
|
infoRight -= st::msgPadding.right() - st::msgDateDelta.x();
|
||||||
infoBottom -= st::msgPadding.bottom() - st::msgDateDelta.y();
|
infoBottom -= st::msgPadding.bottom() - st::msgDateDelta.y();
|
||||||
p.setPen(selected ? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected) : (outbg ? st::msgOutDateFg : st::msgInDateFg));
|
p.setPen(selected ? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected) : (outbg ? st::msgOutDateFg : st::msgInDateFg));
|
||||||
break;
|
break;
|
||||||
case InfoDisplayOverImage:
|
case InfoDisplayOverImage:
|
||||||
infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x();
|
infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x();
|
||||||
infoBottom -= st::msgDateImgDelta + st::msgDateImgPadding.y();
|
infoBottom -= st::msgDateImgDelta + st::msgDateImgPadding.y();
|
||||||
p.setPen(st::msgDateImgColor);
|
p.setPen(st::msgDateImgColor);
|
||||||
break;
|
break;
|
||||||
case InfoDisplayOverBackground:
|
case InfoDisplayOverBackground:
|
||||||
infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x();
|
infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x();
|
||||||
infoBottom -= st::msgDateImgDelta + st::msgDateImgPadding.y();
|
infoBottom -= st::msgDateImgDelta + st::msgDateImgPadding.y();
|
||||||
p.setPen(st::msgServiceColor);
|
p.setPen(st::msgServiceColor);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1152,9 +1192,6 @@ void HistoryMessage::draw(Painter &p, const QRect &r, TextSelection selection, u
|
||||||
int dateh = 0, unreadbarh = 0;
|
int dateh = 0, unreadbarh = 0;
|
||||||
if (auto date = Get<HistoryMessageDate>()) {
|
if (auto date = Get<HistoryMessageDate>()) {
|
||||||
dateh = date->height();
|
dateh = date->height();
|
||||||
//if (r.intersects(QRect(0, 0, _history->width, dateh))) {
|
|
||||||
// date->paint(p, 0, _history->width);
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
if (auto unreadbar = Get<HistoryMessageUnreadBar>()) {
|
if (auto unreadbar = Get<HistoryMessageUnreadBar>()) {
|
||||||
unreadbarh = unreadbar->height();
|
unreadbarh = unreadbar->height();
|
||||||
|
@ -1197,7 +1234,8 @@ void HistoryMessage::draw(Painter &p, const QRect &r, TextSelection selection, u
|
||||||
fromNameUpdated(width);
|
fromNameUpdated(width);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 top = marginTop();
|
auto mediaDisplayed = _media && _media->isDisplayed();
|
||||||
|
auto top = marginTop();
|
||||||
QRect r(left, top, width, height - top - marginBottom());
|
QRect r(left, top, width, height - top - marginBottom());
|
||||||
|
|
||||||
style::color bg(selected ? (outbg ? st::msgOutBgSelected : st::msgInBgSelected) : (outbg ? st::msgOutBg : st::msgInBg));
|
style::color bg(selected ? (outbg ? st::msgOutBgSelected : st::msgInBgSelected) : (outbg ? st::msgOutBg : st::msgInBg));
|
||||||
|
@ -1206,17 +1244,23 @@ void HistoryMessage::draw(Painter &p, const QRect &r, TextSelection selection, u
|
||||||
App::roundRect(p, r, bg, cors, &sh);
|
App::roundRect(p, r, bg, cors, &sh);
|
||||||
|
|
||||||
QRect trect(r.marginsAdded(-st::msgPadding));
|
QRect trect(r.marginsAdded(-st::msgPadding));
|
||||||
paintFromName(p, trect, selected);
|
if (mediaDisplayed && _media->isBubbleTop()) {
|
||||||
paintForwardedInfo(p, trect, selected);
|
trect.setY(trect.y() - st::msgPadding.top());
|
||||||
paintReplyInfo(p, trect, selected);
|
} else {
|
||||||
paintViaBotIdInfo(p, trect, selected);
|
paintFromName(p, trect, selected);
|
||||||
|
paintForwardedInfo(p, trect, selected);
|
||||||
|
paintReplyInfo(p, trect, selected);
|
||||||
|
paintViaBotIdInfo(p, trect, selected);
|
||||||
|
}
|
||||||
|
if (mediaDisplayed && _media->isBubbleBottom()) {
|
||||||
|
trect.setHeight(trect.height() + st::msgPadding.bottom());
|
||||||
|
}
|
||||||
auto needDrawInfo = true;
|
auto needDrawInfo = true;
|
||||||
if (_media && _media->isDisplayed()) {
|
if (mediaDisplayed) {
|
||||||
auto mediaAboveText = _media->isAboveMessage();
|
auto mediaAboveText = _media->isAboveMessage();
|
||||||
auto mediaHeight = _media->height();
|
auto mediaHeight = _media->height();
|
||||||
auto mediaLeft = trect.x() - st::msgPadding.left();
|
auto mediaLeft = trect.x() - st::msgPadding.left();
|
||||||
auto mediaTop = mediaAboveText ? (trect.y() - st::msgPadding.top()) : (r.y() + r.height() - mediaHeight);
|
auto mediaTop = mediaAboveText ? trect.y() : (trect.y() + trect.height() - mediaHeight);
|
||||||
if (!mediaAboveText) {
|
if (!mediaAboveText) {
|
||||||
paintText(p, trect, selection);
|
paintText(p, trect, selection);
|
||||||
}
|
}
|
||||||
|
@ -1361,46 +1405,50 @@ int HistoryMessage::performResizeGetHeight(int width) {
|
||||||
auto reply = Get<HistoryMessageReply>();
|
auto reply = Get<HistoryMessageReply>();
|
||||||
auto via = Get<HistoryMessageVia>();
|
auto via = Get<HistoryMessageVia>();
|
||||||
|
|
||||||
bool media = (_media && _media->isDisplayed());
|
auto mediaDisplayed = false;
|
||||||
|
auto mediaInBubbleState = MediaInBubbleState::None;
|
||||||
|
if (_media) {
|
||||||
|
mediaDisplayed = _media->isDisplayed();
|
||||||
|
mediaInBubbleState = _media->inBubbleState();
|
||||||
|
}
|
||||||
if (width >= _maxw) {
|
if (width >= _maxw) {
|
||||||
_height = _minh;
|
_height = _minh;
|
||||||
if (media) _media->resizeGetHeight(_maxw);
|
if (mediaDisplayed) _media->resizeGetHeight(_maxw);
|
||||||
} else {
|
} else {
|
||||||
if (emptyText()) {
|
if (emptyText()) {
|
||||||
_height = 0;
|
_height = 0;
|
||||||
} else {
|
} else {
|
||||||
int32 textWidth = qMax(width - st::msgPadding.left() - st::msgPadding.right(), 1);
|
auto textWidth = qMax(width - st::msgPadding.left() - st::msgPadding.right(), 1);
|
||||||
if (textWidth != _textWidth) {
|
if (textWidth != _textWidth) {
|
||||||
textstyleSet(&((out() && !isPost()) ? st::outTextStyle : st::inTextStyle));
|
textstyleSet(&((out() && !isPost()) ? st::outTextStyle : st::inTextStyle));
|
||||||
_textWidth = textWidth;
|
_textWidth = textWidth;
|
||||||
_textHeight = _text.countHeight(textWidth);
|
_textHeight = _text.countHeight(textWidth);
|
||||||
textstyleRestore();
|
textstyleRestore();
|
||||||
}
|
}
|
||||||
_height = st::msgPadding.top() + _textHeight + st::msgPadding.bottom();
|
_height = _textHeight;
|
||||||
|
}
|
||||||
|
if (mediaDisplayed) {
|
||||||
|
if (!_media->isBubbleTop()) {
|
||||||
|
_height += st::msgPadding.top() + st::mediaInBubbleSkip;
|
||||||
|
}
|
||||||
|
if (!_media->isBubbleBottom()) {
|
||||||
|
_height += st::msgPadding.bottom() + st::mediaInBubbleSkip;
|
||||||
|
}
|
||||||
|
_height += _media->resizeGetHeight(width);
|
||||||
|
} else {
|
||||||
|
_height += st::msgPadding.top() + st::msgPadding.bottom();
|
||||||
}
|
}
|
||||||
if (media) _height += _media->resizeGetHeight(width);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto mediaTopPaddingAdded = !emptyText();
|
|
||||||
if (displayFromName()) {
|
if (displayFromName()) {
|
||||||
int32 l = 0, w = 0;
|
int32 l = 0, w = 0;
|
||||||
countPositionAndSize(l, w);
|
countPositionAndSize(l, w);
|
||||||
fromNameUpdated(w);
|
fromNameUpdated(w);
|
||||||
|
|
||||||
if (!mediaTopPaddingAdded) {
|
|
||||||
_height += st::msgPadding.top() + st::mediaHeaderSkip;
|
|
||||||
mediaTopPaddingAdded = true;
|
|
||||||
}
|
|
||||||
_height += st::msgNameFont->height;
|
_height += st::msgNameFont->height;
|
||||||
} else if (via && !fwd) {
|
} else if (via && !fwd) {
|
||||||
int32 l = 0, w = 0;
|
int32 l = 0, w = 0;
|
||||||
countPositionAndSize(l, w);
|
countPositionAndSize(l, w);
|
||||||
via->resize(w - st::msgPadding.left() - st::msgPadding.right());
|
via->resize(w - st::msgPadding.left() - st::msgPadding.right());
|
||||||
|
|
||||||
if (!mediaTopPaddingAdded) {
|
|
||||||
_height += st::msgPadding.top() + st::mediaHeaderSkip;
|
|
||||||
mediaTopPaddingAdded = true;
|
|
||||||
}
|
|
||||||
_height += st::msgNameFont->height;
|
_height += st::msgNameFont->height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1408,11 +1456,6 @@ int HistoryMessage::performResizeGetHeight(int width) {
|
||||||
int32 l = 0, w = 0;
|
int32 l = 0, w = 0;
|
||||||
countPositionAndSize(l, w);
|
countPositionAndSize(l, w);
|
||||||
int32 fwdheight = ((fwd->_text.maxWidth() > (w - st::msgPadding.left() - st::msgPadding.right())) ? 2 : 1) * st::semiboldFont->height;
|
int32 fwdheight = ((fwd->_text.maxWidth() > (w - st::msgPadding.left() - st::msgPadding.right())) ? 2 : 1) * st::semiboldFont->height;
|
||||||
|
|
||||||
if (!mediaTopPaddingAdded) {
|
|
||||||
_height += st::msgPadding.top() + st::mediaHeaderSkip;
|
|
||||||
mediaTopPaddingAdded = true;
|
|
||||||
}
|
|
||||||
_height += fwdheight;
|
_height += fwdheight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1420,11 +1463,6 @@ int HistoryMessage::performResizeGetHeight(int width) {
|
||||||
int32 l = 0, w = 0;
|
int32 l = 0, w = 0;
|
||||||
countPositionAndSize(l, w);
|
countPositionAndSize(l, w);
|
||||||
reply->resize(w - st::msgPadding.left() - st::msgPadding.right());
|
reply->resize(w - st::msgPadding.left() - st::msgPadding.right());
|
||||||
|
|
||||||
if (!mediaTopPaddingAdded) {
|
|
||||||
_height += st::msgPadding.top() + st::mediaHeaderSkip;
|
|
||||||
mediaTopPaddingAdded = true;
|
|
||||||
}
|
|
||||||
_height += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
|
_height += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
|
||||||
}
|
}
|
||||||
} else if (_media) {
|
} else if (_media) {
|
||||||
|
@ -1465,12 +1503,12 @@ bool HistoryMessage::pointInTime(int32 right, int32 bottom, int x, int y, InfoDi
|
||||||
int32 infoRight = right, infoBottom = bottom;
|
int32 infoRight = right, infoBottom = bottom;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case InfoDisplayDefault:
|
case InfoDisplayDefault:
|
||||||
infoRight -= st::msgPadding.right() - st::msgDateDelta.x();
|
infoRight -= st::msgPadding.right() - st::msgDateDelta.x();
|
||||||
infoBottom -= st::msgPadding.bottom() - st::msgDateDelta.y();
|
infoBottom -= st::msgPadding.bottom() - st::msgDateDelta.y();
|
||||||
break;
|
break;
|
||||||
case InfoDisplayOverImage:
|
case InfoDisplayOverImage:
|
||||||
infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x();
|
infoRight -= st::msgDateImgDelta + st::msgDateImgPadding.x();
|
||||||
infoBottom -= st::msgDateImgDelta + st::msgDateImgPadding.y();
|
infoBottom -= st::msgDateImgDelta + st::msgDateImgPadding.y();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
int32 dateX = infoRight - HistoryMessage::infoWidth() + HistoryMessage::timeLeft();
|
int32 dateX = infoRight - HistoryMessage::infoWidth() + HistoryMessage::timeLeft();
|
||||||
|
@ -1493,85 +1531,47 @@ HistoryTextState HistoryMessage::getState(int x, int y, HistoryStateRequest requ
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drawBubble()) {
|
if (drawBubble()) {
|
||||||
auto fwd = Get<HistoryMessageForwarded>();
|
auto mediaDisplayed = _media && _media->isDisplayed();
|
||||||
auto via = Get<HistoryMessageVia>();
|
auto top = marginTop();
|
||||||
auto reply = Get<HistoryMessageReply>();
|
|
||||||
|
|
||||||
int top = marginTop();
|
|
||||||
QRect r(left, top, width, height - top - marginBottom());
|
QRect r(left, top, width, height - top - marginBottom());
|
||||||
QRect trect(r.marginsAdded(-st::msgPadding));
|
QRect trect(r.marginsAdded(-st::msgPadding));
|
||||||
if (displayFromName()) {
|
if (mediaDisplayed && _media->isBubbleTop()) {
|
||||||
if (y >= trect.top() && y < trect.top() + st::msgNameFont->height) {
|
trect.setY(trect.y() - st::msgPadding.top());
|
||||||
if (x >= trect.left() && x < trect.left() + trect.width() && x < trect.left() + author()->nameText.maxWidth()) {
|
} else {
|
||||||
result.link = author()->openLink();
|
if (getStateFromName(x, y, trect, &result)) return result;
|
||||||
return result;
|
if (getStateForwardedInfo(x, y, trect, &result, request)) return result;
|
||||||
}
|
if (getStateReplyInfo(x, y, trect, &result)) return result;
|
||||||
if (via && !fwd && x >= trect.left() + author()->nameText.maxWidth() + st::msgServiceFont->spacew && x < trect.left() + author()->nameText.maxWidth() + st::msgServiceFont->spacew + via->_width) {
|
if (getStateViaBotIdInfo(x, y, trect, &result)) return result;
|
||||||
result.link = via->_lnk;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
trect.setTop(trect.top() + st::msgNameFont->height);
|
|
||||||
}
|
}
|
||||||
if (displayForwardedFrom()) {
|
if (mediaDisplayed && _media->isBubbleBottom()) {
|
||||||
int32 fwdheight = ((fwd->_text.maxWidth() > trect.width()) ? 2 : 1) * st::semiboldFont->height;
|
trect.setHeight(trect.height() + st::msgPadding.bottom());
|
||||||
if (y >= trect.top() && y < trect.top() + fwdheight) {
|
|
||||||
bool breakEverywhere = (fwd->_text.countHeight(trect.width()) > 2 * st::semiboldFont->height);
|
|
||||||
auto textRequest = request.forText();
|
|
||||||
if (breakEverywhere) {
|
|
||||||
textRequest.flags |= Text::StateRequest::Flag::BreakEverywhere;
|
|
||||||
}
|
|
||||||
textstyleSet(&st::inFwdTextStyle);
|
|
||||||
result = fwd->_text.getState(x - trect.left(), y - trect.top(), trect.width(), textRequest);
|
|
||||||
textstyleRestore();
|
|
||||||
result.symbol = 0;
|
|
||||||
result.afterSymbol = false;
|
|
||||||
if (breakEverywhere) {
|
|
||||||
result.cursor = HistoryInForwardedCursorState;
|
|
||||||
} else {
|
|
||||||
result.cursor = HistoryDefaultCursorState;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
trect.setTop(trect.top() + fwdheight);
|
|
||||||
}
|
|
||||||
if (reply) {
|
|
||||||
int32 h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
|
|
||||||
if (y >= trect.top() && y < trect.top() + h) {
|
|
||||||
if (reply->replyToMsg && y >= trect.top() + st::msgReplyPadding.top() && y < trect.top() + st::msgReplyPadding.top() + st::msgReplyBarSize.height() && x >= trect.left() && x < trect.left() + trect.width()) {
|
|
||||||
result.link = reply->replyToLink();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
trect.setTop(trect.top() + h);
|
|
||||||
}
|
|
||||||
if (via && !displayFromName() && !displayForwardedFrom()) {
|
|
||||||
if (x >= trect.left() && y >= trect.top() && y < trect.top() + st::msgNameFont->height && x < trect.left() + via->_width) {
|
|
||||||
result.link = via->_lnk;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
trect.setTop(trect.top() + st::msgNameFont->height);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool inDate = false, mediaDisplayed = _media && _media->isDisplayed();
|
|
||||||
if (!mediaDisplayed || !_media->customInfoLayout()) {
|
|
||||||
inDate = HistoryMessage::pointInTime(r.x() + r.width(), r.y() + r.height(), x, y, InfoDisplayDefault);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto needDateCheck = true;
|
||||||
if (mediaDisplayed) {
|
if (mediaDisplayed) {
|
||||||
trect.setBottom(trect.bottom() - _media->height());
|
auto mediaAboveText = _media->isAboveMessage();
|
||||||
if (y >= r.bottom() - _media->height()) {
|
auto mediaHeight = _media->height();
|
||||||
result = _media->getState(x - r.left(), y - (r.bottom() - _media->height()), request);
|
auto mediaLeft = trect.x() - st::msgPadding.left();
|
||||||
|
auto mediaTop = mediaAboveText ? trect.y() : (trect.y() + trect.height() - mediaHeight);
|
||||||
|
|
||||||
|
if (y >= mediaTop && y < mediaTop + mediaHeight) {
|
||||||
|
result = _media->getState(x - mediaLeft, y - mediaTop, request);
|
||||||
result.symbol += _text.length();
|
result.symbol += _text.length();
|
||||||
|
} else {
|
||||||
|
if (mediaAboveText) {
|
||||||
|
trect.setY(trect.y() + mediaHeight);
|
||||||
|
}
|
||||||
|
getStateText(x, y, trect, &result, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
needDateCheck = !_media->customInfoLayout();
|
||||||
|
} else {
|
||||||
|
getStateText(x, y, trect, &result, request);
|
||||||
}
|
}
|
||||||
if (!mediaDisplayed || (y < r.bottom() - _media->height())) {
|
if (needDateCheck) {
|
||||||
textstyleSet(&((out() && !isPost()) ? st::outTextStyle : st::inTextStyle));
|
if (HistoryMessage::pointInTime(r.x() + r.width(), r.y() + r.height(), x, y, InfoDisplayDefault)) {
|
||||||
result = _text.getState(x - trect.x(), y - trect.y(), trect.width(), request.forText());
|
result.cursor = HistoryInDateCursorState;
|
||||||
textstyleRestore();
|
}
|
||||||
}
|
|
||||||
if (inDate) {
|
|
||||||
result.cursor = HistoryInDateCursorState;
|
|
||||||
}
|
}
|
||||||
} else if (_media) {
|
} else if (_media) {
|
||||||
result = _media->getState(x - left, y - marginTop(), request);
|
result = _media->getState(x - left, y - marginTop(), request);
|
||||||
|
@ -1589,6 +1589,89 @@ HistoryTextState HistoryMessage::getState(int x, int y, HistoryStateRequest requ
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HistoryMessage::getStateFromName(int x, int y, QRect &trect, HistoryTextState *outResult) const {
|
||||||
|
if (displayFromName()) {
|
||||||
|
if (y >= trect.top() && y < trect.top() + st::msgNameFont->height) {
|
||||||
|
if (x >= trect.left() && x < trect.left() + trect.width() && x < trect.left() + author()->nameText.maxWidth()) {
|
||||||
|
outResult->link = author()->openLink();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
auto fwd = Get<HistoryMessageForwarded>();
|
||||||
|
auto via = Get<HistoryMessageVia>();
|
||||||
|
if (via && !fwd && x >= trect.left() + author()->nameText.maxWidth() + st::msgServiceFont->spacew && x < trect.left() + author()->nameText.maxWidth() + st::msgServiceFont->spacew + via->_width) {
|
||||||
|
outResult->link = via->_lnk;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trect.setTop(trect.top() + st::msgNameFont->height);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HistoryMessage::getStateForwardedInfo(int x, int y, QRect &trect, HistoryTextState *outResult, const HistoryStateRequest &request) const {
|
||||||
|
if (displayForwardedFrom()) {
|
||||||
|
auto fwd = Get<HistoryMessageForwarded>();
|
||||||
|
int32 fwdheight = ((fwd->_text.maxWidth() > trect.width()) ? 2 : 1) * st::semiboldFont->height;
|
||||||
|
if (y >= trect.top() && y < trect.top() + fwdheight) {
|
||||||
|
bool breakEverywhere = (fwd->_text.countHeight(trect.width()) > 2 * st::semiboldFont->height);
|
||||||
|
auto textRequest = request.forText();
|
||||||
|
if (breakEverywhere) {
|
||||||
|
textRequest.flags |= Text::StateRequest::Flag::BreakEverywhere;
|
||||||
|
}
|
||||||
|
textstyleSet(&st::inFwdTextStyle);
|
||||||
|
*outResult = fwd->_text.getState(x - trect.left(), y - trect.top(), trect.width(), textRequest);
|
||||||
|
textstyleRestore();
|
||||||
|
outResult->symbol = 0;
|
||||||
|
outResult->afterSymbol = false;
|
||||||
|
if (breakEverywhere) {
|
||||||
|
outResult->cursor = HistoryInForwardedCursorState;
|
||||||
|
} else {
|
||||||
|
outResult->cursor = HistoryDefaultCursorState;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
trect.setTop(trect.top() + fwdheight);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HistoryMessage::getStateReplyInfo(int x, int y, QRect &trect, HistoryTextState *outResult) const {
|
||||||
|
if (auto reply = Get<HistoryMessageReply>()) {
|
||||||
|
int32 h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
|
||||||
|
if (y >= trect.top() && y < trect.top() + h) {
|
||||||
|
if (reply->replyToMsg && y >= trect.top() + st::msgReplyPadding.top() && y < trect.top() + st::msgReplyPadding.top() + st::msgReplyBarSize.height() && x >= trect.left() && x < trect.left() + trect.width()) {
|
||||||
|
outResult->link = reply->replyToLink();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
trect.setTop(trect.top() + h);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HistoryMessage::getStateViaBotIdInfo(int x, int y, QRect &trect, HistoryTextState *outResult) const {
|
||||||
|
if (!displayFromName() && !Has<HistoryMessageForwarded>()) {
|
||||||
|
if (auto via = Get<HistoryMessageVia>()) {
|
||||||
|
if (x >= trect.left() && y >= trect.top() && y < trect.top() + st::msgNameFont->height && x < trect.left() + via->_width) {
|
||||||
|
outResult->link = via->_lnk;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
trect.setTop(trect.top() + st::msgNameFont->height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HistoryMessage::getStateText(int x, int y, QRect &trect, HistoryTextState *outResult, const HistoryStateRequest &request) const {
|
||||||
|
if (trect.contains(x, y)) {
|
||||||
|
textstyleSet(&((out() && !isPost()) ? st::outTextStyle : st::inTextStyle));
|
||||||
|
*outResult = _text.getState(x - trect.x(), y - trect.y(), trect.width(), request.forText());
|
||||||
|
textstyleRestore();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
TextSelection HistoryMessage::adjustSelection(TextSelection selection, TextSelectType type) const {
|
TextSelection HistoryMessage::adjustSelection(TextSelection selection, TextSelectType type) const {
|
||||||
if (!_media || selection.to <= _text.length()) {
|
if (!_media || selection.to <= _text.length()) {
|
||||||
return _text.adjustSelection(selection, type);
|
return _text.adjustSelection(selection, type);
|
||||||
|
|
|
@ -174,7 +174,7 @@ private:
|
||||||
void applyEditionToEmpty();
|
void applyEditionToEmpty();
|
||||||
|
|
||||||
bool displayForwardedFrom() const {
|
bool displayForwardedFrom() const {
|
||||||
if (const HistoryMessageForwarded *fwd = Get<HistoryMessageForwarded>()) {
|
if (auto fwd = Get<HistoryMessageForwarded>()) {
|
||||||
return Has<HistoryMessageVia>() || !_media || !_media->isDisplayed() || fwd->_authorOriginal->isChannel() || !_media->hideForwardedFrom();
|
return Has<HistoryMessageVia>() || !_media || !_media->isDisplayed() || fwd->_authorOriginal->isChannel() || !_media->hideForwardedFrom();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -182,12 +182,16 @@ private:
|
||||||
void paintFromName(Painter &p, QRect &trect, bool selected) const;
|
void paintFromName(Painter &p, QRect &trect, bool selected) const;
|
||||||
void paintForwardedInfo(Painter &p, QRect &trect, bool selected) const;
|
void paintForwardedInfo(Painter &p, QRect &trect, bool selected) const;
|
||||||
void paintReplyInfo(Painter &p, QRect &trect, bool selected) const;
|
void paintReplyInfo(Painter &p, QRect &trect, bool selected) const;
|
||||||
|
|
||||||
// this method draws "via @bot" if it is not painted in forwarded info or in from name
|
// this method draws "via @bot" if it is not painted in forwarded info or in from name
|
||||||
void paintViaBotIdInfo(Painter &p, QRect &trect, bool selected) const;
|
void paintViaBotIdInfo(Painter &p, QRect &trect, bool selected) const;
|
||||||
|
|
||||||
void paintText(Painter &p, QRect &trect, TextSelection selection) const;
|
void paintText(Painter &p, QRect &trect, TextSelection selection) const;
|
||||||
|
|
||||||
|
bool getStateFromName(int x, int y, QRect &trect, HistoryTextState *outResult) const;
|
||||||
|
bool getStateForwardedInfo(int x, int y, QRect &trect, HistoryTextState *outResult, const HistoryStateRequest &request) const;
|
||||||
|
bool getStateReplyInfo(int x, int y, QRect &trect, HistoryTextState *outResult) const;
|
||||||
|
bool getStateViaBotIdInfo(int x, int y, QRect &trect, HistoryTextState *outResult) const;
|
||||||
|
bool getStateText(int x, int y, QRect &trect, HistoryTextState *outResult, const HistoryStateRequest &request) const;
|
||||||
|
|
||||||
void setMedia(const MTPMessageMedia *media);
|
void setMedia(const MTPMessageMedia *media);
|
||||||
void setReplyMarkup(const MTPReplyMarkup *markup);
|
void setReplyMarkup(const MTPReplyMarkup *markup);
|
||||||
|
|
||||||
|
@ -223,6 +227,8 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void updateMediaInBubbleState();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline MTPDmessage::Flags newMessageFlags(PeerData *p) {
|
inline MTPDmessage::Flags newMessageFlags(PeerData *p) {
|
||||||
|
|
|
@ -33,6 +33,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "inline_bots/inline_bot_result.h"
|
#include "inline_bots/inline_bot_result.h"
|
||||||
#include "data/data_drafts.h"
|
#include "data/data_drafts.h"
|
||||||
#include "history/history_service_layout.h"
|
#include "history/history_service_layout.h"
|
||||||
|
#include "history/history_media_types.h"
|
||||||
#include "profile/profile_members_widget.h"
|
#include "profile/profile_members_widget.h"
|
||||||
#include "core/click_handler_types.h"
|
#include "core/click_handler_types.h"
|
||||||
#include "stickers/emoji_pan.h"
|
#include "stickers/emoji_pan.h"
|
||||||
|
|
|
@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "inline_bots/inline_bot_layout_item.h"
|
#include "inline_bots/inline_bot_layout_item.h"
|
||||||
|
#include "ui/effects/radial_animation.h"
|
||||||
#include "ui/text/text.h"
|
#include "ui/text/text.h"
|
||||||
|
|
||||||
namespace InlineBots {
|
namespace InlineBots {
|
||||||
|
@ -113,7 +114,7 @@ private:
|
||||||
}
|
}
|
||||||
bool over;
|
bool over;
|
||||||
FloatAnimation _a_over;
|
FloatAnimation _a_over;
|
||||||
RadialAnimation radial;
|
Ui::RadialAnimation radial;
|
||||||
};
|
};
|
||||||
mutable AnimationData *_animation = nullptr;
|
mutable AnimationData *_animation = nullptr;
|
||||||
mutable FloatAnimation _a_deleteOver;
|
mutable FloatAnimation _a_deleteOver;
|
||||||
|
@ -275,7 +276,7 @@ private:
|
||||||
anim::fvalue a_thumbOver;
|
anim::fvalue a_thumbOver;
|
||||||
Animation _a_thumbOver;
|
Animation _a_thumbOver;
|
||||||
|
|
||||||
RadialAnimation radial;
|
Ui::RadialAnimation radial;
|
||||||
};
|
};
|
||||||
mutable std_::unique_ptr<AnimationData> _animation;
|
mutable std_::unique_ptr<AnimationData> _animation;
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "media/view/media_clip_controller.h"
|
#include "media/view/media_clip_controller.h"
|
||||||
#include "styles/style_mediaview.h"
|
#include "styles/style_mediaview.h"
|
||||||
#include "media/media_audio.h"
|
#include "media/media_audio.h"
|
||||||
|
#include "history/history_media_types.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "dropdown.h"
|
#include "dropdown.h"
|
||||||
|
#include "ui/effects/radial_animation.h"
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
namespace Clip {
|
namespace Clip {
|
||||||
|
@ -237,7 +238,7 @@ private:
|
||||||
LinkButton _docDownload, _docSaveAs, _docCancel;
|
LinkButton _docDownload, _docSaveAs, _docCancel;
|
||||||
|
|
||||||
QRect _photoRadialRect;
|
QRect _photoRadialRect;
|
||||||
RadialAnimation _radial;
|
Ui::RadialAnimation _radial;
|
||||||
|
|
||||||
History *_migrated = nullptr;
|
History *_migrated = nullptr;
|
||||||
History *_history = nullptr; // if conversation photos or files overview
|
History *_history = nullptr; // if conversation photos or files overview
|
||||||
|
|
|
@ -654,7 +654,7 @@ inputBotInlineMessageGame#3c00f8aa reply_markup:ReplyMarkup = InputBotInlineMess
|
||||||
inputBotInlineResult#2cbbe15a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:InputBotInlineMessage = InputBotInlineResult;
|
inputBotInlineResult#2cbbe15a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:InputBotInlineMessage = InputBotInlineResult;
|
||||||
inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult;
|
inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult;
|
||||||
inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult;
|
inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult;
|
||||||
inputBotInlineResultGame#efff34f9 flags:# id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult;
|
inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult;
|
||||||
|
|
||||||
botInlineMessageMediaAuto#a74b15b flags:# caption:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
|
botInlineMessageMediaAuto#a74b15b flags:# caption:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
|
||||||
botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
|
botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
|
||||||
|
@ -725,7 +725,7 @@ maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords;
|
||||||
inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia;
|
inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia;
|
||||||
inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia;
|
inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia;
|
||||||
|
|
||||||
game#b351c590 flags:# id:long access_hash:long short_name:string title:string description:string url:string photo:Photo document:flags.0?Document = Game;
|
game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game;
|
||||||
|
|
||||||
inputGameID#32c3e77 id:long access_hash:long = InputGame;
|
inputGameID#32c3e77 id:long access_hash:long = InputGame;
|
||||||
inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame;
|
inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame;
|
||||||
|
|
|
@ -5471,10 +5471,9 @@ void _serialize_inputBotInlineResultGame(MTPStringLogger &to, int32 stage, int32
|
||||||
to.add("\n").addSpaces(lev);
|
to.add("\n").addSpaces(lev);
|
||||||
}
|
}
|
||||||
switch (stage) {
|
switch (stage) {
|
||||||
case 0: to.add(" flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
case 0: to.add(" id: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||||
case 1: to.add(" id: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
case 1: to.add(" short_name: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||||
case 2: to.add(" short_name: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
case 2: to.add(" send_message: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||||
case 3: to.add(" send_message: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
|
||||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6064,9 +6063,8 @@ void _serialize_game(MTPStringLogger &to, int32 stage, int32 lev, Types &types,
|
||||||
case 3: to.add(" short_name: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
case 3: to.add(" short_name: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||||
case 4: to.add(" title: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
case 4: to.add(" title: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||||
case 5: to.add(" description: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
case 5: to.add(" description: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||||
case 6: to.add(" url: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
case 6: to.add(" photo: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||||
case 7: to.add(" photo: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
case 7: to.add(" document: "); ++stages.back(); if (flag & MTPDgame::Flag::f_document) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
|
||||||
case 8: to.add(" document: "); ++stages.back(); if (flag & MTPDgame::Flag::f_document) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
|
|
||||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -478,7 +478,7 @@ enum {
|
||||||
mtpc_inputBotInlineResult = 0x2cbbe15a,
|
mtpc_inputBotInlineResult = 0x2cbbe15a,
|
||||||
mtpc_inputBotInlineResultPhoto = 0xa8d864a7,
|
mtpc_inputBotInlineResultPhoto = 0xa8d864a7,
|
||||||
mtpc_inputBotInlineResultDocument = 0xfff8fdc4,
|
mtpc_inputBotInlineResultDocument = 0xfff8fdc4,
|
||||||
mtpc_inputBotInlineResultGame = 0xefff34f9,
|
mtpc_inputBotInlineResultGame = 0x4fa417f2,
|
||||||
mtpc_botInlineMessageMediaAuto = 0xa74b15b,
|
mtpc_botInlineMessageMediaAuto = 0xa74b15b,
|
||||||
mtpc_botInlineMessageText = 0x8c7f65e2,
|
mtpc_botInlineMessageText = 0x8c7f65e2,
|
||||||
mtpc_botInlineMessageMediaGeo = 0x3a8fd8b8,
|
mtpc_botInlineMessageMediaGeo = 0x3a8fd8b8,
|
||||||
|
@ -524,7 +524,7 @@ enum {
|
||||||
mtpc_maskCoords = 0xaed6dbb2,
|
mtpc_maskCoords = 0xaed6dbb2,
|
||||||
mtpc_inputStickeredMediaPhoto = 0x4a992157,
|
mtpc_inputStickeredMediaPhoto = 0x4a992157,
|
||||||
mtpc_inputStickeredMediaDocument = 0x438865b,
|
mtpc_inputStickeredMediaDocument = 0x438865b,
|
||||||
mtpc_game = 0xb351c590,
|
mtpc_game = 0xbdf9653b,
|
||||||
mtpc_inputGameID = 0x32c3e77,
|
mtpc_inputGameID = 0x32c3e77,
|
||||||
mtpc_inputGameShortName = 0xc331e80a,
|
mtpc_inputGameShortName = 0xc331e80a,
|
||||||
mtpc_highScore = 0x58fffcd0,
|
mtpc_highScore = 0x58fffcd0,
|
||||||
|
@ -14738,18 +14738,11 @@ public:
|
||||||
|
|
||||||
class MTPDinputBotInlineResultGame : public mtpDataImpl<MTPDinputBotInlineResultGame> {
|
class MTPDinputBotInlineResultGame : public mtpDataImpl<MTPDinputBotInlineResultGame> {
|
||||||
public:
|
public:
|
||||||
enum class Flag : int32 {
|
|
||||||
MAX_FIELD = (1 << 0),
|
|
||||||
};
|
|
||||||
Q_DECLARE_FLAGS(Flags, Flag);
|
|
||||||
friend inline Flags operator~(Flag v) { return QFlag(~static_cast<int32>(v)); }
|
|
||||||
|
|
||||||
MTPDinputBotInlineResultGame() {
|
MTPDinputBotInlineResultGame() {
|
||||||
}
|
}
|
||||||
MTPDinputBotInlineResultGame(const MTPflags<MTPDinputBotInlineResultGame::Flags> &_flags, const MTPstring &_id, const MTPstring &_short_name, const MTPInputBotInlineMessage &_send_message) : vflags(_flags), vid(_id), vshort_name(_short_name), vsend_message(_send_message) {
|
MTPDinputBotInlineResultGame(const MTPstring &_id, const MTPstring &_short_name, const MTPInputBotInlineMessage &_send_message) : vid(_id), vshort_name(_short_name), vsend_message(_send_message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
MTPflags<MTPDinputBotInlineResultGame::Flags> vflags;
|
|
||||||
MTPstring vid;
|
MTPstring vid;
|
||||||
MTPstring vshort_name;
|
MTPstring vshort_name;
|
||||||
MTPInputBotInlineMessage vsend_message;
|
MTPInputBotInlineMessage vsend_message;
|
||||||
|
@ -15322,7 +15315,7 @@ public:
|
||||||
|
|
||||||
MTPDgame() {
|
MTPDgame() {
|
||||||
}
|
}
|
||||||
MTPDgame(const MTPflags<MTPDgame::Flags> &_flags, const MTPlong &_id, const MTPlong &_access_hash, const MTPstring &_short_name, const MTPstring &_title, const MTPstring &_description, const MTPstring &_url, const MTPPhoto &_photo, const MTPDocument &_document) : vflags(_flags), vid(_id), vaccess_hash(_access_hash), vshort_name(_short_name), vtitle(_title), vdescription(_description), vurl(_url), vphoto(_photo), vdocument(_document) {
|
MTPDgame(const MTPflags<MTPDgame::Flags> &_flags, const MTPlong &_id, const MTPlong &_access_hash, const MTPstring &_short_name, const MTPstring &_title, const MTPstring &_description, const MTPPhoto &_photo, const MTPDocument &_document) : vflags(_flags), vid(_id), vaccess_hash(_access_hash), vshort_name(_short_name), vtitle(_title), vdescription(_description), vphoto(_photo), vdocument(_document) {
|
||||||
}
|
}
|
||||||
|
|
||||||
MTPflags<MTPDgame::Flags> vflags;
|
MTPflags<MTPDgame::Flags> vflags;
|
||||||
|
@ -15331,7 +15324,6 @@ public:
|
||||||
MTPstring vshort_name;
|
MTPstring vshort_name;
|
||||||
MTPstring vtitle;
|
MTPstring vtitle;
|
||||||
MTPstring vdescription;
|
MTPstring vdescription;
|
||||||
MTPstring vurl;
|
|
||||||
MTPPhoto vphoto;
|
MTPPhoto vphoto;
|
||||||
MTPDocument vdocument;
|
MTPDocument vdocument;
|
||||||
};
|
};
|
||||||
|
@ -25161,8 +25153,8 @@ public:
|
||||||
inline static MTPinputBotInlineResult new_inputBotInlineResultDocument(const MTPflags<MTPDinputBotInlineResultDocument::Flags> &_flags, const MTPstring &_id, const MTPstring &_type, const MTPstring &_title, const MTPstring &_description, const MTPInputDocument &_document, const MTPInputBotInlineMessage &_send_message) {
|
inline static MTPinputBotInlineResult new_inputBotInlineResultDocument(const MTPflags<MTPDinputBotInlineResultDocument::Flags> &_flags, const MTPstring &_id, const MTPstring &_type, const MTPstring &_title, const MTPstring &_description, const MTPInputDocument &_document, const MTPInputBotInlineMessage &_send_message) {
|
||||||
return MTPinputBotInlineResult(new MTPDinputBotInlineResultDocument(_flags, _id, _type, _title, _description, _document, _send_message));
|
return MTPinputBotInlineResult(new MTPDinputBotInlineResultDocument(_flags, _id, _type, _title, _description, _document, _send_message));
|
||||||
}
|
}
|
||||||
inline static MTPinputBotInlineResult new_inputBotInlineResultGame(const MTPflags<MTPDinputBotInlineResultGame::Flags> &_flags, const MTPstring &_id, const MTPstring &_short_name, const MTPInputBotInlineMessage &_send_message) {
|
inline static MTPinputBotInlineResult new_inputBotInlineResultGame(const MTPstring &_id, const MTPstring &_short_name, const MTPInputBotInlineMessage &_send_message) {
|
||||||
return MTPinputBotInlineResult(new MTPDinputBotInlineResultGame(_flags, _id, _short_name, _send_message));
|
return MTPinputBotInlineResult(new MTPDinputBotInlineResultGame(_id, _short_name, _send_message));
|
||||||
}
|
}
|
||||||
inline static MTPbotInlineMessage new_botInlineMessageMediaAuto(const MTPflags<MTPDbotInlineMessageMediaAuto::Flags> &_flags, const MTPstring &_caption, const MTPReplyMarkup &_reply_markup) {
|
inline static MTPbotInlineMessage new_botInlineMessageMediaAuto(const MTPflags<MTPDbotInlineMessageMediaAuto::Flags> &_flags, const MTPstring &_caption, const MTPReplyMarkup &_reply_markup) {
|
||||||
return MTPbotInlineMessage(new MTPDbotInlineMessageMediaAuto(_flags, _caption, _reply_markup));
|
return MTPbotInlineMessage(new MTPDbotInlineMessageMediaAuto(_flags, _caption, _reply_markup));
|
||||||
|
@ -25299,8 +25291,8 @@ public:
|
||||||
inline static MTPinputStickeredMedia new_inputStickeredMediaDocument(const MTPInputDocument &_id) {
|
inline static MTPinputStickeredMedia new_inputStickeredMediaDocument(const MTPInputDocument &_id) {
|
||||||
return MTPinputStickeredMedia(new MTPDinputStickeredMediaDocument(_id));
|
return MTPinputStickeredMedia(new MTPDinputStickeredMediaDocument(_id));
|
||||||
}
|
}
|
||||||
inline static MTPgame new_game(const MTPflags<MTPDgame::Flags> &_flags, const MTPlong &_id, const MTPlong &_access_hash, const MTPstring &_short_name, const MTPstring &_title, const MTPstring &_description, const MTPstring &_url, const MTPPhoto &_photo, const MTPDocument &_document) {
|
inline static MTPgame new_game(const MTPflags<MTPDgame::Flags> &_flags, const MTPlong &_id, const MTPlong &_access_hash, const MTPstring &_short_name, const MTPstring &_title, const MTPstring &_description, const MTPPhoto &_photo, const MTPDocument &_document) {
|
||||||
return MTPgame(new MTPDgame(_flags, _id, _access_hash, _short_name, _title, _description, _url, _photo, _document));
|
return MTPgame(new MTPDgame(_flags, _id, _access_hash, _short_name, _title, _description, _photo, _document));
|
||||||
}
|
}
|
||||||
inline static MTPinputGame new_inputGameID(const MTPlong &_id, const MTPlong &_access_hash) {
|
inline static MTPinputGame new_inputGameID(const MTPlong &_id, const MTPlong &_access_hash) {
|
||||||
return MTPinputGame(new MTPDinputGameID(_id, _access_hash));
|
return MTPinputGame(new MTPDinputGameID(_id, _access_hash));
|
||||||
|
@ -35831,7 +35823,7 @@ inline uint32 MTPinputBotInlineResult::innerLength() const {
|
||||||
}
|
}
|
||||||
case mtpc_inputBotInlineResultGame: {
|
case mtpc_inputBotInlineResultGame: {
|
||||||
const MTPDinputBotInlineResultGame &v(c_inputBotInlineResultGame());
|
const MTPDinputBotInlineResultGame &v(c_inputBotInlineResultGame());
|
||||||
return v.vflags.innerLength() + v.vid.innerLength() + v.vshort_name.innerLength() + v.vsend_message.innerLength();
|
return v.vid.innerLength() + v.vshort_name.innerLength() + v.vsend_message.innerLength();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -35882,7 +35874,6 @@ inline void MTPinputBotInlineResult::read(const mtpPrime *&from, const mtpPrime
|
||||||
case mtpc_inputBotInlineResultGame: _type = cons; {
|
case mtpc_inputBotInlineResultGame: _type = cons; {
|
||||||
if (!data) setData(new MTPDinputBotInlineResultGame());
|
if (!data) setData(new MTPDinputBotInlineResultGame());
|
||||||
MTPDinputBotInlineResultGame &v(_inputBotInlineResultGame());
|
MTPDinputBotInlineResultGame &v(_inputBotInlineResultGame());
|
||||||
v.vflags.read(from, end);
|
|
||||||
v.vid.read(from, end);
|
v.vid.read(from, end);
|
||||||
v.vshort_name.read(from, end);
|
v.vshort_name.read(from, end);
|
||||||
v.vsend_message.read(from, end);
|
v.vsend_message.read(from, end);
|
||||||
|
@ -35927,7 +35918,6 @@ inline void MTPinputBotInlineResult::write(mtpBuffer &to) const {
|
||||||
} break;
|
} break;
|
||||||
case mtpc_inputBotInlineResultGame: {
|
case mtpc_inputBotInlineResultGame: {
|
||||||
const MTPDinputBotInlineResultGame &v(c_inputBotInlineResultGame());
|
const MTPDinputBotInlineResultGame &v(c_inputBotInlineResultGame());
|
||||||
v.vflags.write(to);
|
|
||||||
v.vid.write(to);
|
v.vid.write(to);
|
||||||
v.vshort_name.write(to);
|
v.vshort_name.write(to);
|
||||||
v.vsend_message.write(to);
|
v.vsend_message.write(to);
|
||||||
|
@ -35962,8 +35952,8 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDinputBotInlineResultDocument::Flags)
|
||||||
inline MTPinputBotInlineResult MTP_inputBotInlineResultDocument(const MTPflags<MTPDinputBotInlineResultDocument::Flags> &_flags, const MTPstring &_id, const MTPstring &_type, const MTPstring &_title, const MTPstring &_description, const MTPInputDocument &_document, const MTPInputBotInlineMessage &_send_message) {
|
inline MTPinputBotInlineResult MTP_inputBotInlineResultDocument(const MTPflags<MTPDinputBotInlineResultDocument::Flags> &_flags, const MTPstring &_id, const MTPstring &_type, const MTPstring &_title, const MTPstring &_description, const MTPInputDocument &_document, const MTPInputBotInlineMessage &_send_message) {
|
||||||
return MTP::internal::TypeCreator::new_inputBotInlineResultDocument(_flags, _id, _type, _title, _description, _document, _send_message);
|
return MTP::internal::TypeCreator::new_inputBotInlineResultDocument(_flags, _id, _type, _title, _description, _document, _send_message);
|
||||||
}
|
}
|
||||||
inline MTPinputBotInlineResult MTP_inputBotInlineResultGame(const MTPflags<MTPDinputBotInlineResultGame::Flags> &_flags, const MTPstring &_id, const MTPstring &_short_name, const MTPInputBotInlineMessage &_send_message) {
|
inline MTPinputBotInlineResult MTP_inputBotInlineResultGame(const MTPstring &_id, const MTPstring &_short_name, const MTPInputBotInlineMessage &_send_message) {
|
||||||
return MTP::internal::TypeCreator::new_inputBotInlineResultGame(_flags, _id, _short_name, _send_message);
|
return MTP::internal::TypeCreator::new_inputBotInlineResultGame(_id, _short_name, _send_message);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32 MTPbotInlineMessage::innerLength() const {
|
inline uint32 MTPbotInlineMessage::innerLength() const {
|
||||||
|
@ -37184,7 +37174,7 @@ inline MTPgame::MTPgame() : mtpDataOwner(new MTPDgame()) {
|
||||||
|
|
||||||
inline uint32 MTPgame::innerLength() const {
|
inline uint32 MTPgame::innerLength() const {
|
||||||
const MTPDgame &v(c_game());
|
const MTPDgame &v(c_game());
|
||||||
return v.vflags.innerLength() + v.vid.innerLength() + v.vaccess_hash.innerLength() + v.vshort_name.innerLength() + v.vtitle.innerLength() + v.vdescription.innerLength() + v.vurl.innerLength() + v.vphoto.innerLength() + (v.has_document() ? v.vdocument.innerLength() : 0);
|
return v.vflags.innerLength() + v.vid.innerLength() + v.vaccess_hash.innerLength() + v.vshort_name.innerLength() + v.vtitle.innerLength() + v.vdescription.innerLength() + v.vphoto.innerLength() + (v.has_document() ? v.vdocument.innerLength() : 0);
|
||||||
}
|
}
|
||||||
inline mtpTypeId MTPgame::type() const {
|
inline mtpTypeId MTPgame::type() const {
|
||||||
return mtpc_game;
|
return mtpc_game;
|
||||||
|
@ -37200,7 +37190,6 @@ inline void MTPgame::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId
|
||||||
v.vshort_name.read(from, end);
|
v.vshort_name.read(from, end);
|
||||||
v.vtitle.read(from, end);
|
v.vtitle.read(from, end);
|
||||||
v.vdescription.read(from, end);
|
v.vdescription.read(from, end);
|
||||||
v.vurl.read(from, end);
|
|
||||||
v.vphoto.read(from, end);
|
v.vphoto.read(from, end);
|
||||||
if (v.has_document()) { v.vdocument.read(from, end); } else { v.vdocument = MTPDocument(); }
|
if (v.has_document()) { v.vdocument.read(from, end); } else { v.vdocument = MTPDocument(); }
|
||||||
}
|
}
|
||||||
|
@ -37212,15 +37201,14 @@ inline void MTPgame::write(mtpBuffer &to) const {
|
||||||
v.vshort_name.write(to);
|
v.vshort_name.write(to);
|
||||||
v.vtitle.write(to);
|
v.vtitle.write(to);
|
||||||
v.vdescription.write(to);
|
v.vdescription.write(to);
|
||||||
v.vurl.write(to);
|
|
||||||
v.vphoto.write(to);
|
v.vphoto.write(to);
|
||||||
if (v.has_document()) v.vdocument.write(to);
|
if (v.has_document()) v.vdocument.write(to);
|
||||||
}
|
}
|
||||||
inline MTPgame::MTPgame(MTPDgame *_data) : mtpDataOwner(_data) {
|
inline MTPgame::MTPgame(MTPDgame *_data) : mtpDataOwner(_data) {
|
||||||
}
|
}
|
||||||
Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDgame::Flags)
|
Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDgame::Flags)
|
||||||
inline MTPgame MTP_game(const MTPflags<MTPDgame::Flags> &_flags, const MTPlong &_id, const MTPlong &_access_hash, const MTPstring &_short_name, const MTPstring &_title, const MTPstring &_description, const MTPstring &_url, const MTPPhoto &_photo, const MTPDocument &_document) {
|
inline MTPgame MTP_game(const MTPflags<MTPDgame::Flags> &_flags, const MTPlong &_id, const MTPlong &_access_hash, const MTPstring &_short_name, const MTPstring &_title, const MTPstring &_description, const MTPPhoto &_photo, const MTPDocument &_document) {
|
||||||
return MTP::internal::TypeCreator::new_game(_flags, _id, _access_hash, _short_name, _title, _description, _url, _photo, _document);
|
return MTP::internal::TypeCreator::new_game(_flags, _id, _access_hash, _short_name, _title, _description, _photo, _document);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32 MTPinputGame::innerLength() const {
|
inline uint32 MTPinputGame::innerLength() const {
|
||||||
|
|
|
@ -33,6 +33,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "playerwidget.h"
|
#include "playerwidget.h"
|
||||||
#include "media/media_audio.h"
|
#include "media/media_audio.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
|
#include "history/history_media_types.h"
|
||||||
|
|
||||||
namespace Overview {
|
namespace Overview {
|
||||||
namespace Layout {
|
namespace Layout {
|
||||||
|
@ -91,7 +92,7 @@ void RadialProgressItem::step_radial(uint64 ms, bool timer) {
|
||||||
|
|
||||||
void RadialProgressItem::ensureRadial() const {
|
void RadialProgressItem::ensureRadial() const {
|
||||||
if (!_radial) {
|
if (!_radial) {
|
||||||
_radial = new RadialAnimation(animation(const_cast<RadialProgressItem*>(this), &RadialProgressItem::step_radial));
|
_radial = new Ui::RadialAnimation(animation(const_cast<RadialProgressItem*>(this), &RadialProgressItem::step_radial));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "layout.h"
|
#include "layout.h"
|
||||||
#include "core/click_handler_types.h"
|
#include "core/click_handler_types.h"
|
||||||
|
#include "ui/effects/radial_animation.h"
|
||||||
|
|
||||||
namespace Overview {
|
namespace Overview {
|
||||||
namespace Layout {
|
namespace Layout {
|
||||||
|
@ -130,7 +131,7 @@ protected:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutable RadialAnimation *_radial;
|
mutable Ui::RadialAnimation *_radial;
|
||||||
anim::fvalue a_iconOver;
|
anim::fvalue a_iconOver;
|
||||||
mutable Animation _a_iconOver;
|
mutable Animation _a_iconOver;
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "playerwidget.h"
|
#include "playerwidget.h"
|
||||||
#include "overview/overview_layout.h"
|
#include "overview/overview_layout.h"
|
||||||
|
#include "history/history_media_types.h"
|
||||||
|
|
||||||
// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
|
// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
#include "media/media_audio.h"
|
#include "media/media_audio.h"
|
||||||
|
#include "history/history_media_types.h"
|
||||||
|
|
||||||
PlayerWidget::PlayerWidget(QWidget *parent) : TWidget(parent)
|
PlayerWidget::PlayerWidget(QWidget *parent) : TWidget(parent)
|
||||||
, _a_state(animation(this, &PlayerWidget::step_state))
|
, _a_state(animation(this, &PlayerWidget::step_state))
|
||||||
|
|
|
@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "settings/settings_block_widget.h"
|
#include "settings/settings_block_widget.h"
|
||||||
|
#include "ui/effects/radial_animation.h"
|
||||||
#include "ui/filedialog.h"
|
#include "ui/filedialog.h"
|
||||||
|
|
||||||
class LinkButton;
|
class LinkButton;
|
||||||
|
@ -61,7 +62,7 @@ private:
|
||||||
ChildWidget<LinkButton> _chooseFromGallery;
|
ChildWidget<LinkButton> _chooseFromGallery;
|
||||||
ChildWidget<LinkButton> _chooseFromFile;
|
ChildWidget<LinkButton> _chooseFromFile;
|
||||||
|
|
||||||
RadialAnimation _radial;
|
Ui::RadialAnimation _radial;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
#include "media/media_audio.h"
|
#include "media/media_audio.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
|
#include "history/history_media_types.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int peerColorIndex(const PeerId &peer) {
|
int peerColorIndex(const PeerId &peer) {
|
||||||
|
@ -1628,12 +1629,11 @@ WebPageData::WebPageData(const WebPageId &id, WebPageType type, const QString &u
|
||||||
, pendingTill(pendingTill) {
|
, pendingTill(pendingTill) {
|
||||||
}
|
}
|
||||||
|
|
||||||
GameData::GameData(const GameId &id, const uint64 &accessHash, const QString &shortName, const QString &title, const QString &description, const QString &url, PhotoData *photo, DocumentData *document) : id(id)
|
GameData::GameData(const GameId &id, const uint64 &accessHash, const QString &shortName, const QString &title, const QString &description, PhotoData *photo, DocumentData *document) : id(id)
|
||||||
, accessHash(accessHash)
|
, accessHash(accessHash)
|
||||||
, shortName(shortName)
|
, shortName(shortName)
|
||||||
, title(title)
|
, title(title)
|
||||||
, description(description)
|
, description(description)
|
||||||
, url(url)
|
|
||||||
, photo(photo)
|
, photo(photo)
|
||||||
, document(document) {
|
, document(document) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -1368,7 +1368,7 @@ struct WebPageData {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GameData {
|
struct GameData {
|
||||||
GameData(const GameId &id, const uint64 &accessHash = 0, const QString &shortName = QString(), const QString &title = QString(), const QString &description = QString(), const QString &url = QString(), PhotoData *photo = nullptr, DocumentData *doc = nullptr);
|
GameData(const GameId &id, const uint64 &accessHash = 0, const QString &shortName = QString(), const QString &title = QString(), const QString &description = QString(), PhotoData *photo = nullptr, DocumentData *doc = nullptr);
|
||||||
|
|
||||||
void forget() {
|
void forget() {
|
||||||
if (document) document->forget();
|
if (document) document->forget();
|
||||||
|
@ -1377,7 +1377,7 @@ struct GameData {
|
||||||
|
|
||||||
GameId id;
|
GameId id;
|
||||||
uint64 accessHash;
|
uint64 accessHash;
|
||||||
QString shortName, title, description, url;
|
QString shortName, title, description;
|
||||||
PhotoData *photo;
|
PhotoData *photo;
|
||||||
DocumentData *document;
|
DocumentData *document;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
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-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "ui/effects/radial_animation.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
RadialAnimation::RadialAnimation(AnimationCallbacks &&callbacks)
|
||||||
|
: a_arcEnd(0, 0)
|
||||||
|
, a_arcStart(0, FullArcLength)
|
||||||
|
, _animation(std_::move(callbacks)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void RadialAnimation::start(float64 prg) {
|
||||||
|
_firstStart = _lastStart = _lastTime = getms();
|
||||||
|
int32 iprg = qRound(qMax(prg, 0.0001) * AlmostFullArcLength), iprgstrict = qRound(prg * AlmostFullArcLength);
|
||||||
|
a_arcEnd = anim::ivalue(iprgstrict, iprg);
|
||||||
|
_animation.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RadialAnimation::update(float64 prg, bool finished, uint64 ms) {
|
||||||
|
int32 iprg = qRound(qMax(prg, 0.0001) * AlmostFullArcLength);
|
||||||
|
if (iprg != a_arcEnd.to()) {
|
||||||
|
a_arcEnd.start(iprg);
|
||||||
|
_lastStart = _lastTime;
|
||||||
|
}
|
||||||
|
_lastTime = ms;
|
||||||
|
|
||||||
|
float64 dt = float64(ms - _lastStart), fulldt = float64(ms - _firstStart);
|
||||||
|
_opacity = qMin(fulldt / st::radialDuration, 1.);
|
||||||
|
if (!finished) {
|
||||||
|
a_arcEnd.update(1. - (st::radialDuration / (st::radialDuration + dt)), anim::linear);
|
||||||
|
} else if (dt >= st::radialDuration) {
|
||||||
|
a_arcEnd.update(1, anim::linear);
|
||||||
|
stop();
|
||||||
|
} else {
|
||||||
|
float64 r = dt / st::radialDuration;
|
||||||
|
a_arcEnd.update(r, anim::linear);
|
||||||
|
_opacity *= 1 - r;
|
||||||
|
}
|
||||||
|
float64 fromstart = fulldt / st::radialPeriod;
|
||||||
|
a_arcStart.update(fromstart - std::floor(fromstart), anim::linear);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RadialAnimation::stop() {
|
||||||
|
_firstStart = _lastStart = _lastTime = 0;
|
||||||
|
a_arcEnd = anim::ivalue(0, 0);
|
||||||
|
_animation.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RadialAnimation::step(uint64 ms) {
|
||||||
|
_animation.step(ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RadialAnimation::draw(Painter &p, const QRect &inner, int32 thickness, const style::color &color) {
|
||||||
|
float64 o = p.opacity();
|
||||||
|
p.setOpacity(o * _opacity);
|
||||||
|
|
||||||
|
QPen pen(color->p), was(p.pen());
|
||||||
|
pen.setWidth(thickness);
|
||||||
|
p.setPen(pen);
|
||||||
|
|
||||||
|
int32 len = MinArcLength + a_arcEnd.current();
|
||||||
|
int32 from = QuarterArcLength - a_arcStart.current() - len;
|
||||||
|
if (rtl()) {
|
||||||
|
from = QuarterArcLength - (from - QuarterArcLength) - len;
|
||||||
|
if (from < 0) from += FullArcLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||||
|
p.drawArc(inner, from, len);
|
||||||
|
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
|
||||||
|
|
||||||
|
p.setPen(was);
|
||||||
|
p.setOpacity(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Ui
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
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-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
class RadialAnimation {
|
||||||
|
public:
|
||||||
|
RadialAnimation(AnimationCallbacks &&callbacks);
|
||||||
|
|
||||||
|
float64 opacity() const {
|
||||||
|
return _opacity;
|
||||||
|
}
|
||||||
|
bool animating() const {
|
||||||
|
return _animation.animating();
|
||||||
|
}
|
||||||
|
|
||||||
|
void start(float64 prg);
|
||||||
|
void update(float64 prg, bool finished, uint64 ms);
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
void step(uint64 ms);
|
||||||
|
void step() {
|
||||||
|
step(getms());
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw(Painter &p, const QRect &inner, int32 thickness, const style::color &color);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64 _firstStart = 0;
|
||||||
|
uint64 _lastStart = 0;
|
||||||
|
uint64 _lastTime = 0;
|
||||||
|
float64 _opacity = 0.;
|
||||||
|
anim::ivalue a_arcEnd, a_arcStart;
|
||||||
|
Animation _animation;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Ui
|
|
@ -2891,6 +2891,10 @@ TextSelection Text::adjustSelection(TextSelection selection, TextSelectType sele
|
||||||
return { from, to };
|
return { from, to };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Text::isEmpty() const {
|
||||||
|
return _blocks.empty() || _blocks[0]->type() == TextBlockTSkip;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename AppendPartCallback, typename ClickHandlerStartCallback, typename ClickHandlerFinishCallback, typename FlagsChangeCallback>
|
template <typename AppendPartCallback, typename ClickHandlerStartCallback, typename ClickHandlerFinishCallback, typename FlagsChangeCallback>
|
||||||
void Text::enumerateText(TextSelection selection, AppendPartCallback appendPartCallback, ClickHandlerStartCallback clickHandlerStartCallback, ClickHandlerFinishCallback clickHandlerFinishCallback, FlagsChangeCallback flagsChangeCallback) const {
|
void Text::enumerateText(TextSelection selection, AppendPartCallback appendPartCallback, ClickHandlerStartCallback clickHandlerStartCallback, ClickHandlerFinishCallback clickHandlerFinishCallback, FlagsChangeCallback flagsChangeCallback) const {
|
||||||
if (isEmpty() || selection.empty()) {
|
if (isEmpty() || selection.empty()) {
|
||||||
|
|
|
@ -173,9 +173,7 @@ public:
|
||||||
return (selection.from == 0) && (selection.to >= _text.size());
|
return (selection.from == 0) && (selection.to >= _text.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isEmpty() const {
|
bool isEmpty() const;
|
||||||
return _text.isEmpty();
|
|
||||||
}
|
|
||||||
bool isNull() const {
|
bool isNull() const {
|
||||||
return !_font;
|
return !_font;
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,8 +222,9 @@
|
||||||
'<(src_loc)/history/history_item.h',
|
'<(src_loc)/history/history_item.h',
|
||||||
'<(src_loc)/history/history_location_manager.cpp',
|
'<(src_loc)/history/history_location_manager.cpp',
|
||||||
'<(src_loc)/history/history_location_manager.h',
|
'<(src_loc)/history/history_location_manager.h',
|
||||||
'<(src_loc)/history/history_media.cpp',
|
|
||||||
'<(src_loc)/history/history_media.h',
|
'<(src_loc)/history/history_media.h',
|
||||||
|
'<(src_loc)/history/history_media_types.cpp',
|
||||||
|
'<(src_loc)/history/history_media_types.h',
|
||||||
'<(src_loc)/history/history_message.cpp',
|
'<(src_loc)/history/history_message.cpp',
|
||||||
'<(src_loc)/history/history_message.h',
|
'<(src_loc)/history/history_message.h',
|
||||||
'<(src_loc)/history/history_service_layout.cpp',
|
'<(src_loc)/history/history_service_layout.cpp',
|
||||||
|
@ -404,6 +405,8 @@
|
||||||
'<(src_loc)/ui/buttons/round_button.h',
|
'<(src_loc)/ui/buttons/round_button.h',
|
||||||
'<(src_loc)/ui/effects/fade_animation.cpp',
|
'<(src_loc)/ui/effects/fade_animation.cpp',
|
||||||
'<(src_loc)/ui/effects/fade_animation.h',
|
'<(src_loc)/ui/effects/fade_animation.h',
|
||||||
|
'<(src_loc)/ui/effects/radial_animation.cpp',
|
||||||
|
'<(src_loc)/ui/effects/radial_animation.h',
|
||||||
'<(src_loc)/ui/style/style_core.cpp',
|
'<(src_loc)/ui/style/style_core.cpp',
|
||||||
'<(src_loc)/ui/style/style_core.h',
|
'<(src_loc)/ui/style/style_core.h',
|
||||||
'<(src_loc)/ui/style/style_core_color.cpp',
|
'<(src_loc)/ui/style/style_core_color.cpp',
|
||||||
|
|
Loading…
Reference in New Issue