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 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
sudo make install

View File

@ -1197,6 +1197,18 @@ msgFileRedColor: #e47272;
msgFileYellowColor: #efc274;
msgFileGreenColor: #61b96e;
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);
msgFileSize: 44px;
@ -2161,6 +2173,14 @@ overviewPhotoCheck: sprite(245px, 308px, 32px, 32px);
overviewPhotoChecked: sprite(278px, 308px, 32px, 32px);
overviewPhotoSelectOverlay: #0a7bb03f;
overviewFilePadding: margins(0px, 3px, 16px, 3px);
overviewFileSize: 70px;
overviewFileNameTop: 7px;
overviewFileStatusTop: 27px;
overviewFileDateTop: 49px;
overviewFileChecked: #2fa9e2;
overviewFileCheck: #00000066;
// Mac specific
macAccessory: size(450, 90);
@ -2346,11 +2366,12 @@ playlistPadding: 10px;
linksSearchMargin: margins(20px, 20px, 20px, 0px);
linksMaxWidth: 520px;
linksLetterFont: font(24px);
linksMargin: 5px;
linksMargin: margins(0px, 7px, 0px, 5px);
linksTextTop: 6px;
linksBorder: 1px;
linksBorderFg: #eaeaea;
linksDateColor: #000;
linksDateMargin: 15px;
linksDateColor: #808080;
linksDateMargin: margins(0px, 15px, 0px, 2px);
linksPhotoCheck: sprite(184px, 196px, 16px, 16px);
linksPhotoChecked: sprite(168px, 196px, 16px, 16px);

View File

@ -708,7 +708,7 @@ void Application::checkMapVersion() {
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 = 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();
} else {
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
static const int32 AppVersion = 9015;
static const wchar_t *AppVersionStr = L"0.9.15";
static const int32 AppVersion = 9016;
static const wchar_t *AppVersionStr = L"0.9.16";
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 *AppName = L"Telegram Desktop";

View File

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

View File

@ -344,7 +344,7 @@ public:
void refreshStickers();
void refreshRecentStickers(bool resize = true);
void refreshSavedGifs();
void refreshInlineRows(UserData *bot, const InlineResults &results, bool resultsDeleted);
int32 refreshInlineRows(UserData *bot, const InlineResults &results, bool resultsDeleted);
void refreshRecent();
void inlineBotChanged();
void hideInlineRowsPanel();
@ -458,7 +458,7 @@ private:
InlineLayouts _inlineLayouts;
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);
InlineRow &layoutInlineRow(InlineRow &row, int32 sumWidth = 0);
@ -712,10 +712,10 @@ private:
QTimer _inlineRequestTimer;
void inlineBotChanged();
void showInlineRows(bool newResults);
int32 showInlineRows(bool newResults);
bool hideOnNoInlineResults();
void recountContentMaxHeight();
bool refreshInlineRows();
bool refreshInlineRows(int32 *added = 0);
UserData *_inlineBot;
QString _inlineQuery, _inlineNextQuery, _inlineNextOffset;
mtpRequestId _inlineRequestId;

View File

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

View File

@ -497,8 +497,9 @@ enum ClipReaderNotification {
};
enum ClipReaderSteps {
FirstFrameNotReadStep = -2,
WaitingForRequestStep = -1,
WaitingForDimensionsStep = -3, // before ClipReaderPrivate read the first image and got the original frame size
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;
@ -528,7 +529,7 @@ public:
}
bool currentDisplayed() const {
Frame *frame = frameToShow();
return frame ? frame->displayed : true;
return frame ? (frame->displayed.loadAcquire() != 0) : true;
}
bool paused() const {
return _paused.loadAcquire();
@ -542,7 +543,8 @@ public:
ClipState state() const;
bool started() const {
return _step.loadAcquire() >= 0;
int32 step = _step.loadAcquire();
return (step == WaitingForFirstFrameStep) || (step >= 0);
}
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
struct Frame {
Frame() : displayed(false), when(0) {
Frame() : displayed(false) {
}
void clear() {
pix = QPixmap();
@ -570,13 +572,12 @@ private:
QPixmap pix;
QImage original;
ClipFrameRequest request;
bool displayed;
uint64 when;
QAtomicInt displayed;
};
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 *frameToWriteNext(bool check) const;
Frame *frameToWriteNext(bool check, int32 *index = 0) const;
void moveToNextShow() const;
void moveToNextWrite() const;

View File

@ -1392,7 +1392,9 @@ HistoryItem *History::createItem(HistoryBlock *block, const MTPMessage &msg, boo
case mtpc_messageMediaUnsupported:
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);
} else {
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);
style::sprite icon;
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 {
icon = (selected ? st::msgFileInDownloadSelected : st::msgFileInDownload);
}
p.drawSpriteCenter(inner, icon);
if (!icon.isEmpty()) {
p.drawSpriteCenter(inner, icon);
}
if (radial) {
p.setOpacity(1);
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 (_data->uploading()) {
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 {
lnk = _data->loaded() ? _openl : (_data->loading() ? _cancell : _savel);
lnk = _savel;
}
if (_caption.isEmpty() && parent->getMedia() == this) {
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) {
icon = (selected ? st::msgFileInPlaySelected : st::msgFileInPlay);
} else if (radial || _data->loading()) {
icon = (selected ? st::msgFileInCancelSelected : st::msgFileInCancel);
if (parent->id > 0) {
icon = (selected ? st::msgFileInCancelSelected : st::msgFileInCancel);
}
} else {
icon = (selected ? st::msgFileInDownloadSelected : st::msgFileInDownload);
}
p.drawSpriteCenter(inner, icon);
if (!icon.isEmpty()) {
p.drawSpriteCenter(inner, icon);
}
if (radial) {
p.setOpacity(1);
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;
}
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 {
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)
: bot(App::userLoaded(peerFromUser(userId)))
, width(0)
, fullWidth(st::msgServiceNameFont->width(qsl("via @") + bot->username))
, maxWidth(st::msgServiceNameFont->width(qsl("via @") + bot->username))
, lnk(new ViaInlineBotLink(bot)) {
}
@ -5967,13 +5995,21 @@ bool HistoryMessageVia::isNull() const {
}
void HistoryMessageVia::resize(int32 availw) {
if (width < fullWidth && availw > width) {
if (availw < fullWidth) {
if (width < maxWidth && availw > width) {
if (availw < maxWidth) {
text = st::msgServiceNameFont->elided(qsl("via @") + bot->username, availw);
width = st::msgServiceNameFont->width(text);
} else {
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;
_minh += _media->minHeight();
}
if (via()) {
if (st::msgPadding.left() + via()->fullWidth + st::msgPadding.right() > _maxw) {
_maxw = st::msgPadding.left() + via()->fullWidth + st::msgPadding.right() > _maxw;
if (!_media && !displayFromName() && via() && !toHistoryForwarded()) {
if (st::msgPadding.left() + via()->maxWidth + st::msgPadding.right() > _maxw) {
_maxw = st::msgPadding.left() + via()->maxWidth + st::msgPadding.right();
}
}
} else {
@ -6200,8 +6236,11 @@ void HistoryMessage::countPositionAndSize(int32 &left, int32 &width) const {
void HistoryMessage::fromNameUpdated() const {
if (!_media && displayFromName()) {
int32 _namew = st::msgPadding.left() + _from->nameText.maxWidth() + st::msgPadding.right();
if (_namew > _maxw) _maxw = _namew;
int32 namew = st::msgPadding.left() + _from->nameText.maxWidth() + st::msgPadding.right();
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) {
fromNameUpdated();
// fromNameUpdated();
_fromVersion = _from->nameVersion;
}
@ -6464,6 +6503,10 @@ void HistoryMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 m
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());
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);
}
@ -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 {
bool outbg = out() && !fromChannel(), selected = (selection == FullSelection);
if (via()) {
if (!displayFromName() && via() && !toHistoryForwarded()) {
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);
trect.setY(trect.y() + st::msgServiceNameFont->height);
}
p.setPen(st::msgColor->p);
p.setFont(st::msgFont->f);
p.setPen(st::msgColor);
p.setFont(st::msgFont);
uint16 selectedFrom = (selection == FullSelection) ? 0 : (selection >> 16) & 0xFFFF;
uint16 selectedTo = (selection == FullSelection) ? 0 : selection & 0xFFFF;
_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 {
_height += st::msgNameFont->height;
}
}
if (via()) {
if (via() && !toHistoryForwarded()) {
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());
if (emptyText() && !displayFromName()) {
_height += st::msgPadding.top() + st::msgNameFont->height + st::mediaHeaderSkip;
@ -6612,9 +6657,15 @@ void HistoryMessage::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32
if (drawBubble()) {
QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom());
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()) {
lnk = _from->lnk;
return;
if (y >= r.top() + st::msgPadding.top() && y < r.top() + st::msgPadding.top() + st::msgNameFont->height) {
if (x >= r.left() + st::msgPadding.left() && x < r.left() + r.width() - st::msgPadding.right() && x < r.left() + st::msgPadding.left() + _from->nameText.maxWidth()) {
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);
}
@ -6629,7 +6680,7 @@ void HistoryMessage::getStateFromMessageText(TextLinkPtr &lnk, HistoryCursorStat
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) {
lnk = via()->lnk;
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());
if (displayFromName()) { // from user left name
r.setTop(r.top() + st::msgNameFont->height);
}
if (via()) {
} else if (via() && !toHistoryForwarded()) {
r.setTop(r.top() + st::msgNameFont->height);
}
QRect trect(r.marginsAdded(-st::msgPadding));
@ -6765,12 +6815,16 @@ void HistoryForwarded::initDimensions() {
HistoryMessage::initDimensions();
if (!_media) {
int32 _namew = st::msgPadding.left() + fromWidth + fwdFromName.maxWidth() + st::msgPadding.right();
if (via()) {
_namew += st::msgServiceFont->spacew + via()->maxWidth;
}
if (_namew > _maxw) _maxw = _namew;
}
}
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 {
@ -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.setFont(serviceFont);
if (w >= fromWidth) {
if (via() && w > fromWidth + fwdFromName.maxWidth() + serviceFont->spacew) {
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);
} else {
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);
if (drawBubble()) {
if (displayForwardedFrom()) {
if (emptyText() && !displayFromName() && !via()) {
if (emptyText() && !displayFromName()) {
_height += st::msgPadding.top() + st::msgServiceNameFont->height + st::mediaHeaderSkip;
} else {
_height += st::msgServiceNameFont->height;
}
if (via()) {
via()->resize(width - st::msgPadding.left() - st::msgPadding.right() - fromWidth - fwdFromName.maxWidth() - st::msgServiceFont->spacew);
}
}
}
return _height;
@ -6876,6 +6940,8 @@ void HistoryForwarded::getForwardedState(TextLinkPtr &lnk, HistoryCursorState &s
state = HistoryDefaultCursorState;
if (x >= fromWidth && x < w && x < fromWidth + fwdFromName.maxWidth()) {
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 {
lnk = TextLinkPtr();
}
@ -6910,7 +6976,8 @@ HistoryReply::HistoryReply(History *history, HistoryBlock *block, const MTPDmess
, replyToMsgId(msg.vreply_to_msg_id.v)
, replyToMsg(0)
, replyToVersion(0)
, _maxReplyWidth(0) {
, _maxReplyWidth(0)
, _replyToVia(0) {
if (!updateReplyTo() && App::api()) {
App::api()->requestReplyTo(this, history->peer->asChannel(), replyToMsgId);
}
@ -6921,7 +6988,8 @@ HistoryReply::HistoryReply(History *history, HistoryBlock *block, MsgId msgId, i
, replyToMsgId(replyTo)
, replyToMsg(0)
, replyToVersion(0)
, _maxReplyWidth(0) {
, _maxReplyWidth(0)
, _replyToVia(0) {
if (!updateReplyTo() && App::api()) {
App::api()->requestReplyTo(this, history->peer->asChannel(), replyToMsgId);
}
@ -6932,7 +7000,8 @@ HistoryReply::HistoryReply(History *history, HistoryBlock *block, MsgId msgId, i
, replyToMsgId(replyTo)
, replyToMsg(0)
, replyToVersion(0)
, _maxReplyWidth(0) {
, _maxReplyWidth(0)
, _replyToVia(0) {
if (!updateReplyTo() && App::api()) {
App::api()->requestReplyTo(this, history->peer->asChannel(), replyToMsgId);
}
@ -6952,6 +7021,9 @@ void HistoryReply::initDimensions() {
HistoryMessage::initDimensions();
if (!_media) {
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;
}
}
@ -6959,6 +7031,7 @@ void HistoryReply::initDimensions() {
bool HistoryReply::updateReplyTo(bool force) {
if (replyToMsg || !replyToMsgId) return true;
replyToMsg = App::histItemById(channelId(), replyToMsgId);
if (replyToMsg) {
App::historyRegReply(this, replyToMsg);
replyToText.setText(st::msgFont, replyToMsg->inReplyText(), _textDlgOptions);
@ -6966,6 +7039,11 @@ bool HistoryReply::updateReplyTo(bool force) {
replyToNameUpdated();
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) {
replyToMsgId = 0;
}
@ -6978,12 +7056,17 @@ bool HistoryReply::updateReplyTo(bool force) {
void HistoryReply::replyToNameUpdated() const {
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;
bool hasPreview = replyToMsg->getMedia() ? replyToMsg->getMedia()->hasReplyPreview() : false;
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 {
_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));
}
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();
if (likeService) {
@ -7094,10 +7181,23 @@ int32 HistoryReply::resize(int32 width) {
} else {
_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;
}
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 {
if (drawBubble()) {
int32 left = 0, width = 0;
@ -7186,6 +7286,7 @@ HistoryReply::~HistoryReply() {
} else if (replyToMsgId && App::api()) {
App::api()->itemRemoved(this);
}
deleteAndMark(_replyToVia);
}
void HistoryServiceMsg::setMessageByAction(const MTPmessageAction &action) {

View File

@ -1680,6 +1680,7 @@ public:
}
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 getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const HistoryItem *parent) const;
@ -1979,7 +1980,7 @@ public:
UserData *bot;
QString text;
int32 width, fullWidth;
int32 width, maxWidth;
TextLinkPtr lnk;
};
@ -2164,7 +2165,7 @@ public:
}
QString selectedText(uint32 selection) const;
bool displayForwardedFrom() const {
return (!_media || !_media->isDisplayed() || !_media->hideForwardedFrom());
return via() || !_media || !_media->isDisplayed() || !_media->hideForwardedFrom();
}
HistoryForwarded *toHistoryForwarded() {
@ -2207,6 +2208,7 @@ public:
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;
int32 resize(int32 width);
void resizeVia(int32 w) const;
bool hasPoint(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;
@ -2234,6 +2236,10 @@ protected:
mutable Text replyToName, replyToText;
mutable int32 replyToVersion;
mutable int32 _maxReplyWidth;
HistoryMessageVia *_replyToVia;
HistoryMessageVia *replyToVia() const {
return (_replyToVia && !_replyToVia->isNull()) ? _replyToVia : 0;
}
int32 toWidth;
};

View File

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

View File

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

View File

@ -193,6 +193,21 @@ style::color documentColor(int32 colorIndex) {
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) {
static style::sprite corners[] = { st::msgFileBlue, st::msgFileGreen, st::msgFileRed, st::msgFileYellow };
return corners[colorIndex & 3];
@ -285,14 +300,14 @@ LayoutOverviewDate::LayoutOverviewDate(const QDate &date, bool month)
void LayoutOverviewDate::initDimensions() {
_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 {
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.setFont(st::normalFont);
p.drawTextLeft(0, st::linksDateMargin, _width, _text);
p.setFont(st::semiboldFont);
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))) {
p.setFont(st::normalFont);
p.setPen(selected ? st::mediaInFgSelected : st::mediaInFg);
int32 unreadx = nameleft;
if (_statusSize == FileStatusSizeLoaded || _statusSize == FileStatusSizeReady) {
textstyleSet(&(selected ? st::mediaInStyleSelected : st::mediaInStyle));
_details.drawLeftElided(p, nameleft, statustop, namewidth, _width);
textstyleRestore();
unreadx += _details.maxWidth();
} 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)
, _msgl(new MessageLink(parent))
, _namel(new DocumentOpenLink(_data))
, _thumbForLoaded(false)
, _name(documentName(_data))
, _date(langDateTime(date(_data->date)))
, _namew(st::semiboldFont->width(_name))
@ -728,17 +756,17 @@ LayoutOverviewDocument::LayoutOverviewDocument(DocumentData *document, HistoryIt
_data->thumb->load();
int32 tw = _data->thumb->width(), th = _data->thumb->height();
if (tw > th) {
_thumbw = (tw * st::msgFileThumbSize) / th;
_thumbw = (tw * st::overviewFileSize) / th;
} else {
_thumbw = st::msgFileThumbSize;
_thumbw = st::overviewFileSize;
}
} else {
_thumbw = 0;
}
_extw = st::semiboldFont->width(_ext);
if (_extw > st::msgFileThumbSize - st::msgFileExtPadding * 2) {
_ext = st::semiboldFont->elided(_ext, st::msgFileThumbSize - st::msgFileExtPadding * 2, Qt::ElideMiddle);
if (_extw > st::overviewFileSize - st::msgFileExtPadding * 2) {
_ext = st::semiboldFont->elided(_ext, st::overviewFileSize - st::msgFileExtPadding * 2, Qt::ElideMiddle);
_extw = st::semiboldFont->width(_ext);
}
}
@ -748,7 +776,7 @@ void LayoutOverviewDocument::initDimensions() {
if (_data->song()) {
_minh = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom();
} 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);
}
} else {
nameleft = st::msgFileThumbSize + st::msgFileThumbPadding.right();
nametop = st::linksBorder + st::msgFileThumbNameTop;
statustop = st::linksBorder + st::msgFileThumbStatusTop;
datetop = st::linksBorder + st::msgFileThumbLinkTop;
nameleft = st::overviewFileSize + st::overviewFilePadding.right();
nametop = st::linksBorder + st::overviewFileNameTop;
statustop = st::linksBorder + st::overviewFileStatusTop;
datetop = st::linksBorder + st::overviewFileDateTop;
QRect shadow(rtlrect(nameleft, 0, _width - nameleft, st::linksBorder, _width));
if (clip.intersects(shadow)) {
p.fillRect(clip.intersected(shadow), st::linksBorderFg);
const OverviewPaintContext *pcontext = context->toOverviewPaintContext();
t_assert(pcontext != 0);
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 (wthumb) {
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);
p.drawPixmap(rthumb.topLeft(), thumb);
if (_thumb.isNull() || loaded != _thumbForLoaded) {
_thumbForLoaded = loaded;
_thumb = _data->thumb->pixNoCache(_thumbw, 0, true, !_thumbForLoaded, false, st::overviewFileSize, st::overviewFileSize);
}
p.drawPixmap(rthumb.topLeft(), _thumb);
} else {
App::roundRect(p, rthumb, st::black, BlackCorners);
p.fillRect(rthumb, st::black);
}
} else {
App::roundRect(p, rthumb, documentColor(_colorIndex), documentCorners(_colorIndex));
if (!radial && loaded) {
style::sprite icon = documentCorner(_colorIndex);
p.drawSprite(rthumb.topLeft() + QPoint(rtl() ? 0 : (rthumb.width() - icon.pxWidth()), 0), icon);
if (!_ext.isEmpty()) {
p.setFont(st::semiboldFont);
p.setPen(st::white);
p.drawText(rthumb.left() + (rthumb.width() - _extw) / 2, rthumb.top() + st::msgFileExtTop + st::semiboldFont->ascent, _ext);
}
p.fillRect(rthumb, documentColor(_colorIndex));
if (!radial && loaded && !_ext.isEmpty()) {
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) {
App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, SelectedOverlayCorners);
p.fillRect(rthumb, textstyleCurrent()->selectOverlay);
}
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;
p.setPen(Qt::NoPen);
if (selected) {
p.setBrush(st::msgDateImgBgSelected);
p.setBrush(wthumb ? st::msgDateImgBgSelected : documentSelectedColor(_colorIndex));
} else if (_a_iconOver.animating()) {
_a_iconOver.step(context->ms);
float64 over = a_iconOver.current();
p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over));
p.setBrush(st::black);
if (wthumb) {
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 {
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());
@ -890,10 +923,10 @@ void LayoutOverviewDocument::paint(Painter &p, const QRect &clip, uint32 selecti
}
}
}
if (selected) {
p.drawSprite(rthumb.topLeft() + QPoint(rtl() ? 0 : (rthumb.width() - st::linksPhotoChecked.pxWidth()), rthumb.height() - st::linksPhotoChecked.pxHeight()), st::linksPhotoChecked);
} else if (context->selecting) {
p.drawSprite(rthumb.topLeft() + QPoint(rtl() ? 0 : (rthumb.width() - st::linksPhotoCheck.pxWidth()), rthumb.height() - st::linksPhotoCheck.pxHeight()), st::linksPhotoCheck);
if (selected || context->selecting) {
QRect check(rthumb.topLeft() + QPoint(rtl() ? 0 : (rthumb.width() - st::defaultCheckbox.diameter), rthumb.height() - st::defaultCheckbox.diameter), QSize(st::defaultCheckbox.diameter, st::defaultCheckbox.diameter));
p.fillRect(check, selected ? st::overviewFileChecked : st::overviewFileCheck);
p.drawSpriteCenter(check, st::defaultCheckbox.checkIcon);
}
}
}
@ -946,12 +979,12 @@ void LayoutOverviewDocument::getState(TextLinkPtr &link, HistoryCursorState &cur
return;
}
} else {
nameleft = st::msgFileThumbSize + st::msgFileThumbPadding.right();
nametop = st::linksBorder + st::msgFileThumbNameTop;
statustop = st::linksBorder + st::msgFileThumbStatusTop;
datetop = st::linksBorder + st::msgFileThumbLinkTop;
nameleft = st::overviewFileSize + st::overviewFilePadding.right();
nametop = st::linksBorder + st::overviewFileNameTop;
statustop = st::linksBorder + st::overviewFileStatusTop;
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)) {
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 += _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) {
@ -1168,12 +1201,12 @@ int32 LayoutOverviewLink::resizeGetHeight(int32 width) {
_height += qMin(3 * st::normalFont->height, _text.countHeight(_width - st::dlgPhotoSize - st::dlgPhotoPadding));
}
_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;
}
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 (_page && _page->photo) {
QPixmap pix;
@ -1213,6 +1246,8 @@ void LayoutOverviewLink::paint(Painter &p, const QRect &clip, uint32 selection,
if (!_title.isEmpty() && _text.isEmpty() && _links.size() == 1) {
top += (st::dlgPhotoSize - st::semiboldFont->height - st::normalFont->height) / 2;
} else {
top = st::linksTextTop;
}
p.setPen(st::black);
@ -1241,13 +1276,16 @@ void LayoutOverviewLink::paint(Painter &p, const QRect &clip, uint32 selection,
top += st::normalFont->height;
}
if (clip.intersects(rtlrect(left, 0, w, st::linksBorder, _width))) {
p.fillRect(clip.intersected(rtlrect(left, 0, w, st::linksBorder, _width)), st::linksBorderFg);
const OverviewPaintContext *pcontext = context->toOverviewPaintContext();
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 {
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)) {
link = _photol;
return;
@ -1809,6 +1847,7 @@ void LayoutInlinePhoto::content_forget() {
LayoutInlineWebVideo::LayoutInlineWebVideo(InlineResult *result) : LayoutInlineItem(result, 0, 0)
, _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)
, _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) {
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 {
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;
return;
}
}
@ -1896,6 +1940,7 @@ void LayoutInlineWebVideo::prepareThumb(int32 width, int32 height) const {
LayoutInlineArticle::LayoutInlineArticle(InlineResult *result, bool withThumb) : LayoutInlineItem(result, 0, 0)
, _send(new SendInlineItemLink())
, _url(result->url.isEmpty() ? 0 : linkFromUrl(result->url))
, _link(result->content_url.isEmpty() ? 0 : linkFromUrl(result->content_url))
, _withThumb(withThumb)
, _title(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 {
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) {
int32 left = st::inlineThumbSize + st::inlineThumbSkip;
int32 titleHeight = qMin(_title.countHeight(_width - left), st::semiboldFont->height * 2);
@ -2007,6 +2057,7 @@ void LayoutInlineArticle::getState(TextLinkPtr &link, HistoryCursorState &cursor
}
}
link = _send;
return;
}
}

View File

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

View File

@ -834,7 +834,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
p.setClipRect(r);
}
uint64 ms = getms();
PaintContext context(ms, _selMode);
OverviewPaintContext context(ms, _selMode);
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);
@ -887,6 +887,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
if (_reversed) curY = _height - curY;
if (_marginTop + curY >= r.y() + r.height()) break;
context.isAfterDate = (j > 0) ? !_items.at(j - 1)->toLayoutMediaItem() : false;
p.translate(0, curY - y);
_items.at(i)->paint(p, r.translated(-_rowsLeft, -_marginTop - curY), itemSelectedValue(i), &context);
y = curY;

View File

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

View File

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

View File

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

View File

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