merged for 0.9.16

This commit is contained in:
John Preston 2016-01-04 19:46:15 +08:00
commit 433243fcca
19 changed files with 575 additions and 269 deletions

View File

@ -61,7 +61,7 @@ In Terminal go to **/home/user/TBuild/Libraries** and run
sudo apt-get -y --force-yes install autoconf automake build-essential libass-dev libfreetype6-dev libgpac-dev libsdl1.2-dev libtheora-dev libtool libva-dev libvdpau-dev libvorbis-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev pkg-config texi2html zlib1g-dev sudo apt-get -y --force-yes install autoconf automake build-essential libass-dev libfreetype6-dev libgpac-dev libsdl1.2-dev libtheora-dev libtool libva-dev libvdpau-dev libvorbis-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev pkg-config texi2html zlib1g-dev
sudo apt-get install yasm sudo apt-get install yasm
./configure --prefix=/usr/local --disable-programs --disable-pthreads --disable-doc --disable-everything --enable-libopus --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=aasc --enable-decoder=flac --enable-decoder=gif --enable-decoder=h264 --enable-decoder=h264_vdpau --enable-decoder=mp1 --enable-decoder=mp1float --enable-decoder=mp2 --enable-decoder=mp2float --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mp3adufloat --enable-decoder=mp3float --enable-decoder=mp3on4 --enable-decoder=mp3on4float --enable-decoder=mpeg4 --enable-decoder=mpeg4_vdpau --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=opus --enable-decoder=vorbis --enable-decoder=wavpack --enable-decoder=wmalossless --enable-decoder=wmapro --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmavoice --enable-encoder=libopus --enable-hwaccel=h264_vaapi --enable-hwaccel=h264_vdpau --enable-hwaccel=mpeg4_vaapi --enable-hwaccel=mpeg4_vdpau --enable-parser=aac --enable-parser=aac_latm --enable-parser=flac --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=opus --enable-parser=vorbis --enable-demuxer=aac --enable-demuxer=flac --enable-demuxer=gif --enable-demuxer=h264 --enable-demuxer=mov --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=wav --enable-muxer=ogg --enable-muxer=opus ./configure --prefix=/usr/local --disable-programs --disable-doc --disable-pthreads --disable-mmx --disable-everything --enable-libopus --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=aasc --enable-decoder=flac --enable-decoder=gif --enable-decoder=h264 --enable-decoder=h264_vdpau --enable-decoder=mp1 --enable-decoder=mp1float --enable-decoder=mp2 --enable-decoder=mp2float --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mp3adufloat --enable-decoder=mp3float --enable-decoder=mp3on4 --enable-decoder=mp3on4float --enable-decoder=mpeg4 --enable-decoder=mpeg4_vdpau --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=opus --enable-decoder=vorbis --enable-decoder=wavpack --enable-decoder=wmalossless --enable-decoder=wmapro --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmavoice --enable-encoder=libopus --enable-hwaccel=h264_vaapi --enable-hwaccel=h264_vdpau --enable-hwaccel=mpeg4_vaapi --enable-hwaccel=mpeg4_vdpau --enable-parser=aac --enable-parser=aac_latm --enable-parser=flac --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=opus --enable-parser=vorbis --enable-demuxer=aac --enable-demuxer=flac --enable-demuxer=gif --enable-demuxer=h264 --enable-demuxer=mov --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=wav --enable-muxer=ogg --enable-muxer=opus
make make
sudo make install sudo make install

View File

@ -1197,6 +1197,18 @@ msgFileRedColor: #e47272;
msgFileYellowColor: #efc274; msgFileYellowColor: #efc274;
msgFileGreenColor: #61b96e; msgFileGreenColor: #61b96e;
msgFileBlueColor: #72b1df; msgFileBlueColor: #72b1df;
msgFileRedDark: #cd5b5e;
msgFileYellowDark: #e6a561;
msgFileGreenDark: #4da859;
msgFileBlueDark: #5c9ece;
msgFileRedOver: #c35154;
msgFileYellowOver: #dc9c5a;
msgFileGreenOver: #44a050;
msgFileBlueOver: #5294c4;
msgFileRedSelected: #9f6a82;
msgFileYellowSelected: #b19d84;
msgFileGreenSelected: #46a07e;
msgFileBlueSelected: #5099d0;
msgFileMenuSize: size(36px, 36px); msgFileMenuSize: size(36px, 36px);
msgFileSize: 44px; msgFileSize: 44px;
@ -2161,6 +2173,14 @@ overviewPhotoCheck: sprite(245px, 308px, 32px, 32px);
overviewPhotoChecked: sprite(278px, 308px, 32px, 32px); overviewPhotoChecked: sprite(278px, 308px, 32px, 32px);
overviewPhotoSelectOverlay: #0a7bb03f; overviewPhotoSelectOverlay: #0a7bb03f;
overviewFilePadding: margins(0px, 3px, 16px, 3px);
overviewFileSize: 70px;
overviewFileNameTop: 7px;
overviewFileStatusTop: 27px;
overviewFileDateTop: 49px;
overviewFileChecked: #2fa9e2;
overviewFileCheck: #00000066;
// Mac specific // Mac specific
macAccessory: size(450, 90); macAccessory: size(450, 90);
@ -2346,11 +2366,12 @@ playlistPadding: 10px;
linksSearchMargin: margins(20px, 20px, 20px, 0px); linksSearchMargin: margins(20px, 20px, 20px, 0px);
linksMaxWidth: 520px; linksMaxWidth: 520px;
linksLetterFont: font(24px); linksLetterFont: font(24px);
linksMargin: 5px; linksMargin: margins(0px, 7px, 0px, 5px);
linksTextTop: 6px;
linksBorder: 1px; linksBorder: 1px;
linksBorderFg: #eaeaea; linksBorderFg: #eaeaea;
linksDateColor: #000; linksDateColor: #808080;
linksDateMargin: 15px; linksDateMargin: margins(0px, 15px, 0px, 2px);
linksPhotoCheck: sprite(184px, 196px, 16px, 16px); linksPhotoCheck: sprite(184px, 196px, 16px, 16px);
linksPhotoChecked: sprite(168px, 196px, 16px, 16px); linksPhotoChecked: sprite(168px, 196px, 16px, 16px);

View File

@ -708,7 +708,7 @@ void Application::checkMapVersion() {
if (cDevVersion() && Local::oldMapVersion() < 9016) { if (cDevVersion() && Local::oldMapVersion() < 9016) {
// versionFeatures = QString::fromUtf8("\xe2\x80\x94 Sticker management: manually rearrange your sticker packs, pack order is now synced across all your devices\n\xe2\x80\x94 Click and hold on a sticker to preview it before sending\n\xe2\x80\x94 New context menu for chats in chats list\n\xe2\x80\x94 Support for all existing emoji");// .replace('@', qsl("@") + QChar(0x200D)); // versionFeatures = QString::fromUtf8("\xe2\x80\x94 Sticker management: manually rearrange your sticker packs, pack order is now synced across all your devices\n\xe2\x80\x94 Click and hold on a sticker to preview it before sending\n\xe2\x80\x94 New context menu for chats in chats list\n\xe2\x80\x94 Support for all existing emoji");// .replace('@', qsl("@") + QChar(0x200D));
versionFeatures = lng_new_version_text(lt_gifs_link, qsl("https://telegram.org/blog/gif-revolution"), lt_bots_link, qsl("https://telegram.org/blog/inline-bots")).trimmed(); versionFeatures = lng_new_version_text(lt_gifs_link, qsl("https://telegram.org/blog/gif-revolution"), lt_bots_link, qsl("https://telegram.org/blog/inline-bots")).trimmed();
} else if (Local::oldMapVersion() < 9015) { } else if (Local::oldMapVersion() < 9016) {
versionFeatures = lng_new_version_text(lt_gifs_link, qsl("https://telegram.org/blog/gif-revolution"), lt_bots_link, qsl("https://telegram.org/blog/inline-bots")).trimmed(); versionFeatures = lng_new_version_text(lt_gifs_link, qsl("https://telegram.org/blog/gif-revolution"), lt_bots_link, qsl("https://telegram.org/blog/inline-bots")).trimmed();
} else { } else {
versionFeatures = lang(lng_new_version_minor).trimmed(); versionFeatures = lang(lng_new_version_minor).trimmed();

View File

@ -20,10 +20,10 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
static const int32 AppVersion = 9015; static const int32 AppVersion = 9016;
static const wchar_t *AppVersionStr = L"0.9.15"; static const wchar_t *AppVersionStr = L"0.9.16";
static const bool DevVersion = false; static const bool DevVersion = false;
#define BETA_VERSION (9015007ULL) // just comment this line to build public version //#define BETA_VERSION (9015008ULL) // just comment this line to build public version
static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)"; static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";
static const wchar_t *AppName = L"Telegram Desktop"; static const wchar_t *AppName = L"Telegram Desktop";

View File

@ -1663,14 +1663,14 @@ void StickerPanInner::refreshStickers() {
updateSelected(); updateSelected();
} }
void StickerPanInner::inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, InlineRow &row, int32 &sumWidth) { bool StickerPanInner::inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, InlineRow &row, int32 &sumWidth) {
LayoutInlineItem *layout = 0; LayoutInlineItem *layout = 0;
if (savedGif) { if (savedGif) {
layout = layoutPrepareSavedGif(savedGif, (_inlineRows.size() * MatrixRowShift) + row.items.size()); layout = layoutPrepareSavedGif(savedGif, (_inlineRows.size() * MatrixRowShift) + row.items.size());
} else if (result) { } else if (result) {
layout = layoutPrepareInlineResult(result, (_inlineRows.size() * MatrixRowShift) + row.items.size()); layout = layoutPrepareInlineResult(result, (_inlineRows.size() * MatrixRowShift) + row.items.size());
} }
if (!layout) return; if (!layout) return false;
layout->preload(); layout->preload();
if (inlineRowFinalize(row, sumWidth, layout->fullLine())) { if (inlineRowFinalize(row, sumWidth, layout->fullLine())) {
@ -1678,6 +1678,7 @@ void StickerPanInner::inlineRowsAddItem(DocumentData *savedGif, InlineResult *re
} }
row.items.push_back(layout); row.items.push_back(layout);
sumWidth += layout->maxWidth(); sumWidth += layout->maxWidth();
return true;
} }
bool StickerPanInner::inlineRowFinalize(InlineRow &row, int32 &sumWidth, bool force) { bool StickerPanInner::inlineRowFinalize(InlineRow &row, int32 &sumWidth, bool force) {
@ -1770,7 +1771,7 @@ LayoutInlineItem *StickerPanInner::layoutPrepareInlineResult(InlineResult *resul
layout = new LayoutInlineGif(result, 0, false); layout = new LayoutInlineGif(result, 0, false);
} else if (result->type == qstr("photo")) { } else if (result->type == qstr("photo")) {
layout = new LayoutInlinePhoto(result, 0); layout = new LayoutInlinePhoto(result, 0);
} else if (result->type == qstr("web_player_video")) { } else if (result->type == qstr("video")) {
layout = new LayoutInlineWebVideo(result); layout = new LayoutInlineWebVideo(result);
} else if (result->type == qstr("article")) { } else if (result->type == qstr("article")) {
layout = new LayoutInlineArticle(result, _inlineWithThumb); layout = new LayoutInlineArticle(result, _inlineWithThumb);
@ -1901,14 +1902,14 @@ void StickerPanInner::clearInlineRowsPanel() {
clearInlineRows(false); clearInlineRows(false);
} }
void StickerPanInner::refreshInlineRows(UserData *bot, const InlineResults &results, bool resultsDeleted) { int32 StickerPanInner::refreshInlineRows(UserData *bot, const InlineResults &results, bool resultsDeleted) {
_inlineBot = bot; _inlineBot = bot;
if (results.isEmpty() && (!_inlineBot || _inlineBot->username != cInlineGifBotUsername())) { if (results.isEmpty() && (!_inlineBot || _inlineBot->username != cInlineGifBotUsername())) {
if (resultsDeleted) { if (resultsDeleted) {
clearInlineRows(true); clearInlineRows(true);
} }
emit emptyInlineRows(); emit emptyInlineRows();
return; return 0;
} }
if (_showingInlineItems) { if (_showingInlineItems) {
@ -1921,7 +1922,7 @@ void StickerPanInner::refreshInlineRows(UserData *bot, const InlineResults &resu
_showingInlineItems = true; _showingInlineItems = true;
_showingSavedGifs = false; _showingSavedGifs = false;
int32 count = results.size(), from = validateExistingInlineRows(results); int32 count = results.size(), from = validateExistingInlineRows(results), added = 0;
if (count) { if (count) {
_inlineRows.reserve(count); _inlineRows.reserve(count);
@ -1929,7 +1930,9 @@ void StickerPanInner::refreshInlineRows(UserData *bot, const InlineResults &resu
row.items.reserve(SavedGifsMaxPerRow); row.items.reserve(SavedGifsMaxPerRow);
int32 sumWidth = 0; int32 sumWidth = 0;
for (int32 i = from; i < count; ++i) { for (int32 i = from; i < count; ++i) {
inlineRowsAddItem(0, results.at(i), row, sumWidth); if (inlineRowsAddItem(0, results.at(i), row, sumWidth)) {
++added;
}
} }
inlineRowFinalize(row, sumWidth, true); inlineRowFinalize(row, sumWidth, true);
} }
@ -1943,6 +1946,8 @@ void StickerPanInner::refreshInlineRows(UserData *bot, const InlineResults &resu
_lastMousePos = QCursor::pos(); _lastMousePos = QCursor::pos();
updateSelected(); updateSelected();
} }
return added;
} }
int32 StickerPanInner::validateExistingInlineRows(const InlineResults &results) { int32 StickerPanInner::validateExistingInlineRows(const InlineResults &results) {
@ -3722,7 +3727,10 @@ void EmojiPan::inlineResultsDone(const MTPmessages_BotResults &result) {
} else if (adding) { } else if (adding) {
it.value()->nextOffset = QString(); it.value()->nextOffset = QString();
} }
showInlineRows(!adding);
if (!showInlineRows(!adding)) {
it.value()->nextOffset = QString();
}
onScroll(); onScroll();
} }
@ -3782,7 +3790,7 @@ void EmojiPan::onEmptyInlineRows() {
} }
} }
bool EmojiPan::refreshInlineRows() { bool EmojiPan::refreshInlineRows(int32 *added) {
bool clear = true; bool clear = true;
InlineCache::const_iterator i = _inlineCache.constFind(_inlineQuery); InlineCache::const_iterator i = _inlineCache.constFind(_inlineQuery);
if (i != _inlineCache.cend()) { if (i != _inlineCache.cend()) {
@ -3790,12 +3798,14 @@ bool EmojiPan::refreshInlineRows() {
_inlineNextOffset = i.value()->nextOffset; _inlineNextOffset = i.value()->nextOffset;
} }
if (clear) prepareShowHideCache(); if (clear) prepareShowHideCache();
s_inner.refreshInlineRows(_inlineBot, clear ? InlineResults() : i.value()->results, false); int32 result = s_inner.refreshInlineRows(_inlineBot, clear ? InlineResults() : i.value()->results, false);
if (added) *added = result;
return !clear; return !clear;
} }
void EmojiPan::showInlineRows(bool newResults) { int32 EmojiPan::showInlineRows(bool newResults) {
bool clear = !refreshInlineRows(); int32 added = 0;
bool clear = !refreshInlineRows(&added);
if (newResults) s_scroll.scrollToY(0); if (newResults) s_scroll.scrollToY(0);
e_switch.updateText(clear ? QString() : _inlineBot->username); e_switch.updateText(clear ? QString() : _inlineBot->username);
@ -3819,6 +3829,8 @@ void EmojiPan::showInlineRows(bool newResults) {
onSwitch(); onSwitch();
} }
} }
return added;
} }
void EmojiPan::recountContentMaxHeight() { void EmojiPan::recountContentMaxHeight() {

View File

@ -344,7 +344,7 @@ public:
void refreshStickers(); void refreshStickers();
void refreshRecentStickers(bool resize = true); void refreshRecentStickers(bool resize = true);
void refreshSavedGifs(); void refreshSavedGifs();
void refreshInlineRows(UserData *bot, const InlineResults &results, bool resultsDeleted); int32 refreshInlineRows(UserData *bot, const InlineResults &results, bool resultsDeleted);
void refreshRecent(); void refreshRecent();
void inlineBotChanged(); void inlineBotChanged();
void hideInlineRowsPanel(); void hideInlineRowsPanel();
@ -458,7 +458,7 @@ private:
InlineLayouts _inlineLayouts; InlineLayouts _inlineLayouts;
LayoutInlineItem *layoutPrepareInlineResult(InlineResult *result, int32 position); LayoutInlineItem *layoutPrepareInlineResult(InlineResult *result, int32 position);
void inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, InlineRow &row, int32 &sumWidth); bool inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, InlineRow &row, int32 &sumWidth);
bool inlineRowFinalize(InlineRow &row, int32 &sumWidth, bool force = false); bool inlineRowFinalize(InlineRow &row, int32 &sumWidth, bool force = false);
InlineRow &layoutInlineRow(InlineRow &row, int32 sumWidth = 0); InlineRow &layoutInlineRow(InlineRow &row, int32 sumWidth = 0);
@ -712,10 +712,10 @@ private:
QTimer _inlineRequestTimer; QTimer _inlineRequestTimer;
void inlineBotChanged(); void inlineBotChanged();
void showInlineRows(bool newResults); int32 showInlineRows(bool newResults);
bool hideOnNoInlineResults(); bool hideOnNoInlineResults();
void recountContentMaxHeight(); void recountContentMaxHeight();
bool refreshInlineRows(); bool refreshInlineRows(int32 *added = 0);
UserData *_inlineBot; UserData *_inlineBot;
QString _inlineQuery, _inlineNextQuery, _inlineNextOffset; QString _inlineQuery, _inlineNextQuery, _inlineNextOffset;
mtpRequestId _inlineRequestId; mtpRequestId _inlineRequestId;

View File

@ -225,7 +225,7 @@ ClipReader::ClipReader(const FileLocation &location, const QByteArray &data, Cal
, _state(ClipReading) , _state(ClipReading)
, _width(0) , _width(0)
, _height(0) , _height(0)
, _step(FirstFrameNotReadStep) , _step(WaitingForDimensionsStep)
, _paused(0) , _paused(0)
, _autoplay(false) , _autoplay(false)
, _private(0) { , _private(0) {
@ -248,47 +248,69 @@ ClipReader::ClipReader(const FileLocation &location, const QByteArray &data, Cal
_clipManagers.at(_threadIndex)->append(this, location, data); _clipManagers.at(_threadIndex)->append(this, location, data);
} }
ClipReader::Frame *ClipReader::frameToShow() const { // 0 means not ready ClipReader::Frame *ClipReader::frameToShow(int32 *index) const { // 0 means not ready
int32 step = _step.loadAcquire(); int32 step = _step.loadAcquire(), i;
if (step == FirstFrameNotReadStep) { if (step == WaitingForDimensionsStep) {
return 0;
} else if (step == WaitingForRequestStep) {
return _frames;
}
return _frames + (((step + 1) / 2) % 3);
}
ClipReader::Frame *ClipReader::frameToWrite(int32 *index) const { // 0 means not ready
int32 step = _step.loadAcquire(), i = 0;
if (step == WaitingForRequestStep) {
if (index) *index = 0; if (index) *index = 0;
return 0; return 0;
} else if (step != FirstFrameNotReadStep) { } else if (step == WaitingForRequestStep) {
i = (((step + 3) / 2) % 3); i = 0;
} else if (step == WaitingForFirstFrameStep) {
i = 0;
} else {
i = (step / 2) % 3;
} }
if (index) *index = i; if (index) *index = i;
return _frames + i; return _frames + i;
} }
ClipReader::Frame *ClipReader::frameToWriteNext(bool checkNotWriting) const { ClipReader::Frame *ClipReader::frameToWrite(int32 *index) const { // 0 means not ready
int32 step = _step.loadAcquire(); int32 step = _step.loadAcquire(), i;
if (step == FirstFrameNotReadStep || step == WaitingForRequestStep || (checkNotWriting && !(step % 2))) { if (step == WaitingForDimensionsStep) {
i = 0;
} else if (step == WaitingForRequestStep) {
if (index) *index = 0;
return 0;
} else if (step == WaitingForFirstFrameStep) {
i = 0;
} else {
i = ((step + 2) / 2) % 3;
}
if (index) *index = i;
return _frames + i;
}
ClipReader::Frame *ClipReader::frameToWriteNext(bool checkNotWriting, int32 *index) const {
int32 step = _step.loadAcquire(), i;
if (step == WaitingForDimensionsStep || step == WaitingForRequestStep || (checkNotWriting && (step % 2))) {
if (index) *index = 0;
return 0; return 0;
} }
return _frames + (((step + 5) / 2) % 3); i = ((step + 4) / 2) % 3;
if (index) *index = i;
return _frames + i;
} }
void ClipReader::moveToNextShow() const { void ClipReader::moveToNextShow() const {
int32 step = _step.loadAcquire(); int32 step = _step.loadAcquire();
if (step % 2) { if (step == WaitingForDimensionsStep) {
_step.storeRelease((step + 1) % 6); } else if (step == WaitingForRequestStep) {
_step.storeRelease(WaitingForFirstFrameStep);
} else if (step == WaitingForFirstFrameStep) {
} else if (!(step % 2)) {
_step.storeRelease(step + 1);
} }
} }
void ClipReader::moveToNextWrite() const { void ClipReader::moveToNextWrite() const {
int32 step = _step.loadAcquire(); int32 step = _step.loadAcquire();
if (!(step % 2)) { if (step == WaitingForDimensionsStep) {
_step.storeRelease(step + 1); _step.storeRelease(WaitingForRequestStep);
} else if (step == WaitingForRequestStep) {
} else if (step == WaitingForFirstFrameStep) {
_step.storeRelease(0);
} else if (step % 2) {
_step.storeRelease((step + 1) % 6);
} }
} }
@ -313,7 +335,7 @@ void ClipReader::start(int32 framew, int32 frameh, int32 outerw, int32 outerh, b
request.outerh = outerh * factor; request.outerh = outerh * factor;
request.rounded = rounded; request.rounded = rounded;
_frames[0].request = _frames[1].request = _frames[2].request = request; _frames[0].request = _frames[1].request = _frames[2].request = request;
_step.storeRelease(0); // start working moveToNextShow();
_clipManagers.at(_threadIndex)->start(this); _clipManagers.at(_threadIndex)->start(this);
} }
} }
@ -322,9 +344,8 @@ QPixmap ClipReader::current(int32 framew, int32 frameh, int32 outerw, int32 oute
Frame *frame = frameToShow(); Frame *frame = frameToShow();
t_assert(frame != 0); t_assert(frame != 0);
frame->displayed = true;
if (ms) { if (ms) {
frame->when = ms; frame->displayed.storeRelease(1);
if (_paused.loadAcquire()) { if (_paused.loadAcquire()) {
_paused.storeRelease(0); _paused.storeRelease(0);
if (_clipManagers.size() <= _threadIndex) error(); if (_clipManagers.size() <= _threadIndex) error();
@ -332,6 +353,8 @@ QPixmap ClipReader::current(int32 framew, int32 frameh, int32 outerw, int32 oute
_clipManagers.at(_threadIndex)->update(this); _clipManagers.at(_threadIndex)->update(this);
} }
} }
} else {
frame->displayed.storeRelease(-1); // displayed, but should be paused
} }
int32 factor(cIntRetinaFactor()); int32 factor(cIntRetinaFactor());
@ -412,7 +435,8 @@ public:
, _device(0) , _device(0)
, _dataSize(0) { , _dataSize(0) {
} }
virtual bool readNextFrame(QImage &to, bool &hasAlpha, const QSize &size) = 0; virtual bool readNextFrame() = 0;
virtual bool renderFrame(QImage &to, bool &hasAlpha, const QSize &size) = 0;
virtual int32 nextFrameDelay() = 0; virtual int32 nextFrameDelay() = 0;
virtual bool start(bool onlyGifv) = 0; virtual bool start(bool onlyGifv) = 0;
virtual ~ClipReaderImplementation() { virtual ~ClipReaderImplementation() {
@ -459,30 +483,35 @@ public:
return false; return false;
} }
QImage frame; // QGifHandler always reads first to internal QImage and returns it _frame = QImage(); // QGifHandler always reads first to internal QImage and returns it
if (!_reader->read(&frame)) { if (!_reader->read(&_frame) || _frame.isNull()) {
return false; return false;
} }
--_framesLeft; --_framesLeft;
return true;
}
if (size.isEmpty() || size == frame.size()) { bool renderFrame(QImage &to, bool &hasAlpha, const QSize &size) {
int32 w = frame.width(), h = frame.height(); t_assert(!_frame.isNull());
if (to.width() == w && to.height() == h && to.format() == frame.format()) { if (size.isEmpty() || size == _frame.size()) {
if (to.byteCount() != frame.byteCount()) { int32 w = _frame.width(), h = _frame.height();
int bpl = qMin(to.bytesPerLine(), frame.bytesPerLine()); if (to.width() == w && to.height() == h && to.format() == _frame.format()) {
if (to.byteCount() != _frame.byteCount()) {
int bpl = qMin(to.bytesPerLine(), _frame.bytesPerLine());
for (int i = 0; i < h; ++i) { for (int i = 0; i < h; ++i) {
memcpy(to.scanLine(i), frame.constScanLine(i), bpl); memcpy(to.scanLine(i), _frame.constScanLine(i), bpl);
} }
} else { } else {
memcpy(to.bits(), frame.constBits(), frame.byteCount()); memcpy(to.bits(), _frame.constBits(), _frame.byteCount());
} }
} else { } else {
to = frame.copy(); to = _frame.copy();
} }
} else { } else {
to = frame.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); to = _frame.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
} }
hasAlpha = frame.hasAlphaChannel(); hasAlpha = _frame.hasAlphaChannel();
_frame = QImage();
return true; return true;
} }
@ -502,6 +531,7 @@ public:
private: private:
QImageReader *_reader; QImageReader *_reader;
int32 _framesLeft, _frameDelay; int32 _framesLeft, _frameDelay;
QImage _frame;
bool jumpToStart() { bool jumpToStart() {
if (_reader && _reader->jumpToImage(0)) { if (_reader && _reader->jumpToImage(0)) {
@ -540,6 +570,7 @@ public:
, _frame(0) , _frame(0)
, _opened(false) , _opened(false)
, _hadFrame(false) , _hadFrame(false)
, _frameRead(false)
, _packetSize(0) , _packetSize(0)
, _packetData(0) , _packetData(0)
, _packetWas(false) , _packetWas(false)
@ -555,7 +586,7 @@ public:
_avpkt.size = 0; _avpkt.size = 0;
} }
bool readNextFrame(QImage &to, bool &hasAlpha, const QSize &size) { bool readNextFrame() {
int res; int res;
while (true) { while (true) {
if (_avpkt.size > 0) { // previous packet not finished if (_avpkt.size > 0) { // previous packet not finished
@ -607,56 +638,7 @@ public:
} }
if (got_frame) { if (got_frame) {
_hadFrame = true; _hadFrame = _frameRead = true;
if (!_width || !_height) {
_width = _frame->width;
_height = _frame->height;
if (!_width || !_height) {
LOG(("Gif Error: Bad frame size %1").arg(logData()));
return false;
}
}
QSize toSize(size.isEmpty() ? QSize(_width, _height) : size);
if (to.isNull() || to.size() != toSize) {
to = QImage(toSize, QImage::Format_ARGB32);
}
hasAlpha = (_frame->format == AV_PIX_FMT_BGRA || (_frame->format == -1 && _codecContext->pix_fmt == AV_PIX_FMT_BGRA));
if (_frame->width == toSize.width() && _frame->height == toSize.height() && hasAlpha) {
int32 sbpl = _frame->linesize[0], dbpl = to.bytesPerLine(), bpl = qMin(sbpl, dbpl);
uchar *s = _frame->data[0], *d = to.bits();
for (int32 i = 0, l = _frame->height; i < l; ++i) {
memcpy(d + i * dbpl, s + i * sbpl, bpl);
}
} else {
if ((_swsSize != toSize) || (_frame->format != -1 && _frame->format != _codecContext->pix_fmt) || !_swsContext) {
_swsSize = toSize;
_swsContext = sws_getCachedContext(_swsContext, _frame->width, _frame->height, AVPixelFormat(_frame->format), toSize.width(), toSize.height(), AV_PIX_FMT_BGRA, 0, 0, 0, 0);
}
uint8_t * toData[1] = { to.bits() };
int toLinesize[1] = { to.bytesPerLine() };
if ((res = sws_scale(_swsContext, _frame->data, _frame->linesize, 0, _frame->height, toData, toLinesize)) != _swsSize.height()) {
LOG(("Gif Error: Unable to sws_scale to good size %1, height %2, should be %3").arg(logData()).arg(res).arg(_swsSize.height()));
return false;
}
}
int64 duration = av_frame_get_pkt_duration(_frame);
int64 framePts = (_frame->pkt_pts == AV_NOPTS_VALUE) ? _frame->pkt_dts : _frame->pkt_pts;
int64 frameMs = (framePts * 1000LL * _fmtContext->streams[_streamId]->time_base.num) / _fmtContext->streams[_streamId]->time_base.den;
_currentFrameDelay = _nextFrameDelay;
if (_frameMs + _currentFrameDelay < frameMs) {
_currentFrameDelay = int32(frameMs - _frameMs);
}
if (duration == AV_NOPTS_VALUE) {
_nextFrameDelay = 0;
} else {
_nextFrameDelay = (duration * 1000LL * _fmtContext->streams[_streamId]->time_base.num) / _fmtContext->streams[_streamId]->time_base.den;
}
_frameMs = frameMs;
av_frame_unref(_frame);
return true; return true;
} }
@ -681,6 +663,61 @@ public:
return false; return false;
} }
bool renderFrame(QImage &to, bool &hasAlpha, const QSize &size) {
t_assert(_frameRead);
_frameRead = false;
if (!_width || !_height) {
_width = _frame->width;
_height = _frame->height;
if (!_width || !_height) {
LOG(("Gif Error: Bad frame size %1").arg(logData()));
return false;
}
}
QSize toSize(size.isEmpty() ? QSize(_width, _height) : size);
if (to.isNull() || to.size() != toSize) {
to = QImage(toSize, QImage::Format_ARGB32);
}
hasAlpha = (_frame->format == AV_PIX_FMT_BGRA || (_frame->format == -1 && _codecContext->pix_fmt == AV_PIX_FMT_BGRA));
if (_frame->width == toSize.width() && _frame->height == toSize.height() && hasAlpha) {
int32 sbpl = _frame->linesize[0], dbpl = to.bytesPerLine(), bpl = qMin(sbpl, dbpl);
uchar *s = _frame->data[0], *d = to.bits();
for (int32 i = 0, l = _frame->height; i < l; ++i) {
memcpy(d + i * dbpl, s + i * sbpl, bpl);
}
} else {
if ((_swsSize != toSize) || (_frame->format != -1 && _frame->format != _codecContext->pix_fmt) || !_swsContext) {
_swsSize = toSize;
_swsContext = sws_getCachedContext(_swsContext, _frame->width, _frame->height, AVPixelFormat(_frame->format), toSize.width(), toSize.height(), AV_PIX_FMT_BGRA, 0, 0, 0, 0);
}
uint8_t * toData[1] = { to.bits() };
int toLinesize[1] = { to.bytesPerLine() }, res;
if ((res = sws_scale(_swsContext, _frame->data, _frame->linesize, 0, _frame->height, toData, toLinesize)) != _swsSize.height()) {
LOG(("Gif Error: Unable to sws_scale to good size %1, height %2, should be %3").arg(logData()).arg(res).arg(_swsSize.height()));
return false;
}
}
int64 duration = av_frame_get_pkt_duration(_frame);
int64 framePts = (_frame->pkt_pts == AV_NOPTS_VALUE) ? _frame->pkt_dts : _frame->pkt_pts;
int64 frameMs = (framePts * 1000LL * _fmtContext->streams[_streamId]->time_base.num) / _fmtContext->streams[_streamId]->time_base.den;
_currentFrameDelay = _nextFrameDelay;
if (_frameMs + _currentFrameDelay < frameMs) {
_currentFrameDelay = int32(frameMs - _frameMs);
}
if (duration == AV_NOPTS_VALUE) {
_nextFrameDelay = 0;
} else {
_nextFrameDelay = (duration * 1000LL * _fmtContext->streams[_streamId]->time_base.num) / _fmtContext->streams[_streamId]->time_base.den;
}
_frameMs = frameMs;
av_frame_unref(_frame);
return true;
}
int32 nextFrameDelay() { int32 nextFrameDelay() {
return _currentFrameDelay; return _currentFrameDelay;
} }
@ -776,7 +813,7 @@ private:
AVCodecContext *_codecContext; AVCodecContext *_codecContext;
int32 _streamId; int32 _streamId;
AVFrame *_frame; AVFrame *_frame;
bool _opened, _hadFrame; bool _opened, _hadFrame, _frameRead;
AVPacket _avpkt; AVPacket _avpkt;
int _packetSize; int _packetSize;
@ -835,9 +872,7 @@ public:
, _frame(0) , _frame(0)
, _width(0) , _width(0)
, _height(0) , _height(0)
, _previousMs(0) , _nextFrameWhen(0)
, _currentMs(0)
, _nextUpdateMs(0)
, _paused(false) { , _paused(false) {
if (_data.isEmpty() && !_location->accessEnable()) { if (_data.isEmpty() && !_location->accessEnable()) {
error(); error();
@ -851,7 +886,10 @@ public:
return error(); return error();
} }
if (frame() && frame()->original.isNull()) { if (frame() && frame()->original.isNull()) {
if (!_implementation->readNextFrame(frame()->original, frame()->alpha, QSize())) { if (!_implementation->readNextFrame()) {
return error();
}
if (!_implementation->renderFrame(frame()->original, frame()->alpha, QSize())) {
return error(); return error();
} }
_width = frame()->original.width(); _width = frame()->original.width();
@ -868,23 +906,22 @@ public:
return start(ms); return start(ms);
} }
if (!_paused && ms >= _nextUpdateMs) { if (!_paused && ms >= _nextFrameWhen) {
return ClipProcessRepaint; return ClipProcessRepaint;
} }
return ClipProcessWait; return ClipProcessWait;
} }
ClipProcessResult finishProcess(uint64 ms) { ClipProcessResult finishProcess(uint64 ms) {
_previousMs = _currentMs; if (!readNextFrame()) {
if (!prepareNextFrame()) {
return error(); return error();
} }
if (ms >= _nextUpdateMs) { if (ms >= _nextFrameWhen && !readNextFrame(true)) {
if (!prepareNextFrame()) { return error();
return error(); }
} if (!renderFrame()) {
return error();
} }
_currentMs = qMax(ms, _nextUpdateMs);
return ClipProcessCopyFrame; return ClipProcessCopyFrame;
} }
@ -893,15 +930,26 @@ public:
return qMax(delay, 5); return qMax(delay, 5);
} }
bool prepareNextFrame() { bool readNextFrame(bool keepup = false) {
t_assert(frame() != 0 && _request.valid()); if (!_implementation->readNextFrame()) {
if (!_implementation->readNextFrame(frame()->original, frame()->alpha, QSize(_request.framew, _request.frameh))) { return false;
}
_nextFrameWhen += nextFrameDelay();
if (keepup) {
_nextFrameWhen = qMax(_nextFrameWhen, getms());
}
return true;
}
bool renderFrame() {
t_assert(frame() != 0 && _request.valid());
if (!_implementation->renderFrame(frame()->original, frame()->alpha, QSize(_request.framew, _request.frameh))) {
return false; return false;
} }
_nextUpdateMs = _currentMs + nextFrameDelay();
frame()->original.setDevicePixelRatio(_request.factor); frame()->original.setDevicePixelRatio(_request.factor);
frame()->pix = QPixmap(); frame()->pix = QPixmap();
frame()->pix = _prepareFrame(_request, frame()->original, frame()->alpha, frame()->cache); frame()->pix = _prepareFrame(_request, frame()->original, frame()->alpha, frame()->cache);
frame()->when = _nextFrameWhen;
return true; return true;
} }
@ -962,11 +1010,12 @@ private:
ClipFrameRequest _request; ClipFrameRequest _request;
struct Frame { struct Frame {
Frame() : alpha(true) { Frame() : alpha(true), when(0) {
} }
QPixmap pix; QPixmap pix;
QImage original, cache; QImage original, cache;
bool alpha; bool alpha;
uint64 when;
}; };
Frame _frames[3]; Frame _frames[3];
int32 _frame; int32 _frame;
@ -976,7 +1025,7 @@ private:
int32 _width, _height; int32 _width, _height;
uint64 _previousMs, _currentMs, _nextUpdateMs; uint64 _nextFrameWhen;
bool _paused; bool _paused;
@ -1070,13 +1119,16 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess
if (result == ClipProcessStarted) { if (result == ClipProcessStarted) {
_loadLevel.fetchAndAddRelaxed(reader->_width * reader->_height - AverageGifSize); _loadLevel.fetchAndAddRelaxed(reader->_width * reader->_height - AverageGifSize);
} }
if (!reader->_paused && (result == ClipProcessRepaint || result == ClipProcessWait)) { if (!reader->_paused && result == ClipProcessRepaint) {
ClipReader::Frame *other = it.key()->frameToWriteNext(false); int32 ishowing, iprevious;
t_assert(other != 0); ClipReader::Frame *showing = it.key()->frameToShow(&ishowing), *previous = it.key()->frameToWriteNext(false, &iprevious);
if (other->when && other->when + WaitBeforeGifPause < qMax(reader->_previousMs, ms)) { t_assert(previous != 0 && showing != 0 && ishowing >= 0 && iprevious >= 0);
reader->_paused = true; if (reader->_frames[ishowing].when > 0 && showing->displayed.loadAcquire() <= 0) { // current frame was not shown
it.key()->_paused.storeRelease(1); if (reader->_frames[ishowing].when + WaitBeforeGifPause < ms || (reader->_frames[iprevious].when && previous->displayed.loadAcquire() <= 0)) {
result = ClipProcessPaused; reader->_paused = true;
it.key()->_paused.storeRelease(1);
result = ClipProcessPaused;
}
} }
} }
if (result == ClipProcessStarted || result == ClipProcessCopyFrame) { if (result == ClipProcessStarted || result == ClipProcessCopyFrame) {
@ -1085,14 +1137,17 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess
frame->clear(); frame->clear();
frame->pix = reader->frame()->pix; frame->pix = reader->frame()->pix;
frame->original = reader->frame()->original; frame->original = reader->frame()->original;
frame->displayed = false; frame->displayed.storeRelease(0);
it.key()->moveToNextWrite();
if (result == ClipProcessStarted) { if (result == ClipProcessStarted) {
reader->_nextFrameWhen = ms;
it.key()->moveToNextWrite();
emit callback(it.key(), it.key()->threadIndex(), ClipReaderReinit); emit callback(it.key(), it.key()->threadIndex(), ClipReaderReinit);
} }
} else if (result == ClipProcessPaused) { } else if (result == ClipProcessPaused) {
it.key()->moveToNextWrite();
emit callback(it.key(), it.key()->threadIndex(), ClipReaderReinit); emit callback(it.key(), it.key()->threadIndex(), ClipReaderReinit);
} else if (result == ClipProcessRepaint) { } else if (result == ClipProcessRepaint) {
it.key()->moveToNextWrite();
emit callback(it.key(), it.key()->threadIndex(), ClipReaderRepaint); emit callback(it.key(), it.key()->threadIndex(), ClipReaderRepaint);
} }
return true; return true;
@ -1174,7 +1229,7 @@ void ClipReadManager::process() {
return; return;
} }
ms = getms(); ms = getms();
i.value() = reader->_nextUpdateMs ? reader->_nextUpdateMs : (ms + 86400 * 1000ULL); i.value() = reader->_nextFrameWhen ? reader->_nextFrameWhen : (ms + 86400 * 1000ULL);
} }
if (!reader->_paused && i.value() < minms) { if (!reader->_paused && i.value() < minms) {
minms = i.value(); minms = i.value();
@ -1224,7 +1279,7 @@ MTPDocumentAttribute clipReadAnimatedAttributes(const QString &fname, const QByt
FFMpegReaderImplementation *reader = new FFMpegReaderImplementation(&localloc, &localdata); FFMpegReaderImplementation *reader = new FFMpegReaderImplementation(&localloc, &localdata);
if (reader->start(true)) { if (reader->start(true)) {
bool hasAlpha = false; bool hasAlpha = false;
if (reader->readNextFrame(cover, hasAlpha, QSize())) { if (reader->readNextFrame() && reader->renderFrame(cover, hasAlpha, QSize())) {
if (cover.width() > 0 && cover.height() > 0 && cover.width() < cover.height() * 10 && cover.height() < cover.width() * 10) { if (cover.width() > 0 && cover.height() > 0 && cover.width() < cover.height() * 10 && cover.height() < cover.width() * 10) {
if (hasAlpha) { if (hasAlpha) {
QImage cacheForResize; QImage cacheForResize;

View File

@ -497,8 +497,9 @@ enum ClipReaderNotification {
}; };
enum ClipReaderSteps { enum ClipReaderSteps {
FirstFrameNotReadStep = -2, WaitingForDimensionsStep = -3, // before ClipReaderPrivate read the first image and got the original frame size
WaitingForRequestStep = -1, WaitingForRequestStep = -2, // before ClipReader got the original frame size and prepared the frame request
WaitingForFirstFrameStep = -1, // before ClipReaderPrivate got the frame request and started waiting for the 1-2 delay
}; };
class ClipReaderPrivate; class ClipReaderPrivate;
@ -528,7 +529,7 @@ public:
} }
bool currentDisplayed() const { bool currentDisplayed() const {
Frame *frame = frameToShow(); Frame *frame = frameToShow();
return frame ? frame->displayed : true; return frame ? (frame->displayed.loadAcquire() != 0) : true;
} }
bool paused() const { bool paused() const {
return _paused.loadAcquire(); return _paused.loadAcquire();
@ -542,7 +543,8 @@ public:
ClipState state() const; ClipState state() const;
bool started() const { bool started() const {
return _step.loadAcquire() >= 0; int32 step = _step.loadAcquire();
return (step == WaitingForFirstFrameStep) || (step >= 0);
} }
bool ready() const; bool ready() const;
@ -561,7 +563,7 @@ private:
mutable QAtomicInt _step; // -2, -1 - init, 0-5 - work, show ((state + 1) / 2) % 3 state, write ((state + 3) / 2) % 3 mutable QAtomicInt _step; // -2, -1 - init, 0-5 - work, show ((state + 1) / 2) % 3 state, write ((state + 3) / 2) % 3
struct Frame { struct Frame {
Frame() : displayed(false), when(0) { Frame() : displayed(false) {
} }
void clear() { void clear() {
pix = QPixmap(); pix = QPixmap();
@ -570,13 +572,12 @@ private:
QPixmap pix; QPixmap pix;
QImage original; QImage original;
ClipFrameRequest request; ClipFrameRequest request;
bool displayed; QAtomicInt displayed;
uint64 when;
}; };
mutable Frame _frames[3]; mutable Frame _frames[3];
Frame *frameToShow() const; // 0 means not ready Frame *frameToShow(int32 *index = 0) const; // 0 means not ready
Frame *frameToWrite(int32 *index = 0) const; // 0 means not ready Frame *frameToWrite(int32 *index = 0) const; // 0 means not ready
Frame *frameToWriteNext(bool check) const; Frame *frameToWriteNext(bool check, int32 *index = 0) const;
void moveToNextShow() const; void moveToNextShow() const;
void moveToNextWrite() const; void moveToNextWrite() const;

View File

@ -1392,7 +1392,9 @@ HistoryItem *History::createItem(HistoryBlock *block, const MTPMessage &msg, boo
case mtpc_messageMediaUnsupported: case mtpc_messageMediaUnsupported:
default: badMedia = 1; break; default: badMedia = 1; break;
} }
if (badMedia) { if (false && badMedia == 1) {
// QString text(lng_message_unsupported(lt_link, qsl("https://desktop.telegram.org")));
} else if (badMedia) {
result = new HistoryServiceMsg(this, block, m.vid.v, date(m.vdate), lang((badMedia == 2) ? lng_message_empty : lng_media_unsupported), m.vflags.v, 0, m.has_from_id() ? m.vfrom_id.v : 0); result = new HistoryServiceMsg(this, block, m.vid.v, date(m.vdate), lang((badMedia == 2) ? lng_message_empty : lng_media_unsupported), m.vflags.v, 0, m.has_from_id() ? m.vfrom_id.v : 0);
} else { } else {
if ((m.has_fwd_date() && m.vfwd_date.v > 0) || (m.has_fwd_from_id() && peerFromMTP(m.vfwd_from_id) != 0)) { if ((m.has_fwd_date() && m.vfwd_date.v > 0) || (m.has_fwd_from_id() && peerFromMTP(m.vfwd_from_id) != 0)) {
@ -3352,11 +3354,16 @@ void HistoryPhoto::draw(Painter &p, const HistoryItem *parent, const QRect &r, b
p.setOpacity(radialOpacity); p.setOpacity(radialOpacity);
style::sprite icon; style::sprite icon;
if (radial || _data->loading()) { if (radial || _data->loading()) {
icon = (selected ? st::msgFileInCancelSelected : st::msgFileInCancel); DelayedStorageImage *delayed = _data->full->toDelayedStorageImage();
if (!delayed || !delayed->location().isNull()) {
icon = (selected ? st::msgFileInCancelSelected : st::msgFileInCancel);
}
} else { } else {
icon = (selected ? st::msgFileInDownloadSelected : st::msgFileInDownload); icon = (selected ? st::msgFileInDownloadSelected : st::msgFileInDownload);
} }
p.drawSpriteCenter(inner, icon); if (!icon.isEmpty()) {
p.drawSpriteCenter(inner, icon);
}
if (radial) { if (radial) {
p.setOpacity(1); p.setOpacity(1);
QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine))); QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine)));
@ -3401,8 +3408,15 @@ void HistoryPhoto::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x
if (x >= skipx && y >= skipy && x < skipx + width && y < skipy + height) { if (x >= skipx && y >= skipy && x < skipx + width && y < skipy + height) {
if (_data->uploading()) { if (_data->uploading()) {
lnk = _cancell; lnk = _cancell;
} else if (_data->loaded()) {
lnk = _openl;
} else if (_data->loading()) {
DelayedStorageImage *delayed = _data->full->toDelayedStorageImage();
if (!delayed || !delayed->location().isNull()) {
lnk = _cancell;
}
} else { } else {
lnk = _data->loaded() ? _openl : (_data->loading() ? _cancell : _savel); lnk = _savel;
} }
if (_caption.isEmpty() && parent->getMedia() == this) { if (_caption.isEmpty() && parent->getMedia() == this) {
int32 fullRight = skipx + width, fullBottom = skipy + height; int32 fullRight = skipx + width, fullBottom = skipy + height;
@ -4561,11 +4575,15 @@ void HistoryGif::draw(Painter &p, const HistoryItem *parent, const QRect &r, boo
if (_data->loaded() && !radial) { if (_data->loaded() && !radial) {
icon = (selected ? st::msgFileInPlaySelected : st::msgFileInPlay); icon = (selected ? st::msgFileInPlaySelected : st::msgFileInPlay);
} else if (radial || _data->loading()) { } else if (radial || _data->loading()) {
icon = (selected ? st::msgFileInCancelSelected : st::msgFileInCancel); if (parent->id > 0) {
icon = (selected ? st::msgFileInCancelSelected : st::msgFileInCancel);
}
} else { } else {
icon = (selected ? st::msgFileInDownloadSelected : st::msgFileInDownload); icon = (selected ? st::msgFileInDownloadSelected : st::msgFileInDownload);
} }
p.drawSpriteCenter(inner, icon); if (!icon.isEmpty()) {
p.drawSpriteCenter(inner, icon);
}
if (radial) { if (radial) {
p.setOpacity(1); p.setOpacity(1);
QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine))); QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine)));
@ -4762,6 +4780,16 @@ void HistorySticker::initDimensions(const HistoryItem *parent) {
_height = _minh; _height = _minh;
} }
int32 HistorySticker::resize(int32 width, const HistoryItem *parent) { // return new height
_width = qMin(width, _maxw);
if (const HistoryReply *reply = toHistoryReply(parent)) {
int32 usew = _maxw - st::msgReplyPadding.left() - reply->replyToWidth();
int32 rw = _width - usew - st::msgReplyPadding.left() - st::msgReplyPadding.left() - st::msgReplyPadding.right();
reply->resizeVia(rw);
}
return _height;
}
void HistorySticker::draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const { void HistorySticker::draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const {
if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return;
@ -5958,7 +5986,7 @@ void ViaInlineBotLink::onClick(Qt::MouseButton button) const {
HistoryMessageVia::HistoryMessageVia(int32 userId) HistoryMessageVia::HistoryMessageVia(int32 userId)
: bot(App::userLoaded(peerFromUser(userId))) : bot(App::userLoaded(peerFromUser(userId)))
, width(0) , width(0)
, fullWidth(st::msgServiceNameFont->width(qsl("via @") + bot->username)) , maxWidth(st::msgServiceNameFont->width(qsl("via @") + bot->username))
, lnk(new ViaInlineBotLink(bot)) { , lnk(new ViaInlineBotLink(bot)) {
} }
@ -5967,13 +5995,21 @@ bool HistoryMessageVia::isNull() const {
} }
void HistoryMessageVia::resize(int32 availw) { void HistoryMessageVia::resize(int32 availw) {
if (width < fullWidth && availw > width) { if (width < maxWidth && availw > width) {
if (availw < fullWidth) { if (availw < maxWidth) {
text = st::msgServiceNameFont->elided(qsl("via @") + bot->username, availw); text = st::msgServiceNameFont->elided(qsl("via @") + bot->username, availw);
width = st::msgServiceNameFont->width(text); width = st::msgServiceNameFont->width(text);
} else { } else {
text = qsl("via @") + bot->username; text = qsl("via @") + bot->username;
width = fullWidth; width = maxWidth;
}
} else if (availw < width) {
if (availw > 0) {
text = st::msgServiceNameFont->elided(qsl("via @") + bot->username, availw);
width = st::msgServiceNameFont->width(text);
} else {
text = QString();
width = 0;
} }
} }
} }
@ -6165,9 +6201,9 @@ void HistoryMessage::initDimensions() {
if (maxw > _maxw) _maxw = maxw; if (maxw > _maxw) _maxw = maxw;
_minh += _media->minHeight(); _minh += _media->minHeight();
} }
if (via()) { if (!_media && !displayFromName() && via() && !toHistoryForwarded()) {
if (st::msgPadding.left() + via()->fullWidth + st::msgPadding.right() > _maxw) { if (st::msgPadding.left() + via()->maxWidth + st::msgPadding.right() > _maxw) {
_maxw = st::msgPadding.left() + via()->fullWidth + st::msgPadding.right() > _maxw; _maxw = st::msgPadding.left() + via()->maxWidth + st::msgPadding.right();
} }
} }
} else { } else {
@ -6200,8 +6236,11 @@ void HistoryMessage::countPositionAndSize(int32 &left, int32 &width) const {
void HistoryMessage::fromNameUpdated() const { void HistoryMessage::fromNameUpdated() const {
if (!_media && displayFromName()) { if (!_media && displayFromName()) {
int32 _namew = st::msgPadding.left() + _from->nameText.maxWidth() + st::msgPadding.right(); int32 namew = st::msgPadding.left() + _from->nameText.maxWidth() + st::msgPadding.right();
if (_namew > _maxw) _maxw = _namew; if (via() && !toHistoryForwarded()) {
namew += st::msgServiceFont->spacew + via()->maxWidth;
}
if (namew > _maxw) _maxw = namew;
} }
} }
@ -6437,7 +6476,7 @@ void HistoryMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 m
} }
if (_from->nameVersion > _fromVersion) { if (_from->nameVersion > _fromVersion) {
fromNameUpdated(); // fromNameUpdated();
_fromVersion = _from->nameVersion; _fromVersion = _from->nameVersion;
} }
@ -6464,6 +6503,10 @@ void HistoryMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 m
p.setPen(_from->color); p.setPen(_from->color);
} }
_from->nameText.drawElided(p, r.left() + st::msgPadding.left(), r.top() + st::msgPadding.top(), width - st::msgPadding.left() - st::msgPadding.right()); _from->nameText.drawElided(p, r.left() + st::msgPadding.left(), r.top() + st::msgPadding.top(), width - st::msgPadding.left() - st::msgPadding.right());
if (via() && !toHistoryForwarded() && width > st::msgPadding.left() + st::msgPadding.right() + _from->nameText.maxWidth() + st::msgServiceFont->spacew) {
p.setPen(selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg));
p.drawText(r.left() + st::msgPadding.left() + _from->nameText.maxWidth() + st::msgServiceFont->spacew, r.top() + st::msgPadding.top() + st::msgServiceFont->ascent, via()->text);
}
r.setTop(r.top() + st::msgNameFont->height); r.setTop(r.top() + st::msgNameFont->height);
} }
@ -6495,15 +6538,15 @@ void HistoryMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 m
void HistoryMessage::drawMessageText(Painter &p, QRect trect, uint32 selection) const { void HistoryMessage::drawMessageText(Painter &p, QRect trect, uint32 selection) const {
bool outbg = out() && !fromChannel(), selected = (selection == FullSelection); bool outbg = out() && !fromChannel(), selected = (selection == FullSelection);
if (via()) { if (!displayFromName() && via() && !toHistoryForwarded()) {
p.setFont(st::msgServiceNameFont); p.setFont(st::msgServiceNameFont);
p.setPen((selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg))->p); p.setPen(selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg));
p.drawTextLeft(trect.left(), trect.top(), _history->width, via()->text); p.drawTextLeft(trect.left(), trect.top(), _history->width, via()->text);
trect.setY(trect.y() + st::msgServiceNameFont->height); trect.setY(trect.y() + st::msgServiceNameFont->height);
} }
p.setPen(st::msgColor->p); p.setPen(st::msgColor);
p.setFont(st::msgFont->f); p.setFont(st::msgFont);
uint16 selectedFrom = (selection == FullSelection) ? 0 : (selection >> 16) & 0xFFFF; uint16 selectedFrom = (selection == FullSelection) ? 0 : (selection >> 16) & 0xFFFF;
uint16 selectedTo = (selection == FullSelection) ? 0 : selection & 0xFFFF; uint16 selectedTo = (selection == FullSelection) ? 0 : selection & 0xFFFF;
_text.draw(p, trect.x(), trect.y(), trect.width(), Qt::AlignLeft, 0, -1, selectedFrom, selectedTo); _text.draw(p, trect.x(), trect.y(), trect.width(), Qt::AlignLeft, 0, -1, selectedFrom, selectedTo);
@ -6549,8 +6592,10 @@ int32 HistoryMessage::resize(int32 width) {
} else { } else {
_height += st::msgNameFont->height; _height += st::msgNameFont->height;
} }
} if (via() && !toHistoryForwarded()) {
if (via()) { via()->resize(width - st::msgPadding.left() - st::msgPadding.right() - _from->nameText.maxWidth() - st::msgServiceFont->spacew);
}
} else if (via() && !toHistoryForwarded()) {
via()->resize(width - st::msgPadding.left() - st::msgPadding.right()); via()->resize(width - st::msgPadding.left() - st::msgPadding.right());
if (emptyText() && !displayFromName()) { if (emptyText() && !displayFromName()) {
_height += st::msgPadding.top() + st::msgNameFont->height + st::mediaHeaderSkip; _height += st::msgPadding.top() + st::msgNameFont->height + st::mediaHeaderSkip;
@ -6612,9 +6657,15 @@ void HistoryMessage::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32
if (drawBubble()) { if (drawBubble()) {
QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom()); QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom());
if (displayFromName()) { // from user left name if (displayFromName()) { // from user left name
if (x >= r.left() + st::msgPadding.left() && y >= r.top() + st::msgPadding.top() && y < r.top() + st::msgPadding.top() + st::msgNameFont->height && x < r.left() + r.width() - st::msgPadding.right() && x < r.left() + st::msgPadding.left() + _from->nameText.maxWidth()) { if (y >= r.top() + st::msgPadding.top() && y < r.top() + st::msgPadding.top() + st::msgNameFont->height) {
lnk = _from->lnk; if (x >= r.left() + st::msgPadding.left() && x < r.left() + r.width() - st::msgPadding.right() && x < r.left() + st::msgPadding.left() + _from->nameText.maxWidth()) {
return; lnk = _from->lnk;
return;
}
if (via() && !toHistoryForwarded() && x >= r.left() + st::msgPadding.left() + _from->nameText.maxWidth() + st::msgServiceFont->spacew && x < r.left() + st::msgPadding.left() + _from->nameText.maxWidth() + st::msgServiceFont->spacew + via()->width) {
lnk = via()->lnk;
return;
}
} }
r.setTop(r.top() + st::msgNameFont->height); r.setTop(r.top() + st::msgNameFont->height);
} }
@ -6629,7 +6680,7 @@ void HistoryMessage::getStateFromMessageText(TextLinkPtr &lnk, HistoryCursorStat
QRect trect(r.marginsAdded(-st::msgPadding)); QRect trect(r.marginsAdded(-st::msgPadding));
if (via()) { if (!displayFromName() && via() && !toHistoryForwarded()) {
if (x >= trect.left() && y >= trect.top() && y < trect.top() + st::msgNameFont->height && x < trect.left() + via()->width) { if (x >= trect.left() && y >= trect.top() && y < trect.top() + st::msgNameFont->height && x < trect.left() + via()->width) {
lnk = via()->lnk; lnk = via()->lnk;
return; return;
@ -6678,8 +6729,7 @@ void HistoryMessage::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x,
QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom()); QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom());
if (displayFromName()) { // from user left name if (displayFromName()) { // from user left name
r.setTop(r.top() + st::msgNameFont->height); r.setTop(r.top() + st::msgNameFont->height);
} } else if (via() && !toHistoryForwarded()) {
if (via()) {
r.setTop(r.top() + st::msgNameFont->height); r.setTop(r.top() + st::msgNameFont->height);
} }
QRect trect(r.marginsAdded(-st::msgPadding)); QRect trect(r.marginsAdded(-st::msgPadding));
@ -6765,12 +6815,16 @@ void HistoryForwarded::initDimensions() {
HistoryMessage::initDimensions(); HistoryMessage::initDimensions();
if (!_media) { if (!_media) {
int32 _namew = st::msgPadding.left() + fromWidth + fwdFromName.maxWidth() + st::msgPadding.right(); int32 _namew = st::msgPadding.left() + fromWidth + fwdFromName.maxWidth() + st::msgPadding.right();
if (via()) {
_namew += st::msgServiceFont->spacew + via()->maxWidth;
}
if (_namew > _maxw) _maxw = _namew; if (_namew > _maxw) _maxw = _namew;
} }
} }
void HistoryForwarded::fwdNameUpdated() const { void HistoryForwarded::fwdNameUpdated() const {
fwdFromName.setText(st::msgServiceNameFont, App::peerName(fwdFrom), _textNameOptions); QString fwdName((via() && fwdFrom->isUser()) ? fwdFrom->asUser()->firstName : App::peerName(fwdFrom));
fwdFromName.setText(st::msgServiceNameFont, fwdName, _textNameOptions);
} }
void HistoryForwarded::draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const { void HistoryForwarded::draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const {
@ -6788,10 +6842,17 @@ void HistoryForwarded::drawForwardedFrom(Painter &p, int32 x, int32 y, int32 w,
p.setPen((selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg))->p); p.setPen((selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg))->p);
p.setFont(serviceFont); p.setFont(serviceFont);
if (w >= fromWidth) { if (via() && w > fromWidth + fwdFromName.maxWidth() + serviceFont->spacew) {
p.drawText(x, y + serviceFont->ascent, lang(lng_forwarded_from)); p.drawText(x, y + serviceFont->ascent, lang(lng_forwarded_from));
p.setFont(serviceName->f); p.setFont(serviceName);
fwdFromName.draw(p, x + fromWidth, y, w - fromWidth);
p.drawText(x + fromWidth + fwdFromName.maxWidth() + serviceFont->spacew, y + serviceFont->ascent, via()->text);
} else if (w > fromWidth) {
p.drawText(x, y + serviceFont->ascent, lang(lng_forwarded_from));
p.setFont(serviceName);
fwdFromName.drawElided(p, x + fromWidth, y, w - fromWidth); fwdFromName.drawElided(p, x + fromWidth, y, w - fromWidth);
} else { } else {
p.drawText(x, y + serviceFont->ascent, serviceFont->elided(lang(lng_forwarded_from), w)); p.drawText(x, y + serviceFont->ascent, serviceFont->elided(lang(lng_forwarded_from), w));
@ -6810,11 +6871,14 @@ int32 HistoryForwarded::resize(int32 width) {
HistoryMessage::resize(width); HistoryMessage::resize(width);
if (drawBubble()) { if (drawBubble()) {
if (displayForwardedFrom()) { if (displayForwardedFrom()) {
if (emptyText() && !displayFromName() && !via()) { if (emptyText() && !displayFromName()) {
_height += st::msgPadding.top() + st::msgServiceNameFont->height + st::mediaHeaderSkip; _height += st::msgPadding.top() + st::msgServiceNameFont->height + st::mediaHeaderSkip;
} else { } else {
_height += st::msgServiceNameFont->height; _height += st::msgServiceNameFont->height;
} }
if (via()) {
via()->resize(width - st::msgPadding.left() - st::msgPadding.right() - fromWidth - fwdFromName.maxWidth() - st::msgServiceFont->spacew);
}
} }
} }
return _height; return _height;
@ -6876,6 +6940,8 @@ void HistoryForwarded::getForwardedState(TextLinkPtr &lnk, HistoryCursorState &s
state = HistoryDefaultCursorState; state = HistoryDefaultCursorState;
if (x >= fromWidth && x < w && x < fromWidth + fwdFromName.maxWidth()) { if (x >= fromWidth && x < w && x < fromWidth + fwdFromName.maxWidth()) {
lnk = fwdFrom->lnk; lnk = fwdFrom->lnk;
} else if (via() && x >= fromWidth + fwdFromName.maxWidth() + st::msgServiceFont->spacew && x < w && x < fromWidth + fwdFromName.maxWidth() + st::msgServiceFont->spacew + via()->maxWidth) {
lnk = via()->lnk;
} else { } else {
lnk = TextLinkPtr(); lnk = TextLinkPtr();
} }
@ -6910,7 +6976,8 @@ HistoryReply::HistoryReply(History *history, HistoryBlock *block, const MTPDmess
, replyToMsgId(msg.vreply_to_msg_id.v) , replyToMsgId(msg.vreply_to_msg_id.v)
, replyToMsg(0) , replyToMsg(0)
, replyToVersion(0) , replyToVersion(0)
, _maxReplyWidth(0) { , _maxReplyWidth(0)
, _replyToVia(0) {
if (!updateReplyTo() && App::api()) { if (!updateReplyTo() && App::api()) {
App::api()->requestReplyTo(this, history->peer->asChannel(), replyToMsgId); App::api()->requestReplyTo(this, history->peer->asChannel(), replyToMsgId);
} }
@ -6921,7 +6988,8 @@ HistoryReply::HistoryReply(History *history, HistoryBlock *block, MsgId msgId, i
, replyToMsgId(replyTo) , replyToMsgId(replyTo)
, replyToMsg(0) , replyToMsg(0)
, replyToVersion(0) , replyToVersion(0)
, _maxReplyWidth(0) { , _maxReplyWidth(0)
, _replyToVia(0) {
if (!updateReplyTo() && App::api()) { if (!updateReplyTo() && App::api()) {
App::api()->requestReplyTo(this, history->peer->asChannel(), replyToMsgId); App::api()->requestReplyTo(this, history->peer->asChannel(), replyToMsgId);
} }
@ -6932,7 +7000,8 @@ HistoryReply::HistoryReply(History *history, HistoryBlock *block, MsgId msgId, i
, replyToMsgId(replyTo) , replyToMsgId(replyTo)
, replyToMsg(0) , replyToMsg(0)
, replyToVersion(0) , replyToVersion(0)
, _maxReplyWidth(0) { , _maxReplyWidth(0)
, _replyToVia(0) {
if (!updateReplyTo() && App::api()) { if (!updateReplyTo() && App::api()) {
App::api()->requestReplyTo(this, history->peer->asChannel(), replyToMsgId); App::api()->requestReplyTo(this, history->peer->asChannel(), replyToMsgId);
} }
@ -6952,6 +7021,9 @@ void HistoryReply::initDimensions() {
HistoryMessage::initDimensions(); HistoryMessage::initDimensions();
if (!_media) { if (!_media) {
int32 replyw = st::msgPadding.left() + _maxReplyWidth - st::msgReplyPadding.left() - st::msgReplyPadding.right() + st::msgPadding.right(); int32 replyw = st::msgPadding.left() + _maxReplyWidth - st::msgReplyPadding.left() - st::msgReplyPadding.right() + st::msgPadding.right();
if (replyToVia()) {
replyw += st::msgServiceFont->spacew + via()->maxWidth;
}
if (replyw > _maxw) _maxw = replyw; if (replyw > _maxw) _maxw = replyw;
} }
} }
@ -6959,6 +7031,7 @@ void HistoryReply::initDimensions() {
bool HistoryReply::updateReplyTo(bool force) { bool HistoryReply::updateReplyTo(bool force) {
if (replyToMsg || !replyToMsgId) return true; if (replyToMsg || !replyToMsgId) return true;
replyToMsg = App::histItemById(channelId(), replyToMsgId); replyToMsg = App::histItemById(channelId(), replyToMsgId);
if (replyToMsg) { if (replyToMsg) {
App::historyRegReply(this, replyToMsg); App::historyRegReply(this, replyToMsg);
replyToText.setText(st::msgFont, replyToMsg->inReplyText(), _textDlgOptions); replyToText.setText(st::msgFont, replyToMsg->inReplyText(), _textDlgOptions);
@ -6966,6 +7039,11 @@ bool HistoryReply::updateReplyTo(bool force) {
replyToNameUpdated(); replyToNameUpdated();
replyToLnk = TextLinkPtr(new MessageLink(replyToMsg->history()->peer->id, replyToMsg->id)); replyToLnk = TextLinkPtr(new MessageLink(replyToMsg->history()->peer->id, replyToMsg->id));
if (!replyToMsg->toHistoryForwarded()) {
if (UserData *bot = replyToMsg->viaBot()) {
_replyToVia = new HistoryMessageVia(peerToUser(bot->id));
}
}
} else if (force) { } else if (force) {
replyToMsgId = 0; replyToMsgId = 0;
} }
@ -6978,12 +7056,17 @@ bool HistoryReply::updateReplyTo(bool force) {
void HistoryReply::replyToNameUpdated() const { void HistoryReply::replyToNameUpdated() const {
if (replyToMsg) { if (replyToMsg) {
replyToName.setText(st::msgServiceNameFont, App::peerName(replyToMsg->from()), _textNameOptions); QString name = (replyToVia() && replyToMsg->from()->isUser()) ? replyToMsg->from()->asUser()->firstName : App::peerName(replyToMsg->from());
replyToName.setText(st::msgServiceNameFont, name, _textNameOptions);
replyToVersion = replyToMsg->from()->nameVersion; replyToVersion = replyToMsg->from()->nameVersion;
bool hasPreview = replyToMsg->getMedia() ? replyToMsg->getMedia()->hasReplyPreview() : false; bool hasPreview = replyToMsg->getMedia() ? replyToMsg->getMedia()->hasReplyPreview() : false;
int32 previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0; int32 previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0;
int32 w = replyToName.maxWidth();
if (replyToVia()) {
w += st::msgServiceFont->spacew + replyToVia()->maxWidth;
}
_maxReplyWidth = previewSkip + qMax(replyToName.maxWidth(), qMin(replyToText.maxWidth(), 4 * replyToName.maxWidth())); _maxReplyWidth = previewSkip + qMax(w, qMin(replyToText.maxWidth(), 4 * w));
} else { } else {
_maxReplyWidth = st::msgDateFont->width(lang(replyToMsgId ? lng_profile_loading : lng_deleted_message)); _maxReplyWidth = st::msgDateFont->width(lang(replyToMsgId ? lng_profile_loading : lng_deleted_message));
} }
@ -7056,6 +7139,10 @@ void HistoryReply::drawReplyTo(Painter &p, int32 x, int32 y, int32 w, bool selec
p.setPen(selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg)); p.setPen(selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg));
} }
replyToName.drawLeftElided(p, x + st::msgReplyBarSkip + previewSkip, y + st::msgReplyPadding.top(), w - st::msgReplyBarSkip - previewSkip, w + 2 * x); replyToName.drawLeftElided(p, x + st::msgReplyBarSkip + previewSkip, y + st::msgReplyPadding.top(), w - st::msgReplyBarSkip - previewSkip, w + 2 * x);
if (replyToVia() && w > st::msgReplyBarSkip + previewSkip + replyToName.maxWidth() + st::msgServiceFont->spacew) {
p.setFont(st::msgServiceFont);
p.drawText(x + st::msgReplyBarSkip + previewSkip + replyToName.maxWidth() + st::msgServiceFont->spacew, y + st::msgReplyPadding.top() + st::msgServiceFont->ascent, replyToVia()->text);
}
HistoryMessage *replyToAsMsg = replyToMsg->toHistoryMessage(); HistoryMessage *replyToAsMsg = replyToMsg->toHistoryMessage();
if (likeService) { if (likeService) {
@ -7094,10 +7181,23 @@ int32 HistoryReply::resize(int32 width) {
} else { } else {
_height += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); _height += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
} }
if (replyToVia()) {
bool hasPreview = replyToMsg->getMedia() ? replyToMsg->getMedia()->hasReplyPreview() : false;
int previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0;
replyToVia()->resize(width - st::msgPadding.left() - st::msgPadding.right() - st::msgReplyBarSkip + previewSkip + replyToName.maxWidth() + st::msgServiceFont->spacew);
}
} }
return _height; return _height;
} }
void HistoryReply::resizeVia(int32 w) const {
if (!replyToVia()) return;
bool hasPreview = replyToMsg->getMedia() ? replyToMsg->getMedia()->hasReplyPreview() : false;
int previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0;
replyToVia()->resize(w - st::msgReplyBarSkip - previewSkip - replyToName.maxWidth() - st::msgServiceFont->spacew);
}
bool HistoryReply::hasPoint(int32 x, int32 y) const { bool HistoryReply::hasPoint(int32 x, int32 y) const {
if (drawBubble()) { if (drawBubble()) {
int32 left = 0, width = 0; int32 left = 0, width = 0;
@ -7186,6 +7286,7 @@ HistoryReply::~HistoryReply() {
} else if (replyToMsgId && App::api()) { } else if (replyToMsgId && App::api()) {
App::api()->itemRemoved(this); App::api()->itemRemoved(this);
} }
deleteAndMark(_replyToVia);
} }
void HistoryServiceMsg::setMessageByAction(const MTPmessageAction &action) { void HistoryServiceMsg::setMessageByAction(const MTPmessageAction &action) {

View File

@ -1680,6 +1680,7 @@ public:
} }
void initDimensions(const HistoryItem *parent); void initDimensions(const HistoryItem *parent);
int32 resize(int32 width, const HistoryItem *parent);
void draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const; void draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const;
void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const HistoryItem *parent) const; void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const HistoryItem *parent) const;
@ -1979,7 +1980,7 @@ public:
UserData *bot; UserData *bot;
QString text; QString text;
int32 width, fullWidth; int32 width, maxWidth;
TextLinkPtr lnk; TextLinkPtr lnk;
}; };
@ -2164,7 +2165,7 @@ public:
} }
QString selectedText(uint32 selection) const; QString selectedText(uint32 selection) const;
bool displayForwardedFrom() const { bool displayForwardedFrom() const {
return (!_media || !_media->isDisplayed() || !_media->hideForwardedFrom()); return via() || !_media || !_media->isDisplayed() || !_media->hideForwardedFrom();
} }
HistoryForwarded *toHistoryForwarded() { HistoryForwarded *toHistoryForwarded() {
@ -2207,6 +2208,7 @@ public:
void drawReplyTo(Painter &p, int32 x, int32 y, int32 w, bool selected, bool likeService = false) const; void drawReplyTo(Painter &p, int32 x, int32 y, int32 w, bool selected, bool likeService = false) const;
void drawMessageText(Painter &p, QRect trect, uint32 selection) const; void drawMessageText(Painter &p, QRect trect, uint32 selection) const;
int32 resize(int32 width); int32 resize(int32 width);
void resizeVia(int32 w) const;
bool hasPoint(int32 x, int32 y) const; bool hasPoint(int32 x, int32 y) const;
void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const; void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const;
void getStateFromMessageText(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const QRect &r) const; void getStateFromMessageText(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const QRect &r) const;
@ -2234,6 +2236,10 @@ protected:
mutable Text replyToName, replyToText; mutable Text replyToName, replyToText;
mutable int32 replyToVersion; mutable int32 replyToVersion;
mutable int32 _maxReplyWidth; mutable int32 _maxReplyWidth;
HistoryMessageVia *_replyToVia;
HistoryMessageVia *replyToVia() const {
return (_replyToVia && !_replyToVia->isNull()) ? _replyToVia : 0;
}
int32 toWidth; int32 toWidth;
}; };

View File

@ -2630,6 +2630,8 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
, _migrated(0) , _migrated(0)
, _history(0) , _history(0)
, _histInited(false) , _histInited(false)
, _lastScroll(0)
, _lastScrolled(0)
, _toHistoryEnd(this, st::historyToEnd) , _toHistoryEnd(this, st::historyToEnd)
, _collapseComments(this) , _collapseComments(this)
, _attachMention(this) , _attachMention(this)
@ -2722,6 +2724,9 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
connect(audioCapture(), SIGNAL(onDone(QByteArray,qint32)), this, SLOT(onRecordDone(QByteArray,qint32))); connect(audioCapture(), SIGNAL(onDone(QByteArray,qint32)), this, SLOT(onRecordDone(QByteArray,qint32)));
} }
_updateHistoryItems.setSingleShot(true);
connect(&_updateHistoryItems, SIGNAL(timeout()), this, SLOT(onUpdateHistoryItems()));
_scrollTimer.setSingleShot(false); _scrollTimer.setSingleShot(false);
_sendActionStopTimer.setSingleShot(true); _sendActionStopTimer.setSingleShot(true);
@ -3508,6 +3513,8 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
_scroll.setWidget(_list); _scroll.setWidget(_list);
_list->show(); _list->show();
_updateHistoryItems.stop();
if (_history->lastWidth || _history->isReadyFor(_showAtMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop)) { if (_history->lastWidth || _history->isReadyFor(_showAtMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop)) {
_fixedInScrollMsgId = 0; _fixedInScrollMsgId = 0;
_fixedInScrollMsgTop = 0; _fixedInScrollMsgTop = 0;
@ -4360,6 +4367,11 @@ void HistoryWidget::onListScroll() {
break; break;
} }
} }
if (st != _lastScroll) {
_lastScrolled = getms();
_lastScroll = st;
}
} }
void HistoryWidget::onVisibleChanged() { void HistoryWidget::onVisibleChanged() {
@ -4407,8 +4419,9 @@ void HistoryWidget::onSend(bool ctrlShiftEnter, MsgId replyTo) {
_saveDraftStart = getms(); _saveDraftStart = getms();
onDraftSave(); onDraftSave();
onCheckMentionDropdown(); if (!_attachMention.isHidden()) _attachMention.hideStart();
if (!_attachType.isHidden()) _attachType.hideStart(); if (!_attachType.isHidden()) _attachType.hideStart();
if (!_emojiPan.isHidden()) _emojiPan.hideStart();
if (replyTo < 0) cancelReply(lastKeyboardUsed); if (replyTo < 0) cancelReply(lastKeyboardUsed);
if (_previewData && _previewData->pendingTill) previewCancel(); if (_previewData && _previewData->pendingTill) previewCancel();
@ -5834,7 +5847,23 @@ bool HistoryWidget::isItemVisible(HistoryItem *item) {
void HistoryWidget::ui_repaintHistoryItem(const HistoryItem *item) { void HistoryWidget::ui_repaintHistoryItem(const HistoryItem *item) {
if (_peer && _list && (item->history() == _history || (_migrated && item->history() == _migrated))) { if (_peer && _list && (item->history() == _history || (_migrated && item->history() == _migrated))) {
_list->repaintItem(item); uint64 ms = getms();
if (_lastScrolled + 100 <= ms) {
_list->repaintItem(item);
} else {
_updateHistoryItems.start(_lastScrolled + 100 - ms);
}
}
}
void HistoryWidget::onUpdateHistoryItems() {
if (!_list) return;
uint64 ms = getms();
if (_lastScrolled + 100 <= ms) {
_list->update();
} else {
_updateHistoryItems.start(_lastScrolled + 100 - ms);
} }
} }
@ -6459,8 +6488,9 @@ void HistoryWidget::onInlineResultSend(InlineResult *result, UserData *bot) {
Local::writeRecentHashtagsAndBots(); Local::writeRecentHashtagsAndBots();
} }
onCheckMentionDropdown(); if (!_attachMention.isHidden()) _attachMention.hideStart();
if (!_attachType.isHidden()) _attachType.hideStart(); if (!_attachType.isHidden()) _attachType.hideStart();
if (!_emojiPan.isHidden()) _emojiPan.hideStart();
_field.setFocus(); _field.setFocus();
} }

View File

@ -682,6 +682,8 @@ public slots:
void onRecordDone(QByteArray result, qint32 samples); void onRecordDone(QByteArray result, qint32 samples);
void onRecordUpdate(qint16 level, qint32 samples); void onRecordUpdate(qint16 level, qint32 samples);
void onUpdateHistoryItems();
private: private:
MsgId _replyToId; MsgId _replyToId;
@ -771,6 +773,10 @@ private:
History *_migrated, *_history; History *_migrated, *_history;
bool _histInited; // initial updateListSize() called bool _histInited; // initial updateListSize() called
int32 _lastScroll;
uint64 _lastScrolled;
QTimer _updateHistoryItems; // gifs optimization
IconedButton _toHistoryEnd; IconedButton _toHistoryEnd;
CollapseButton _collapseComments; CollapseButton _collapseComments;

View File

@ -193,6 +193,21 @@ style::color documentColor(int32 colorIndex) {
return colors[colorIndex & 3]; return colors[colorIndex & 3];
} }
style::color documentDarkColor(int32 colorIndex) {
static style::color colors[] = { st::msgFileBlueDark, st::msgFileGreenDark, st::msgFileRedDark, st::msgFileYellowDark };
return colors[colorIndex & 3];
}
style::color documentOverColor(int32 colorIndex) {
static style::color colors[] = { st::msgFileBlueOver, st::msgFileGreenOver, st::msgFileRedOver, st::msgFileYellowOver };
return colors[colorIndex & 3];
}
style::color documentSelectedColor(int32 colorIndex) {
static style::color colors[] = { st::msgFileBlueSelected, st::msgFileGreenSelected, st::msgFileRedSelected, st::msgFileYellowSelected };
return colors[colorIndex & 3];
}
style::sprite documentCorner(int32 colorIndex) { style::sprite documentCorner(int32 colorIndex) {
static style::sprite corners[] = { st::msgFileBlue, st::msgFileGreen, st::msgFileRed, st::msgFileYellow }; static style::sprite corners[] = { st::msgFileBlue, st::msgFileGreen, st::msgFileRed, st::msgFileYellow };
return corners[colorIndex & 3]; return corners[colorIndex & 3];
@ -285,14 +300,14 @@ LayoutOverviewDate::LayoutOverviewDate(const QDate &date, bool month)
void LayoutOverviewDate::initDimensions() { void LayoutOverviewDate::initDimensions() {
_maxw = st::normalFont->width(_text); _maxw = st::normalFont->width(_text);
_minh = st::linksDateMargin + st::normalFont->height + st::linksDateMargin + st::linksBorder; _minh = st::linksDateMargin.top() + st::normalFont->height + st::linksDateMargin.bottom() + st::linksBorder;
} }
void LayoutOverviewDate::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { void LayoutOverviewDate::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const {
if (clip.intersects(QRect(0, st::linksDateMargin, _width, st::normalFont->height))) { if (clip.intersects(QRect(0, st::linksDateMargin.top(), _width, st::normalFont->height))) {
p.setPen(st::linksDateColor); p.setPen(st::linksDateColor);
p.setFont(st::normalFont); p.setFont(st::semiboldFont);
p.drawTextLeft(0, st::linksDateMargin, _width, _text); p.drawTextLeft(0, st::linksDateMargin.top(), _width, _text);
} }
} }
@ -629,12 +644,24 @@ void LayoutOverviewAudio::paint(Painter &p, const QRect &clip, uint32 selection,
if (clip.intersects(rtlrect(nameleft, statustop, namewidth, st::normalFont->height, _width))) { if (clip.intersects(rtlrect(nameleft, statustop, namewidth, st::normalFont->height, _width))) {
p.setFont(st::normalFont); p.setFont(st::normalFont);
p.setPen(selected ? st::mediaInFgSelected : st::mediaInFg); p.setPen(selected ? st::mediaInFgSelected : st::mediaInFg);
int32 unreadx = nameleft;
if (_statusSize == FileStatusSizeLoaded || _statusSize == FileStatusSizeReady) { if (_statusSize == FileStatusSizeLoaded || _statusSize == FileStatusSizeReady) {
textstyleSet(&(selected ? st::mediaInStyleSelected : st::mediaInStyle)); textstyleSet(&(selected ? st::mediaInStyleSelected : st::mediaInStyle));
_details.drawLeftElided(p, nameleft, statustop, namewidth, _width); _details.drawLeftElided(p, nameleft, statustop, namewidth, _width);
textstyleRestore(); textstyleRestore();
unreadx += _details.maxWidth();
} else { } else {
p.drawTextLeft(nameleft, statustop, _width, _statusText); int32 statusw = st::normalFont->width(_statusText);
p.drawTextLeft(nameleft, statustop, _width, _statusText, statusw);
unreadx += statusw;
}
if (_parent->isMediaUnread() && unreadx + st::mediaUnreadSkip + st::mediaUnreadSize <= _width) {
p.setPen(Qt::NoPen);
p.setBrush(selected ? st::msgFileInBgSelected : st::msgFileInBg);
p.setRenderHint(QPainter::HighQualityAntialiasing, true);
p.drawEllipse(rtlrect(unreadx + st::mediaUnreadSkip, statustop + st::mediaUnreadTop, st::mediaUnreadSize, st::mediaUnreadSize, _width));
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
} }
} }
} }
@ -715,6 +742,7 @@ LayoutOverviewDocument::LayoutOverviewDocument(DocumentData *document, HistoryIt
, _data(document) , _data(document)
, _msgl(new MessageLink(parent)) , _msgl(new MessageLink(parent))
, _namel(new DocumentOpenLink(_data)) , _namel(new DocumentOpenLink(_data))
, _thumbForLoaded(false)
, _name(documentName(_data)) , _name(documentName(_data))
, _date(langDateTime(date(_data->date))) , _date(langDateTime(date(_data->date)))
, _namew(st::semiboldFont->width(_name)) , _namew(st::semiboldFont->width(_name))
@ -728,17 +756,17 @@ LayoutOverviewDocument::LayoutOverviewDocument(DocumentData *document, HistoryIt
_data->thumb->load(); _data->thumb->load();
int32 tw = _data->thumb->width(), th = _data->thumb->height(); int32 tw = _data->thumb->width(), th = _data->thumb->height();
if (tw > th) { if (tw > th) {
_thumbw = (tw * st::msgFileThumbSize) / th; _thumbw = (tw * st::overviewFileSize) / th;
} else { } else {
_thumbw = st::msgFileThumbSize; _thumbw = st::overviewFileSize;
} }
} else { } else {
_thumbw = 0; _thumbw = 0;
} }
_extw = st::semiboldFont->width(_ext); _extw = st::semiboldFont->width(_ext);
if (_extw > st::msgFileThumbSize - st::msgFileExtPadding * 2) { if (_extw > st::overviewFileSize - st::msgFileExtPadding * 2) {
_ext = st::semiboldFont->elided(_ext, st::msgFileThumbSize - st::msgFileExtPadding * 2, Qt::ElideMiddle); _ext = st::semiboldFont->elided(_ext, st::overviewFileSize - st::msgFileExtPadding * 2, Qt::ElideMiddle);
_extw = st::semiboldFont->width(_ext); _extw = st::semiboldFont->width(_ext);
} }
} }
@ -748,7 +776,7 @@ void LayoutOverviewDocument::initDimensions() {
if (_data->song()) { if (_data->song()) {
_minh = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom(); _minh = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom();
} else { } else {
_minh = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom() + st::lineWidth; _minh = st::overviewFilePadding.top() + st::overviewFileSize + st::overviewFilePadding.bottom() + st::lineWidth;
} }
} }
@ -817,39 +845,40 @@ void LayoutOverviewDocument::paint(Painter &p, const QRect &clip, uint32 selecti
p.drawSpriteCenter(inner, icon); p.drawSpriteCenter(inner, icon);
} }
} else { } else {
nameleft = st::msgFileThumbSize + st::msgFileThumbPadding.right(); nameleft = st::overviewFileSize + st::overviewFilePadding.right();
nametop = st::linksBorder + st::msgFileThumbNameTop; nametop = st::linksBorder + st::overviewFileNameTop;
statustop = st::linksBorder + st::msgFileThumbStatusTop; statustop = st::linksBorder + st::overviewFileStatusTop;
datetop = st::linksBorder + st::msgFileThumbLinkTop; datetop = st::linksBorder + st::overviewFileDateTop;
QRect shadow(rtlrect(nameleft, 0, _width - nameleft, st::linksBorder, _width)); const OverviewPaintContext *pcontext = context->toOverviewPaintContext();
if (clip.intersects(shadow)) { t_assert(pcontext != 0);
p.fillRect(clip.intersected(shadow), st::linksBorderFg); QRect border(rtlrect(nameleft, 0, _width - nameleft, st::linksBorder, _width));
if (!pcontext->isAfterDate && clip.intersects(border)) {
p.fillRect(clip.intersected(border), st::linksBorderFg);
} }
QRect rthumb(rtlrect(0, st::linksBorder + st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, _width)); QRect rthumb(rtlrect(0, st::linksBorder + st::overviewFilePadding.top(), st::overviewFileSize, st::overviewFileSize, _width));
if (clip.intersects(rthumb)) { if (clip.intersects(rthumb)) {
if (wthumb) { if (wthumb) {
if (_data->thumb->loaded()) { if (_data->thumb->loaded()) {
QPixmap thumb = loaded ? _data->thumb->pixSingle(_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize) : _data->thumb->pixBlurredSingle(_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize); if (_thumb.isNull() || loaded != _thumbForLoaded) {
p.drawPixmap(rthumb.topLeft(), thumb); _thumbForLoaded = loaded;
_thumb = _data->thumb->pixNoCache(_thumbw, 0, true, !_thumbForLoaded, false, st::overviewFileSize, st::overviewFileSize);
}
p.drawPixmap(rthumb.topLeft(), _thumb);
} else { } else {
App::roundRect(p, rthumb, st::black, BlackCorners); p.fillRect(rthumb, st::black);
} }
} else { } else {
App::roundRect(p, rthumb, documentColor(_colorIndex), documentCorners(_colorIndex)); p.fillRect(rthumb, documentColor(_colorIndex));
if (!radial && loaded) { if (!radial && loaded && !_ext.isEmpty()) {
style::sprite icon = documentCorner(_colorIndex); p.setFont(st::semiboldFont);
p.drawSprite(rthumb.topLeft() + QPoint(rtl() ? 0 : (rthumb.width() - icon.pxWidth()), 0), icon); p.setPen(st::white);
if (!_ext.isEmpty()) { p.drawText(rthumb.left() + (rthumb.width() - _extw) / 2, rthumb.top() + st::msgFileExtTop + st::semiboldFont->ascent, _ext);
p.setFont(st::semiboldFont);
p.setPen(st::white);
p.drawText(rthumb.left() + (rthumb.width() - _extw) / 2, rthumb.top() + st::msgFileExtTop + st::semiboldFont->ascent, _ext);
}
} }
} }
if (selected) { if (selected) {
App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, SelectedOverlayCorners); p.fillRect(rthumb, textstyleCurrent()->selectOverlay);
} }
if (radial || (!loaded && !_data->loading())) { if (radial || (!loaded && !_data->loading())) {
@ -858,15 +887,19 @@ void LayoutOverviewDocument::paint(Painter &p, const QRect &clip, uint32 selecti
float64 radialOpacity = (radial && loaded && !_data->uploading()) ? _radial->opacity() : 1; float64 radialOpacity = (radial && loaded && !_data->uploading()) ? _radial->opacity() : 1;
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
if (selected) { if (selected) {
p.setBrush(st::msgDateImgBgSelected); p.setBrush(wthumb ? st::msgDateImgBgSelected : documentSelectedColor(_colorIndex));
} else if (_a_iconOver.animating()) { } else if (_a_iconOver.animating()) {
_a_iconOver.step(context->ms); _a_iconOver.step(context->ms);
float64 over = a_iconOver.current(); float64 over = a_iconOver.current();
p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over)); if (wthumb) {
p.setBrush(st::black); p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over));
p.setBrush(st::black);
} else {
p.setBrush(style::interpolate(documentDarkColor(_colorIndex), documentOverColor(_colorIndex), over));
}
} else { } else {
bool over = textlnkDrawOver(_data->loading() ? _cancell : _savel); bool over = textlnkDrawOver(_data->loading() ? _cancell : _savel);
p.setBrush(over ? st::msgDateImgBgOver : st::msgDateImgBg); p.setBrush(over ? (wthumb ? st::msgDateImgBgOver : documentOverColor(_colorIndex)) : (wthumb ? st::msgDateImgBg : documentDarkColor(_colorIndex)));
} }
p.setOpacity(radialOpacity * p.opacity()); p.setOpacity(radialOpacity * p.opacity());
@ -890,10 +923,10 @@ void LayoutOverviewDocument::paint(Painter &p, const QRect &clip, uint32 selecti
} }
} }
} }
if (selected) { if (selected || context->selecting) {
p.drawSprite(rthumb.topLeft() + QPoint(rtl() ? 0 : (rthumb.width() - st::linksPhotoChecked.pxWidth()), rthumb.height() - st::linksPhotoChecked.pxHeight()), st::linksPhotoChecked); QRect check(rthumb.topLeft() + QPoint(rtl() ? 0 : (rthumb.width() - st::defaultCheckbox.diameter), rthumb.height() - st::defaultCheckbox.diameter), QSize(st::defaultCheckbox.diameter, st::defaultCheckbox.diameter));
} else if (context->selecting) { p.fillRect(check, selected ? st::overviewFileChecked : st::overviewFileCheck);
p.drawSprite(rthumb.topLeft() + QPoint(rtl() ? 0 : (rthumb.width() - st::linksPhotoCheck.pxWidth()), rthumb.height() - st::linksPhotoCheck.pxHeight()), st::linksPhotoCheck); p.drawSpriteCenter(check, st::defaultCheckbox.checkIcon);
} }
} }
} }
@ -946,12 +979,12 @@ void LayoutOverviewDocument::getState(TextLinkPtr &link, HistoryCursorState &cur
return; return;
} }
} else { } else {
nameleft = st::msgFileThumbSize + st::msgFileThumbPadding.right(); nameleft = st::overviewFileSize + st::overviewFilePadding.right();
nametop = st::linksBorder + st::msgFileThumbNameTop; nametop = st::linksBorder + st::overviewFileNameTop;
statustop = st::linksBorder + st::msgFileThumbStatusTop; statustop = st::linksBorder + st::overviewFileStatusTop;
datetop = st::linksBorder + st::msgFileThumbLinkTop; datetop = st::linksBorder + st::overviewFileDateTop;
QRect rthumb(rtlrect(0, st::linksBorder + st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, _width)); QRect rthumb(rtlrect(0, st::linksBorder + st::overviewFilePadding.top(), st::overviewFileSize, st::overviewFileSize, _width));
if (rthumb.contains(x, y)) { if (rthumb.contains(x, y)) {
link = loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _savel); link = loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _savel);
@ -1150,7 +1183,7 @@ void LayoutOverviewLink::initDimensions() {
_minh += qMin(3 * st::normalFont->height, _text.countHeight(_maxw - st::dlgPhotoSize - st::dlgPhotoPadding)); _minh += qMin(3 * st::normalFont->height, _text.countHeight(_maxw - st::dlgPhotoSize - st::dlgPhotoPadding));
} }
_minh += _links.size() * st::normalFont->height; _minh += _links.size() * st::normalFont->height;
_minh = qMax(_minh, int32(st::dlgPhotoSize)) + st::linksMargin * 2 + st::linksBorder; _minh = qMax(_minh, int32(st::dlgPhotoSize)) + st::linksMargin.top() + st::linksMargin.bottom() + st::linksBorder;
} }
int32 LayoutOverviewLink::resizeGetHeight(int32 width) { int32 LayoutOverviewLink::resizeGetHeight(int32 width) {
@ -1168,12 +1201,12 @@ int32 LayoutOverviewLink::resizeGetHeight(int32 width) {
_height += qMin(3 * st::normalFont->height, _text.countHeight(_width - st::dlgPhotoSize - st::dlgPhotoPadding)); _height += qMin(3 * st::normalFont->height, _text.countHeight(_width - st::dlgPhotoSize - st::dlgPhotoPadding));
} }
_height += _links.size() * st::normalFont->height; _height += _links.size() * st::normalFont->height;
_height = qMax(_height, int32(st::dlgPhotoSize)) + st::linksMargin * 2 + st::linksBorder; _height = qMax(_height, int32(st::dlgPhotoSize)) + st::linksMargin.top() + st::linksMargin.bottom() + st::linksBorder;
return _height; return _height;
} }
void LayoutOverviewLink::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { void LayoutOverviewLink::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const {
int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, top = st::linksMargin + st::linksBorder, w = _width - left; int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, top = st::linksMargin.top() + st::linksBorder, w = _width - left;
if (clip.intersects(rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width))) { if (clip.intersects(rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width))) {
if (_page && _page->photo) { if (_page && _page->photo) {
QPixmap pix; QPixmap pix;
@ -1213,6 +1246,8 @@ void LayoutOverviewLink::paint(Painter &p, const QRect &clip, uint32 selection,
if (!_title.isEmpty() && _text.isEmpty() && _links.size() == 1) { if (!_title.isEmpty() && _text.isEmpty() && _links.size() == 1) {
top += (st::dlgPhotoSize - st::semiboldFont->height - st::normalFont->height) / 2; top += (st::dlgPhotoSize - st::semiboldFont->height - st::normalFont->height) / 2;
} else {
top = st::linksTextTop;
} }
p.setPen(st::black); p.setPen(st::black);
@ -1241,13 +1276,16 @@ void LayoutOverviewLink::paint(Painter &p, const QRect &clip, uint32 selection,
top += st::normalFont->height; top += st::normalFont->height;
} }
if (clip.intersects(rtlrect(left, 0, w, st::linksBorder, _width))) { const OverviewPaintContext *pcontext = context->toOverviewPaintContext();
p.fillRect(clip.intersected(rtlrect(left, 0, w, st::linksBorder, _width)), st::linksBorderFg); t_assert(pcontext != 0);
QRect border(rtlrect(left, 0, w, st::linksBorder, _width));
if (!pcontext->isAfterDate && clip.intersects(border)) {
p.fillRect(clip.intersected(border), st::linksBorderFg);
} }
} }
void LayoutOverviewLink::getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const { void LayoutOverviewLink::getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const {
int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, top = st::linksMargin + st::linksBorder, w = _width - left; int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, top = st::linksMargin.top() + st::linksBorder, w = _width - left;
if (rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width).contains(x, y)) { if (rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width).contains(x, y)) {
link = _photol; link = _photol;
return; return;
@ -1809,6 +1847,7 @@ void LayoutInlinePhoto::content_forget() {
LayoutInlineWebVideo::LayoutInlineWebVideo(InlineResult *result) : LayoutInlineItem(result, 0, 0) LayoutInlineWebVideo::LayoutInlineWebVideo(InlineResult *result) : LayoutInlineItem(result, 0, 0)
, _send(new SendInlineItemLink()) , _send(new SendInlineItemLink())
, _link(result->content_url.isEmpty() ? 0 : linkFromUrl(result->content_url))
, _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) , _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip)
, _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) { , _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) {
if (_result->duration) { if (_result->duration) {
@ -1866,8 +1905,13 @@ void LayoutInlineWebVideo::paint(Painter &p, const QRect &clip, uint32 selection
} }
void LayoutInlineWebVideo::getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const { void LayoutInlineWebVideo::getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const {
if (x >= 0 && x < _width && y >= 0 && y < _height) { if (x >= 0 && x < st::inlineThumbSize && y >= st::inlineRowMargin && y < st::inlineRowMargin + st::inlineThumbSize) {
link = _link;
return;
}
if (x >= st::inlineThumbSize + st::inlineThumbSkip && x < _width && y >= 0 && y < _height) {
link = _send; link = _send;
return;
} }
} }
@ -1896,6 +1940,7 @@ void LayoutInlineWebVideo::prepareThumb(int32 width, int32 height) const {
LayoutInlineArticle::LayoutInlineArticle(InlineResult *result, bool withThumb) : LayoutInlineItem(result, 0, 0) LayoutInlineArticle::LayoutInlineArticle(InlineResult *result, bool withThumb) : LayoutInlineItem(result, 0, 0)
, _send(new SendInlineItemLink()) , _send(new SendInlineItemLink())
, _url(result->url.isEmpty() ? 0 : linkFromUrl(result->url)) , _url(result->url.isEmpty() ? 0 : linkFromUrl(result->url))
, _link(result->content_url.isEmpty() ? 0 : linkFromUrl(result->content_url))
, _withThumb(withThumb) , _withThumb(withThumb)
, _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) , _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip)
, _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) { , _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) {
@ -1995,7 +2040,12 @@ void LayoutInlineArticle::paint(Painter &p, const QRect &clip, uint32 selection,
} }
void LayoutInlineArticle::getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const { void LayoutInlineArticle::getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const {
if (x >= 0 && x < _width && y >= 0 && y < _height) { int32 left = _withThumb ? (st::inlineThumbSize + st::inlineThumbSkip) : 0;
if (x >= 0 && x < left - st::inlineThumbSkip && y >= st::inlineRowMargin && y < st::inlineRowMargin + st::inlineThumbSize) {
link = _link;
return;
}
if (x >= left && x < _width && y >= 0 && y < _height) {
if (_url) { if (_url) {
int32 left = st::inlineThumbSize + st::inlineThumbSkip; int32 left = st::inlineThumbSize + st::inlineThumbSkip;
int32 titleHeight = qMin(_title.countHeight(_width - left), st::semiboldFont->height * 2); int32 titleHeight = qMin(_title.countHeight(_width - left), st::semiboldFont->height * 2);
@ -2007,6 +2057,7 @@ void LayoutInlineArticle::getState(TextLinkPtr &link, HistoryCursorState &cursor
} }
} }
link = _send; link = _send;
return;
} }
} }

View File

@ -75,9 +75,13 @@ QString formatPlayedText(qint64 played, qint64 duration);
QString documentName(DocumentData *document); QString documentName(DocumentData *document);
int32 documentColorIndex(DocumentData *document, QString &ext); int32 documentColorIndex(DocumentData *document, QString &ext);
style::color documentColor(int32 colorIndex); style::color documentColor(int32 colorIndex);
style::color documentDarkColor(int32 colorIndex);
style::color documentOverColor(int32 colorIndex);
style::color documentSelectedColor(int32 colorIndex);
style::sprite documentCorner(int32 colorIndex); style::sprite documentCorner(int32 colorIndex);
RoundCorners documentCorners(int32 colorIndex); RoundCorners documentCorners(int32 colorIndex);
class OverviewPaintContext;
class InlinePaintContext; class InlinePaintContext;
class PaintContext { class PaintContext {
public: public:
@ -86,6 +90,10 @@ public:
} }
uint64 ms; uint64 ms;
bool selecting; bool selecting;
virtual const OverviewPaintContext *toOverviewPaintContext() const {
return 0;
}
virtual const InlinePaintContext *toInlinePaintContext() const { virtual const InlinePaintContext *toInlinePaintContext() const {
return 0; return 0;
} }
@ -257,6 +265,17 @@ protected:
}; };
class OverviewPaintContext : public PaintContext {
public:
OverviewPaintContext(uint64 ms, bool selecting) : PaintContext(ms, selecting), isAfterDate(false) {
}
const OverviewPaintContext *toOverviewPaintContext() const {
return this;
}
bool isAfterDate;
};
class OverviewItemInfo { class OverviewItemInfo {
public: public:
OverviewItemInfo() : _top(0) { OverviewItemInfo() : _top(0) {
@ -267,7 +286,7 @@ public:
void setTop(int32 top) { void setTop(int32 top) {
_top = top; _top = top;
} }
private: private:
int32 _top; int32 _top;
@ -276,7 +295,7 @@ private:
class LayoutOverviewDate : public LayoutItem { class LayoutOverviewDate : public LayoutItem {
public: public:
LayoutOverviewDate(const QDate &date, bool month); LayoutOverviewDate(const QDate &date, bool month);
virtual void initDimensions(); virtual void initDimensions();
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const; virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const;
@ -426,6 +445,9 @@ private:
DocumentData *_data; DocumentData *_data;
TextLinkPtr _msgl, _namel; TextLinkPtr _msgl, _namel;
mutable bool _thumbForLoaded;
mutable QPixmap _thumb;
QString _name, _date, _ext; QString _name, _date, _ext;
int32 _namew, _datew, _extw; int32 _namew, _datew, _extw;
int32 _thumbw, _colorIndex; int32 _thumbw, _colorIndex;
@ -492,7 +514,7 @@ class LayoutInlineItem : public LayoutItem {
public: public:
LayoutInlineItem(InlineResult *result, DocumentData *doc, PhotoData *photo); LayoutInlineItem(InlineResult *result, DocumentData *doc, PhotoData *photo);
virtual void setPosition(int32 position); virtual void setPosition(int32 position);
int32 position() const; int32 position() const;
@ -644,7 +666,7 @@ public:
private: private:
TextLinkPtr _send; TextLinkPtr _send, _link;
mutable QPixmap _thumb; mutable QPixmap _thumb;
Text _title, _description; Text _title, _description;
@ -667,7 +689,7 @@ public:
private: private:
TextLinkPtr _send, _url; TextLinkPtr _send, _url, _link;
bool _withThumb; bool _withThumb;
mutable QPixmap _thumb; mutable QPixmap _thumb;

View File

@ -834,7 +834,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
p.setClipRect(r); p.setClipRect(r);
} }
uint64 ms = getms(); uint64 ms = getms();
PaintContext context(ms, _selMode); OverviewPaintContext context(ms, _selMode);
if (_history->overview[_type].isEmpty() && (!_migrated || !_history->overviewLoaded(_type) || _migrated->overview[_type].isEmpty())) { if (_history->overview[_type].isEmpty() && (!_migrated || !_history->overviewLoaded(_type) || _migrated->overview[_type].isEmpty())) {
QPoint dogPos((_width - st::msgDogImg.pxWidth()) / 2, ((height() - st::msgDogImg.pxHeight()) * 4) / 9); QPoint dogPos((_width - st::msgDogImg.pxWidth()) / 2, ((height() - st::msgDogImg.pxHeight()) * 4) / 9);
@ -887,6 +887,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
if (_reversed) curY = _height - curY; if (_reversed) curY = _height - curY;
if (_marginTop + curY >= r.y() + r.height()) break; if (_marginTop + curY >= r.y() + r.height()) break;
context.isAfterDate = (j > 0) ? !_items.at(j - 1)->toLayoutMediaItem() : false;
p.translate(0, curY - y); p.translate(0, curY - y);
_items.at(i)->paint(p, r.translated(-_rowsLeft, -_marginTop - curY), itemSelectedValue(i), &context); _items.at(i)->paint(p, r.translated(-_rowsLeft, -_marginTop - curY), itemSelectedValue(i), &context);
y = curY; y = curY;

View File

@ -11,7 +11,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.9.15</string> <string>0.9.16</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleURLTypes</key> <key>CFBundleURLTypes</key>

View File

@ -34,8 +34,8 @@ IDI_ICON1 ICON "SourceFiles\\art\\icon256.ico"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,9,15,7 FILEVERSION 0,9,16,0
PRODUCTVERSION 0,9,15,7 PRODUCTVERSION 0,9,16,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -51,10 +51,10 @@ BEGIN
BLOCK "040904b0" BLOCK "040904b0"
BEGIN BEGIN
VALUE "CompanyName", "Telegram Messenger LLP" VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileVersion", "0.9.15.7" VALUE "FileVersion", "0.9.16.0"
VALUE "LegalCopyright", "Copyright (C) 2013" VALUE "LegalCopyright", "Copyright (C) 2013"
VALUE "ProductName", "Telegram Desktop" VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "0.9.15.7" VALUE "ProductVersion", "0.9.16.0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -1701,7 +1701,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.9.15; CURRENT_PROJECT_VERSION = 0.9.16;
DEBUG_INFORMATION_FORMAT = dwarf; DEBUG_INFORMATION_FORMAT = dwarf;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_OPTIMIZATION_LEVEL = 0; GCC_OPTIMIZATION_LEVEL = 0;
@ -1720,7 +1720,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COPY_PHASE_STRIP = YES; COPY_PHASE_STRIP = YES;
CURRENT_PROJECT_VERSION = 0.9.15; CURRENT_PROJECT_VERSION = 0.9.16;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_OPTIMIZATION_LEVEL = fast; GCC_OPTIMIZATION_LEVEL = fast;
GCC_PREFIX_HEADER = ./SourceFiles/stdafx.h; GCC_PREFIX_HEADER = ./SourceFiles/stdafx.h;
@ -1747,10 +1747,10 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = ""; CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.9.15; CURRENT_PROJECT_VERSION = 0.9.16;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DYLIB_COMPATIBILITY_VERSION = 0.9; DYLIB_COMPATIBILITY_VERSION = 0.9;
DYLIB_CURRENT_VERSION = 0.9.15; DYLIB_CURRENT_VERSION = 0.9.16;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = ""; FRAMEWORK_SEARCH_PATHS = "";
GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
@ -1882,10 +1882,10 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = ""; CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.9.15; CURRENT_PROJECT_VERSION = 0.9.16;
DEBUG_INFORMATION_FORMAT = dwarf; DEBUG_INFORMATION_FORMAT = dwarf;
DYLIB_COMPATIBILITY_VERSION = 0.9; DYLIB_COMPATIBILITY_VERSION = 0.9;
DYLIB_CURRENT_VERSION = 0.9.15; DYLIB_CURRENT_VERSION = 0.9.16;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
FRAMEWORK_SEARCH_PATHS = ""; FRAMEWORK_SEARCH_PATHS = "";

View File

@ -1,6 +1,6 @@
AppVersion 9015 AppVersion 9016
AppVersionStrMajor 0.9 AppVersionStrMajor 0.9
AppVersionStrSmall 0.9.15 AppVersionStrSmall 0.9.16
AppVersionStr 0.9.15 AppVersionStr 0.9.16
DevChannel 0 DevChannel 0
BetaVersion 9015007 BetaVersion 0 9015008