diff --git a/Telegram/Resources/basic_types.style b/Telegram/Resources/basic_types.style index ca5392b13..55b11e353 100644 --- a/Telegram/Resources/basic_types.style +++ b/Telegram/Resources/basic_types.style @@ -449,3 +449,17 @@ OutlineButton { font: font; padding: margins; } + +IconButton { + width: pixels; + height: pixels; + + opacity: double; + overOpacity: double; + + icon: icon; + iconPosition: point; + downIconPosition: point; + + duration: int; +} diff --git a/Telegram/Resources/icons/media_fullscreen_from.png b/Telegram/Resources/icons/media_fullscreen_from.png new file mode 100644 index 000000000..6d241d992 Binary files /dev/null and b/Telegram/Resources/icons/media_fullscreen_from.png differ diff --git a/Telegram/Resources/icons/media_fullscreen_from@2x.png b/Telegram/Resources/icons/media_fullscreen_from@2x.png new file mode 100644 index 000000000..448b42b0f Binary files /dev/null and b/Telegram/Resources/icons/media_fullscreen_from@2x.png differ diff --git a/Telegram/Resources/icons/media_fullscreen_to.png b/Telegram/Resources/icons/media_fullscreen_to.png new file mode 100644 index 000000000..43c7a54c7 Binary files /dev/null and b/Telegram/Resources/icons/media_fullscreen_to.png differ diff --git a/Telegram/Resources/icons/media_fullscreen_to@2x.png b/Telegram/Resources/icons/media_fullscreen_to@2x.png new file mode 100644 index 000000000..cf386f13d Binary files /dev/null and b/Telegram/Resources/icons/media_fullscreen_to@2x.png differ diff --git a/Telegram/Resources/icons/media_pause.png b/Telegram/Resources/icons/media_pause.png new file mode 100644 index 000000000..2ae4e1ebb Binary files /dev/null and b/Telegram/Resources/icons/media_pause.png differ diff --git a/Telegram/Resources/icons/media_pause@2x.png b/Telegram/Resources/icons/media_pause@2x.png new file mode 100644 index 000000000..ffba955ad Binary files /dev/null and b/Telegram/Resources/icons/media_pause@2x.png differ diff --git a/Telegram/Resources/icons/media_play.png b/Telegram/Resources/icons/media_play.png new file mode 100644 index 000000000..018ef78e9 Binary files /dev/null and b/Telegram/Resources/icons/media_play.png differ diff --git a/Telegram/Resources/icons/media_play@2x.png b/Telegram/Resources/icons/media_play@2x.png new file mode 100644 index 000000000..44805a939 Binary files /dev/null and b/Telegram/Resources/icons/media_play@2x.png differ diff --git a/Telegram/Resources/icons/media_volume.png b/Telegram/Resources/icons/media_volume.png new file mode 100644 index 000000000..1b64a994d Binary files /dev/null and b/Telegram/Resources/icons/media_volume.png differ diff --git a/Telegram/Resources/icons/media_volume@2x.png b/Telegram/Resources/icons/media_volume@2x.png new file mode 100644 index 000000000..91c9d6037 Binary files /dev/null and b/Telegram/Resources/icons/media_volume@2x.png differ diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp index f26bbb6e3..62ba8e2d4 100644 --- a/Telegram/SourceFiles/application.cpp +++ b/Telegram/SourceFiles/application.cpp @@ -533,6 +533,12 @@ namespace Sandbox { } } + void removeEventFilter(QObject *filter) { + if (Application *a = application()) { + a->removeEventFilter(filter); + } + } + void execExternal(const QString &cmd) { DEBUG_LOG(("Application Info: executing external command '%1'").arg(cmd)); if (cmd == "show") { diff --git a/Telegram/SourceFiles/application.h b/Telegram/SourceFiles/application.h index 4b6023131..78983d070 100644 --- a/Telegram/SourceFiles/application.h +++ b/Telegram/SourceFiles/application.h @@ -114,6 +114,7 @@ namespace Sandbox { bool isSavingSession(); void installEventFilter(QObject *filter); + void removeEventFilter(QObject *filter); void execExternal(const QString &cmd); diff --git a/Telegram/SourceFiles/codegen/style/generator.cpp b/Telegram/SourceFiles/codegen/style/generator.cpp index 84aa5e57e..286cd7cfc 100644 --- a/Telegram/SourceFiles/codegen/style/generator.cpp +++ b/Telegram/SourceFiles/codegen/style/generator.cpp @@ -327,8 +327,11 @@ bool Generator::writeHeaderStyleNamespace() { header_->stream() << "void init_" << baseName_ << "();\n\n"; header_->popNamespace(); } + bool wroteForwardDeclarations = writeStructsForwardDeclarations(); if (module_.hasStructs()) { - header_->newline(); + if (!wroteForwardDeclarations) { + header_->newline(); + } if (!writeStructsDefinitions()) { return false; } @@ -338,6 +341,32 @@ bool Generator::writeHeaderStyleNamespace() { return true; } +bool Generator::writeStructsForwardDeclarations() { + bool hasNoExternalStructs = module_.enumVariables([this](const Variable &value) -> bool { + if (value.value.type().tag == structure::TypeTag::Struct) { + if (!module_.findStructInModule(value.value.type().name, module_)) { + return false; + } + } + return true; + }); + if (hasNoExternalStructs) { + return false; + } + + header_->newline(); + bool result = module_.enumVariables([this](const Variable &value) -> bool { + if (value.value.type().tag == structure::TypeTag::Struct) { + if (!module_.findStructInModule(value.value.type().name, module_)) { + header_->stream() << "struct " << value.value.type().name.back() << ";\n"; + } + } + return true; + }); + header_->newline(); + return result; +} + bool Generator::writeStructsDefinitions() { if (!module_.hasStructs()) { return true; diff --git a/Telegram/SourceFiles/codegen/style/generator.h b/Telegram/SourceFiles/codegen/style/generator.h index 0c5bf2151..4d7319dae 100644 --- a/Telegram/SourceFiles/codegen/style/generator.h +++ b/Telegram/SourceFiles/codegen/style/generator.h @@ -47,6 +47,7 @@ private: QString valueAssignmentCode(structure::Value value) const; bool writeHeaderStyleNamespace(); + bool writeStructsForwardDeclarations(); bool writeStructsDefinitions(); bool writeRefsDeclarations(); diff --git a/Telegram/SourceFiles/codegen/style/module.h b/Telegram/SourceFiles/codegen/style/module.h index f8a043286..3c2df33ca 100644 --- a/Telegram/SourceFiles/codegen/style/module.h +++ b/Telegram/SourceFiles/codegen/style/module.h @@ -94,6 +94,9 @@ public: return !fullpath_.isEmpty(); } + const Struct *findStructInModule(const FullName &name, const Module &module) const; + const Variable *findVariableInModule(const FullName &name, const Module &module) const; + private: QString fullpath_; std::vector> included_; @@ -102,9 +105,6 @@ private: QMap structsByName_; QMap variablesByName_; - const Struct *findStructInModule(const FullName &name, const Module &module) const; - const Variable *findVariableInModule(const FullName &name, const Module &module) const; - }; } // namespace structure diff --git a/Telegram/SourceFiles/media/view/media_clip_controller.cpp b/Telegram/SourceFiles/media/view/media_clip_controller.cpp new file mode 100644 index 000000000..f784e7e62 --- /dev/null +++ b/Telegram/SourceFiles/media/view/media_clip_controller.cpp @@ -0,0 +1,116 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#include "stdafx.h" +#include "media/view/media_clip_controller.h" + +#include "media/view/media_clip_playback.h" +#include "media/view/media_clip_volume_controller.h" +#include "styles/style_mediaview.h" +#include "ui/widgets/label_simple.h" +#include "ui/effects/fade_animation.h" +#include "ui/buttons/icon_button.h" +#include "media/media_audio.h" + +namespace Media { +namespace Clip { + +Controller::Controller(QWidget *parent) : TWidget(parent) +, _playPauseResume(this, st::mediaviewPlayButton) +, _playback(this) +, _volumeController(this) +, _fullScreenToggle(this, st::mediaviewFullScreenButton) +, _playedAlready(this, st::mediaviewPlayProgressLabel) +, _toPlayLeft(this, st::mediaviewPlayProgressLabel) +, _fadeAnimation(std_::make_unique(this)) { + _fadeAnimation->show(); + connect(_playPauseResume, SIGNAL(clicked()), this, SIGNAL(playPressed())); + connect(_fullScreenToggle, SIGNAL(clicked()), this, SIGNAL(toFullScreenPressed())); + connect(_playback, SIGNAL(seekProgress(int64)), this, SLOT(onSeekProgress(int64))); + connect(_playback, SIGNAL(seekFinished(int64)), this, SLOT(onSeekFinished(int64))); + connect(_volumeController, SIGNAL(volumeChanged(float64)), this, SIGNAL(volumeChanged(float64))); +} + +void Controller::onSeekProgress(int64 position) { + _seekPosition = position; + emit seekProgress(position); +} + +void Controller::onSeekFinished(int64 position) { + _seekPosition = -1; + emit seekFinished(position); +} + +void Controller::showAnimated() { + _fadeAnimation->fadeIn(st::mvShowDuration); +} + +void Controller::hideAnimated() { + _fadeAnimation->fadeOut(st::mvHideDuration); +} + +void Controller::updatePlayback(const AudioPlaybackState &playbackState) { + bool showPause = (playbackState.state == AudioPlayerPlaying || playbackState.state == AudioPlayerResuming); + if (showPause != _showPause) { + disconnect(_playPauseResume, SIGNAL(clicked()), this, _showPause ? SIGNAL(pausePressed()) : SIGNAL(playPressed())); + _showPause = showPause; + connect(_playPauseResume, SIGNAL(clicked()), this, _showPause ? SIGNAL(pausePressed()) : SIGNAL(playPressed())); + + _playPauseResume->setIcon(_showPause ? &st::mediaviewPauseIcon : nullptr); + } + + _playback->updateState(playbackState); +} + +void Controller::setInFullScreen(bool inFullScreen) { + _fullScreenToggle->setIcon(inFullScreen ? &st::mediaviewFullScreenOutIcon : nullptr); + disconnect(_fullScreenToggle, SIGNAL(clicked()), this, SIGNAL(toFullScreenPressed())); + disconnect(_fullScreenToggle, SIGNAL(clicked()), this, SIGNAL(fromFullScreenPressed())); + + auto handler = inFullScreen ? SIGNAL(fromFullScreenPressed()) : SIGNAL(toFullScreenPressed()); + connect(_fullScreenToggle, SIGNAL(clicked()), this, handler); +} + +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); +} + +void Controller::paintEvent(QPaintEvent *e) { + Painter p(this); + + if (_fadeAnimation->paint(p)) { + return; + } + + App::roundRect(p, rect(), st::medviewSaveMsg, MediaviewSaveCorners); +} + +} // namespace Clip +} // namespace Media diff --git a/Telegram/SourceFiles/media/view/media_clip_controller.h b/Telegram/SourceFiles/media/view/media_clip_controller.h new file mode 100644 index 000000000..13bf40dd8 --- /dev/null +++ b/Telegram/SourceFiles/media/view/media_clip_controller.h @@ -0,0 +1,82 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#pragma once + +namespace Ui { +class LabelSimple; +class FadeAnimation; +class IconButton; +} // namespace Ui + +struct AudioPlaybackState; + +namespace Media { +namespace Clip { + +class Playback; +class VolumeController; + +class Controller : public TWidget { + Q_OBJECT + +public: + Controller(QWidget *parent); + + void showAnimated(); + void hideAnimated(); + + void updatePlayback(const AudioPlaybackState &playbackState); + void setInFullScreen(bool inFullScreen); + +signals: + void playPressed(); + void pausePressed(); + void seekProgress(int64 position); + void seekFinished(int64 position); + void volumeChanged(float64 volume); + void toFullScreenPressed(); + void fromFullScreenPressed(); + +private slots: + void onSeekProgress(int64 position); + void onSeekFinished(int64 position); + +protected: + void resizeEvent(QResizeEvent *e) override; + void paintEvent(QPaintEvent *e) override; + +private: + bool _showPause = false; + int64 _seekPosition = -1; + + ChildWidget _playPauseResume; + ChildWidget _playback; + ChildWidget _volumeController; + ChildWidget _fullScreenToggle; + ChildWidget _playedAlready; + ChildWidget _toPlayLeft; + + std_::unique_ptr _fadeAnimation; + +}; + +} // namespace Clip +} // namespace Media diff --git a/Telegram/SourceFiles/media/view/media_clip_playback.cpp b/Telegram/SourceFiles/media/view/media_clip_playback.cpp new file mode 100644 index 000000000..a80b9b554 --- /dev/null +++ b/Telegram/SourceFiles/media/view/media_clip_playback.cpp @@ -0,0 +1,131 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#include "stdafx.h" +#include "media/view/media_clip_playback.h" + +#include "styles/style_mediaview.h" +#include "media/media_audio.h" + +namespace Media { +namespace Clip { + +Playback::Playback(QWidget *parent) : TWidget(parent) +, _a_progress(animation(this, &Playback::step_progress)) { + setCursor(style::cur_pointer); +} + +void Playback::updateState(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; + } + + float64 progress = 0.; + if (duration) { + progress = duration ? snap(float64(position) / duration, 0., 1.) : 0.; + } + if (duration != _duration || position != _position) { + if (duration && _duration) { + a_progress.start(progress); + _a_progress.start(); + } else { + a_progress = anim::fvalue(progress, progress); + _a_progress.stop(); + } + _position = position; + _duration = duration; + } +} + +void Playback::step_progress(float64 ms, bool timer) { + float64 dt = ms / (2 * AudioVoiceMsgUpdateView); + if (_duration && dt >= 1) { + _a_progress.stop(); + a_progress.finish(); + } else { + a_progress.update(qMin(dt, 1.), anim::linear); + } + if (timer) update(); +} + +void Playback::paintEvent(QPaintEvent *e) { + Painter p(this); + + int radius = st::mediaviewPlaybackWidth / 2; + p.setPen(Qt::NoPen); + p.setRenderHint(QPainter::HighQualityAntialiasing); + + auto over = _a_over.current(getms(), _over ? 1. : 0.); + int skip = (st::mediaviewSeekSize.width() / 2); + int length = (width() - st::mediaviewSeekSize.width()); + float64 prg = _mouseDown ? _downProgress : a_progress.current(); + 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.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.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.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); +} + +void Playback::mouseMoveEvent(QMouseEvent *e) { +} + +void Playback::mousePressEvent(QMouseEvent *e) { +} + +void Playback::mouseReleaseEvent(QMouseEvent *e) { +} + +void Playback::enterEvent(QEvent *e) { + setOver(true); +} + +void Playback::leaveEvent(QEvent *e) { + setOver(false); +} + +void Playback::setOver(bool over) { + if (_over == over) return; + + _over = over; + auto from = _over ? 0. : 1., to = _over ? 1. : 0.; + START_ANIMATION(_a_over, func(this, &Playback::updateCallback), from, to, st::mediaviewOverDuration, anim::linear); +} + +} // namespace Clip +} // namespace Media diff --git a/Telegram/SourceFiles/media/view/media_clip_playback.h b/Telegram/SourceFiles/media/view/media_clip_playback.h new file mode 100644 index 000000000..d362d770e --- /dev/null +++ b/Telegram/SourceFiles/media/view/media_clip_playback.h @@ -0,0 +1,69 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#pragma once + +struct AudioPlaybackState; + +namespace Media { +namespace Clip { + +class Playback : public TWidget { + Q_OBJECT + +public: + Playback(QWidget *parent); + + void updateState(const AudioPlaybackState &playbackState); + +signals: + void seekProgress(int64 position); + void seekFinished(int64 position); + +protected: + void paintEvent(QPaintEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + void enterEvent(QEvent *e) override; + void leaveEvent(QEvent *e) override; + +private: + void step_progress(float64 ms, bool timer); + void updateCallback() { + update(); + } + void setOver(bool over); + + bool _over = false; + FloatAnimation _a_over; + + int64 _position = 0; + int64 _duration = 0; + anim::fvalue a_progress = { 0., 0. }; + Animation _a_progress; + + bool _mouseDown = false; + float64 _downProgress = 0.; + +}; + +} // namespace Clip +} // namespace Media diff --git a/Telegram/SourceFiles/media/view/media_clip_volume_controller.cpp b/Telegram/SourceFiles/media/view/media_clip_volume_controller.cpp new file mode 100644 index 000000000..57021db79 --- /dev/null +++ b/Telegram/SourceFiles/media/view/media_clip_volume_controller.cpp @@ -0,0 +1,85 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#include "stdafx.h" +#include "media/view/media_clip_volume_controller.h" + +#include "styles/style_mediaview.h" + +namespace Media { +namespace Clip { + +VolumeController::VolumeController(QWidget *parent) : TWidget(parent) { + resize(st::mediaviewVolumeSize); + setCursor(style::cur_pointer); +} + +void VolumeController::setVolume(float64 volume) { + _volume = volume; + update(); +} + +void VolumeController::paintEvent(QPaintEvent *e) { + Painter p(this); + + int32 top = (height() - st::mediaviewVolumeIcon.height()) / 2; + int32 left = (width() - st::mediaviewVolumeIcon.width()) / 2; + int32 mid = left + qRound(st::mediaviewVolumeIcon.width() * _volume); + int32 right = left + st::mediaviewVolumeIcon.width(); + + if (mid > left) { + auto over = _a_over.current(getms(), _over ? 1. : 0.); + p.setOpacity(over * st::mediaviewActiveOpacity + (1. - over) * st::mediaviewInactiveOpacity); + p.setClipRect(rtlrect(left, top, mid - left, st::mediaviewVolumeIcon.height(), width())); + st::mediaviewVolumeOnIcon.paint(p, QPoint(left, top), width()); + } + if (right > mid) { + p.setClipRect(rtlrect(mid, top, right - mid, st::mediaviewVolumeIcon.height(), width())); + st::mediaviewVolumeIcon.paint(p, QPoint(left, top), width()); + } +} + +void VolumeController::mouseMoveEvent(QMouseEvent *e) { +} + +void VolumeController::mousePressEvent(QMouseEvent *e) { +} + +void VolumeController::mouseReleaseEvent(QMouseEvent *e) { +} + +void VolumeController::enterEvent(QEvent *e) { + setOver(true); +} + +void VolumeController::leaveEvent(QEvent *e) { + setOver(false); +} + +void VolumeController::setOver(bool over) { + if (_over == over) return; + + _over = over; + auto from = _over ? 0. : 1., to = _over ? 1. : 0.; + START_ANIMATION(_a_over, func(this, &VolumeController::updateCallback), from, to, st::mediaviewOverDuration, anim::linear); +} + +} // namespace Clip +} // namespace Media diff --git a/Telegram/SourceFiles/media/view/media_clip_volume_controller.h b/Telegram/SourceFiles/media/view/media_clip_volume_controller.h new file mode 100644 index 000000000..6d891d321 --- /dev/null +++ b/Telegram/SourceFiles/media/view/media_clip_volume_controller.h @@ -0,0 +1,59 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#pragma once + +namespace Media { +namespace Clip { + +class VolumeController : public TWidget { + Q_OBJECT + +public: + VolumeController(QWidget *parent); + + void setVolume(float64 volume); + +signals: + void volumeChanged(float64 volume); + +protected: + void paintEvent(QPaintEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + void enterEvent(QEvent *e) override; + void leaveEvent(QEvent *e) override; + +private: + void updateCallback() { + update(); + } + void setOver(bool over); + + float64 _volume = 0.; + + bool _over = false; + FloatAnimation _a_over; + +}; + +} // namespace Clip +} // namespace Media diff --git a/Telegram/SourceFiles/media/view/mediaview.style b/Telegram/SourceFiles/media/view/mediaview.style new file mode 100644 index 000000000..7540b269b --- /dev/null +++ b/Telegram/SourceFiles/media/view/mediaview.style @@ -0,0 +1,74 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ + +using "basic.style"; +using "ui/widgets/widgets.style"; + +mediaviewActiveOpacity: 1.; +mediaviewInactiveOpacity: 0.78; +mediaviewOverDuration: 150; + +mediaviewControllerSize: size(600px, 50px); +mediaviewPlayProgressLabel: LabelSimple(defaultLabelSimple) { + textFg: #ffffffc7; +} +mediaviewPlayButton: IconButton { + width: 25px; + height: 24px; + + opacity: mediaviewInactiveOpacity; + overOpacity: mediaviewActiveOpacity; + + icon: icon { + { "media_play", #ffffff, point(0px, 0px) }, + }; + iconPosition: point(3px, 1px); + downIconPosition: point(3px, 1px); + + duration: mediaviewOverDuration; +} +mediaviewPauseIcon: icon { + { "media_pause", #ffffff, point(1px, 1px) } +}; + +mediaviewFullScreenButton: IconButton(mediaviewPlayButton) { + icon: icon { + { "media_fullscreen_to", #ffffff, point(0px, 0px) }, + }; + iconPosition: point(0px, 0px); + downIconPosition: point(0px, 0px); +} +mediaviewFullScreenOutIcon: icon { + { "media_fullscreen_from", #ffffff, point(0px, 0px) }, +}; + +mediaviewPlaybackActive: #ffffff; +mediaviewPlaybackInactive: #474747; +mediaviewPlaybackWidth: 3px; +mediaviewSeekSize: size(2px, 13px); + +mediaviewVolumeSize: size(44px, 12px); +mediaviewVolumeIcon: icon { + { "media_volume", mediaviewPlaybackInactive, point(0px, 0px) }, +}; +mediaviewVolumeOnIcon: icon { + { "media_volume", mediaviewPlaybackActive, point(0px, 0px) }, +}; diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index 834da50ce..4134d7503 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -27,6 +27,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "application.h" #include "ui/filedialog.h" #include "media/media_clip_reader.h" +#include "media/view/media_clip_controller.h" +#include "styles/style_mediaview.h" namespace { @@ -228,8 +230,9 @@ bool MediaView::gifShown() const { } void MediaView::stopGif() { - delete _gif; _gif = nullptr; + _clipController.destroy(); + Sandbox::removeEventFilter(this); } void MediaView::documentUpdated(DocumentData *doc) { @@ -364,6 +367,7 @@ void MediaView::updateControls() { } else { _leftNavVisible = _rightNavVisible = false; } + if (!_caption.isEmpty()) { int32 skipw = qMax(_dateNav.left() + _dateNav.width(), _headerNav.left() + _headerNav.width()); int32 maxw = qMin(qMax(width() - 2 * skipw - st::mvCaptionPadding.left() - st::mvCaptionPadding.right() - 2 * st::mvCaptionMargin.width(), int(st::msgMinWidth)), _caption.maxWidth()); @@ -372,6 +376,9 @@ void MediaView::updateControls() { } else { _captionRect = QRect(); } + if (_clipController) { + setClipControllerGeometry(); + } updateOver(mapFromGlobal(QCursor::pos())); update(); } @@ -519,7 +526,6 @@ void MediaView::clearData() { } MediaView::~MediaView() { - deleteAndMark(_gif); deleteAndMark(_menu); } @@ -551,6 +557,9 @@ void MediaView::activateControls() { a_cOpacity.start(1); if (!_a_state.animating()) _a_state.start(); } + if (_clipController) { + _clipController->showAnimated(); + } } void MediaView::onHideControls(bool force) { @@ -560,6 +569,9 @@ void MediaView::onHideControls(bool force) { _controlsAnimStarted = getms(); a_cOpacity.start(0); if (!_a_state.animating()) _a_state.start(); + if (_clipController) { + _clipController->hideAnimated(); + } } void MediaView::onDropdownHiding() { @@ -1072,24 +1084,11 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) { // empty } else { _doc->automaticLoad(item); - const FileLocation &location(_doc->location(true)); - if (!_doc->data().isEmpty() && (_doc->isAnimation() || _doc->isVideo())) { - if (!_gif) { - if (_doc->dimensions.width() && _doc->dimensions.height()) { - _current = _doc->thumb->pixNoCache(_doc->dimensions.width(), _doc->dimensions.height(), ImagePixSmooth | ImagePixBlurred, _doc->dimensions.width(), _doc->dimensions.height()); - } - _gif = new Media::Clip::Reader(location, _doc->data(), func(this, &MediaView::clipCallback)); - } - } else if (location.accessEnable()) { - if (_doc->isAnimation() || _doc->isVideo()) { - if (!_gif) { - if (_doc->dimensions.width() && _doc->dimensions.height()) { - _current = _doc->thumb->pixNoCache(_doc->dimensions.width(), _doc->dimensions.height(), ImagePixSmooth | ImagePixBlurred, _doc->dimensions.width(), _doc->dimensions.height()); - } - auto mode = _doc->isVideo() ? Media::Clip::Reader::Mode::Video : Media::Clip::Reader::Mode::Gif; - _gif = new Media::Clip::Reader(location, _doc->data(), func(this, &MediaView::clipCallback), mode); - } - } else { + if (_doc->isAnimation() || _doc->isVideo()) { + initAnimation(); + } else { + const FileLocation &location(_doc->location(true)); + if (location.accessEnable()) { if (QImageReader(location.name()).canRead()) { _current = QPixmap::fromImage(App::readImage(location.name(), 0, false), Qt::ColorOnly); } @@ -1202,6 +1201,94 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) { // empty } } +void MediaView::initAnimation() { + t_assert(_doc != nullptr); + t_assert(_doc->isAnimation() || _doc->isVideo()); + + auto &location = _doc->location(true); + if (!_doc->data().isEmpty()) { + createClipReader(); + } else if (location.accessEnable()) { + createClipReader(); + location.accessDisable(); + } +} + +void MediaView::createClipReader() { + if (_gif) return; + + t_assert(_doc != nullptr); + t_assert(_doc->isAnimation() || _doc->isVideo()); + + if (_doc->dimensions.width() && _doc->dimensions.height()) { + _current = _doc->thumb->pixNoCache(_doc->dimensions.width(), _doc->dimensions.height(), ImagePixSmooth | ImagePixBlurred, _doc->dimensions.width(), _doc->dimensions.height()); + } + auto mode = _doc->isVideo() ? Media::Clip::Reader::Mode::Video : Media::Clip::Reader::Mode::Gif; + _gif = std_::make_unique(_doc->location(), _doc->data(), func(this, &MediaView::clipCallback), mode); + + createClipController(); +} + +void MediaView::createClipController() { + if (!_doc->isVideo()) return; + + _clipController.destroy(); + _clipController = new Media::Clip::Controller(this); + setClipControllerGeometry(); + _clipController->show(); + + connect(_clipController, SIGNAL(playPressed()), this, SLOT(onVideoPlay())); + connect(_clipController, SIGNAL(pausePressed()), this, SLOT(onVideoPause())); + connect(_clipController, SIGNAL(seekProgress(int64)), this, SLOT(onVideoSeekProgress(int64))); + connect(_clipController, SIGNAL(seekFinished(int64)), this, SLOT(onVideoSeekFinished(int64))); + connect(_clipController, SIGNAL(volumeChanged(float64)), this, SLOT(onVideoVolumeChanged(float64))); + connect(_clipController, SIGNAL(toFullScreenPressed()), this, SLOT(onVideoToFullScreen())); + connect(_clipController, SIGNAL(fromFullScreenPressed()), this, SLOT(onVideoFromFullScreen())); + + Sandbox::removeEventFilter(this); + Sandbox::installEventFilter(this); +} + +void MediaView::setClipControllerGeometry() { + t_assert(_clipController != nullptr); + + int controllerBottom = _captionRect.isEmpty() ? height() : _captionRect.y(); + _clipController->setGeometry( + (width() - _clipController->width()) / 2, + controllerBottom - _clipController->height() - st::mvCaptionPadding.bottom() - st::mvCaptionMargin.height(), + st::mediaviewControllerSize.width(), + st::mediaviewControllerSize.height()); + myEnsureResized(_clipController); +} + +void MediaView::onVideoPlay() { + +} + +void MediaView::onVideoPause() { + +} + +void MediaView::onVideoSeekProgress(int64 position) { + +} + +void MediaView::onVideoSeekFinished(int64 position) { + +} + +void MediaView::onVideoVolumeChanged(float64 volume) { + +} + +void MediaView::onVideoToFullScreen() { + +} + +void MediaView::onVideoFromFullScreen() { + +} + void MediaView::paintEvent(QPaintEvent *e) { QRect r(e->rect()); QRegion region(e->region()); @@ -1833,9 +1920,6 @@ void MediaView::snapXY() { } void MediaView::mouseMoveEvent(QMouseEvent *e) { - bool moved = (e->pos() != _lastMouseMovePos); - _lastMouseMovePos = e->pos(); - updateOver(e->pos()); if (_lastAction.x() >= 0 && (e->pos() - _lastAction).manhattanLength() >= st::mvDeltaFromLastAction) { _lastAction = QPoint(-st::mvDeltaFromLastAction, -st::mvDeltaFromLastAction); @@ -1858,7 +1942,6 @@ void MediaView::mouseMoveEvent(QMouseEvent *e) { update(); } } - if (moved) activateControls(); } void MediaView::updateOverRect(OverState state) { @@ -2105,6 +2188,18 @@ bool MediaView::event(QEvent *e) { return QWidget::event(e); } +bool MediaView::eventFilter(QObject *obj, QEvent *e) { + if (e->type() == QEvent::MouseMove && obj->isWidgetType()) { + if (isAncestorOf(static_cast(obj))) { + auto mousePosition = mapFromGlobal(static_cast(e)->globalPos()); + bool moved = (mousePosition != _lastMouseMovePos); + _lastMouseMovePos = mousePosition; + if (moved) activateControls(); + } + } + return TWidget::eventFilter(obj, e); +} + void MediaView::hide() { _controlsHideTimer.stop(); _controlsState = ControlsShown; diff --git a/Telegram/SourceFiles/mediaview.h b/Telegram/SourceFiles/mediaview.h index 34c94617d..03ff51eb7 100644 --- a/Telegram/SourceFiles/mediaview.h +++ b/Telegram/SourceFiles/mediaview.h @@ -22,23 +22,18 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "dropdown.h" +namespace Media { +namespace Clip { +class Controller; +} // namespace Clip +} // namespace Media + class MediaView : public TWidget, public RPCSender, public ClickHandlerHost { Q_OBJECT public: MediaView(); - void paintEvent(QPaintEvent *e) override; - - void keyPressEvent(QKeyEvent *e) override; - void mousePressEvent(QMouseEvent *e) override; - void mouseMoveEvent(QMouseEvent *e) override; - void mouseReleaseEvent(QMouseEvent *e) override; - void contextMenuEvent(QContextMenuEvent *e) override; - void touchEvent(QTouchEvent *e); - - bool event(QEvent *e) override; - void hide(); void updateOver(QPoint mpos); @@ -106,12 +101,40 @@ public slots: void updateImage(); +protected: + void paintEvent(QPaintEvent *e) override; + + void keyPressEvent(QKeyEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + void contextMenuEvent(QContextMenuEvent *e) override; + void touchEvent(QTouchEvent *e); + + bool event(QEvent *e) override; + bool eventFilter(QObject *obj, QEvent *e) override; + +private slots: + void onVideoPlay(); + void onVideoPause(); + void onVideoSeekProgress(int64 position); + void onVideoSeekFinished(int64 position); + void onVideoVolumeChanged(float64 volume); + void onVideoToFullScreen(); + void onVideoFromFullScreen(); + private: void displayPhoto(PhotoData *photo, HistoryItem *item); void displayDocument(DocumentData *doc, HistoryItem *item); void findCurrent(); void loadBack(); + void createClipController(); + void setClipControllerGeometry(); + + void initAnimation(); + void createClipReader(); + // Radial animation interface. float64 radialProgress() const; bool radialLoading() const; @@ -154,6 +177,8 @@ private: QString _dateText; QString _headerText; + ChildWidget _clipController = { nullptr }; + Text _caption; QRect _captionRect; @@ -168,7 +193,7 @@ private: bool _pressed = false; int32 _dragging = 0; QPixmap _current; - Media::Clip::Reader *_gif = nullptr; + std_::unique_ptr _gif; int32 _full = -1; // -1 - thumb, 0 - medium, 1 - full bool fileShown() const; diff --git a/Telegram/SourceFiles/ui/animation.h b/Telegram/SourceFiles/ui/animation.h index 3482ef0e9..8fc5201cf 100644 --- a/Telegram/SourceFiles/ui/animation.h +++ b/Telegram/SourceFiles/ui/animation.h @@ -486,7 +486,6 @@ using FloatAnimation = SimpleAnimation; using IntAnimation = SimpleAnimation; using ColorAnimation = SimpleAnimation; - // Macro allows us to lazily create updateCallback. #define ENSURE_ANIMATION(animation, updateCallback, from) \ if ((animation).isNull()) { \ diff --git a/Telegram/SourceFiles/ui/buttons/icon_button.cpp b/Telegram/SourceFiles/ui/buttons/icon_button.cpp new file mode 100644 index 000000000..43498c7cc --- /dev/null +++ b/Telegram/SourceFiles/ui/buttons/icon_button.cpp @@ -0,0 +1,56 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#include "stdafx.h" +#include "ui/buttons/icon_button.h" + +namespace Ui { + +IconButton::IconButton(QWidget *parent, const style::IconButton &st) : Button(parent) +, _st(st) { + resize(_st.width, _st.height); + setCursor(style::cur_pointer); +} + +void IconButton::setIcon(const style::icon *icon) { + _iconOverride = icon; + update(); +} + +void IconButton::paintEvent(QPaintEvent *e) { + Painter p(this); + + auto over = _a_over.current(getms(), (_state & StateOver) ? 1. : 0.); + p.setOpacity(over * _st.overOpacity + (1. - over) * _st.opacity); + + auto position = (_state & StateDown) ? _st.downIconPosition : _st.iconPosition; + (_iconOverride ? _iconOverride : &_st.icon)->paint(p, position, width()); +} + +void IconButton::onStateChanged(int oldState, ButtonStateChangeSource source) { + auto over = (_state & StateOver); + if (over != (oldState & StateOver)) { + auto from = over ? 0. : 1.; + auto to = over ? 1. : 0.; + START_ANIMATION(_a_over, func(this, &IconButton::updateCallback), from, to, _st.duration, anim::linear); + } +} + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/buttons/icon_button.h b/Telegram/SourceFiles/ui/buttons/icon_button.h new file mode 100644 index 000000000..758c59567 --- /dev/null +++ b/Telegram/SourceFiles/ui/buttons/icon_button.h @@ -0,0 +1,51 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include "ui/button.h" + +namespace Ui { + +class IconButton : public Button { +public: + IconButton(QWidget *parent, const style::IconButton &st); + + // Pass nullptr to restore the default icon. + void setIcon(const style::icon *icon); + +protected: + void paintEvent(QPaintEvent *e) override; + + void onStateChanged(int oldState, ButtonStateChangeSource source) override; + +private: + void updateCallback() { + update(); + } + + const style::IconButton &_st; + const style::icon *_iconOverride = nullptr; + + FloatAnimation _a_over; + +}; + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/effects/fade_animation.cpp b/Telegram/SourceFiles/ui/effects/fade_animation.cpp new file mode 100644 index 000000000..29da4c50d --- /dev/null +++ b/Telegram/SourceFiles/ui/effects/fade_animation.cpp @@ -0,0 +1,99 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#include "stdafx.h" +#include "ui/effects/fade_animation.h" + +namespace Ui { + +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::setFinishedCallback(FinishedCallback &&callback) { + _finishedCallback = std_::move(callback); +} + +void FadeAnimation::show() { + _visible = true; + stopAnimation(); +} + +void FadeAnimation::hide() { + _visible = false; + stopAnimation(); +} + +void FadeAnimation::stopAnimation() { + _animation.finish(); + if (!_cache.isNull()) { + _cache = QPixmap(); + updateCallback(); + _widget->showChildren(); + _finishedCallback.call(); + } + if (_visible == _widget->isHidden()) { + _widget->setVisible(_visible); + } +} + +void FadeAnimation::fadeIn(int duration) { + if (_visible) return; + + _visible = true; + startAnimation(duration); +} + +void FadeAnimation::fadeOut(int duration) { + if (!_visible) return; + + _visible = false; + startAnimation(duration); +} + +void FadeAnimation::startAnimation(int duration) { + if (_cache.isNull()) { + _cache = myGrab(_widget); + _widget->hideChildren(); + } + START_ANIMATION(_animation, func(this, &FadeAnimation::updateCallback), _visible ? 0. : 1., _visible ? 1. : 0., duration, anim::linear); + updateCallback(); + if (_widget->isHidden()) { + _widget->show(); + } +} + +void FadeAnimation::updateCallback() { + _widget->update(); +} + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/effects/fade_animation.h b/Telegram/SourceFiles/ui/effects/fade_animation.h new file mode 100644 index 000000000..cc5793bef --- /dev/null +++ b/Telegram/SourceFiles/ui/effects/fade_animation.h @@ -0,0 +1,57 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#pragma once + +class TWidget; + +namespace Ui { + +class FadeAnimation { +public: + FadeAnimation(TWidget *widget); + + bool paint(Painter &p); + + using FinishedCallback = Function; + void setFinishedCallback(FinishedCallback &&callback); + + void show(); + void hide(); + + void fadeIn(int duration); + void fadeOut(int duration); + +private: + void startAnimation(int duration); + void stopAnimation(); + + void updateCallback(); + + TWidget *_widget; + FloatAnimation _animation; + QPixmap _cache; + bool _visible = false; + + FinishedCallback _finishedCallback; + +}; + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/widgets/label_simple.cpp b/Telegram/SourceFiles/ui/widgets/label_simple.cpp new file mode 100644 index 000000000..13ae9eb4f --- /dev/null +++ b/Telegram/SourceFiles/ui/widgets/label_simple.cpp @@ -0,0 +1,52 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#include "stdafx.h" +#include "ui/widgets/label_simple.h" + +namespace Ui { + +LabelSimple::LabelSimple(QWidget *parent, const style::LabelSimple &st, const QString &value) : TWidget(parent) +, _st(st) { + setText(value); +} + +void LabelSimple::setText(const QString &value) { + _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); + _textWidth = _st.font->width(_text); + } + resize(_textWidth, _st.font->height); +} + +void LabelSimple::paintEvent(QPaintEvent *e) { + Painter p(this); + + p.setFont(_st.font); + p.setPen(_st.textFg); + p.drawTextLeft(0, 0, width(), _text, _textWidth); +} + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/widgets/label_simple.h b/Telegram/SourceFiles/ui/widgets/label_simple.h new file mode 100644 index 000000000..6317da344 --- /dev/null +++ b/Telegram/SourceFiles/ui/widgets/label_simple.h @@ -0,0 +1,48 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include "styles/style_widgets.h" + +namespace Ui { + +class LabelSimple : public TWidget { +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); + +protected: + void paintEvent(QPaintEvent *e) override; + +private: + QString _fullText; + int _fullTextWidth; + + QString _text; + int _textWidth; + + const style::LabelSimple &_st; + +}; + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/widgets/widgets.style b/Telegram/SourceFiles/ui/widgets/widgets.style new file mode 100644 index 000000000..9b9af8124 --- /dev/null +++ b/Telegram/SourceFiles/ui/widgets/widgets.style @@ -0,0 +1,34 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org +*/ + +using "basic.style"; + +LabelSimple { + font: font; + maxWidth: pixels; + textFg: color; +} + +defaultLabelSimple: LabelSimple { + font: normalFont; + maxWidth: 0px; + textFg: windowTextFg; +} diff --git a/Telegram/Telegram.vcxproj b/Telegram/Telegram.vcxproj index 42dc178c9..e060ac8f8 100644 --- a/Telegram/Telegram.vcxproj +++ b/Telegram/Telegram.vcxproj @@ -375,10 +375,22 @@ true true + + true + true + + + true + true + true true + + true + true + true true @@ -713,10 +725,22 @@ true true + + true + true + + + true + true + true true + + true + true + true true @@ -1082,10 +1106,22 @@ true true + + true + true + + + true + true + true true + + true + true + true true @@ -1211,8 +1247,10 @@ + + @@ -1282,6 +1320,9 @@ + + + @@ -1388,10 +1429,12 @@ + + @@ -1416,6 +1459,7 @@ + @@ -1491,8 +1535,10 @@ + + $(QTDIR)\bin\moc.exe;%(FullPath) @@ -1588,6 +1634,48 @@ + + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing media_clip_controller.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/media/view/media_clip_controller.h" -DAL_LIBTYPE_STATIC -DCUSTOM_API_ID -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing media_clip_controller.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/media/view/media_clip_controller.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl_debug\Debug\include" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing media_clip_controller.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/media/view/media_clip_controller.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include" + + + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing media_clip_playback.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/media/view/media_clip_playback.h" -DAL_LIBTYPE_STATIC -DCUSTOM_API_ID -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing media_clip_playback.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/media/view/media_clip_playback.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl_debug\Debug\include" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing media_clip_playback.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/media/view/media_clip_playback.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include" + + + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing media_clip_volume_controller.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/media/view/media_clip_volume_controller.h" -DAL_LIBTYPE_STATIC -DCUSTOM_API_ID -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing media_clip_volume_controller.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/media/view/media_clip_volume_controller.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl_debug\Debug\include" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing media_clip_volume_controller.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/media/view/media_clip_volume_controller.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include" + $(QTDIR)\bin\moc.exe;%(FullPath) @@ -1934,9 +2022,11 @@ "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include" "-fstdafx.h" "-f../../SourceFiles/ui/countryinput.h" + + @@ -2119,6 +2209,7 @@ "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/window/section_widget.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include" + @@ -2929,6 +3020,8 @@ true true + + Document "$(SolutionDir)$(Platform)\codegen\$(Configuration)\codegen_style.exe" "-I.\Resources" "-I.\SourceFiles" "-o.\GeneratedFiles\styles" %(FullPath) diff --git a/Telegram/Telegram.vcxproj.filters b/Telegram/Telegram.vcxproj.filters index 6993d85e1..247d35253 100644 --- a/Telegram/Telegram.vcxproj.filters +++ b/Telegram/Telegram.vcxproj.filters @@ -115,6 +115,15 @@ {a281888a-8b70-4e95-9b03-ebcb02837df4} + + {1937d8d7-6dd1-4147-8afb-6f03daff4f0e} + + + {59996402-fc66-481c-9a12-5619112c60a5} + + + {4fdf499d-a1be-46ce-9f17-af007a72e915} + @@ -1389,6 +1398,57 @@ SourceFiles\media + + SourceFiles\ui\widgets + + + GeneratedFiles\Deploy + + + GeneratedFiles\Debug + + + GeneratedFiles\Release + + + SourceFiles\media\view + + + GeneratedFiles\styles + + + GeneratedFiles\styles + + + SourceFiles\ui\effects + + + SourceFiles\ui\buttons + + + SourceFiles\media\view + + + GeneratedFiles\Deploy + + + SourceFiles\media\view + + + GeneratedFiles\Debug + + + GeneratedFiles\Release + + + GeneratedFiles\Deploy + + + GeneratedFiles\Debug + + + GeneratedFiles\Release + @@ -1658,6 +1718,18 @@ SourceFiles\media + + GeneratedFiles\styles + + + GeneratedFiles\styles + + + SourceFiles\ui\effects + + + SourceFiles\ui\buttons + @@ -1954,6 +2026,18 @@ SourceFiles\media + + SourceFiles\ui\widgets + + + SourceFiles\media\view + + + SourceFiles\media\view + + + SourceFiles\media\view + @@ -2035,6 +2119,12 @@ SourceFiles\profile + + SourceFiles\ui\widgets + + + SourceFiles\media\view +