From 01d448c1bdbf20d38d5ba1e51296a9a330af5450 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 12 Jul 2016 14:38:16 +0300 Subject: [PATCH] Video play progress displayed in MediaView (in case of audio stream). --- Telegram/SourceFiles/media/media_audio.cpp | 8 ++ Telegram/SourceFiles/media/media_audio.h | 7 +- .../SourceFiles/media/media_clip_ffmpeg.cpp | 4 +- .../SourceFiles/media/media_clip_ffmpeg.h | 2 +- .../SourceFiles/media/media_clip_reader.cpp | 10 ++- .../SourceFiles/media/media_clip_reader.h | 7 +- .../media/view/media_clip_controller.cpp | 73 +++++++++++++++++-- .../media/view/media_clip_controller.h | 11 +++ .../media/view/media_clip_playback.cpp | 12 ++- .../media/view/media_clip_playback.h | 3 + .../SourceFiles/media/view/mediaview.style | 3 + Telegram/SourceFiles/mediaview.cpp | 21 ++++++ Telegram/SourceFiles/mediaview.h | 1 + .../SourceFiles/ui/effects/fade_animation.cpp | 23 ++++-- .../SourceFiles/ui/effects/fade_animation.h | 5 ++ .../SourceFiles/ui/widgets/label_simple.cpp | 16 +++- .../SourceFiles/ui/widgets/label_simple.h | 2 +- 17 files changed, 178 insertions(+), 30 deletions(-) diff --git a/Telegram/SourceFiles/media/media_audio.cpp b/Telegram/SourceFiles/media/media_audio.cpp index 9bc7791c2..3cdee8d4e 100644 --- a/Telegram/SourceFiles/media/media_audio.cpp +++ b/Telegram/SourceFiles/media/media_audio.cpp @@ -718,6 +718,14 @@ void AudioPlayer::stopAndClear() { } } +AudioPlaybackState AudioPlayer::currentVideoState(uint64 videoPlayId) { + QMutexLocker lock(&playerMutex); + auto current = dataForType(AudioMsgId::Type::Video); + if (!current || current->videoPlayId != videoPlayId) return AudioPlaybackState(); + + return current->playbackState; +} + AudioPlaybackState AudioPlayer::currentState(AudioMsgId *audio, AudioMsgId::Type type) { QMutexLocker lock(&playerMutex); auto current = dataForType(type); diff --git a/Telegram/SourceFiles/media/media_audio.h b/Telegram/SourceFiles/media/media_audio.h index 38b251a88..529e730ce 100644 --- a/Telegram/SourceFiles/media/media_audio.h +++ b/Telegram/SourceFiles/media/media_audio.h @@ -71,6 +71,7 @@ public: void feedFromVideo(VideoSoundPart &&part); int64 getVideoCorrectedTime(uint64 playId, uint64 systemMs); void videoSoundProgress(const AudioMsgId &audio); + AudioPlaybackState currentVideoState(uint64 videoPlayId); void stopAndClear(); @@ -215,12 +216,10 @@ class AudioPlayerFader : public QObject { Q_OBJECT public: - AudioPlayerFader(QThread *thread); void resumeDevice(); signals: - void error(const AudioMsgId &audio); void playPositionUpdated(const AudioMsgId &audio); void audioStopped(const AudioMsgId &audio); @@ -228,8 +227,7 @@ signals: void stopPauseDevice(); - public slots: - +public slots: void onInit(); void onTimer(); void onPauseTimer(); @@ -241,7 +239,6 @@ signals: void onSongVolumeChanged(); private: - enum { EmitError = 0x01, EmitStopped = 0x02, diff --git a/Telegram/SourceFiles/media/media_clip_ffmpeg.cpp b/Telegram/SourceFiles/media/media_clip_ffmpeg.cpp index 31903856a..749fe795c 100644 --- a/Telegram/SourceFiles/media/media_clip_ffmpeg.cpp +++ b/Telegram/SourceFiles/media/media_clip_ffmpeg.cpp @@ -28,7 +28,8 @@ namespace Media { namespace Clip { namespace internal { -FFMpegReaderImplementation::FFMpegReaderImplementation(FileLocation *location, QByteArray *data) : ReaderImplementation(location, data) { +FFMpegReaderImplementation::FFMpegReaderImplementation(FileLocation *location, QByteArray *data, uint64 playId) : ReaderImplementation(location, data) +, _playId(playId) { _frame = av_frame_alloc(); av_init_packet(&_packetNull); _packetNull.data = nullptr; @@ -311,7 +312,6 @@ bool FFMpegReaderImplementation::start(Mode mode) { } else { soundData->length = (_fmtContext->streams[_audioStreamId]->duration * soundData->frequency * _fmtContext->streams[_audioStreamId]->time_base.num) / _fmtContext->streams[_audioStreamId]->time_base.den; } - _playId = rand_value(); audioPlayer()->playFromVideo(AudioMsgId(AudioMsgId::Type::Video), _playId, std_::move(soundData), 0); } diff --git a/Telegram/SourceFiles/media/media_clip_ffmpeg.h b/Telegram/SourceFiles/media/media_clip_ffmpeg.h index 0bd5d12a6..ed47711b7 100644 --- a/Telegram/SourceFiles/media/media_clip_ffmpeg.h +++ b/Telegram/SourceFiles/media/media_clip_ffmpeg.h @@ -35,7 +35,7 @@ namespace internal { class FFMpegReaderImplementation : public ReaderImplementation { public: - FFMpegReaderImplementation(FileLocation *location, QByteArray *data); + FFMpegReaderImplementation(FileLocation *location, QByteArray *data, uint64 playId); bool readFramesTill(int64 ms) override; uint64 framePresentationTime() const override; diff --git a/Telegram/SourceFiles/media/media_clip_reader.cpp b/Telegram/SourceFiles/media/media_clip_reader.cpp index c5998e137..f750dcd11 100644 --- a/Telegram/SourceFiles/media/media_clip_reader.cpp +++ b/Telegram/SourceFiles/media/media_clip_reader.cpp @@ -87,7 +87,8 @@ QPixmap _prepareFrame(const FrameRequest &request, const QImage &original, bool Reader::Reader(const FileLocation &location, const QByteArray &data, Callback &&callback, Mode mode) : _callback(std_::move(callback)) -, _mode(mode) { +, _mode(mode) +, _playId(rand_value()) { if (threads.size() < ClipThreadsCount) { _threadIndex = threads.size(); threads.push_back(new QThread()); @@ -289,6 +290,7 @@ class ReaderPrivate { public: ReaderPrivate(Reader *reader, const FileLocation &location, const QByteArray &data) : _interface(reader) , _mode(reader->mode()) + , _playId(reader->playId()) , _data(data) , _location(_data.isEmpty() ? new FileLocation(location) : 0) { if (_data.isEmpty() && !_location->accessEnable()) { @@ -364,7 +366,7 @@ public: } } - _implementation = std_::make_unique(_location, &_data); + _implementation = std_::make_unique(_location, &_data, _playId); // _implementation = new QtGifReaderImplementation(_location, &_data); auto implementationMode = [this]() { @@ -410,6 +412,7 @@ private: Reader *_interface; State _state = State::Reading; Reader::Mode _mode; + uint64 _playId; QByteArray _data; FileLocation *_location; @@ -687,7 +690,8 @@ MTPDocumentAttribute readAttributes(const QString &fname, const QByteArray &data FileLocation localloc(StorageFilePartial, fname); QByteArray localdata(data); - auto reader = std_::make_unique(&localloc, &localdata); + auto playId = 0ULL; + auto reader = std_::make_unique(&localloc, &localdata, playId); if (reader->start(internal::ReaderImplementation::Mode::OnlyGifv)) { bool hasAlpha = false; if (reader->readFramesTill(-1) && reader->renderFrame(cover, hasAlpha, QSize())) { diff --git a/Telegram/SourceFiles/media/media_clip_reader.h b/Telegram/SourceFiles/media/media_clip_reader.h index 43b2768ea..85ee447cc 100644 --- a/Telegram/SourceFiles/media/media_clip_reader.h +++ b/Telegram/SourceFiles/media/media_clip_reader.h @@ -51,7 +51,6 @@ enum ReaderSteps { class ReaderPrivate; class Reader { public: - using Callback = Function; enum class Mode { Gif, @@ -68,6 +67,10 @@ public: return _autoplay; } + uint64 playId() const { + return _playId; + } + void start(int framew, int frameh, int outerw, int outerh, bool rounded); QPixmap current(int framew, int frameh, int outerw, int outerh, uint64 ms); QPixmap frameOriginal() const { @@ -114,6 +117,8 @@ private: State _state = State::Reading; + uint64 _playId; + mutable int _width = 0; mutable int _height = 0; diff --git a/Telegram/SourceFiles/media/view/media_clip_controller.cpp b/Telegram/SourceFiles/media/view/media_clip_controller.cpp index f784e7e62..4a89e0f6c 100644 --- a/Telegram/SourceFiles/media/view/media_clip_controller.cpp +++ b/Telegram/SourceFiles/media/view/media_clip_controller.cpp @@ -41,6 +41,8 @@ Controller::Controller(QWidget *parent) : TWidget(parent) , _toPlayLeft(this, st::mediaviewPlayProgressLabel) , _fadeAnimation(std_::make_unique(this)) { _fadeAnimation->show(); + _fadeAnimation->setFinishedCallback(func(this, &Controller::fadeFinished)); + _fadeAnimation->setUpdatedCallback(func(this, &Controller::fadeUpdated)); connect(_playPauseResume, SIGNAL(clicked()), this, SIGNAL(playPressed())); connect(_fullScreenToggle, SIGNAL(clicked()), this, SIGNAL(toFullScreenPressed())); connect(_playback, SIGNAL(seekProgress(int64)), this, SLOT(onSeekProgress(int64))); @@ -59,14 +61,38 @@ void Controller::onSeekFinished(int64 position) { } void Controller::showAnimated() { - _fadeAnimation->fadeIn(st::mvShowDuration); + startFading([this]() { + _fadeAnimation->fadeIn(st::mvShowDuration); + }); } void Controller::hideAnimated() { - _fadeAnimation->fadeOut(st::mvHideDuration); + startFading([this]() { + _fadeAnimation->fadeOut(st::mvShowDuration); + }); +} + +template +void Controller::startFading(Callback start) { + start(); + _playback->show(); +} + +void Controller::fadeFinished() { + fadeUpdated(1.); +} + +void Controller::fadeUpdated(float64 opacity) { + _playback->setFadeOpacity(opacity); } void Controller::updatePlayback(const AudioPlaybackState &playbackState) { + updatePlayPauseResumeState(playbackState); + _playback->updateState(playbackState); + updateTimeTexts(playbackState); +} + +void Controller::updatePlayPauseResumeState(const AudioPlaybackState &playbackState) { bool showPause = (playbackState.state == AudioPlayerPlaying || playbackState.state == AudioPlayerResuming); if (showPause != _showPause) { disconnect(_playPauseResume, SIGNAL(clicked()), this, _showPause ? SIGNAL(pausePressed()) : SIGNAL(playPressed())); @@ -75,8 +101,32 @@ void Controller::updatePlayback(const AudioPlaybackState &playbackState) { _playPauseResume->setIcon(_showPause ? &st::mediaviewPauseIcon : nullptr); } +} - _playback->updateState(playbackState); +void Controller::updateTimeTexts(const AudioPlaybackState &playbackState) { + qint64 position = 0, duration = playbackState.duration; + + if (!(playbackState.state & AudioPlayerStoppedMask) && playbackState.state != AudioPlayerFinishing) { + position = playbackState.position; + } else if (playbackState.state == AudioPlayerStoppedAtEnd) { + position = playbackState.duration; + } else { + position = 0; + } + auto playFrequency = (playbackState.frequency ? playbackState.frequency : AudioVoiceMsgFrequency); + auto playAlready = position / playFrequency; + auto playLeft = (playbackState.duration / playFrequency) - playAlready; + + auto timeAlready = formatDurationText(playAlready); + auto minus = QChar(8722); + auto timeLeft = minus + formatDurationText(playLeft); + + auto alreadyChanged = false, leftChanged = false; + _playedAlready->setText(timeAlready, &alreadyChanged); + _toPlayLeft->setText(timeLeft, &leftChanged); + if (alreadyChanged || leftChanged) { + _fadeAnimation->refreshCache(); + } } void Controller::setInFullScreen(bool inFullScreen) { @@ -88,18 +138,29 @@ void Controller::setInFullScreen(bool inFullScreen) { connect(_fullScreenToggle, SIGNAL(clicked()), this, handler); } +void Controller::grabStart() { + showChildren(); + _playback->hide(); +} + +void Controller::grabFinish() { + hideChildren(); + _playback->show(); +} + void Controller::resizeEvent(QResizeEvent *e) { int playTop = (height() - _playPauseResume->height()) / 2; _playPauseResume->moveToLeft(playTop, playTop); - _playedAlready->moveToLeft(playTop + _playPauseResume->width() + playTop, 0); int fullScreenTop = (height() - _fullScreenToggle->height()) / 2; _fullScreenToggle->moveToRight(fullScreenTop, fullScreenTop); - _toPlayLeft->moveToRight(fullScreenTop + _fullScreenToggle->width() + fullScreenTop, 0); _volumeController->moveToRight(fullScreenTop + _fullScreenToggle->width() + fullScreenTop, (height() - _volumeController->height()) / 2); _playback->resize(width() - playTop - _playPauseResume->width() - playTop - fullScreenTop - _volumeController->width() - fullScreenTop - _fullScreenToggle->width() - fullScreenTop, _volumeController->height()); - _playback->moveToLeft(playTop + _playPauseResume->width() + playTop, (height() - _playback->height()) / 2); + _playback->moveToLeft(playTop + _playPauseResume->width() + playTop, st::mediaviewPlaybackTop); + + _playedAlready->moveToLeft(playTop + _playPauseResume->width() + playTop, st::mediaviewPlayProgressTop); + _toPlayLeft->moveToRight(width() - (playTop + _playPauseResume->width() + playTop) - _playback->width(), st::mediaviewPlayProgressTop); } void Controller::paintEvent(QPaintEvent *e) { diff --git a/Telegram/SourceFiles/media/view/media_clip_controller.h b/Telegram/SourceFiles/media/view/media_clip_controller.h index 13bf40dd8..3cf6016f3 100644 --- a/Telegram/SourceFiles/media/view/media_clip_controller.h +++ b/Telegram/SourceFiles/media/view/media_clip_controller.h @@ -46,6 +46,9 @@ public: void updatePlayback(const AudioPlaybackState &playbackState); void setInFullScreen(bool inFullScreen); + void grabStart() override; + void grabFinish() override; + signals: void playPressed(); void pausePressed(); @@ -64,6 +67,14 @@ protected: void paintEvent(QPaintEvent *e) override; private: + template + void startFading(Callback start); + void fadeFinished(); + void fadeUpdated(float64 opacity); + + void updatePlayPauseResumeState(const AudioPlaybackState &playbackState); + void updateTimeTexts(const AudioPlaybackState &playbackState); + bool _showPause = false; int64 _seekPosition = -1; diff --git a/Telegram/SourceFiles/media/view/media_clip_playback.cpp b/Telegram/SourceFiles/media/view/media_clip_playback.cpp index a80b9b554..29ca25924 100644 --- a/Telegram/SourceFiles/media/view/media_clip_playback.cpp +++ b/Telegram/SourceFiles/media/view/media_clip_playback.cpp @@ -60,6 +60,11 @@ void Playback::updateState(const AudioPlaybackState &playbackState) { } } +void Playback::setFadeOpacity(float64 opacity) { + _fadeOpacity = opacity; + update(); +} + void Playback::step_progress(float64 ms, bool timer) { float64 dt = ms / (2 * AudioVoiceMsgUpdateView); if (_duration && dt >= 1) { @@ -75,6 +80,7 @@ void Playback::paintEvent(QPaintEvent *e) { Painter p(this); int radius = st::mediaviewPlaybackWidth / 2; + p.setOpacity(_fadeOpacity); p.setPen(Qt::NoPen); p.setRenderHint(QPainter::HighQualityAntialiasing); @@ -85,19 +91,19 @@ void Playback::paintEvent(QPaintEvent *e) { int32 from = skip, mid = qRound(from + prg * length), end = from + length; if (mid > from) { p.setClipRect(0, 0, mid, height()); - p.setOpacity(over * st::mediaviewActiveOpacity + (1. - over) * st::mediaviewInactiveOpacity); + p.setOpacity(_fadeOpacity * (over * st::mediaviewActiveOpacity + (1. - over) * st::mediaviewInactiveOpacity)); p.setBrush(st::mediaviewPlaybackActive); p.drawRoundedRect(0, (height() - st::mediaviewPlaybackWidth) / 2, mid + radius, st::mediaviewPlaybackWidth, radius, radius); } if (end > mid) { p.setClipRect(mid, 0, width() - mid, height()); - p.setOpacity(1.); + p.setOpacity(_fadeOpacity); p.setBrush(st::mediaviewPlaybackInactive); p.drawRoundedRect(mid - radius, (height() - st::mediaviewPlaybackWidth) / 2, width() - (mid - radius), st::mediaviewPlaybackWidth, radius, radius); } int x = mid - skip; p.setClipRect(rect()); - p.setOpacity(over * st::mediaviewActiveOpacity + (1. - over) * st::mediaviewInactiveOpacity); + p.setOpacity(_fadeOpacity * (over * st::mediaviewActiveOpacity + (1. - over) * st::mediaviewInactiveOpacity)); p.setBrush(st::mediaviewPlaybackActive); p.drawRoundedRect(x, (height() - st::mediaviewSeekSize.height()) / 2, st::mediaviewSeekSize.width(), st::mediaviewSeekSize.height(), st::mediaviewSeekSize.width() / 2, st::mediaviewSeekSize.width() / 2); } diff --git a/Telegram/SourceFiles/media/view/media_clip_playback.h b/Telegram/SourceFiles/media/view/media_clip_playback.h index d362d770e..a74d0ee83 100644 --- a/Telegram/SourceFiles/media/view/media_clip_playback.h +++ b/Telegram/SourceFiles/media/view/media_clip_playback.h @@ -32,6 +32,7 @@ public: Playback(QWidget *parent); void updateState(const AudioPlaybackState &playbackState); + void setFadeOpacity(float64 opacity); signals: void seekProgress(int64 position); @@ -63,6 +64,8 @@ private: bool _mouseDown = false; float64 _downProgress = 0.; + float64 _fadeOpacity = 1.; + }; } // namespace Clip diff --git a/Telegram/SourceFiles/media/view/mediaview.style b/Telegram/SourceFiles/media/view/mediaview.style index 7540b269b..98e48c6e1 100644 --- a/Telegram/SourceFiles/media/view/mediaview.style +++ b/Telegram/SourceFiles/media/view/mediaview.style @@ -28,8 +28,10 @@ mediaviewOverDuration: 150; mediaviewControllerSize: size(600px, 50px); mediaviewPlayProgressLabel: LabelSimple(defaultLabelSimple) { + font: semiboldFont; textFg: #ffffffc7; } +mediaviewPlayProgressTop: 8px; mediaviewPlayButton: IconButton { width: 25px; height: 24px; @@ -63,6 +65,7 @@ mediaviewFullScreenOutIcon: icon { mediaviewPlaybackActive: #ffffff; mediaviewPlaybackInactive: #474747; mediaviewPlaybackWidth: 3px; +mediaviewPlaybackTop: 23px; mediaviewSeekSize: size(2px, 13px); mediaviewVolumeSize: size(44px, 12px); diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index 4134d7503..925d9d769 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -29,6 +29,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "media/media_clip_reader.h" #include "media/view/media_clip_controller.h" #include "styles/style_mediaview.h" +#include "media/media_audio.h" namespace { @@ -233,6 +234,9 @@ void MediaView::stopGif() { _gif = nullptr; _clipController.destroy(); Sandbox::removeEventFilter(this); + if (audioPlayer()) { + disconnect(audioPlayer(), SIGNAL(updated(const AudioMsgId&)), this, SLOT(onVideoPlayProgress(const AudioMsgId&))); + } } void MediaView::documentUpdated(DocumentData *doc) { @@ -1247,6 +1251,10 @@ void MediaView::createClipController() { Sandbox::removeEventFilter(this); Sandbox::installEventFilter(this); + + if (audioPlayer()) { + connect(audioPlayer(), SIGNAL(updated(const AudioMsgId&)), this, SLOT(onVideoPlayProgress(const AudioMsgId&))); + } } void MediaView::setClipControllerGeometry() { @@ -1289,6 +1297,19 @@ void MediaView::onVideoFromFullScreen() { } +void MediaView::onVideoPlayProgress(const AudioMsgId &audioId) { + if (audioId.type() != AudioMsgId::Type::Video) { + return; + } + + t_assert(_gif != nullptr); + t_assert(audioPlayer() != nullptr); + auto state = audioPlayer()->currentVideoState(_gif->playId()); + if (state.frequency) { + _clipController->updatePlayback(state); + } +} + void MediaView::paintEvent(QPaintEvent *e) { QRect r(e->rect()); QRegion region(e->region()); diff --git a/Telegram/SourceFiles/mediaview.h b/Telegram/SourceFiles/mediaview.h index 03ff51eb7..9ff96395c 100644 --- a/Telegram/SourceFiles/mediaview.h +++ b/Telegram/SourceFiles/mediaview.h @@ -122,6 +122,7 @@ private slots: void onVideoVolumeChanged(float64 volume); void onVideoToFullScreen(); void onVideoFromFullScreen(); + void onVideoPlayProgress(const AudioMsgId &audioId); private: void displayPhoto(PhotoData *photo, HistoryItem *item); diff --git a/Telegram/SourceFiles/ui/effects/fade_animation.cpp b/Telegram/SourceFiles/ui/effects/fade_animation.cpp index 29da4c50d..9936c51e5 100644 --- a/Telegram/SourceFiles/ui/effects/fade_animation.cpp +++ b/Telegram/SourceFiles/ui/effects/fade_animation.cpp @@ -29,20 +29,26 @@ FadeAnimation::FadeAnimation(TWidget *widget) : _widget(widget) { bool FadeAnimation::paint(Painter &p) { if (_cache.isNull()) return false; - bool animating = _animation.animating(getms()); - p.setOpacity(_animation.current(_visible ? 1. : 0.)); p.drawPixmap(0, 0, _cache); - if (!animating) { - stopAnimation(); - } return true; } +void FadeAnimation::refreshCache() { + if (!_cache.isNull()) { + _cache = QPixmap(); + _cache = myGrab(_widget); + } +} + void FadeAnimation::setFinishedCallback(FinishedCallback &&callback) { _finishedCallback = std_::move(callback); } +void FadeAnimation::setUpdatedCallback(UpdatedCallback &&callback) { + _updatedCallback = std_::move(callback); +} + void FadeAnimation::show() { _visible = true; stopAnimation(); @@ -93,7 +99,12 @@ void FadeAnimation::startAnimation(int duration) { } void FadeAnimation::updateCallback() { - _widget->update(); + if (_animation.animating(getms())) { + _widget->update(); + _updatedCallback.call(_animation.current()); + } else { + stopAnimation(); + } } } // namespace Ui diff --git a/Telegram/SourceFiles/ui/effects/fade_animation.h b/Telegram/SourceFiles/ui/effects/fade_animation.h index cc5793bef..aaf95129f 100644 --- a/Telegram/SourceFiles/ui/effects/fade_animation.h +++ b/Telegram/SourceFiles/ui/effects/fade_animation.h @@ -29,10 +29,14 @@ public: FadeAnimation(TWidget *widget); bool paint(Painter &p); + void refreshCache(); using FinishedCallback = Function; void setFinishedCallback(FinishedCallback &&callback); + using UpdatedCallback = Function; + void setUpdatedCallback(UpdatedCallback &&callback); + void show(); void hide(); @@ -51,6 +55,7 @@ private: bool _visible = false; FinishedCallback _finishedCallback; + UpdatedCallback _updatedCallback; }; diff --git a/Telegram/SourceFiles/ui/widgets/label_simple.cpp b/Telegram/SourceFiles/ui/widgets/label_simple.cpp index 13ae9eb4f..f7c802ad2 100644 --- a/Telegram/SourceFiles/ui/widgets/label_simple.cpp +++ b/Telegram/SourceFiles/ui/widgets/label_simple.cpp @@ -28,17 +28,29 @@ LabelSimple::LabelSimple(QWidget *parent, const style::LabelSimple &st, const QS setText(value); } -void LabelSimple::setText(const QString &value) { +void LabelSimple::setText(const QString &value, bool *outTextChanged) { + if (_fullText == value) { + if (outTextChanged) *outTextChanged = false; + return; + } + _fullText = value; _fullTextWidth = _st.font->width(_fullText); if (!_st.maxWidth || _fullTextWidth <= _st.maxWidth) { _text = _fullText; _textWidth = _fullTextWidth; } else { - _text = _st.font->elided(_fullText, _st.maxWidth); + auto newText = _st.font->elided(_fullText, _st.maxWidth); + if (newText == _text) { + if (outTextChanged) *outTextChanged = false; + return; + } + _text = newText; _textWidth = _st.font->width(_text); } resize(_textWidth, _st.font->height); + update(); + if (outTextChanged) *outTextChanged = true; } void LabelSimple::paintEvent(QPaintEvent *e) { diff --git a/Telegram/SourceFiles/ui/widgets/label_simple.h b/Telegram/SourceFiles/ui/widgets/label_simple.h index 6317da344..a1b823705 100644 --- a/Telegram/SourceFiles/ui/widgets/label_simple.h +++ b/Telegram/SourceFiles/ui/widgets/label_simple.h @@ -29,7 +29,7 @@ public: LabelSimple(QWidget *parent, const style::LabelSimple &st = st::defaultLabelSimple, const QString &value = QString()); // This method also resizes the label. - void setText(const QString &newText); + void setText(const QString &newText, bool *outTextChanged = nullptr); protected: void paintEvent(QPaintEvent *e) override;