Some more ripple animations. Now only anim::value (float64).

Also each FloatAnimation now stops MTP responses.
Also slide animations done by FloatAnimation.
Closed beta 10019012.
This commit is contained in:
John Preston 2016-12-05 14:01:08 +03:00
parent a248cef15d
commit 06ed7b8eaf
109 changed files with 2129 additions and 1796 deletions

View file

@ -475,17 +475,17 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_profile_shared_media" = "Shared media"; "lng_profile_shared_media" = "Shared media";
"lng_profile_no_media" = "No media in this conversation."; "lng_profile_no_media" = "No media in this conversation.";
"lng_profile_photos" = "{count:_not_used_|# photo|# photos}"; "lng_profile_photos" = "{count:_not_used_|# photo|# photos}";
"lng_profile_photos_header" = "Photos overview"; "lng_profile_photos_header" = "Photos";
"lng_profile_videos" = "{count:_not_used_|# video|# videos}"; "lng_profile_videos" = "{count:_not_used_|# video|# videos}";
"lng_profile_videos_header" = "Videos overview"; "lng_profile_videos_header" = "Videos";
"lng_profile_songs" = "{count:_not_used_|# audio file|# audio files}"; "lng_profile_songs" = "{count:_not_used_|# audio file|# audio files}";
"lng_profile_songs_header" = "Audio files overview"; "lng_profile_songs_header" = "Audio files";
"lng_profile_files" = "{count:_not_used_|# file|# files}"; "lng_profile_files" = "{count:_not_used_|# file|# files}";
"lng_profile_files_header" = "Files overview"; "lng_profile_files_header" = "Files";
"lng_profile_audios" = "{count:_not_used_|# voice message|# voice messages}"; "lng_profile_audios" = "{count:_not_used_|# voice message|# voice messages}";
"lng_profile_audios_header" = "Voice messages overview"; "lng_profile_audios_header" = "Voice messages";
"lng_profile_shared_links" = "{count:_not_used_|# shared link|# shared links}"; "lng_profile_shared_links" = "{count:_not_used_|# shared link|# shared links}";
"lng_profile_shared_links_header" = "Shared links overview"; "lng_profile_shared_links_header" = "Shared links";
"lng_profile_copy_phone" = "Copy Phone Number"; "lng_profile_copy_phone" = "Copy Phone Number";
"lng_profile_copy_fullname" = "Copy Name"; "lng_profile_copy_fullname" = "Copy Name";
"lng_profile_drop_area_title" = "Drop your image here"; "lng_profile_drop_area_title" = "Drop your image here";

View file

@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,10,19,11 FILEVERSION 0,10,19,12
PRODUCTVERSION 0,10,19,11 PRODUCTVERSION 0,10,19,12
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -51,10 +51,10 @@ BEGIN
BLOCK "040904b0" BLOCK "040904b0"
BEGIN BEGIN
VALUE "CompanyName", "Telegram Messenger LLP" VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileVersion", "0.10.19.11" VALUE "FileVersion", "0.10.19.12"
VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "LegalCopyright", "Copyright (C) 2014-2016"
VALUE "ProductName", "Telegram Desktop" VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "0.10.19.11" VALUE "ProductVersion", "0.10.19.12"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,10,19,11 FILEVERSION 0,10,19,12
PRODUCTVERSION 0,10,19,11 PRODUCTVERSION 0,10,19,12
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -43,10 +43,10 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Telegram Messenger LLP" VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileDescription", "Telegram Updater" VALUE "FileDescription", "Telegram Updater"
VALUE "FileVersion", "0.10.19.11" VALUE "FileVersion", "0.10.19.12"
VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "LegalCopyright", "Copyright (C) 2014-2016"
VALUE "ProductName", "Telegram Desktop" VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "0.10.19.11" VALUE "ProductVersion", "0.10.19.12"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -1246,7 +1246,7 @@ namespace {
if (auto history = App::historyLoaded(peer)) { if (auto history = App::historyLoaded(peer)) {
history->outboxRead(upTo); history->outboxRead(upTo);
if (history->lastMsg && history->lastMsg->out() && history->lastMsg->id <= upTo) { if (history->lastMsg && history->lastMsg->out() && history->lastMsg->id <= upTo) {
if (App::main()) App::main()->dlgUpdated(history, history->lastMsg->id); if (App::main()) App::main()->dlgUpdated(history->peer, history->lastMsg->id);
} }
history->updateChatListEntry(); history->updateChatListEntry();

View file

@ -711,8 +711,6 @@ AppClass::AppClass() : QObject() {
cChangeTimeFormat(QLocale::system().timeFormat(QLocale::ShortFormat)); cChangeTimeFormat(QLocale::system().timeFormat(QLocale::ShortFormat));
connect(&_mtpUnpauseTimer, SIGNAL(timeout()), this, SLOT(doMtpUnpause()));
connect(&killDownloadSessionsTimer, SIGNAL(timeout()), this, SLOT(killDownloadSessions())); connect(&killDownloadSessionsTimer, SIGNAL(timeout()), this, SLOT(killDownloadSessions()));
DEBUG_LOG(("Application Info: starting app...")); DEBUG_LOG(("Application Info: starting app..."));
@ -832,19 +830,6 @@ void AppClass::cancelPhotoUpdate(const PeerId &peer) {
} }
} }
void AppClass::mtpPause() {
MTP::pause();
_mtpUnpauseTimer.start(st::slideDuration * 2);
}
void AppClass::mtpUnpause() {
_mtpUnpauseTimer.start(1);
}
void AppClass::doMtpUnpause() {
MTP::unpause();
}
void AppClass::selfPhotoCleared(const MTPUserProfilePhoto &result) { void AppClass::selfPhotoCleared(const MTPUserProfilePhoto &result) {
if (!App::self()) return; if (!App::self()) return;
App::self()->setPhoto(result); App::self()->setPhoto(result);

View file

@ -159,9 +159,6 @@ public:
bool isPhotoUpdating(const PeerId &peer); bool isPhotoUpdating(const PeerId &peer);
void cancelPhotoUpdate(const PeerId &peer); void cancelPhotoUpdate(const PeerId &peer);
void mtpPause();
void mtpUnpause();
void selfPhotoCleared(const MTPUserProfilePhoto &result); void selfPhotoCleared(const MTPUserProfilePhoto &result);
void chatPhotoCleared(PeerId peer, const MTPUpdates &updates); void chatPhotoCleared(PeerId peer, const MTPUpdates &updates);
void selfPhotoDone(const MTPphotos_Photo &result); void selfPhotoDone(const MTPphotos_Photo &result);
@ -185,9 +182,6 @@ signals:
void adjustSingleTimers(); void adjustSingleTimers();
public slots: public slots:
void doMtpUnpause();
void photoUpdated(const FullMsgId &msgId, bool silent, const MTPInputFile &file); void photoUpdated(const FullMsgId &msgId, bool silent, const MTPInputFile &file);
void onSwitchDebugMode(); void onSwitchDebugMode();
@ -217,6 +211,4 @@ private:
FileUploader *_uploader = nullptr; FileUploader *_uploader = nullptr;
Translator *_translator = nullptr; Translator *_translator = nullptr;
SingleTimer _mtpUnpauseTimer;
}; };

View file

@ -557,7 +557,7 @@ void SetupChannelBox::mousePressEvent(QMouseEvent *e) {
if (_linkOver) { if (_linkOver) {
Application::clipboard()->setText(_channel->inviteLink()); Application::clipboard()->setText(_channel->inviteLink());
_goodTextLink = lang(lng_create_channel_link_copied); _goodTextLink = lang(lng_create_channel_link_copied);
a_goodOpacity = anim::fvalue(1, 0); a_goodOpacity = anim::value(1, 0);
_a_goodFade.start(); _a_goodFade.start();
} }
} }

View file

@ -190,7 +190,7 @@ private:
QString _sentUsername, _checkUsername, _errorText, _goodText; QString _sentUsername, _checkUsername, _errorText, _goodText;
QString _goodTextLink; QString _goodTextLink;
anim::fvalue a_goodOpacity; anim::value a_goodOpacity;
Animation _a_goodFade; Animation _a_goodFade;
QTimer _checkTimer; QTimer _checkTimer;

View file

@ -332,6 +332,7 @@ contactsPhotoCheckbox: RoundImageCheckbox {
} }
contactsPhotoDisabledCheckFg: #bbbbbb; contactsPhotoDisabledCheckFg: #bbbbbb;
contactsNameCheckedFg: #2b88b8; contactsNameCheckedFg: #2b88b8;
contactsRipple: defaultRippleAnimation;
localStorageBoxSkip: 10px; localStorageBoxSkip: 10px;
@ -381,15 +382,21 @@ sessionWhenFont: msgDateFont;
sessionWhenFg: #aaaaaa; sessionWhenFg: #aaaaaa;
sessionInfoFont: msgFont; sessionInfoFont: msgFont;
sessionInfoFg: #888888; sessionInfoFg: #888888;
sessionTerminateTop: 30px; sessionTerminateTop: 28px;
sessionTerminateSkip: 18px; sessionTerminateSkip: 22px;
sessionTerminate: IconButton { sessionTerminate: IconButton {
width: 16px; width: 20px;
height: 16px; height: 20px;
icon: simpleCloseIcon; icon: simpleCloseIcon;
iconOver: simpleCloseIconOver; iconOver: simpleCloseIconOver;
iconPosition: point(3px, 3px); iconPosition: point(5px, 5px);
rippleAreaPosition: point(0px, 0px);
rippleAreaSize: 20px;
ripple: RippleAnimation(defaultRippleAnimation) {
color: windowBgOver;
}
} }
sessionTerminateAllButton: LinkButton(boxLinkButton) { sessionTerminateAllButton: LinkButton(boxLinkButton) {
color: #d15948; color: #d15948;

View file

@ -226,7 +226,7 @@ void MaxInviteBox::mousePressEvent(QMouseEvent *e) {
if (_linkOver) { if (_linkOver) {
Application::clipboard()->setText(_link); Application::clipboard()->setText(_link);
_goodTextLink = lang(lng_create_channel_link_copied); _goodTextLink = lang(lng_create_channel_link_copied);
a_goodOpacity = anim::fvalue(1, 0); a_goodOpacity = anim::value(1, 0);
_a_good.start(); _a_good.start();
} }
} }

View file

@ -178,7 +178,7 @@ private:
QPoint _lastMousePos; QPoint _lastMousePos;
QString _goodTextLink; QString _goodTextLink;
anim::fvalue a_goodOpacity; anim::value a_goodOpacity;
Animation _a_good; Animation _a_good;
}; };

View file

@ -37,6 +37,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "ui/widgets/multi_select.h" #include "ui/widgets/multi_select.h"
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
#include "ui/effects/widget_slide_wrap.h" #include "ui/effects/widget_slide_wrap.h"
#include "ui/effects/ripple_animation.h"
#include "boxes/photocropbox.h" #include "boxes/photocropbox.h"
#include "boxes/confirmbox.h" #include "boxes/confirmbox.h"
#include "observer_peer.h" #include "observer_peer.h"
@ -546,10 +547,14 @@ bool ContactsBox::creationFail(const RPCError &error) {
return false; return false;
} }
ContactsBox::Inner::ContactData::ContactData() = default;
ContactsBox::Inner::ContactData::ContactData(PeerData *peer, const base::lambda_copy<void()> &updateCallback) ContactsBox::Inner::ContactData::ContactData(PeerData *peer, const base::lambda_copy<void()> &updateCallback)
: checkbox(std_::make_unique<Ui::RoundImageCheckbox>(st::contactsPhotoCheckbox, updateCallback, PaintUserpicCallback(peer))) { : checkbox(std_::make_unique<Ui::RoundImageCheckbox>(st::contactsPhotoCheckbox, updateCallback, PaintUserpicCallback(peer))) {
} }
ContactsBox::Inner::ContactData::~ContactData() = default;
ContactsBox::Inner::Inner(QWidget *parent, CreatingGroupType creating) : TWidget(parent) ContactsBox::Inner::Inner(QWidget *parent, CreatingGroupType creating) : TWidget(parent)
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom()) , _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
, _creating(creating) , _creating(creating)
@ -924,16 +929,16 @@ ContactsBox::Inner::ContactData *ContactsBox::Inner::contactData(Dialogs::Row *r
return data; return data;
} }
void ContactsBox::Inner::paintDialog(Painter &p, TimeMs ms, PeerData *peer, ContactData *data, bool sel) { void ContactsBox::Inner::paintDialog(Painter &p, TimeMs ms, PeerData *peer, ContactData *data, bool selected) {
UserData *user = peer->asUser(); auto user = peer->asUser();
if (_chat && _membersFilter == MembersFilter::Admins) { if (_chat && _membersFilter == MembersFilter::Admins) {
if (_allAdmins->checked() || peer->id == peerFromUser(_chat->creator) || _saving) { if (_allAdmins->checked() || peer->id == peerFromUser(_chat->creator) || _saving) {
sel = false; selected = false;
} }
} else { } else {
if (data->disabledChecked || selectedCount() >= Global::MegagroupSizeMax()) { if (data->disabledChecked || selectedCount() >= Global::MegagroupSizeMax()) {
sel = false; selected = false;
} }
} }
@ -945,7 +950,13 @@ void ContactsBox::Inner::paintDialog(Painter &p, TimeMs ms, PeerData *peer, Cont
} }
auto checkedRatio = 0.; auto checkedRatio = 0.;
p.fillRect(0, 0, width(), _rowHeight, sel ? st::contactsBgOver : st::contactsBg); p.fillRect(0, 0, width(), _rowHeight, selected ? st::contactsBgOver : st::contactsBg);
if (data->ripple) {
data->ripple->paint(p, 0, 0, width(), ms);
if (data->ripple->empty()) {
data->ripple.reset();
}
}
if (paintDisabledCheck) { if (paintDisabledCheck) {
paintDisabledCheckUserpic(p, peer, st::contactsPadding.left(), st::contactsPadding.top(), width()); paintDisabledCheckUserpic(p, peer, st::contactsPadding.left(), st::contactsPadding.top(), width());
} else if (usingMultiSelect()) { } else if (usingMultiSelect()) {
@ -979,14 +990,14 @@ void ContactsBox::Inner::paintDialog(Painter &p, TimeMs ms, PeerData *peer, Cont
int32 secondw = st::contactsStatusFont->width(second); int32 secondw = st::contactsStatusFont->width(second);
p.setPen(st::contactsStatusFgOnline); p.setPen(st::contactsStatusFgOnline);
p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width() - secondw, first); p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width() - secondw, first);
p.setPen(sel ? st::contactsStatusFgOver : st::contactsStatusFg); p.setPen(selected ? st::contactsStatusFgOver : st::contactsStatusFg);
p.drawTextLeft(namex + w, st::contactsPadding.top() + st::contactsStatusTop, width() + w, second); p.drawTextLeft(namex + w, st::contactsPadding.top() + st::contactsStatusTop, width() + w, second);
} }
} else { } else {
if ((user && (uname || data->statusHasOnlineColor)) || (peer->isChannel() && uname)) { if ((user && (uname || data->statusHasOnlineColor)) || (peer->isChannel() && uname)) {
p.setPen(st::contactsStatusFgOnline); p.setPen(st::contactsStatusFgOnline);
} else { } else {
p.setPen(sel ? st::contactsStatusFgOver : st::contactsStatusFg); p.setPen(selected ? st::contactsStatusFgOver : st::contactsStatusFg);
} }
p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width(), data->statusText); p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width(), data->statusText);
} }
@ -1064,7 +1075,8 @@ void ContactsBox::Inner::paintEvent(QPaintEvent *e) {
if ((*i)->pos() * _rowHeight >= yTo) { if ((*i)->pos() * _rowHeight >= yTo) {
break; break;
} }
paintDialog(p, ms, (*i)->history()->peer, contactData(*i), (*i == _sel)); auto selected = _pressed ? (*i == _pressed) : (*i == _selected);
paintDialog(p, ms, (*i)->history()->peer, contactData(*i), selected);
p.translate(0, _rowHeight); p.translate(0, _rowHeight);
} }
yFrom -= _contacts->size() * _rowHeight; yFrom -= _contacts->size() * _rowHeight;
@ -1080,11 +1092,12 @@ void ContactsBox::Inner::paintEvent(QPaintEvent *e) {
yTo -= st::searchedBarHeight; yTo -= st::searchedBarHeight;
p.translate(0, st::searchedBarHeight); p.translate(0, st::searchedBarHeight);
int32 from = floorclamp(yFrom, _rowHeight, 0, _byUsername.size()); auto from = floorclamp(yFrom, _rowHeight, 0, _byUsername.size());
int32 to = ceilclamp(yTo, _rowHeight, 0, _byUsername.size()); auto to = ceilclamp(yTo, _rowHeight, 0, _byUsername.size());
p.translate(0, from * _rowHeight); p.translate(0, from * _rowHeight);
for (; from < to; ++from) { for (; from < to; ++from) {
paintDialog(p, ms, _byUsername[from], d_byUsername[from], (_byUsernameSel == from)); auto selected = (_searchedPressed >= 0) ? (_searchedPressed == from) : (_searchedSelected == from);
paintDialog(p, ms, _byUsername[from], d_byUsername[from], selected);
p.translate(0, _rowHeight); p.translate(0, _rowHeight);
} }
} }
@ -1130,7 +1143,8 @@ void ContactsBox::Inner::paintEvent(QPaintEvent *e) {
int32 to = ceilclamp(yTo, _rowHeight, 0, _filtered.size()); int32 to = ceilclamp(yTo, _rowHeight, 0, _filtered.size());
p.translate(0, from * _rowHeight); p.translate(0, from * _rowHeight);
for (; from < to; ++from) { for (; from < to; ++from) {
paintDialog(p, ms, _filtered[from]->history()->peer, contactData(_filtered[from]), (_filteredSel == from)); auto selected = (_filteredPressed >= 0) ? (_filteredPressed == from) : (_filteredSelected == from);
paintDialog(p, ms, _filtered[from]->history()->peer, contactData(_filtered[from]), selected);
p.translate(0, _rowHeight); p.translate(0, _rowHeight);
} }
} }
@ -1147,7 +1161,8 @@ void ContactsBox::Inner::paintEvent(QPaintEvent *e) {
int32 to = ceilclamp(yTo, _rowHeight, 0, _byUsernameFiltered.size()); int32 to = ceilclamp(yTo, _rowHeight, 0, _byUsernameFiltered.size());
p.translate(0, from * _rowHeight); p.translate(0, from * _rowHeight);
for (; from < to; ++from) { for (; from < to; ++from) {
paintDialog(p, ms, _byUsernameFiltered[from], d_byUsernameFiltered[from], (_byUsernameSel == from)); auto selected = (_searchedPressed >= 0) ? (_searchedPressed == from) : (_searchedSelected == from);
paintDialog(p, ms, _byUsernameFiltered[from], d_byUsernameFiltered[from], selected);
p.translate(0, _rowHeight); p.translate(0, _rowHeight);
} }
} }
@ -1161,16 +1176,16 @@ void ContactsBox::Inner::enterEvent(QEvent *e) {
int ContactsBox::Inner::getSelectedRowTop() const { int ContactsBox::Inner::getSelectedRowTop() const {
if (_filter.isEmpty()) { if (_filter.isEmpty()) {
if (_sel) { if (_selected) {
return _aboutHeight + (_sel->pos() * _rowHeight); return _aboutHeight + (_selected->pos() * _rowHeight);
} else if (_byUsernameSel >= 0) { } else if (_searchedSelected >= 0) {
return _aboutHeight + (_contacts->size() * _rowHeight) + st::searchedBarHeight + (_byUsernameSel * _rowHeight); return _aboutHeight + (_contacts->size() * _rowHeight) + st::searchedBarHeight + (_searchedSelected * _rowHeight);
} }
} else { } else {
if (_filteredSel >= 0) { if (_filteredSelected >= 0) {
return (_filteredSel * _rowHeight); return (_filteredSelected * _rowHeight);
} else if (_byUsernameSel >= 0) { } else if (_searchedSelected >= 0) {
return (_filtered.size() * _rowHeight + st::searchedBarHeight + _byUsernameSel * _rowHeight); return (_filtered.size() * _rowHeight + st::searchedBarHeight + _searchedSelected * _rowHeight);
} }
} }
return -1; return -1;
@ -1222,53 +1237,130 @@ void ContactsBox::Inner::updateRowWithPeer(PeerData *peer) {
} }
void ContactsBox::Inner::leaveEvent(QEvent *e) { void ContactsBox::Inner::leaveEvent(QEvent *e) {
_mouseSel = false; _mouseSelection = false;
setMouseTracking(false); setMouseTracking(false);
if (_sel || _filteredSel >= 0 || _byUsernameSel >= 0) { if (_selected || _filteredSelected >= 0 || _searchedSelected >= 0) {
updateSelectedRow(); updateSelectedRow();
_sel = 0; _selected = nullptr;
_filteredSel = _byUsernameSel = -1; _filteredSelected = _searchedSelected = -1;
} }
} }
void ContactsBox::Inner::mouseMoveEvent(QMouseEvent *e) { void ContactsBox::Inner::mouseMoveEvent(QMouseEvent *e) {
_mouseSel = true; _mouseSelection = true;
_lastMousePos = e->globalPos(); _lastMousePos = e->globalPos();
updateSelection(); updateSelection();
} }
void ContactsBox::Inner::mousePressEvent(QMouseEvent *e) { void ContactsBox::Inner::mousePressEvent(QMouseEvent *e) {
_mouseSel = true; _mouseSelection = true;
_lastMousePos = e->globalPos(); _lastMousePos = e->globalPos();
updateSelection(); updateSelection();
if (e->button() == Qt::LeftButton) {
chooseParticipant(); setPressed(_selected);
setFilteredPressed(_filteredSelected);
setSearchedPressed(_searchedSelected);
if (_pressed) {
addRipple(contactData(_selected));
} else if (_filteredSelected >= 0 && _filteredSelected < _filtered.size()) {
addRipple(contactData(_filtered[_filteredSelected]));
} else if (_searchedSelected >= 0) {
if (_filter.isEmpty() && _searchedSelected < d_byUsername.size()) {
addRipple(d_byUsername[_searchedSelected]);
} else if (!_filter.isEmpty() && _searchedSelected < d_byUsernameFiltered.size()) {
addRipple(d_byUsernameFiltered[_searchedSelected]);
}
} }
} }
void ContactsBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
auto pressed = _pressed;
setPressed(nullptr);
auto filteredPressed = _filteredPressed;
setFilteredPressed(-1);
auto searchedPressed = _searchedPressed;
setSearchedPressed(-1);
updateSelectedRow();
if (e->button() == Qt::LeftButton) {
if (pressed && pressed == _selected) {
chooseParticipant();
} else if (filteredPressed >= 0 && filteredPressed == _filteredSelected) {
chooseParticipant();
} else if (searchedPressed >= 0 && searchedPressed == _searchedSelected) {
chooseParticipant();
}
}
}
void ContactsBox::Inner::addRipple(ContactData *data) {
auto rowTop = getSelectedRowTop();
if (!data->ripple) {
auto mask = Ui::RippleAnimation::rectMask(QSize(width(), _rowHeight));
data->ripple = std_::make_unique<Ui::RippleAnimation>(st::contactsRipple, std_::move(mask), [this, data] {
updateRowWithTop(data->rippleRowTop);
});
}
data->rippleRowTop = rowTop;
data->ripple->add(mapFromGlobal(QCursor::pos()) - QPoint(0, rowTop));
}
void ContactsBox::Inner::stopLastRipple(ContactData *data) {
if (data->ripple) {
data->ripple->lastStop();
}
}
void ContactsBox::Inner::setPressed(Dialogs::Row *pressed) {
if (_pressed != pressed) {
if (_pressed) {
stopLastRipple(contactData(_pressed));
}
_pressed = pressed;
}
}
void ContactsBox::Inner::setFilteredPressed(int pressed) {
if (_filteredPressed >= 0 && _filteredPressed < _filtered.size()) {
stopLastRipple(contactData(_filtered[_filteredPressed]));
}
_filteredPressed = pressed;
}
void ContactsBox::Inner::setSearchedPressed(int pressed) {
if (_searchedPressed >= 0) {
if (_searchedPressed < d_byUsername.size()) {
stopLastRipple(d_byUsername[_searchedPressed]);
}
if (_searchedPressed < d_byUsernameFiltered.size()) {
stopLastRipple(d_byUsernameFiltered[_searchedPressed]);
}
}
_searchedPressed = pressed;
}
void ContactsBox::Inner::chooseParticipant() { void ContactsBox::Inner::chooseParticipant() {
if (_saving) return; if (_saving) return;
bool addingAdmin = (_channel && _membersFilter == MembersFilter::Admins); bool addingAdmin = (_channel && _membersFilter == MembersFilter::Admins);
if (!addingAdmin && usingMultiSelect()) { if (!addingAdmin && usingMultiSelect()) {
_time = unixtime(); _time = unixtime();
if (_filter.isEmpty()) { if (_filter.isEmpty()) {
if (_byUsernameSel >= 0 && _byUsernameSel < _byUsername.size()) { if (_searchedSelected >= 0 && _searchedSelected < _byUsername.size()) {
auto data = d_byUsername[_byUsernameSel]; auto data = d_byUsername[_searchedSelected];
auto peer = _byUsername[_byUsernameSel]; auto peer = _byUsername[_searchedSelected];
if (data->disabledChecked) return; if (data->disabledChecked) return;
changeCheckState(data, peer); changeCheckState(data, peer);
} else if (_sel) { } else if (_selected) {
auto data = contactData(_sel); auto data = contactData(_selected);
auto peer = _sel->history()->peer; auto peer = _selected->history()->peer;
if (data->disabledChecked) return; if (data->disabledChecked) return;
changeCheckState(_sel); changeCheckState(_selected);
} }
} else { } else {
if (_byUsernameSel >= 0 && _byUsernameSel < _byUsernameFiltered.size()) { if (_searchedSelected >= 0 && _searchedSelected < _byUsernameFiltered.size()) {
auto data = d_byUsernameFiltered[_byUsernameSel]; auto data = d_byUsernameFiltered[_searchedSelected];
auto peer = _byUsernameFiltered[_byUsernameSel]; auto peer = _byUsernameFiltered[_searchedSelected];
if (data->disabledChecked) return; if (data->disabledChecked) return;
int i = 0, l = d_byUsername.size(); int i = 0, l = d_byUsername.size();
@ -1291,9 +1383,9 @@ void ContactsBox::Inner::chooseParticipant() {
} }
changeCheckState(data, peer); changeCheckState(data, peer);
} else if (_filteredSel >= 0 && _filteredSel < _filtered.size()) { } else if (_filteredSelected >= 0 && _filteredSelected < _filtered.size()) {
auto data = contactData(_filtered[_filteredSel]); auto data = contactData(_filtered[_filteredSelected]);
auto peer = _filtered[_filteredSel]->history()->peer; auto peer = _filtered[_filteredSelected]->history()->peer;
if (data->disabledChecked) return; if (data->disabledChecked) return;
changeCheckState(data, peer); changeCheckState(data, peer);
@ -1302,17 +1394,17 @@ void ContactsBox::Inner::chooseParticipant() {
} else { } else {
PeerData *peer = 0; PeerData *peer = 0;
if (_filter.isEmpty()) { if (_filter.isEmpty()) {
if (_byUsernameSel >= 0 && _byUsernameSel < _byUsername.size()) { if (_searchedSelected >= 0 && _searchedSelected < _byUsername.size()) {
peer = _byUsername[_byUsernameSel]; peer = _byUsername[_searchedSelected];
} else if (_sel) { } else if (_selected) {
peer = _sel->history()->peer; peer = _selected->history()->peer;
} }
} else { } else {
if (_byUsernameSel >= 0 && _byUsernameSel < _byUsernameFiltered.size()) { if (_searchedSelected >= 0 && _searchedSelected < _byUsernameFiltered.size()) {
peer = _byUsernameFiltered[_byUsernameSel]; peer = _byUsernameFiltered[_searchedSelected];
} else { } else {
if (_filteredSel < 0 || _filteredSel >= _filtered.size()) return; if (_filteredSelected < 0 || _filteredSelected >= _filtered.size()) return;
peer = _filtered[_filteredSel]->history()->peer; peer = _filtered[_filteredSelected]->history()->peer;
} }
} }
if (peer) { if (peer) {
@ -1408,31 +1500,35 @@ int32 ContactsBox::Inner::selectedCount() const {
} }
void ContactsBox::Inner::updateSelection() { void ContactsBox::Inner::updateSelection() {
if (!_mouseSel) return; if (!_mouseSelection) return;
QPoint p(mapFromGlobal(_lastMousePos)); auto p = mapFromGlobal(_lastMousePos);
bool in = parentWidget()->rect().contains(parentWidget()->mapFromGlobal(_lastMousePos)); bool in = parentWidget()->rect().contains(parentWidget()->mapFromGlobal(_lastMousePos));
if (_filter.isEmpty()) { if (_filter.isEmpty()) {
_filteredSelected = -1;
setFilteredPressed(-1);
if (_aboutHeight) { if (_aboutHeight) {
p.setY(p.y() - _aboutHeight); p.setY(p.y() - _aboutHeight);
} }
Dialogs::Row *newSel = (in && (p.y() >= 0) && (p.y() < _contacts->size() * _rowHeight)) ? _contacts->rowAtY(p.y(), _rowHeight) : nullptr; auto selected = (in && (p.y() >= 0) && (p.y() < _contacts->size() * _rowHeight)) ? _contacts->rowAtY(p.y(), _rowHeight) : nullptr;
int32 byUsernameSel = (in && p.y() >= _contacts->size() * _rowHeight + st::searchedBarHeight) ? ((p.y() - _contacts->size() * _rowHeight - st::searchedBarHeight) / _rowHeight) : -1; auto searchedSelected = (in && p.y() >= _contacts->size() * _rowHeight + st::searchedBarHeight) ? ((p.y() - _contacts->size() * _rowHeight - st::searchedBarHeight) / _rowHeight) : -1;
if (byUsernameSel >= _byUsername.size()) byUsernameSel = -1; if (searchedSelected >= _byUsername.size()) searchedSelected = -1;
if (newSel != _sel || byUsernameSel != _byUsernameSel) { if (_selected != selected || _searchedSelected != searchedSelected) {
updateSelectedRow(); updateSelectedRow();
_sel = newSel; _selected = selected;
_byUsernameSel = byUsernameSel; _searchedSelected = searchedSelected;
updateSelectedRow(); updateSelectedRow();
} }
} else { } else {
int32 newFilteredSel = (in && p.y() >= 0 && p.y() < _filtered.size() * _rowHeight) ? (p.y() / _rowHeight) : -1; _selected = nullptr;
int32 byUsernameSel = (in && p.y() >= _filtered.size() * _rowHeight + st::searchedBarHeight) ? ((p.y() - _filtered.size() * _rowHeight - st::searchedBarHeight) / _rowHeight) : -1; setPressed(nullptr);
if (byUsernameSel >= _byUsernameFiltered.size()) byUsernameSel = -1; auto filteredSelected = (in && p.y() >= 0 && p.y() < _filtered.size() * _rowHeight) ? (p.y() / _rowHeight) : -1;
if (newFilteredSel != _filteredSel || byUsernameSel != _byUsernameSel) { auto searchedSelected = (in && p.y() >= _filtered.size() * _rowHeight + st::searchedBarHeight) ? ((p.y() - _filtered.size() * _rowHeight - st::searchedBarHeight) / _rowHeight) : -1;
if (searchedSelected >= _byUsernameFiltered.size()) searchedSelected = -1;
if (_filteredSelected != filteredSelected || _searchedSelected != searchedSelected) {
updateSelectedRow(); updateSelectedRow();
_filteredSel = newFilteredSel; _filteredSelected = filteredSelected;
_byUsernameSel = byUsernameSel; _searchedSelected = searchedSelected;
updateSelectedRow(); updateSelectedRow();
} }
} }
@ -1461,13 +1557,15 @@ void ContactsBox::Inner::updateFilter(QString filter) {
_byUsernameFiltered.clear(); _byUsernameFiltered.clear();
d_byUsernameFiltered.clear(); d_byUsernameFiltered.clear();
for (int i = 0, l = _byUsernameDatas.size(); i < l; ++i) { clearSearchedContactDatas();
delete _byUsernameDatas[i];
}
_byUsernameDatas.clear();
_selected = nullptr;
setPressed(nullptr);
_filteredSelected = -1;
setFilteredPressed(-1);
_searchedSelected = -1;
setSearchedPressed(-1);
if (_filter.isEmpty()) { if (_filter.isEmpty()) {
_sel = 0;
refresh(); refresh();
} else { } else {
if (!_addContactLnk->isHidden()) _addContactLnk->hide(); if (!_addContactLnk->isHidden()) _addContactLnk->hide();
@ -1534,21 +1632,19 @@ void ContactsBox::Inner::updateFilter(QString filter) {
} }
} }
} }
_filteredSel = -1;
if (!_filtered.isEmpty()) { if (!_filtered.isEmpty()) {
for (_filteredSel = 0; (_filteredSel < _filtered.size()) && contactData(_filtered[_filteredSel])->disabledChecked;) { for (_filteredSelected = 0; (_filteredSelected < _filtered.size()) && contactData(_filtered[_filteredSelected])->disabledChecked;) {
++_filteredSel; ++_filteredSelected;
} }
if (_filteredSel == _filtered.size()) _filteredSel = -1; if (_filteredSelected == _filtered.size()) _filteredSelected = -1;
} }
_byUsernameSel = -1; if (_filteredSelected < 0 && !_byUsernameFiltered.isEmpty()) {
if (_filteredSel < 0 && !_byUsernameFiltered.isEmpty()) { for (_searchedSelected = 0; (_searchedSelected < _byUsernameFiltered.size()) && d_byUsernameFiltered[_searchedSelected]->disabledChecked;) {
for (_byUsernameSel = 0; (_byUsernameSel < _byUsernameFiltered.size()) && d_byUsernameFiltered[_byUsernameSel]->disabledChecked;) { ++_searchedSelected;
++_byUsernameSel;
} }
if (_byUsernameSel == _byUsernameFiltered.size()) _byUsernameSel = -1; if (_searchedSelected == _byUsernameFiltered.size()) _searchedSelected = -1;
} }
_mouseSel = false; _mouseSelection = false;
refresh(); refresh();
if ((!bot() || sharingBotGame()) && (!_chat || _membersFilter != MembersFilter::Admins)) { if ((!bot() || sharingBotGame()) && (!_chat || _membersFilter != MembersFilter::Admins)) {
@ -1561,9 +1657,15 @@ void ContactsBox::Inner::updateFilter(QString filter) {
} }
} }
void ContactsBox::Inner::clearSearchedContactDatas() {
for (auto data : base::take(_byUsernameDatas)) {
delete data;
}
}
void ContactsBox::Inner::onDialogRowReplaced(Dialogs::Row *oldRow, Dialogs::Row *newRow) { void ContactsBox::Inner::onDialogRowReplaced(Dialogs::Row *oldRow, Dialogs::Row *newRow) {
if (!_filter.isEmpty()) { if (!_filter.isEmpty()) {
for (FilteredDialogs::iterator i = _filtered.begin(), e = _filtered.end(); i != e;) { for (auto i = _filtered.begin(), e = _filtered.end(); i != e;) {
if (*i == oldRow) { // this row is shown in filtered and maybe is in contacts! if (*i == oldRow) { // this row is shown in filtered and maybe is in contacts!
if (newRow) { if (newRow) {
*i = newRow; *i = newRow;
@ -1575,18 +1677,21 @@ void ContactsBox::Inner::onDialogRowReplaced(Dialogs::Row *oldRow, Dialogs::Row
++i; ++i;
} }
} }
if (_filteredSel >= _filtered.size()) { if (_filteredSelected >= _filtered.size()) {
_filteredSel = -1; _filteredSelected = -1;
}
if (_filteredPressed >= _filtered.size()) {
_filteredPressed = -1;
} }
} else { } else {
if (_sel == oldRow) { if (_selected == oldRow) {
_sel = newRow; _selected = newRow;
}
if (_pressed == oldRow) {
setPressed(newRow);
} }
} }
_mouseSel = false; refresh();
int cnt = (_filter.isEmpty() ? _contacts->size() : _filtered.size());
int newh = cnt ? (cnt * _rowHeight) : st::noContactsHeight;
resize(width(), newh);
} }
void ContactsBox::Inner::peopleReceived(const QString &query, const QVector<MTPPeer> &people) { void ContactsBox::Inner::peopleReceived(const QString &query, const QVector<MTPPeer> &people) {
@ -1707,6 +1812,10 @@ ContactsBox::Inner::~Inner() {
for (auto contactData : base::take(_contactsData)) { for (auto contactData : base::take(_contactsData)) {
delete contactData; delete contactData;
} }
clearSearchedContactDatas();
for (auto data : base::take(d_byUsername)) {
delete data;
}
if (_bot) { if (_bot) {
if (auto &info = _bot->botInfo) { if (auto &info = _bot->botInfo) {
info->startGroupToken = QString(); info->startGroupToken = QString();
@ -1722,127 +1831,127 @@ void ContactsBox::Inner::resizeEvent(QResizeEvent *e) {
void ContactsBox::Inner::selectSkip(int32 dir) { void ContactsBox::Inner::selectSkip(int32 dir) {
_time = unixtime(); _time = unixtime();
_mouseSel = false; _mouseSelection = false;
if (_filter.isEmpty()) { if (_filter.isEmpty()) {
int cur = 0; int cur = 0;
if (_sel) { if (_selected) {
for (auto i = _contacts->cbegin(); *i != _sel; ++i) { for (auto i = _contacts->cbegin(); *i != _selected; ++i) {
++cur; ++cur;
} }
} else if (_byUsernameSel >= 0) { } else if (_searchedSelected >= 0) {
cur = (_contacts->size() + _byUsernameSel); cur = (_contacts->size() + _searchedSelected);
} else { } else {
cur = -1; cur = -1;
} }
cur += dir; cur += dir;
if (cur <= 0) { if (cur <= 0) {
_sel = (!_contacts->isEmpty()) ? *_contacts->cbegin() : nullptr; _selected = (!_contacts->isEmpty()) ? *_contacts->cbegin() : nullptr;
_byUsernameSel = (_contacts->isEmpty() && !_byUsername.isEmpty()) ? 0 : -1; _searchedSelected = (_contacts->isEmpty() && !_byUsername.isEmpty()) ? 0 : -1;
} else if (cur >= _contacts->size()) { } else if (cur >= _contacts->size()) {
if (_byUsername.isEmpty()) { if (_byUsername.isEmpty()) {
_sel = _contacts->isEmpty() ? nullptr : *(_contacts->cend() - 1); _selected = _contacts->isEmpty() ? nullptr : *(_contacts->cend() - 1);
_byUsernameSel = -1; _searchedSelected = -1;
} else { } else {
_sel = nullptr; _selected = nullptr;
_byUsernameSel = cur - _contacts->size(); _searchedSelected = cur - _contacts->size();
if (_byUsernameSel >= _byUsername.size()) _byUsernameSel = _byUsername.size() - 1; if (_searchedSelected >= _byUsername.size()) _searchedSelected = _byUsername.size() - 1;
} }
} else { } else {
for (auto i = _contacts->cbegin(); ; ++i) { for (auto i = _contacts->cbegin(); ; ++i) {
_sel = *i; _selected = *i;
if (!cur) { if (!cur) {
break; break;
} else { } else {
--cur; --cur;
} }
} }
_byUsernameSel = -1; _searchedSelected = -1;
} }
if (dir > 0) { if (dir > 0) {
for (auto i = _contacts->cfind(_sel), end = _contacts->cend(); i != end && contactData(*i)->disabledChecked; ++i) { for (auto i = _contacts->cfind(_selected), end = _contacts->cend(); i != end && contactData(*i)->disabledChecked; ++i) {
_sel = *i; _selected = *i;
} }
if (_sel && contactData(_sel)->disabledChecked) { if (_selected && contactData(_selected)->disabledChecked) {
_sel = nullptr; _selected = nullptr;
} }
if (!_sel) { if (!_selected) {
if (!_byUsername.isEmpty()) { if (!_byUsername.isEmpty()) {
if (_byUsernameSel < 0) _byUsernameSel = 0; if (_searchedSelected < 0) _searchedSelected = 0;
for (; _byUsernameSel < _byUsername.size() && d_byUsername[_byUsernameSel]->disabledChecked;) { for (; _searchedSelected < _byUsername.size() && d_byUsername[_searchedSelected]->disabledChecked;) {
++_byUsernameSel; ++_searchedSelected;
} }
if (_byUsernameSel == _byUsername.size()) _byUsernameSel = -1; if (_searchedSelected == _byUsername.size()) _searchedSelected = -1;
} }
} }
} else { } else {
while (_byUsernameSel >= 0 && d_byUsername[_byUsernameSel]->disabledChecked) { while (_searchedSelected >= 0 && d_byUsername[_searchedSelected]->disabledChecked) {
--_byUsernameSel; --_searchedSelected;
} }
if (_byUsernameSel < 0) { if (_searchedSelected < 0) {
if (!_contacts->isEmpty()) { if (!_contacts->isEmpty()) {
if (!_sel) _sel = *(_contacts->cend() - 1); if (!_selected) _selected = *(_contacts->cend() - 1);
if (_sel) { if (_selected) {
for (auto i = _contacts->cfind(_sel), b = _contacts->cbegin(); i != b && contactData(*i)->disabledChecked; --i) { for (auto i = _contacts->cfind(_selected), b = _contacts->cbegin(); i != b && contactData(*i)->disabledChecked; --i) {
_sel = *i; _selected = *i;
} }
if (contactData(_sel)->disabledChecked) { if (contactData(_selected)->disabledChecked) {
_sel = nullptr; _selected = nullptr;
} }
} }
} }
} }
} }
if (_sel) { if (_selected) {
emit mustScrollTo(_aboutHeight + _sel->pos() * _rowHeight, _aboutHeight + (_sel->pos() + 1) * _rowHeight); emit mustScrollTo(_aboutHeight + _selected->pos() * _rowHeight, _aboutHeight + (_selected->pos() + 1) * _rowHeight);
} else if (_byUsernameSel >= 0) { } else if (_searchedSelected >= 0) {
emit mustScrollTo(_aboutHeight + (_contacts->size() + _byUsernameSel) * _rowHeight + st::searchedBarHeight, _aboutHeight + (_contacts->size() + _byUsernameSel + 1) * _rowHeight + st::searchedBarHeight); emit mustScrollTo(_aboutHeight + (_contacts->size() + _searchedSelected) * _rowHeight + st::searchedBarHeight, _aboutHeight + (_contacts->size() + _searchedSelected + 1) * _rowHeight + st::searchedBarHeight);
} }
} else { } else {
int cur = (_filteredSel >= 0) ? _filteredSel : ((_byUsernameSel >= 0) ? (_filtered.size() + _byUsernameSel) : -1); int cur = (_filteredSelected >= 0) ? _filteredSelected : ((_searchedSelected >= 0) ? (_filtered.size() + _searchedSelected) : -1);
cur += dir; cur += dir;
if (cur <= 0) { if (cur <= 0) {
_filteredSel = _filtered.isEmpty() ? -1 : 0; _filteredSelected = _filtered.isEmpty() ? -1 : 0;
_byUsernameSel = (_filtered.isEmpty() && !_byUsernameFiltered.isEmpty()) ? 0 : -1; _searchedSelected = (_filtered.isEmpty() && !_byUsernameFiltered.isEmpty()) ? 0 : -1;
} else if (cur >= _filtered.size()) { } else if (cur >= _filtered.size()) {
_filteredSel = -1; _filteredSelected = -1;
_byUsernameSel = cur - _filtered.size(); _searchedSelected = cur - _filtered.size();
if (_byUsernameSel >= _byUsernameFiltered.size()) _byUsernameSel = _byUsernameFiltered.size() - 1; if (_searchedSelected >= _byUsernameFiltered.size()) _searchedSelected = _byUsernameFiltered.size() - 1;
} else { } else {
_filteredSel = cur; _filteredSelected = cur;
_byUsernameSel = -1; _searchedSelected = -1;
} }
if (dir > 0) { if (dir > 0) {
while (_filteredSel >= 0 && _filteredSel < _filtered.size() && contactData(_filtered[_filteredSel])->disabledChecked) { while (_filteredSelected >= 0 && _filteredSelected < _filtered.size() && contactData(_filtered[_filteredSelected])->disabledChecked) {
++_filteredSel; ++_filteredSelected;
} }
if (_filteredSel < 0 || _filteredSel >= _filtered.size()) { if (_filteredSelected < 0 || _filteredSelected >= _filtered.size()) {
_filteredSel = -1; _filteredSelected = -1;
if (!_byUsernameFiltered.isEmpty()) { if (!_byUsernameFiltered.isEmpty()) {
if (_byUsernameSel < 0) _byUsernameSel = 0; if (_searchedSelected < 0) _searchedSelected = 0;
for (; _byUsernameSel < _byUsernameFiltered.size() && d_byUsernameFiltered[_byUsernameSel]->disabledChecked;) { for (; _searchedSelected < _byUsernameFiltered.size() && d_byUsernameFiltered[_searchedSelected]->disabledChecked;) {
++_byUsernameSel; ++_searchedSelected;
} }
if (_byUsernameSel == _byUsernameFiltered.size()) _byUsernameSel = -1; if (_searchedSelected == _byUsernameFiltered.size()) _searchedSelected = -1;
} }
} }
} else { } else {
while (_byUsernameSel >= 0 && d_byUsernameFiltered[_byUsernameSel]->disabledChecked) { while (_searchedSelected >= 0 && d_byUsernameFiltered[_searchedSelected]->disabledChecked) {
--_byUsernameSel; --_searchedSelected;
} }
if (_byUsernameSel < 0) { if (_searchedSelected < 0) {
if (!_filtered.isEmpty()) { if (!_filtered.isEmpty()) {
if (_filteredSel < 0) _filteredSel = _filtered.size() - 1; if (_filteredSelected < 0) _filteredSelected = _filtered.size() - 1;
for (; _filteredSel >= 0 && contactData(_filtered[_filteredSel])->disabledChecked;) { for (; _filteredSelected >= 0 && contactData(_filtered[_filteredSelected])->disabledChecked;) {
--_filteredSel; --_filteredSelected;
} }
} }
} }
} }
if (_filteredSel >= 0) { if (_filteredSelected >= 0) {
emit mustScrollTo(_filteredSel * _rowHeight, (_filteredSel + 1) * _rowHeight); emit mustScrollTo(_filteredSelected * _rowHeight, (_filteredSelected + 1) * _rowHeight);
} else if (_byUsernameSel >= 0) { } else if (_searchedSelected >= 0) {
int skip = _filtered.size() * _rowHeight + st::searchedBarHeight; int skip = _filtered.size() * _rowHeight + st::searchedBarHeight;
emit mustScrollTo(skip + _byUsernameSel * _rowHeight, skip + (_byUsernameSel + 1) * _rowHeight); emit mustScrollTo(skip + _searchedSelected * _rowHeight, skip + (_searchedSelected + 1) * _rowHeight);
} }
} }
update(); update();

View file

@ -31,6 +31,7 @@ class IndexedList;
} // namespace Dialogs } // namespace Dialogs
namespace Ui { namespace Ui {
class RippleAnimation;
class RoundButton; class RoundButton;
class LinkButton; class LinkButton;
class Checkbox; class Checkbox;
@ -208,19 +209,29 @@ protected:
void leaveEvent(QEvent *e) override; void leaveEvent(QEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override;
void mousePressEvent(QMouseEvent *e) override; void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void resizeEvent(QResizeEvent *e) override; void resizeEvent(QResizeEvent *e) override;
private: private:
struct ContactData { struct ContactData {
ContactData() = default; ContactData();
ContactData(PeerData *peer, const base::lambda_copy<void()> &updateCallback); ContactData(PeerData *peer, const base::lambda_copy<void()> &updateCallback);
~ContactData();
std_::unique_ptr<Ui::RoundImageCheckbox> checkbox; std_::unique_ptr<Ui::RoundImageCheckbox> checkbox;
std_::unique_ptr<Ui::RippleAnimation> ripple;
int rippleRowTop = 0;
Text name; Text name;
QString statusText; QString statusText;
bool statusHasOnlineColor = false; bool statusHasOnlineColor = false;
bool disabledChecked = false; bool disabledChecked = false;
}; };
void addRipple(ContactData *data);
void stopLastRipple(ContactData *data);
void setPressed(Dialogs::Row *pressed);
void setFilteredPressed(int pressed);
void setSearchedPressed(int pressed);
void clearSearchedContactDatas();
void init(); void init();
void initList(); void initList();
@ -277,12 +288,14 @@ private:
std_::unique_ptr<Dialogs::IndexedList> _customList; std_::unique_ptr<Dialogs::IndexedList> _customList;
Dialogs::IndexedList *_contacts = nullptr; Dialogs::IndexedList *_contacts = nullptr;
Dialogs::Row *_sel = nullptr; Dialogs::Row *_selected = nullptr;
Dialogs::Row *_pressed = nullptr;
QString _filter; QString _filter;
using FilteredDialogs = QVector<Dialogs::Row*>; using FilteredDialogs = QVector<Dialogs::Row*>;
FilteredDialogs _filtered; FilteredDialogs _filtered;
int _filteredSel = -1; int _filteredSelected = -1;
bool _mouseSel = false; int _filteredPressed = -1;
bool _mouseSelection = false;
using ContactsData = QMap<PeerData*, ContactData*>; using ContactsData = QMap<PeerData*, ContactData*>;
ContactsData _contactsData; ContactsData _contactsData;
@ -298,7 +311,8 @@ private:
ByUsernameRows _byUsername, _byUsernameFiltered; ByUsernameRows _byUsername, _byUsernameFiltered;
ByUsernameDatas d_byUsername, d_byUsernameFiltered; // filtered is partly subset of d_byUsername, partly subset of _byUsernameDatas ByUsernameDatas d_byUsername, d_byUsernameFiltered; // filtered is partly subset of d_byUsername, partly subset of _byUsernameDatas
ByUsernameDatas _byUsernameDatas; ByUsernameDatas _byUsernameDatas;
int _byUsernameSel = -1; int _searchedSelected = -1;
int _searchedPressed = -1;
QPoint _lastMousePos; QPoint _lastMousePos;
ChildWidget<Ui::LinkButton> _addContactLnk; ChildWidget<Ui::LinkButton> _addContactLnk;

View file

@ -44,8 +44,8 @@ void MembersAddButton::paintEvent(QPaintEvent *e) {
Painter p(this); Painter p(this);
auto ms = getms(); auto ms = getms();
auto over = (_state & StateOver); auto over = isOver();
auto down = (_state & StateDown); auto down = isDown();
((over || down) ? _st.iconBelowOver : _st.iconBelow).paint(p, _st.iconPosition, width()); ((over || down) ? _st.iconBelowOver : _st.iconBelow).paint(p, _st.iconPosition, width());
paintRipple(p, _st.rippleAreaPosition.x(), _st.rippleAreaPosition.y(), ms); paintRipple(p, _st.rippleAreaPosition.x(), _st.rippleAreaPosition.y(), ms);

View file

@ -311,7 +311,7 @@ void SessionsBox::Inner::paintEvent(QPaintEvent *e) {
void SessionsBox::Inner::onTerminate() { void SessionsBox::Inner::onTerminate() {
for (TerminateButtons::iterator i = _terminateButtons.begin(), e = _terminateButtons.end(); i != e; ++i) { for (TerminateButtons::iterator i = _terminateButtons.begin(), e = _terminateButtons.end(); i != e; ++i) {
if (i.value()->getState() & Ui::AbstractButton::StateOver) { if (i.value()->isOver()) {
_terminating = i.key(); _terminating = i.key();
if (_terminateBox) _terminateBox->deleteLater(); if (_terminateBox) _terminateBox->deleteLater();

View file

@ -274,7 +274,7 @@ void ShareBox::onMustScrollTo(int top, int bottom) {
} }
if (from != to) { if (from != to) {
_scrollAnimation.start([this]() { _scrollAnimation.start([this]() {
scrollArea()->scrollToY(_scrollAnimation.current(scrollArea()->scrollTop())); scrollArea()->scrollToY(qRound(_scrollAnimation.current(scrollArea()->scrollTop())));
}, from, to, st::shareScrollDuration, anim::sineInOut); }, from, to, st::shareScrollDuration, anim::sineInOut);
} }
} }

View file

@ -107,7 +107,7 @@ private:
using PeopleQueries = QMap<mtpRequestId, QString>; using PeopleQueries = QMap<mtpRequestId, QString>;
PeopleQueries _peopleQueries; PeopleQueries _peopleQueries;
IntAnimation _scrollAnimation; FloatAnimation _scrollAnimation;
}; };

View file

@ -663,7 +663,7 @@ QRect StickersBox::Inner::relativeButtonRect(bool removeButton) const {
void StickersBox::Inner::paintRow(Painter &p, int index, TimeMs ms) { void StickersBox::Inner::paintRow(Painter &p, int index, TimeMs ms) {
auto s = _rows.at(index); auto s = _rows.at(index);
auto xadd = 0, yadd = s->yadd.current(); auto xadd = 0, yadd = qRound(s->yadd.current());
if (xadd || yadd) p.translate(xadd, yadd); if (xadd || yadd) p.translate(xadd, yadd);
if (_section == Section::Installed) { if (_section == Section::Installed) {
@ -673,7 +673,7 @@ void StickersBox::Inner::paintRow(Painter &p, int index, TimeMs ms) {
if (_started >= 0) { if (_started >= 0) {
float64 o = aboveShadowOpacity(); float64 o = aboveShadowOpacity();
if (o > current) { if (o > current) {
_aboveShadowFadeOpacity = anim::fvalue(o, o); _aboveShadowFadeOpacity = anim::value(o, o);
current = o; current = o;
} }
} }
@ -858,14 +858,14 @@ void StickersBox::Inner::onUpdateSelected() {
shift = -floorclamp(_dragStart.y() - local.y() + (_rowHeight / 2), _rowHeight, 0, _dragging - firstSetIndex); shift = -floorclamp(_dragStart.y() - local.y() + (_rowHeight / 2), _rowHeight, 0, _dragging - firstSetIndex);
for (int32 from = _dragging, to = _dragging + shift; from > to; --from) { for (int32 from = _dragging, to = _dragging + shift; from > to; --from) {
qSwap(_rows[from], _rows[from - 1]); qSwap(_rows[from], _rows[from - 1]);
_rows.at(from)->yadd = anim::ivalue(_rows.at(from)->yadd.current() - _rowHeight, 0); _rows[from]->yadd = anim::value(_rows[from]->yadd.current() - _rowHeight, 0);
_animStartTimes[from] = ms; _animStartTimes[from] = ms;
} }
} else if (_dragStart.y() < local.y() && _dragging + 1 < _rows.size()) { } else if (_dragStart.y() < local.y() && _dragging + 1 < _rows.size()) {
shift = floorclamp(local.y() - _dragStart.y() + (_rowHeight / 2), _rowHeight, 0, _rows.size() - _dragging - 1); shift = floorclamp(local.y() - _dragStart.y() + (_rowHeight / 2), _rowHeight, 0, _rows.size() - _dragging - 1);
for (int32 from = _dragging, to = _dragging + shift; from < to; ++from) { for (int32 from = _dragging, to = _dragging + shift; from < to; ++from) {
qSwap(_rows[from], _rows[from + 1]); qSwap(_rows[from], _rows[from + 1]);
_rows.at(from)->yadd = anim::ivalue(_rows.at(from)->yadd.current() + _rowHeight, 0); _rows[from]->yadd = anim::value(_rows[from]->yadd.current() + _rowHeight, 0);
_animStartTimes[from] = ms; _animStartTimes[from] = ms;
} }
} }
@ -877,7 +877,7 @@ void StickersBox::Inner::onUpdateSelected() {
_a_shifting.start(); _a_shifting.start();
} }
} }
_rows.at(_dragging)->yadd = anim::ivalue(local.y() - _dragStart.y(), local.y() - _dragStart.y()); _rows[_dragging]->yadd = anim::value(local.y() - _dragStart.y(), local.y() - _dragStart.y());
_animStartTimes[_dragging] = 0; _animStartTimes[_dragging] = 0;
_a_shifting.step(getms(), true); _a_shifting.step(getms(), true);
@ -926,8 +926,8 @@ void StickersBox::Inner::onUpdateSelected() {
float64 StickersBox::Inner::aboveShadowOpacity() const { float64 StickersBox::Inner::aboveShadowOpacity() const {
if (_above < 0) return 0; if (_above < 0) return 0;
int32 dx = 0; auto dx = 0;
int32 dy = qAbs(_above * _rowHeight + _rows.at(_above)->yadd.current() - _started * _rowHeight); auto dy = qAbs(_above * _rowHeight + qRound(_rows[_above]->yadd.current()) - _started * _rowHeight);
return qMin((dx + dy) * 2. / _rowHeight, 1.); return qMin((dx + dy) * 2. / _rowHeight, 1.);
} }
@ -948,9 +948,9 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
} }
} else if (_dragging >= 0) { } else if (_dragging >= 0) {
QPoint local(mapFromGlobal(_mouse)); QPoint local(mapFromGlobal(_mouse));
_rows[_dragging]->yadd.start(0); _rows[_dragging]->yadd.start(0.);
_aboveShadowFadeStart = _animStartTimes[_dragging] = getms(); _aboveShadowFadeStart = _animStartTimes[_dragging] = getms();
_aboveShadowFadeOpacity = anim::fvalue(aboveShadowOpacity(), 0); _aboveShadowFadeOpacity = anim::value(aboveShadowOpacity(), 0);
if (!_a_shifting.animating()) { if (!_a_shifting.animating()) {
_a_shifting.start(); _a_shifting.start();
} }
@ -994,10 +994,10 @@ void StickersBox::Inner::step_shifting(TimeMs ms, bool timer) {
if (updateMin < 0) updateMin = i; if (updateMin < 0) updateMin = i;
updateMax = i; updateMax = i;
if (start + st::stickersRowDuration > ms && ms >= start) { if (start + st::stickersRowDuration > ms && ms >= start) {
_rows.at(i)->yadd.update(float64(ms - start) / st::stickersRowDuration, anim::sineInOut); _rows[i]->yadd.update(float64(ms - start) / st::stickersRowDuration, anim::sineInOut);
animating = true; animating = true;
} else { } else {
_rows.at(i)->yadd.finish(); _rows[i]->yadd.finish();
_animStartTimes[i] = 0; _animStartTimes[i] = 0;
} }
} }
@ -1035,7 +1035,7 @@ void StickersBox::Inner::clear() {
_rows.clear(); _rows.clear();
_animStartTimes.clear(); _animStartTimes.clear();
_aboveShadowFadeStart = 0; _aboveShadowFadeStart = 0;
_aboveShadowFadeOpacity = anim::fvalue(0, 0); _aboveShadowFadeOpacity = anim::value();
_a_shifting.stop(); _a_shifting.stop();
_above = _dragging = _started = -1; _above = _dragging = _started = -1;
_selected = -1; _selected = -1;

View file

@ -229,7 +229,7 @@ private:
int titleWidth; int titleWidth;
bool installed, official, unread, archived, removed; bool installed, official, unread, archived, removed;
int32 pixw, pixh; int32 pixw, pixh;
anim::ivalue yadd; anim::value yadd;
QSharedPointer<Ui::RippleAnimation> ripple; QSharedPointer<Ui::RippleAnimation> ripple;
}; };
using Rows = QList<Row*>; using Rows = QList<Row*>;
@ -245,7 +245,7 @@ private:
Rows _rows; Rows _rows;
QList<TimeMs> _animStartTimes; QList<TimeMs> _animStartTimes;
TimeMs _aboveShadowFadeStart = 0; TimeMs _aboveShadowFadeStart = 0;
anim::fvalue _aboveShadowFadeOpacity = { 0., 0. }; anim::value _aboveShadowFadeOpacity;
Animation _a_shifting; Animation _a_shifting;
base::lambda<void(uint64 setId)> _installSetCallback; base::lambda<void(uint64 setId)> _installSetCallback;

View file

@ -200,6 +200,7 @@ public:
} }
~unique_ptr() noexcept { ~unique_ptr() noexcept {
if (_p) { if (_p) {
static_assert(sizeof(T) > 0, "can't delete an incomplete type");
delete _p; delete _p;
_p = nullptr; _p = nullptr;
} }
@ -228,6 +229,7 @@ public:
auto old = _p; auto old = _p;
_p = p; _p = p;
if (old) { if (old) {
static_assert(sizeof(T) > 0, "can't delete an incomplete type");
delete old; delete old;
} }
} }

View file

@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "core/utils.h" #include "core/utils.h"
#define BETA_VERSION_MACRO (10019011ULL) #define BETA_VERSION_MACRO (10019012ULL)
constexpr int AppVersion = 10020; constexpr int AppVersion = 10020;
constexpr str_const AppVersionStr = "0.10.20"; constexpr str_const AppVersionStr = "0.10.20";

View file

@ -27,6 +27,10 @@ dialogsUnreadFont: font(12px bold);
dialogsUnreadHeight: 19px; dialogsUnreadHeight: 19px;
dialogsUnreadPadding: 5px; dialogsUnreadPadding: 5px;
dialogsRipple: defaultRippleAnimation;
dialogsRippleBg: windowBgRipple;
dialogsRippleBgActive: activeButtonBgRipple;
dialogsTextFont: font(fsize); dialogsTextFont: font(fsize);
dialogsDateFont: font(13px); dialogsDateFont: font(13px);
dialogsDateSkip: 5px; dialogsDateSkip: 5px;

View file

@ -59,20 +59,21 @@ void paintRowDate(Painter &p, const QDateTime &date, QRect &rectForName, bool ac
} }
template <typename PaintItemCallback> template <typename PaintItemCallback>
void paintRow(Painter &p, History *history, HistoryItem *item, Data::Draft *draft, QDateTime date, int w, bool active, bool selected, bool onlyBackground, TimeMs ms, PaintItemCallback paintItemCallback) { void paintRow(Painter &p, const RippleRow *row, History *history, HistoryItem *item, Data::Draft *draft, QDateTime date, int fullWidth, bool active, bool selected, bool onlyBackground, TimeMs ms, PaintItemCallback paintItemCallback) {
QRect fullRect(0, 0, w, st::dialogsRowHeight); QRect fullRect(0, 0, fullWidth, st::dialogsRowHeight);
p.fillRect(fullRect, active ? st::dialogsBgActive : (selected ? st::dialogsBgOver : st::dialogsBg)); p.fillRect(fullRect, active ? st::dialogsBgActive : (selected ? st::dialogsBgOver : st::dialogsBg));
row->paintRipple(p, 0, 0, fullWidth, ms, &(active ? st::dialogsRippleBgActive : st::dialogsRippleBg)->c);
if (onlyBackground) return; if (onlyBackground) return;
PeerData *userpicPeer = (history->peer->migrateTo() ? history->peer->migrateTo() : history->peer); auto userpicPeer = (history->peer->migrateTo() ? history->peer->migrateTo() : history->peer);
userpicPeer->paintUserpicLeft(p, st::dialogsPhotoSize, st::dialogsPadding.x(), st::dialogsPadding.y(), w); userpicPeer->paintUserpicLeft(p, st::dialogsPhotoSize, st::dialogsPadding.x(), st::dialogsPadding.y(), fullWidth);
int32 nameleft = st::dialogsPadding.x() + st::dialogsPhotoSize + st::dialogsPhotoPadding; auto nameleft = st::dialogsPadding.x() + st::dialogsPhotoSize + st::dialogsPhotoPadding;
int32 namewidth = w - nameleft - st::dialogsPadding.x(); auto namewidth = fullWidth - nameleft - st::dialogsPadding.x();
QRect rectForName(nameleft, st::dialogsPadding.y() + st::dialogsNameTop, namewidth, st::msgNameFont->height); QRect rectForName(nameleft, st::dialogsPadding.y() + st::dialogsNameTop, namewidth, st::msgNameFont->height);
if (auto chatTypeIcon = ChatTypeIcon(history->peer, active, selected)) { if (auto chatTypeIcon = ChatTypeIcon(history->peer, active, selected)) {
chatTypeIcon->paint(p, rectForName.topLeft(), w); chatTypeIcon->paint(p, rectForName.topLeft(), fullWidth);
rectForName.setLeft(rectForName.left() + st::dialogsChatTypeSkip); rectForName.setLeft(rectForName.left() + st::dialogsChatTypeSkip);
} }
@ -82,7 +83,7 @@ void paintRow(Painter &p, History *history, HistoryItem *item, Data::Draft *draf
p.setFont(st::dialogsTextFont); p.setFont(st::dialogsTextFont);
auto &color = active ? st::dialogsTextFgServiceActive : (selected ? st::dialogsTextFgServiceOver : st::dialogsTextFgService); auto &color = active ? st::dialogsTextFgServiceActive : (selected ? st::dialogsTextFgServiceOver : st::dialogsTextFgService);
if (!history->paintSendAction(p, nameleft, texttop, namewidth, w, color, ms)) { if (!history->paintSendAction(p, nameleft, texttop, namewidth, fullWidth, color, ms)) {
if (history->cloudDraftTextCache.isEmpty()) { if (history->cloudDraftTextCache.isEmpty()) {
auto draftWrapped = textcmdLink(1, lng_dialogs_text_from_wrapped(lt_from, lang(lng_from_draft))); auto draftWrapped = textcmdLink(1, lng_dialogs_text_from_wrapped(lt_from, lang(lng_from_draft)));
auto draftText = lng_dialogs_text_with_from(lt_from_part, draftWrapped, lt_message, textClean(draft->textWithTags.text)); auto draftText = lng_dialogs_text_with_from(lt_from_part, draftWrapped, lt_message, textClean(draft->textWithTags.text));
@ -96,7 +97,7 @@ void paintRow(Painter &p, History *history, HistoryItem *item, Data::Draft *draf
} else if (!item) { } else if (!item) {
auto &color = active ? st::dialogsTextFgServiceActive : (selected ? st::dialogsTextFgServiceOver : st::dialogsTextFgService); auto &color = active ? st::dialogsTextFgServiceActive : (selected ? st::dialogsTextFgServiceOver : st::dialogsTextFgService);
p.setFont(st::dialogsTextFont); p.setFont(st::dialogsTextFont);
if (!history->paintSendAction(p, nameleft, texttop, namewidth, w, color, ms)) { if (!history->paintSendAction(p, nameleft, texttop, namewidth, fullWidth, color, ms)) {
p.setPen(color); p.setPen(color);
p.drawText(nameleft, texttop + st::msgNameFont->ascent, lang(lng_empty_history)); p.drawText(nameleft, texttop + st::msgNameFont->ascent, lang(lng_empty_history));
} }
@ -123,13 +124,13 @@ void paintRow(Painter &p, History *history, HistoryItem *item, Data::Draft *draf
})(); })();
if (sendStateIcon) { if (sendStateIcon) {
rectForName.setWidth(rectForName.width() - st::dialogsSendStateSkip); rectForName.setWidth(rectForName.width() - st::dialogsSendStateSkip);
sendStateIcon->paint(p, rectForName.topLeft() + QPoint(rectForName.width(), 0), w); sendStateIcon->paint(p, rectForName.topLeft() + QPoint(rectForName.width(), 0), fullWidth);
} }
if (history->peer->isUser() && history->peer->isVerified()) { if (history->peer->isUser() && history->peer->isVerified()) {
auto icon = &(active ? st::dialogsVerifiedIconActive : (selected ? st::dialogsVerifiedIconOver : st::dialogsVerifiedIcon)); auto icon = &(active ? st::dialogsVerifiedIconActive : (selected ? st::dialogsVerifiedIconOver : st::dialogsVerifiedIcon));
rectForName.setWidth(rectForName.width() - icon->width()); rectForName.setWidth(rectForName.width() - icon->width());
icon->paint(p, rectForName.topLeft() + QPoint(qMin(history->peer->dialogName().maxWidth(), rectForName.width()), 0), w); icon->paint(p, rectForName.topLeft() + QPoint(qMin(history->peer->dialogName().maxWidth(), rectForName.width()), 0), fullWidth);
} }
p.setPen(active ? st::dialogsNameFgActive : (selected ? st::dialogsNameFgOver : st::dialogsNameFg)); p.setPen(active ? st::dialogsNameFgActive : (selected ? st::dialogsNameFgOver : st::dialogsNameFg));
@ -241,7 +242,7 @@ void paintUnreadCount(Painter &p, const QString &text, int x, int y, const Unrea
p.drawText(unreadRectLeft + (unreadRectWidth - unreadWidth) / 2, unreadRectTop + textTop + st.font->ascent, text); p.drawText(unreadRectLeft + (unreadRectWidth - unreadWidth) / 2, unreadRectTop + textTop + st.font->ascent, text);
} }
void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool selected, bool onlyBackground, TimeMs ms) { void RowPainter::paint(Painter &p, const Row *row, int fullWidth, bool active, bool selected, bool onlyBackground, TimeMs ms) {
auto history = row->history(); auto history = row->history();
auto item = history->lastMsg; auto item = history->lastMsg;
auto cloudDraft = history->cloudDraft(); auto cloudDraft = history->cloudDraft();
@ -267,15 +268,15 @@ void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool sele
if (item && cloudDraft && unreadCount > 0) { if (item && cloudDraft && unreadCount > 0) {
cloudDraft = nullptr; // Draw item, if draft is older. cloudDraft = nullptr; // Draw item, if draft is older.
} }
paintRow(p, history, item, cloudDraft, displayDate(), w, active, selected, onlyBackground, ms, [&p, w, active, selected, ms, history, unreadCount](int nameleft, int namewidth, HistoryItem *item) { paintRow(p, row, history, item, cloudDraft, displayDate(), fullWidth, active, selected, onlyBackground, ms, [&p, fullWidth, active, selected, ms, history, unreadCount](int nameleft, int namewidth, HistoryItem *item) {
int availableWidth = namewidth; int availableWidth = namewidth;
int texttop = st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip; int texttop = st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip;
if (unreadCount) { if (unreadCount) {
auto counter = QString::number(unreadCount); auto counter = QString::number(unreadCount);
auto mutedCounter = history->mute(); auto mutedCounter = history->mute();
int unreadRight = w - st::dialogsPadding.x(); auto unreadRight = fullWidth - st::dialogsPadding.x();
int unreadTop = texttop + st::dialogsTextFont->ascent - st::dialogsUnreadFont->ascent - (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2; auto unreadTop = texttop + st::dialogsTextFont->ascent - st::dialogsUnreadFont->ascent - (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2;
int unreadWidth = 0; auto unreadWidth = 0;
UnreadBadgeStyle st; UnreadBadgeStyle st;
st.active = active; st.active = active;
@ -284,16 +285,16 @@ void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool sele
availableWidth -= unreadWidth + st.padding; availableWidth -= unreadWidth + st.padding;
} }
auto &color = active ? st::dialogsTextFgServiceActive : (selected ? st::dialogsTextFgServiceOver : st::dialogsTextFgService); auto &color = active ? st::dialogsTextFgServiceActive : (selected ? st::dialogsTextFgServiceOver : st::dialogsTextFgService);
if (!history->paintSendAction(p, nameleft, texttop, availableWidth, w, color, ms)) { if (!history->paintSendAction(p, nameleft, texttop, availableWidth, fullWidth, color, ms)) {
item->drawInDialog(p, QRect(nameleft, texttop, availableWidth, st::dialogsTextFont->height), active, selected, history->textCachedFor, history->lastItemTextCache); item->drawInDialog(p, QRect(nameleft, texttop, availableWidth, st::dialogsTextFont->height), active, selected, history->textCachedFor, history->lastItemTextCache);
} }
}); });
} }
void RowPainter::paint(Painter &p, const FakeRow *row, int w, bool active, bool selected, bool onlyBackground, TimeMs ms) { void RowPainter::paint(Painter &p, const FakeRow *row, int fullWidth, bool active, bool selected, bool onlyBackground, TimeMs ms) {
auto item = row->item(); auto item = row->item();
auto history = item->history(); auto history = item->history();
paintRow(p, history, item, nullptr, item->date, w, active, selected, onlyBackground, ms, [&p, row, active, selected](int nameleft, int namewidth, HistoryItem *item) { paintRow(p, row, history, item, nullptr, item->date, fullWidth, active, selected, onlyBackground, ms, [&p, row, active, selected](int nameleft, int namewidth, HistoryItem *item) {
int lastWidth = namewidth, texttop = st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip; int lastWidth = namewidth, texttop = st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip;
item->drawInDialog(p, QRect(nameleft, texttop, lastWidth, st::dialogsTextFont->height), active, selected, row->_cacheFor, row->_cache); item->drawInDialog(p, QRect(nameleft, texttop, lastWidth, st::dialogsTextFont->height), active, selected, row->_cacheFor, row->_cache);
}); });
@ -306,8 +307,8 @@ QRect RowPainter::sendActionAnimationRect(int animationWidth, int animationHeigh
return QRect(nameleft, texttop, textUpdated ? namewidth : animationWidth, animationHeight); return QRect(nameleft, texttop, textUpdated ? namewidth : animationWidth, animationHeight);
} }
void paintImportantSwitch(Painter &p, Mode current, int w, bool selected, bool onlyBackground) { void paintImportantSwitch(Painter &p, Mode current, int fullWidth, bool selected, bool onlyBackground) {
p.fillRect(0, 0, w, st::dialogsImportantBarHeight, selected ? st::dialogsBgOver : st::dialogsBg); p.fillRect(0, 0, fullWidth, st::dialogsImportantBarHeight, selected ? st::dialogsBgOver : st::dialogsBg);
if (onlyBackground) { if (onlyBackground) {
return; return;
} }
@ -323,7 +324,7 @@ void paintImportantSwitch(Painter &p, Mode current, int w, bool selected, bool o
if (mutedHidden) { if (mutedHidden) {
if (int32 unread = App::histories().unreadMutedCount()) { if (int32 unread = App::histories().unreadMutedCount()) {
int unreadRight = w - st::dialogsPadding.x(); int unreadRight = fullWidth - st::dialogsPadding.x();
UnreadBadgeStyle st; UnreadBadgeStyle st;
st.muted = true; st.muted = true;
paintUnreadCount(p, QString::number(unread), unreadRight, unreadTop, st, nullptr); paintUnreadCount(p, QString::number(unread), unreadRight, unreadTop, st, nullptr);

View file

@ -31,13 +31,13 @@ const style::icon *ChatTypeIcon(PeerData *peer, bool active, bool selected);
class RowPainter { class RowPainter {
public: public:
static void paint(Painter &p, const Row *row, int w, bool active, bool selected, bool onlyBackground, TimeMs ms); static void paint(Painter &p, const Row *row, int fullWidth, bool active, bool selected, bool onlyBackground, TimeMs ms);
static void paint(Painter &p, const FakeRow *row, int w, bool active, bool selected, bool onlyBackground, TimeMs ms); static void paint(Painter &p, const FakeRow *row, int fullWidth, bool active, bool selected, bool onlyBackground, TimeMs ms);
static QRect sendActionAnimationRect(int animationWidth, int animationHeight, int fullWidth, bool textUpdated); static QRect sendActionAnimationRect(int animationWidth, int animationHeight, int fullWidth, bool textUpdated);
}; };
void paintImportantSwitch(Painter &p, Mode current, int w, bool selected, bool onlyBackground); void paintImportantSwitch(Painter &p, Mode current, int fullWidth, bool selected, bool onlyBackground);
enum UnreadBadgeSize { enum UnreadBadgeSize {
UnreadBadgeInDialogs = 0, UnreadBadgeInDialogs = 0,

View file

@ -201,7 +201,7 @@ bool List::del(PeerId peerId, Row *replacedBy) {
auto i = _rowByPeer.find(peerId); auto i = _rowByPeer.find(peerId);
if (i == _rowByPeer.cend()) return false; if (i == _rowByPeer.cend()) return false;
Row *row = i.value(); auto row = i.value();
if (App::main()) { if (App::main()) {
emit App::main()->dialogRowReplaced(row, replacedBy); emit App::main()->dialogRowReplaced(row, replacedBy);
} }
@ -209,7 +209,7 @@ bool List::del(PeerId peerId, Row *replacedBy) {
if (row == _current) { if (row == _current) {
_current = row->_next; _current = row->_next;
} }
for (Row *change = row->_next; change != _end; change = change->_next) { for (auto change = row->_next; change != _end; change = change->_next) {
--change->_pos; --change->_pos;
} }
--_end->_pos; --_end->_pos;

View file

@ -22,9 +22,37 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "dialogs/dialogs_row.h" #include "dialogs/dialogs_row.h"
#include "styles/style_dialogs.h" #include "styles/style_dialogs.h"
#include "ui/effects/ripple_animation.h"
#include "mainwidget.h"
namespace Dialogs { namespace Dialogs {
RippleRow::RippleRow() = default;
RippleRow::~RippleRow() = default;
void RippleRow::addRipple(QPoint origin, QSize size, base::lambda_copy<void()> &&updateCallback) {
if (!_ripple) {
auto mask = Ui::RippleAnimation::rectMask(size);
_ripple = std_::make_unique<Ui::RippleAnimation>(st::dialogsRipple, std_::move(mask), std_::move(updateCallback));
}
_ripple->add(origin);
}
void RippleRow::stopLastRipple() {
if (_ripple) {
_ripple->lastStop();
}
}
void RippleRow::paintRipple(Painter &p, int x, int y, int outerWidth, TimeMs ms, const QColor *colorOverride) const {
if (_ripple) {
_ripple->paint(p, x, y, outerWidth, ms, colorOverride);
if (_ripple->empty()) {
_ripple.reset();
}
}
}
FakeRow::FakeRow(HistoryItem *item) : _item(item), _cache(st::dialogsTextWidthMin) { FakeRow::FakeRow(HistoryItem *item) : _item(item), _cache(st::dialogsTextWidthMin) {
} }

View file

@ -25,13 +25,32 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
class History; class History;
class HistoryItem; class HistoryItem;
namespace Ui {
class RippleAnimation;
} // namespace Ui
namespace Dialogs { namespace Dialogs {
namespace Layout { namespace Layout {
class RowPainter; class RowPainter;
} // namespace Layout } // namespace Layout
class RippleRow {
public:
RippleRow();
~RippleRow();
void addRipple(QPoint origin, QSize size, base::lambda_copy<void()> &&updateCallback);
void stopLastRipple();
void paintRipple(Painter &p, int x, int y, int outerWidth, TimeMs ms, const QColor *colorOverride = nullptr) const;
private:
mutable std_::unique_ptr<Ui::RippleAnimation> _ripple;
};
class List; class List;
class Row { class Row : public RippleRow {
public: public:
Row(History *history, Row *prev, Row *next, int pos) Row(History *history, Row *prev, Row *next, int pos)
: _history(history) : _history(history)
@ -57,7 +76,7 @@ private:
}; };
class FakeRow { class FakeRow : public RippleRow {
public: public:
FakeRow(HistoryItem *item); FakeRow(HistoryItem *item);

File diff suppressed because it is too large Load diff

View file

@ -57,25 +57,24 @@ public:
void dialogsReceived(const QVector<MTPDialog> &dialogs); void dialogsReceived(const QVector<MTPDialog> &dialogs);
void addSavedPeersAfter(const QDateTime &date); void addSavedPeersAfter(const QDateTime &date);
void addAllSavedPeers(); void addAllSavedPeers();
bool searchReceived(const QVector<MTPMessage> &messages, DialogsSearchRequestType type, int32 fullCount); bool searchReceived(const QVector<MTPMessage> &result, DialogsSearchRequestType type, int32 fullCount);
void peopleReceived(const QString &query, const QVector<MTPPeer> &people); void peerSearchReceived(const QString &query, const QVector<MTPPeer> &result);
void showMore(int32 pixels); void showMore(int32 pixels);
void activate(); void activate();
void contactsReceived(const QVector<MTPContact> &contacts); void contactsReceived(const QVector<MTPContact> &result);
void selectSkip(int32 direction); void selectSkip(int32 direction);
void selectSkipPage(int32 pixels, int32 direction); void selectSkipPage(int32 pixels, int32 direction);
void createDialog(History *history); void createDialog(History *history);
void dlgUpdated(Dialogs::Mode list, Dialogs::Row *row); void dlgUpdated(Dialogs::Mode list, Dialogs::Row *row);
void dlgUpdated(History *row, MsgId msgId); void dlgUpdated(PeerData *peer, MsgId msgId);
void removeDialog(History *history); void removeDialog(History *history);
void dragLeft(); void dragLeft();
void loadPeerPhotos(int32 yFrom);
void clearFilter(); void clearFilter();
void refresh(bool toTop = false); void refresh(bool toTop = false);
@ -88,21 +87,14 @@ public:
void peerAfter(const PeerData *inPeer, MsgId inMsg, PeerData *&outPeer, MsgId &outMsg) const; void peerAfter(const PeerData *inPeer, MsgId inMsg, PeerData *&outPeer, MsgId &outMsg) const;
void scrollToPeer(const PeerId &peer, MsgId msgId); void scrollToPeer(const PeerId &peer, MsgId msgId);
typedef QVector<Dialogs::Row*> FilteredDialogs;
typedef QVector<PeerData*> PeopleResults;
typedef QVector<Dialogs::FakeRow*> SearchResults;
Dialogs::IndexedList *contactsList(); Dialogs::IndexedList *contactsList();
Dialogs::IndexedList *dialogsList(); Dialogs::IndexedList *dialogsList();
FilteredDialogs &filteredList();
PeopleResults &peopleList();
SearchResults &searchList();
int32 lastSearchDate() const; int32 lastSearchDate() const;
PeerData *lastSearchPeer() const; PeerData *lastSearchPeer() const;
MsgId lastSearchId() const; MsgId lastSearchId() const;
MsgId lastSearchMigratedId() const; MsgId lastSearchMigratedId() const;
void setMouseSel(bool msel, bool toTop = false); void setMouseSelection(bool mouseSelection, bool toTop = false);
enum State { enum State {
DefaultState = 0, DefaultState = 0,
@ -120,7 +112,10 @@ public:
PeerData *updateFromParentDrag(QPoint globalPos); PeerData *updateFromParentDrag(QPoint globalPos);
void updateNotifySettings(PeerData *peer); void setLoadMoreCallback(base::lambda<void()> &&callback) {
_loadMoreCallback = std_::move(callback);
}
void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
void notify_userIsContactChanged(UserData *user, bool fromThisApp); void notify_userIsContactChanged(UserData *user, bool fromThisApp);
void notify_historyMuteUpdated(History *history); void notify_historyMuteUpdated(History *history);
@ -128,7 +123,6 @@ public:
~DialogsInner(); ~DialogsInner();
public slots: public slots:
void onUpdateSelected(bool force = false);
void onParentGeometryChanged(); void onParentGeometryChanged();
void onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars); void onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars);
void onPeerPhotoChanged(PeerData *peer); void onPeerPhotoChanged(PeerData *peer);
@ -149,67 +143,109 @@ protected:
void paintRegion(Painter &p, const QRegion &region, bool paintingOther) override; void paintRegion(Painter &p, const QRegion &region, bool paintingOther) override;
void mouseMoveEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override;
void mousePressEvent(QMouseEvent *e) override; void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void resizeEvent(QResizeEvent *e) override; void resizeEvent(QResizeEvent *e) override;
void enterEvent(QEvent *e) override; void enterEvent(QEvent *e) override;
void leaveEvent(QEvent *e) override; void leaveEvent(QEvent *e) override;
void contextMenuEvent(QContextMenuEvent *e) override; void contextMenuEvent(QContextMenuEvent *e) override;
private: private:
struct ImportantSwitch;
using DialogsList = std_::unique_ptr<Dialogs::IndexedList>;
using FilteredDialogs = QVector<Dialogs::Row*>;
using SearchResults = std_::vector_of_moveable<std_::unique_ptr<Dialogs::FakeRow>>;
struct HashtagResult;
using HashtagResults = std_::vector_of_moveable<std_::unique_ptr<HashtagResult>>;
struct PeerSearchResult;
using PeerSearchResults = std_::vector_of_moveable<std_::unique_ptr<PeerSearchResult>>;
void mousePressReleased(Qt::MouseButton button);
void clearIrrelevantState();
void updateSelected() {
updateSelected(mapFromGlobal(QCursor::pos()));
}
void updateSelected(QPoint localPos);
void loadPeerPhotos(int visibleTop);
void setImportantSwitchPressed(bool pressed);
void setPressed(Dialogs::Row *pressed);
void setHashtagPressed(int pressed);
void setFilteredPressed(int pressed);
void setPeerSearchPressed(int pressed);
void setSearchedPressed(int pressed);
bool isPressed() const {
return _importantSwitchPressed || _pressed || (_hashtagPressed >= 0) || (_filteredPressed >= 0) || (_peerSearchPressed >= 0) || (_searchedPressed >= 0);
}
bool isSelected() const {
return _importantSwitchSelected || _selected || (_hashtagSelected >= 0) || (_filteredSelected>= 0) || (_peerSearchSelected >= 0) || (_searchedSelected >= 0);
}
void itemRemoved(HistoryItem *item); void itemRemoved(HistoryItem *item);
enum class UpdateRowSection { enum class UpdateRowSection {
Default = 0x01, Default = 0x01,
Filtered = 0x02, Filtered = 0x02,
GlobalSearch = 0x04, PeerSearch = 0x04,
MessageSearch = 0x08, MessageSearch = 0x08,
All = 0x0F, All = 0x0F,
}; };
Q_DECLARE_FLAGS(UpdateRowSections, UpdateRowSection); Q_DECLARE_FLAGS(UpdateRowSections, UpdateRowSection);
Q_DECLARE_FRIEND_OPERATORS_FOR_FLAGS(UpdateRowSections); Q_DECLARE_FRIEND_OPERATORS_FOR_FLAGS(UpdateRowSections);
void updateDialogRow(History *history, MsgId msgId, QRect updateRect, UpdateRowSections sections = UpdateRowSection::All); void updateDialogRow(PeerData *peer, MsgId msgId, QRect updateRect, UpdateRowSections sections = UpdateRowSection::All);
int dialogsOffset() const; int dialogsOffset() const;
int filteredOffset() const; int filteredOffset() const;
int peopleOffset() const; int peerSearchOffset() const;
int searchedOffset() const; int searchedOffset() const;
void peopleResultPaint(PeerData *peer, Painter &p, int32 w, bool active, bool selected, bool onlyBackground) const; void paintDialog(QPainter &p, Dialogs::Row *dialog);
void searchInPeerPaint(Painter &p, int32 w, bool onlyBackground) const; void paintPeerSearchResult(Painter &p, const PeerSearchResult *result, int32 w, bool active, bool selected, bool onlyBackground, TimeMs ms) const;
void paintSearchInPeer(Painter &p, int32 w, bool onlyBackground) const;
void clearSelection(); void clearSelection();
void clearSearchResults(bool clearPeople = true); void clearSearchResults(bool clearPeerSearchResults = true);
void updateSelectedRow(PeerData *peer = 0); void updateSelectedRow(PeerData *peer = 0);
Dialogs::IndexedList *shownDialogs() const { Dialogs::IndexedList *shownDialogs() const {
return (Global::DialogsMode() == Dialogs::Mode::Important) ? importantDialogs.get() : dialogs.get(); return (Global::DialogsMode() == Dialogs::Mode::Important) ? _dialogsImportant.get() : _dialogs.get();
} }
using DialogsList = std_::unique_ptr<Dialogs::IndexedList>; DialogsList _dialogs;
DialogsList dialogs; DialogsList _dialogsImportant;
DialogsList importantDialogs;
DialogsList contactsNoDialogs; DialogsList _contactsNoDialogs;
DialogsList contacts; DialogsList _contacts;
bool _importantSwitchSel = false; bool _mouseSelection = false;
Dialogs::Row *_sel = nullptr; Qt::MouseButton _pressButton = Qt::LeftButton;
bool _selByMouse = false;
std_::unique_ptr<ImportantSwitch> _importantSwitch;
bool _importantSwitchSelected = false;
bool _importantSwitchPressed = false;
Dialogs::Row *_selected = nullptr;
Dialogs::Row *_pressed = nullptr;
int _visibleAreaHeight = 0;
QString _filter, _hashtagFilter; QString _filter, _hashtagFilter;
QStringList _hashtagResults; HashtagResults _hashtagResults;
int _hashtagSel = -1; int _hashtagSelected = -1;
int _hashtagPressed = -1;
bool _hashtagDeleteSelected = false;
bool _hashtagDeletePressed = false;
FilteredDialogs _filterResults; FilteredDialogs _filterResults;
int _filteredSel = -1; int _filteredSelected = -1;
int _filteredPressed = -1;
QString _peerSearchQuery;
PeerSearchResults _peerSearchResults;
int _peerSearchSelected = -1;
int _peerSearchPressed = -1;
SearchResults _searchResults; SearchResults _searchResults;
int _searchedCount = 0; int _searchedCount = 0;
int _searchedMigratedCount = 0; int _searchedMigratedCount = 0;
int _searchedSel = -1; int _searchedSelected = -1;
int _searchedPressed = -1;
QString _peopleQuery;
PeopleResults _peopleResults;
int _peopleSel = -1;
int _lastSearchDate = 0; int _lastSearchDate = 0;
PeerData *_lastSearchPeer = nullptr; PeerData *_lastSearchPeer = nullptr;
@ -218,21 +254,17 @@ private:
State _state = DefaultState; State _state = DefaultState;
QPoint lastMousePos;
void paintDialog(QPainter &p, Dialogs::Row *dialog);
ChildWidget<Ui::LinkButton> _addContactLnk; ChildWidget<Ui::LinkButton> _addContactLnk;
ChildWidget<Ui::IconButton> _cancelSearchInPeer; ChildWidget<Ui::IconButton> _cancelSearchInPeer;
bool _overDelete = false;
PeerData *_searchInPeer = nullptr; PeerData *_searchInPeer = nullptr;
PeerData *_searchInMigrated = nullptr; PeerData *_searchInMigrated = nullptr;
PeerData *_menuPeer = nullptr; PeerData *_menuPeer = nullptr;
Ui::PopupMenu *_menu = nullptr; Ui::PopupMenu *_menu = nullptr;
base::lambda<void()> _loadMoreCallback;
}; };
Q_DECLARE_OPERATORS_FOR_FLAGS(DialogsInner::UpdateRowSections); Q_DECLARE_OPERATORS_FOR_FLAGS(DialogsInner::UpdateRowSections);
@ -243,27 +275,14 @@ class DialogsWidget : public TWidget, public RPCSender, private base::Subscriber
public: public:
DialogsWidget(QWidget *parent); DialogsWidget(QWidget *parent);
void dialogsReceived(const MTPmessages_Dialogs &dialogs, mtpRequestId req);
void contactsReceived(const MTPcontacts_Contacts &contacts);
void searchReceived(DialogsSearchRequestType type, const MTPmessages_Messages &result, mtpRequestId req);
void peopleReceived(const MTPcontacts_Found &result, mtpRequestId req);
void dragEnterEvent(QDragEnterEvent *e) override;
void dragMoveEvent(QDragMoveEvent *e) override;
void dragLeaveEvent(QDragLeaveEvent *e) override;
void dropEvent(QDropEvent *e) override;
void updateDragInScroll(bool inScroll); void updateDragInScroll(bool inScroll);
void resizeEvent(QResizeEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
void paintEvent(QPaintEvent *e) override;
void searchInPeer(PeerData *peer); void searchInPeer(PeerData *peer);
void loadDialogs(); void loadDialogs();
void createDialog(History *history); void createDialog(History *history);
void dlgUpdated(Dialogs::Mode list, Dialogs::Row *row); void dlgUpdated(Dialogs::Mode list, Dialogs::Row *row);
void dlgUpdated(History *row, MsgId msgId); void dlgUpdated(PeerData *peer, MsgId msgId);
void dialogsToUp(); void dialogsToUp();
@ -272,7 +291,6 @@ public:
} }
void showAnimated(Window::SlideDirection direction, const Window::SectionSlideParams &params); void showAnimated(Window::SlideDirection direction, const Window::SectionSlideParams &params);
void showFast(); void showFast();
void step_show(float64 ms, bool timer);
void destroyData(); void destroyData();
@ -321,7 +339,22 @@ private slots:
void onCheckUpdateStatus(); void onCheckUpdateStatus();
#endif // TDESKTOP_DISABLE_AUTOUPDATE #endif // TDESKTOP_DISABLE_AUTOUPDATE
protected:
void dragEnterEvent(QDragEnterEvent *e) override;
void dragMoveEvent(QDragMoveEvent *e) override;
void dragLeaveEvent(QDragLeaveEvent *e) override;
void dropEvent(QDropEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
void paintEvent(QPaintEvent *e) override;
private: private:
void animationCallback();
void dialogsReceived(const MTPmessages_Dialogs &dialogs, mtpRequestId req);
void contactsReceived(const MTPcontacts_Contacts &result);
void searchReceived(DialogsSearchRequestType type, const MTPmessages_Messages &result, mtpRequestId req);
void peerSearchReceived(const MTPcontacts_Found &result, mtpRequestId req);
void setSearchInPeer(PeerData *peer); void setSearchInPeer(PeerData *peer);
void showMainMenu(); void showMainMenu();
void updateLockUnlockVisibility(); void updateLockUnlockVisibility();
@ -354,31 +387,34 @@ private:
ChildWidget<DialogsInner> _inner; ChildWidget<DialogsInner> _inner;
ChildWidget<Ui::FlatButton> _updateTelegram = { nullptr }; ChildWidget<Ui::FlatButton> _updateTelegram = { nullptr };
Animation _a_show; FloatAnimation _a_show;
Window::SlideDirection _showDirection;
QPixmap _cacheUnder, _cacheOver; QPixmap _cacheUnder, _cacheOver;
anim::ivalue a_coordUnder, a_coordOver;
anim::fvalue a_progress;
PeerData *_searchInPeer = nullptr; PeerData *_searchInPeer = nullptr;
PeerData *_searchInMigrated = nullptr; PeerData *_searchInMigrated = nullptr;
QTimer _searchTimer; QTimer _searchTimer;
QString _searchQuery, _peopleQuery;
QString _peerSearchQuery;
bool _peerSearchFull = false;
mtpRequestId _peerSearchRequest = 0;
QString _searchQuery;
bool _searchFull = false; bool _searchFull = false;
bool _searchFullMigrated = false; bool _searchFullMigrated = false;
bool _peopleFull = false; mtpRequestId _searchRequest = 0;
mtpRequestId _searchRequest, _peopleRequest;
typedef QMap<QString, MTPmessages_Messages> SearchCache; using SearchCache = QMap<QString, MTPmessages_Messages>;
SearchCache _searchCache; SearchCache _searchCache;
typedef QMap<mtpRequestId, QString> SearchQueries; using SearchQueries = QMap<mtpRequestId, QString>;
SearchQueries _searchQueries; SearchQueries _searchQueries;
typedef QMap<QString, MTPcontacts_Found> PeopleCache; using PeerSearchCache = QMap<QString, MTPcontacts_Found>;
PeopleCache _peopleCache; PeerSearchCache _peerSearchCache;
typedef QMap<mtpRequestId, QString> PeopleQueries; using PeerSearchQueries = QMap<mtpRequestId, QString>;
PeopleQueries _peopleQueries; PeerSearchQueries _peerSearchQueries;
}; };

View file

@ -395,7 +395,7 @@ void FieldAutocomplete::hideFast() {
if (_a_appearance.animating()) { if (_a_appearance.animating()) {
_a_appearance.stop(); _a_appearance.stop();
} }
a_opacity = anim::fvalue(0, 0); a_opacity = anim::value();
hideFinish(); hideFinish();
} }

View file

@ -131,7 +131,7 @@ private:
int32 _width, _height; int32 _width, _height;
bool _hiding = false; bool _hiding = false;
anim::fvalue a_opacity; anim::value a_opacity;
Animation _a_appearance; Animation _a_appearance;
friend class internal::FieldAutocompleteInner; friend class internal::FieldAutocompleteInner;

View file

@ -240,8 +240,6 @@ historyAttachEmoji: IconButton(historyAttach) {
icon: icon {{ "send_control_emoji", historyComposeIconFg }}; icon: icon {{ "send_control_emoji", historyComposeIconFg }};
iconOver: icon {{ "send_control_emoji", historyComposeIconFgOver }}; iconOver: icon {{ "send_control_emoji", historyComposeIconFgOver }};
iconPosition: point(15px, 15px); iconPosition: point(15px, 15px);
ripple: emptyRippleAnimation;
} }
historyEmojiCircle: size(20px, 20px); historyEmojiCircle: size(20px, 20px);
historyEmojiCirclePeriod: 1500; historyEmojiCirclePeriod: 1500;
@ -251,16 +249,16 @@ historyEmojiCircleLine: 2px;
historyEmojiCircleFg: historyComposeIconFg; historyEmojiCircleFg: historyComposeIconFg;
historyEmojiCircleFgOver: historyComposeIconFgOver; historyEmojiCircleFgOver: historyComposeIconFgOver;
historyEmojiCirclePart: 3.5; historyEmojiCirclePart: 3.5;
historyBotKeyboardShow: IconButton(historySend) { historyBotKeyboardShow: IconButton(historyAttach) {
icon: icon {{ "send_control_bot_keyboard", historyComposeIconFg }}; icon: icon {{ "send_control_bot_keyboard", historyComposeIconFg }};
iconOver: icon {{ "send_control_bot_keyboard", historyComposeIconFgOver }}; iconOver: icon {{ "send_control_bot_keyboard", historyComposeIconFgOver }};
} }
historyBotKeyboardHide: IconButton(historySend) { historyBotKeyboardHide: IconButton(historyAttach) {
icon: icon {{ "send_control_bot_keyboard_hide", historyComposeIconFg }}; icon: icon {{ "send_control_bot_keyboard_hide", historyComposeIconFg }};
iconOver: icon {{ "send_control_bot_keyboard_hide", historyComposeIconFgOver }}; iconOver: icon {{ "send_control_bot_keyboard_hide", historyComposeIconFgOver }};
iconPosition: point(11px, 16px); iconPosition: point(11px, 16px);
} }
historyBotCommandStart: IconButton(historySend) { historyBotCommandStart: IconButton(historyAttach) {
icon: icon {{ "send_control_bot_command", historyComposeIconFg }}; icon: icon {{ "send_control_bot_command", historyComposeIconFg }};
iconOver: icon {{ "send_control_bot_command", historyComposeIconFgOver }}; iconOver: icon {{ "send_control_bot_command", historyComposeIconFgOver }};
} }
@ -270,6 +268,7 @@ historyRecordVoiceFgActive: windowBgActive;
historyRecordVoice: icon {{ "send_control_record", historyRecordVoiceFg }}; historyRecordVoice: icon {{ "send_control_record", historyRecordVoiceFg }};
historyRecordVoiceOver: icon {{ "send_control_record", historyRecordVoiceFgOver }}; historyRecordVoiceOver: icon {{ "send_control_record", historyRecordVoiceFgOver }};
historyRecordVoiceActive: icon {{ "send_control_record", historyRecordVoiceFgActive }}; historyRecordVoiceActive: icon {{ "send_control_record", historyRecordVoiceFgActive }};
historyRecordVoiceRippleBgActive: lightButtonBgOver;
historyRecordSignalColor: #f17077; historyRecordSignalColor: #f17077;
historyRecordSignalMin: 5px; historyRecordSignalMin: 5px;
historyRecordSignalMax: 12px; historyRecordSignalMax: 12px;

View file

@ -133,14 +133,14 @@ void DragArea::hideFast() {
if (_a_appearance.animating()) { if (_a_appearance.animating()) {
_a_appearance.stop(); _a_appearance.stop();
} }
a_opacity = anim::fvalue(0, 0); a_opacity = anim::value();
hide(); hide();
} }
void DragArea::hideStart() { void DragArea::hideStart() {
_hiding = true; _hiding = true;
_in = false; _in = false;
a_opacity.start(0); a_opacity.start(0.);
a_colorDrop.start(_in ? 1. : 0.); a_colorDrop.start(_in ? 1. : 0.);
_a_appearance.start(); _a_appearance.start();
} }
@ -148,7 +148,7 @@ void DragArea::hideStart() {
void DragArea::hideFinish() { void DragArea::hideFinish() {
hide(); hide();
_in = false; _in = false;
a_colorDrop = anim::fvalue(0.); a_colorDrop = anim::value();
} }
void DragArea::showStart() { void DragArea::showStart() {

View file

@ -70,8 +70,8 @@ private:
bool _hiding, _in; bool _hiding, _in;
base::lambda<void(const QMimeData *data)> _droppedCallback; base::lambda<void(const QMimeData *data)> _droppedCallback;
anim::fvalue a_opacity; anim::value a_opacity;
anim::fvalue a_colorDrop; anim::value a_colorDrop;
Animation _a_appearance; Animation _a_appearance;
Ui::RectShadow _shadow; Ui::RectShadow _shadow;

View file

@ -584,7 +584,7 @@ void HistoryItem::finishCreate() {
void HistoryItem::finishEdition(int oldKeyboardTop) { void HistoryItem::finishEdition(int oldKeyboardTop) {
setPendingInitDimensions(); setPendingInitDimensions();
if (App::main()) { if (App::main()) {
App::main()->dlgUpdated(history(), id); App::main()->dlgUpdated(history()->peer, id);
} }
// invalidate cache for drawInDialog // invalidate cache for drawInDialog

View file

@ -1456,7 +1456,7 @@ bool HistoryDocument::updateStatusText() const {
if (voice->_playback->_position < playbackState.position) { if (voice->_playback->_position < playbackState.position) {
voice->_playback->a_progress.start(prg); voice->_playback->a_progress.start(prg);
} else { } else {
voice->_playback->a_progress = anim::fvalue(0., prg); voice->_playback->a_progress = anim::value(0., prg);
} }
voice->_playback->_position = playbackState.position; voice->_playback->_position = playbackState.position;
voice->_playback->_a_progress.start(); voice->_playback->_a_progress.start();

View file

@ -99,7 +99,7 @@ protected:
, _a_thumbOver(std_::move(thumbOverCallbacks)) , _a_thumbOver(std_::move(thumbOverCallbacks))
, radial(std_::move(radialCallbacks)) { , radial(std_::move(radialCallbacks)) {
} }
anim::fvalue a_thumbOver; anim::value a_thumbOver;
Animation _a_thumbOver; Animation _a_thumbOver;
Ui::RadialAnimation radial; Ui::RadialAnimation radial;
@ -306,7 +306,7 @@ struct HistoryDocumentVoicePlayback {
HistoryDocumentVoicePlayback(const HistoryDocument *that); HistoryDocumentVoicePlayback(const HistoryDocument *that);
int32 _position; int32 _position;
anim::fvalue a_progress; anim::value a_progress;
Animation _a_progress; Animation _a_progress;
}; };
struct HistoryDocumentVoice : public RuntimeComponent<HistoryDocumentVoice> { struct HistoryDocumentVoice : public RuntimeComponent<HistoryDocumentVoice> {

View file

@ -2329,7 +2329,7 @@ bool HistoryService::updateDependentText() {
history()->textCachedFor = 0; history()->textCachedFor = 0;
} }
if (App::main()) { if (App::main()) {
App::main()->dlgUpdated(history(), id); App::main()->dlgUpdated(history()->peer, id);
} }
App::historyUpdateDependent(this); App::historyUpdateDependent(this);
return result; return result;

View file

@ -34,6 +34,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/inner_dropdown.h" #include "ui/widgets/inner_dropdown.h"
#include "ui/widgets/dropdown_menu.h" #include "ui/widgets/dropdown_menu.h"
#include "ui/effects/ripple_animation.h"
#include "inline_bots/inline_bot_result.h" #include "inline_bots/inline_bot_result.h"
#include "data/data_drafts.h" #include "data/data_drafts.h"
#include "history/history_service_layout.h" #include "history/history_service_layout.h"
@ -2971,7 +2972,7 @@ void SilentToggle::mouseMoveEvent(QMouseEvent *e) {
void SilentToggle::setChecked(bool checked) { void SilentToggle::setChecked(bool checked) {
if (_checked != checked) { if (_checked != checked) {
_checked = checked; _checked = checked;
setIcon(_checked ? &st::historySilentToggleOn : nullptr, _checked ? &st::historySilentToggleOnOver : nullptr); setIconOverride(_checked ? &st::historySilentToggleOn : nullptr, _checked ? &st::historySilentToggleOnOver : nullptr);
} }
} }
@ -3051,9 +3052,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
, _botCommandStart(this, st::historyBotCommandStart) , _botCommandStart(this, st::historyBotCommandStart)
, _silent(this) , _silent(this)
, _field(this, st::historyComposeField, lang(lng_message_ph)) , _field(this, st::historyComposeField, lang(lng_message_ph))
, _a_record(animation(this, &HistoryWidget::step_record))
, _a_recording(animation(this, &HistoryWidget::step_recording)) , _a_recording(animation(this, &HistoryWidget::step_recording))
, a_recordCancelActive(0, 0)
, _recordCancelWidth(st::historyRecordFont->width(lang(lng_record_cancel))) , _recordCancelWidth(st::historyRecordFont->width(lang(lng_record_cancel)))
, _kbScroll(this, st::botKbScroll) , _kbScroll(this, st::botKbScroll)
, _keyboard(this) , _keyboard(this)
@ -3061,7 +3060,6 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
, _attachDragDocument(this) , _attachDragDocument(this)
, _attachDragPhoto(this) , _attachDragPhoto(this)
, _fileLoader(this, FileLoaderQueueStopTimeout) , _fileLoader(this, FileLoaderQueueStopTimeout)
, _a_show(animation(this, &HistoryWidget::step_show))
, _topShadow(this, st::shadowColor) { , _topShadow(this, st::shadowColor) {
setAcceptDrops(true); setAcceptDrops(true);
@ -3318,10 +3316,8 @@ void HistoryWidget::onTextChange() {
_send->show(); _send->show();
} }
updateMouseTracking(); updateMouseTracking();
_a_record.stop(); _a_recordActive.finish();
_inRecord = _inField = false; _inRecord = _inField = false;
a_recordDown = anim::fvalue(0, 0);
a_recordCancelActive = anim::fvalue(0, 0);
} }
} }
if (updateCmdStartShown()) { if (updateCmdStartShown()) {
@ -4197,7 +4193,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
historyLoaded(); historyLoaded();
} }
App::main()->dlgUpdated(wasHistory, wasMsgId); App::main()->dlgUpdated(wasHistory ? wasHistory->peer : nullptr, wasMsgId);
emit historyShown(_history, _showAtMsgId); emit historyShown(_history, _showAtMsgId);
App::main()->topBar()->update(); App::main()->topBar()->update();
@ -4358,7 +4354,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
if (App::wnd()) QTimer::singleShot(0, App::wnd(), SLOT(setInnerFocus())); if (App::wnd()) QTimer::singleShot(0, App::wnd(), SLOT(setInnerFocus()));
App::main()->dlgUpdated(wasHistory, wasMsgId); App::main()->dlgUpdated(wasHistory ? wasHistory->peer : nullptr, wasMsgId);
emit historyShown(_history, _showAtMsgId); emit historyShown(_history, _showAtMsgId);
App::main()->historyPeerChanged().notify(_peer, true); App::main()->historyPeerChanged().notify(_peer, true);
@ -4650,7 +4646,7 @@ void HistoryWidget::updateControlsVisibility() {
} else { } else {
_send->show(); _send->show();
} }
_a_record.stop(); _a_recordActive.finish();
_inRecord = _inField = false; _inRecord = _inField = false;
} }
if (_recording) { if (_recording) {
@ -5441,9 +5437,9 @@ PeerData *HistoryWidget::peer() const {
void HistoryWidget::setMsgId(MsgId showAtMsgId) { // sometimes _showAtMsgId is set directly void HistoryWidget::setMsgId(MsgId showAtMsgId) { // sometimes _showAtMsgId is set directly
if (_showAtMsgId != showAtMsgId) { if (_showAtMsgId != showAtMsgId) {
MsgId wasMsgId = _showAtMsgId; auto wasMsgId = _showAtMsgId;
_showAtMsgId = showAtMsgId; _showAtMsgId = showAtMsgId;
App::main()->dlgUpdated(_history, wasMsgId); App::main()->dlgUpdated(_history ? _history->peer : nullptr, wasMsgId);
emit historyShown(_history, _showAtMsgId); emit historyShown(_history, _showAtMsgId);
} }
} }
@ -5453,7 +5449,9 @@ MsgId HistoryWidget::msgId() const {
} }
void HistoryWidget::showAnimated(Window::SlideDirection direction, const Window::SectionSlideParams &params) { void HistoryWidget::showAnimated(Window::SlideDirection direction, const Window::SectionSlideParams &params) {
if (App::app()) App::app()->mtpPause(); _showDirection = direction;
_a_show.finish();
_cacheUnder = params.oldContentCache; _cacheUnder = params.oldContentCache;
show(); show();
@ -5487,47 +5485,26 @@ void HistoryWidget::showAnimated(Window::SlideDirection direction, const Window:
_pinnedBar->cancel->hide(); _pinnedBar->cancel->hide();
} }
int delta = st::slideShift; if (_showDirection == Window::SlideDirection::FromLeft) {
if (direction == Window::SlideDirection::FromLeft) {
a_progress = anim::fvalue(1, 0);
std::swap(_cacheUnder, _cacheOver); std::swap(_cacheUnder, _cacheOver);
a_coordUnder = anim::ivalue(-delta, 0);
a_coordOver = anim::ivalue(0, width());
} else {
a_progress = anim::fvalue(0, 1);
a_coordUnder = anim::ivalue(0, -delta);
a_coordOver = anim::ivalue(width(), 0);
} }
_a_show.start(); _a_show.start([this] { animationCallback(); }, 0., 1., st::slideDuration, Window::SlideAnimation::transition());
App::main()->topBar()->update(); App::main()->topBar()->update();
activate(); activate();
} }
void HistoryWidget::step_show(float64 ms, bool timer) { void HistoryWidget::animationCallback() {
float64 dt = ms / st::slideDuration; update();
if (dt >= 1) { App::main()->topBar()->update();
_a_show.stop(); if (!_a_show.animating()) {
_topShadow->setVisible(_peer ? true : false); _topShadow->setVisible(_peer ? true : false);
_historyToEnd->finishAnimation(); _historyToEnd->finishAnimation();
a_coordUnder.finish();
a_coordOver.finish();
a_progress.finish();
_cacheUnder = _cacheOver = QPixmap(); _cacheUnder = _cacheOver = QPixmap();
App::main()->topBar()->stopAnim(); App::main()->topBar()->stopAnim();
doneShow(); doneShow();
if (App::app()) App::app()->mtpUnpause();
} else {
a_coordUnder.update(dt, Window::SlideAnimation::transition());
a_coordOver.update(dt, Window::SlideAnimation::transition());
a_progress.update(dt, Window::SlideAnimation::transition());
}
if (timer) {
update();
App::main()->topBar()->update();
} }
} }
@ -5547,29 +5524,21 @@ void HistoryWidget::doneShow() {
} }
} }
void HistoryWidget::animStop() { void HistoryWidget::finishAnimation() {
if (!_a_show.animating()) return; if (!_a_show.animating()) return;
_a_show.stop(); _a_show.finish();
_topShadow->setVisible(_peer ? true : false); _topShadow->setVisible(_peer ? true : false);
_historyToEnd->finishAnimation(); _historyToEnd->finishAnimation();
} }
void HistoryWidget::step_record(float64 ms, bool timer) { void HistoryWidget::recordActiveCallback() {
float64 dt = ms / st::historyComposeButton.duration; if (_recording) {
if (dt >= 1 || !_send->isHidden() || (_inlineBotCancel && !_inlineBotCancel->isHidden()) || isBotStart() || isBlocked()) { updateField();
_a_record.stop();
a_recordDown.finish();
a_recordCancelActive.finish();
} else { } else {
a_recordDown.update(dt, anim::linear); update(_send->geometry());
a_recordCancelActive.update(dt, anim::linear);
} }
if (timer) { if (!_send->isHidden() || (_inlineBotCancel && !_inlineBotCancel->isHidden()) || isBotStart() || isBlocked()) {
if (_recording) { _a_recordActive.finish();
updateField();
} else {
update(_send->geometry());
}
} }
} }
@ -5665,9 +5634,7 @@ void HistoryWidget::mouseMoveEvent(QMouseEvent *e) {
} }
if (inField != _inField && _recording) { if (inField != _inField && _recording) {
_inField = inField; _inField = inField;
a_recordDown.start(_inField ? 1 : 0); _a_recordActive.start([this] { recordActiveCallback(); }, _inField ? 0. : 1., _inField ? 1. : 0., st::historyComposeButton.duration);
a_recordCancelActive.start(_inField ? 0. : 1.);
_a_record.start();
} }
_inReplyEdit = inReplyEdit; _inReplyEdit = inReplyEdit;
_inPinnedMsg = inPinnedMsg; _inPinnedMsg = inPinnedMsg;
@ -5698,7 +5665,7 @@ void HistoryWidget::mouseReleaseEvent(QMouseEvent *e) {
void HistoryWidget::stopRecording(bool send) { void HistoryWidget::stopRecording(bool send) {
emit audioCapture()->stop(send); emit audioCapture()->stop(send);
a_recordingLevel = anim::ivalue(0, 0); a_recordingLevel = anim::value();
_a_recording.stop(); _a_recording.stop();
_recording = false; _recording = false;
@ -5712,9 +5679,13 @@ void HistoryWidget::stopRecording(bool send) {
updateField(); updateField();
a_recordDown.start(0); if (_inField) {
a_recordCancelActive = anim::fvalue(0., 0.); _a_recordActive.start([this] { recordActiveCallback(); }, 1., 0., st::historyComposeButton.duration);
_a_record.start(); }
if (_recordRipple) {
_recordRipple->lastStop();
}
} }
void HistoryWidget::sendBotCommand(PeerData *peer, UserData *bot, const QString &cmd, MsgId replyTo) { // replyTo != 0 from ReplyKeyboardMarkup, == 0 from cmd links void HistoryWidget::sendBotCommand(PeerData *peer, UserData *bot, const QString &cmd, MsgId replyTo) { // replyTo != 0 from ReplyKeyboardMarkup, == 0 from cmd links
@ -6202,16 +6173,21 @@ void HistoryWidget::onForwardHere() {
bool HistoryWidget::paintTopBar(Painter &p, int decreaseWidth, TimeMs ms) { bool HistoryWidget::paintTopBar(Painter &p, int decreaseWidth, TimeMs ms) {
if (_a_show.animating()) { if (_a_show.animating()) {
int retina = cIntRetinaFactor(); auto progress = _a_show.current(1.);
if (a_coordOver.current() > 0) { auto retina = cIntRetinaFactor();
p.drawPixmap(QRect(0, 0, a_coordOver.current(), st::topBarHeight), _cacheUnder, QRect(-a_coordUnder.current() * retina, 0, a_coordOver.current() * retina, st::topBarHeight * retina)); auto fromLeft = (_showDirection == Window::SlideDirection::FromLeft);
p.setOpacity(a_progress.current()); auto coordUnder = fromLeft ? anim::interpolate(-st::slideShift, 0, progress) : anim::interpolate(0, -st::slideShift, progress);
p.fillRect(0, 0, a_coordOver.current(), st::topBarHeight, st::slideFadeOutBg); auto coordOver = fromLeft ? anim::interpolate(0, width(), progress) : anim::interpolate(width(), 0, progress);
auto shadow = fromLeft ? (1. - progress) : progress;
if (coordOver > 0) {
p.drawPixmap(QRect(0, 0, coordOver, st::topBarHeight), _cacheUnder, QRect(-coordUnder * retina, 0, coordOver * retina, st::topBarHeight * retina));
p.setOpacity(shadow);
p.fillRect(0, 0, coordOver, st::topBarHeight, st::slideFadeOutBg);
p.setOpacity(1); p.setOpacity(1);
} }
p.drawPixmap(QRect(a_coordOver.current(), 0, _cacheOver.width() / retina, st::topBarHeight), _cacheOver, QRect(0, 0, _cacheOver.width(), st::topBarHeight * retina)); p.drawPixmap(QRect(coordOver, 0, _cacheOver.width() / retina, st::topBarHeight), _cacheOver, QRect(0, 0, _cacheOver.width(), st::topBarHeight * retina));
p.setOpacity(a_progress.current()); p.setOpacity(shadow);
st::slideShadow.fill(p, QRect(a_coordOver.current() - st::slideShadow.width(), 0, st::slideShadow.width(), st::topBarHeight)); st::slideShadow.fill(p, QRect(coordOver - st::slideShadow.width(), 0, st::slideShadow.width(), st::topBarHeight));
return false; return false;
} }
@ -6481,14 +6457,14 @@ void HistoryWidget::onCheckFieldAutocomplete() {
void HistoryWidget::updateFieldPlaceholder() { void HistoryWidget::updateFieldPlaceholder() {
if (_editMsgId) { if (_editMsgId) {
_field->setPlaceholder(lang(lng_edit_message_text)); _field->setPlaceholder(lang(lng_edit_message_text));
_send->setIcon(&st::historyEditSaveIcon, &st::historyEditSaveIconOver); _send->setIconOverride(&st::historyEditSaveIcon, &st::historyEditSaveIconOver);
} else { } else {
if (_inlineBot && _inlineBot != Ui::LookingUpInlineBot) { if (_inlineBot && _inlineBot != Ui::LookingUpInlineBot) {
_field->setPlaceholder(_inlineBot->botInfo->inlinePlaceholder.mid(1), _inlineBot->username.size() + 2); _field->setPlaceholder(_inlineBot->botInfo->inlinePlaceholder.mid(1), _inlineBot->username.size() + 2);
} else { } else {
_field->setPlaceholder(lang((_history && _history->isChannel() && !_history->isMegagroup()) ? (_silent->checked() ? lng_broadcast_silent_ph : lng_broadcast_ph) : lng_message_ph)); _field->setPlaceholder(lang((_history && _history->isChannel() && !_history->isMegagroup()) ? (_silent->checked() ? lng_broadcast_silent_ph : lng_broadcast_ph) : lng_message_ph));
} }
_send->setIcon(nullptr); _send->setIconOverride(nullptr);
} }
} }
@ -7511,8 +7487,13 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) {
updateField(); updateField();
a_recordDown.start(1); _a_recordActive.start([this] { recordActiveCallback(); }, 0., 1., st::historyComposeButton.duration);
_a_record.start();
if (!_recordRipple) {
auto mask = Ui::RippleAnimation::ellipseMask(QSize(st::historyAttachEmoji.rippleAreaSize, st::historyAttachEmoji.rippleAreaSize));
_recordRipple = std_::make_unique<Ui::RippleAnimation>(st::historyAttachEmoji.ripple, std_::move(mask), [this] { update(_send->geometry()); });
}
_recordRipple->add(mapFromGlobal(QCursor::pos()) - QPoint(_send->x() + (_send->width() - st::historyAttachEmoji.rippleAreaSize) / 2, _send->y() + st::historyAttachEmoji.rippleAreaPosition.y()));
} else if (_inReplyEdit) { } else if (_inReplyEdit) {
Ui::showPeerHistory(_peer, _editMsgId ? _editMsgId : replyToId()); Ui::showPeerHistory(_peer, _editMsgId ? _editMsgId : replyToId());
} else if (_inPinnedMsg) { } else if (_inPinnedMsg) {
@ -8582,7 +8563,7 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
Text *from = 0, *text = 0; Text *from = 0, *text = 0;
bool serviceColor = false, hasForward = readyToForward(); bool serviceColor = false, hasForward = readyToForward();
ImagePtr preview; ImagePtr preview;
HistoryItem *drawMsgText = (_editMsgId || _replyToId) ? _replyEditMsg : _kbReplyTo; auto drawMsgText = (_editMsgId || _replyToId) ? _replyEditMsg : _kbReplyTo;
if (_editMsgId || _replyToId || (!hasForward && _kbReplyTo)) { if (_editMsgId || _replyToId || (!hasForward && _kbReplyTo)) {
if (!_editMsgId && drawMsgText && drawMsgText->author()->nameVersion > _replyToNameVersion) { if (!_editMsgId && drawMsgText && drawMsgText->author()->nameVersion > _replyToNameVersion) {
updateReplyToName(); updateReplyToName();
@ -8718,10 +8699,16 @@ void HistoryWidget::paintEditHeader(Painter &p, const QRect &rect, int left, int
} }
} }
void HistoryWidget::drawRecordButton(Painter &p) { void HistoryWidget::drawRecordButton(Painter &p, float64 recordActive, TimeMs ms) {
auto down = a_recordDown.current(); if (_recordRipple) {
auto fastIcon = [down, this] { auto rippleColor = anim::color(st::historyAttachEmoji.ripple.color, st::historyRecordVoiceRippleBgActive, recordActive);
if (down == 1.) { _recordRipple->paint(p, _send->x() + (_send->width() - st::historyAttachEmoji.rippleAreaSize) / 2, _send->y() + st::historyAttachEmoji.rippleAreaPosition.y(), width(), ms, &rippleColor);
if (_recordRipple->empty()) {
_recordRipple.reset();
}
}
auto fastIcon = [recordActive, this] {
if (recordActive == 1.) {
return &st::historyRecordVoiceActive; return &st::historyRecordVoiceActive;
} else if (_inRecord) { } else if (_inRecord) {
return &st::historyRecordVoiceOver; return &st::historyRecordVoiceOver;
@ -8729,19 +8716,19 @@ void HistoryWidget::drawRecordButton(Painter &p) {
return &st::historyRecordVoice; return &st::historyRecordVoice;
}; };
fastIcon()->paintInCenter(p, _send->geometry()); fastIcon()->paintInCenter(p, _send->geometry());
if (down > 0. && down < 1.) { if (recordActive > 0. && recordActive < 1.) {
p.setOpacity(down); p.setOpacity(recordActive);
st::historyRecordVoiceActive.paintInCenter(p, _send->geometry()); st::historyRecordVoiceActive.paintInCenter(p, _send->geometry());
p.setOpacity(1.); p.setOpacity(1.);
} }
} }
void HistoryWidget::drawRecording(Painter &p) { void HistoryWidget::drawRecording(Painter &p, float64 recordActive) {
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.setBrush(st::historyRecordSignalColor); p.setBrush(st::historyRecordSignalColor);
float64 delta = qMin(float64(a_recordingLevel.current()) / 0x4000, 1.); auto delta = qMin(a_recordingLevel.current() / 0x4000, 1.);
int32 d = 2 * qRound(st::historyRecordSignalMin + (delta * (st::historyRecordSignalMax - st::historyRecordSignalMin))); auto d = 2 * qRound(st::historyRecordSignalMin + (delta * (st::historyRecordSignalMax - st::historyRecordSignalMin)));
{ {
PainterHighQualityEnabler hq(p); PainterHighQualityEnabler hq(p);
p.drawEllipse(_attachToggle->x() + (_attachEmoji->width() - d) / 2, _attachToggle->y() + (_attachToggle->height() - d) / 2, d, d); p.drawEllipse(_attachToggle->x() + (_attachEmoji->width() - d) / 2, _attachToggle->y() + (_attachToggle->height() - d) / 2, d, d);
@ -8756,7 +8743,7 @@ void HistoryWidget::drawRecording(Painter &p) {
int32 left = _attachToggle->x() + _attachEmoji->width() + st::historyRecordFont->width(duration) + ((_send->width() - st::historyRecordVoice.width()) / 2); int32 left = _attachToggle->x() + _attachEmoji->width() + st::historyRecordFont->width(duration) + ((_send->width() - st::historyRecordVoice.width()) / 2);
int32 right = width() - _send->width(); int32 right = width() - _send->width();
p.setPen(anim::pen(st::historyRecordCancel, st::historyRecordCancelActive, a_recordCancelActive.current())); p.setPen(anim::pen(st::historyRecordCancel, st::historyRecordCancelActive, 1. - recordActive));
p.drawText(left + (right - left - _recordCancelWidth) / 2, _attachToggle->y() + st::historyRecordTextTop + st::historyRecordFont->ascent, lang(lng_record_cancel)); p.drawText(left + (right - left - _recordCancelWidth) / 2, _attachToggle->y() + st::historyRecordTextTop + st::historyRecordFont->ascent, lang(lng_record_cancel));
} }
@ -8809,18 +8796,24 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
} }
bool hasTopBar = !App::main()->topBar()->isHidden(); bool hasTopBar = !App::main()->topBar()->isHidden();
auto ms = getms();
auto progress = _a_show.current(ms, 1.);
if (_a_show.animating()) { if (_a_show.animating()) {
int retina = cIntRetinaFactor(); auto retina = cIntRetinaFactor();
int inCacheTop = hasTopBar ? st::topBarHeight : 0; auto inCacheTop = hasTopBar ? st::topBarHeight : 0;
if (a_coordOver.current() > 0) { auto fromLeft = (_showDirection == Window::SlideDirection::FromLeft);
p.drawPixmap(QRect(0, 0, a_coordOver.current(), height()), _cacheUnder, QRect(-a_coordUnder.current() * retina, inCacheTop * retina, a_coordOver.current() * retina, height() * retina)); auto coordUnder = fromLeft ? anim::interpolate(-st::slideShift, 0, progress) : anim::interpolate(0, -st::slideShift, progress);
p.setOpacity(a_progress.current()); auto coordOver = fromLeft ? anim::interpolate(0, width(), progress) : anim::interpolate(width(), 0, progress);
p.fillRect(0, 0, a_coordOver.current(), height(), st::slideFadeOutBg); auto shadow = fromLeft ? (1. - progress) : progress;
if (coordOver > 0) {
p.drawPixmap(QRect(0, 0, coordOver, height()), _cacheUnder, QRect(-coordUnder * retina, inCacheTop * retina, coordOver * retina, height() * retina));
p.setOpacity(shadow);
p.fillRect(0, 0, coordOver, height(), st::slideFadeOutBg);
p.setOpacity(1); p.setOpacity(1);
} }
p.drawPixmap(QRect(a_coordOver.current(), 0, _cacheOver.width() / retina, height()), _cacheOver, QRect(0, inCacheTop * retina, _cacheOver.width(), height() * retina)); p.drawPixmap(QRect(coordOver, 0, _cacheOver.width() / retina, height()), _cacheOver, QRect(0, inCacheTop * retina, _cacheOver.width(), height() * retina));
p.setOpacity(a_progress.current()); p.setOpacity(shadow);
st::slideShadow.fill(p, QRect(a_coordOver.current() - st::slideShadow.width(), 0, st::slideShadow.width(), height())); st::slideShadow.fill(p, QRect(coordOver - st::slideShadow.width(), 0, st::slideShadow.width(), height()));
return; return;
} }
@ -8854,8 +8847,9 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
if (!_field->isHidden() || _recording) { if (!_field->isHidden() || _recording) {
drawField(p, r); drawField(p, r);
if (_send->isHidden() && (!_inlineBotCancel || _inlineBotCancel->isHidden())) { if (_send->isHidden() && (!_inlineBotCancel || _inlineBotCancel->isHidden())) {
drawRecordButton(p); auto recordActive = _a_recordActive.current(ms, _inField ? 1. : 0.);
if (_recording) drawRecording(p); drawRecordButton(p, recordActive, ms);
if (_recording) drawRecording(p, recordActive);
} }
} }
if (_pinnedBar && !_pinnedBar->cancel->isHidden()) { if (_pinnedBar && !_pinnedBar->cancel->isHidden()) {

View file

@ -510,7 +510,7 @@ private:
ChildWidget<Ui::RoundButton> _cancel; ChildWidget<Ui::RoundButton> _cancel;
PeerData *_offered = nullptr; PeerData *_offered = nullptr;
anim::fvalue a_opacity; anim::value a_opacity;
Animation _a_appearance; Animation _a_appearance;
QRect _box; QRect _box;
@ -613,8 +613,7 @@ public:
return peer() != nullptr; return peer() != nullptr;
} }
void showAnimated(Window::SlideDirection direction, const Window::SectionSlideParams &params); void showAnimated(Window::SlideDirection direction, const Window::SectionSlideParams &params);
void step_show(float64 ms, bool timer); void finishAnimation();
void animStop();
void doneShow(); void doneShow();
@ -650,7 +649,6 @@ public:
void updatePreview(); void updatePreview();
void previewCancel(); void previewCancel();
void step_record(float64 ms, bool timer);
void step_recording(float64 ms, bool timer); void step_recording(float64 ms, bool timer);
void stopRecording(bool send); void stopRecording(bool send);
@ -849,6 +847,8 @@ private slots:
void updateField(); void updateField();
private: private:
void animationCallback();
void recordActiveCallback();
void chooseAttach(); void chooseAttach();
void notifyFileQueryUpdated(const FileDialog::QueryUpdate &update); void notifyFileQueryUpdated(const FileDialog::QueryUpdate &update);
struct SendingFilesLists { struct SendingFilesLists {
@ -931,8 +931,8 @@ private:
void drawField(Painter &p, const QRect &rect); void drawField(Painter &p, const QRect &rect);
void paintEditHeader(Painter &p, const QRect &rect, int left, int top) const; void paintEditHeader(Painter &p, const QRect &rect, int left, int top) const;
void drawRecordButton(Painter &p); void drawRecordButton(Painter &p, float64 recordActive, TimeMs ms);
void drawRecording(Painter &p); void drawRecording(Painter &p, float64 recordActive);
void drawPinnedBar(Painter &p); void drawPinnedBar(Painter &p);
void updateMouseTracking(); void updateMouseTracking();
@ -1122,18 +1122,18 @@ private:
ChildWidget<SilentToggle> _silent; ChildWidget<SilentToggle> _silent;
bool _cmdStartShown = false; bool _cmdStartShown = false;
ChildWidget<MessageField> _field; ChildWidget<MessageField> _field;
Animation _a_record, _a_recording; Animation _a_recording;
bool _recording = false; bool _recording = false;
bool _inRecord = false; bool _inRecord = false;
bool _inField = false; bool _inField = false;
bool _inReplyEdit = false; bool _inReplyEdit = false;
bool _inPinnedMsg = false; bool _inPinnedMsg = false;
bool _inClickable = false; bool _inClickable = false;
anim::ivalue a_recordingLevel = { 0, 0 }; anim::value a_recordingLevel;
int32 _recordingSamples = 0; int _recordingSamples = 0;
anim::fvalue a_recordDown = { 0, 0 }; FloatAnimation _a_recordActive;
anim::fvalue a_recordCancelActive; std_::unique_ptr<Ui::RippleAnimation> _recordRipple;
int32 _recordCancelWidth; int _recordCancelWidth;
FileDialog::QueryId _attachFilesQueryId = 0; FileDialog::QueryId _attachFilesQueryId = 0;
@ -1163,10 +1163,9 @@ private:
bool _titlePeerTextOnline = false; bool _titlePeerTextOnline = false;
int _titlePeerTextWidth = 0; int _titlePeerTextWidth = 0;
Animation _a_show; FloatAnimation _a_show;
Window::SlideDirection _showDirection;
QPixmap _cacheUnder, _cacheOver; QPixmap _cacheUnder, _cacheOver;
anim::ivalue a_coordUnder, a_coordOver;
anim::fvalue a_progress;
QTimer _scrollTimer; QTimer _scrollTimer;
int32 _scrollDelta = 0; int32 _scrollDelta = 0;

View file

@ -786,7 +786,7 @@ void File::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
} else { } else {
if (!_animation) { if (!_animation) {
ensureAnimation(); ensureAnimation();
_animation->a_thumbOver = anim::fvalue(1, 1); _animation->a_thumbOver = anim::value(1, 1);
} }
_animation->a_thumbOver.start(0); _animation->a_thumbOver.start(0);
} }

View file

@ -267,7 +267,7 @@ private:
, _a_thumbOver(std_::move(thumbOverCallbacks)) , _a_thumbOver(std_::move(thumbOverCallbacks))
, radial(std_::move(radialCallbacks)) { , radial(std_::move(radialCallbacks)) {
} }
anim::fvalue a_thumbOver; anim::value a_thumbOver;
Animation _a_thumbOver; Animation _a_thumbOver;
Ui::RadialAnimation radial; Ui::RadialAnimation radial;

View file

@ -21,6 +21,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
using "basic.style"; using "basic.style";
using "ui/widgets/widgets.style"; using "ui/widgets/widgets.style";
countryRipple: defaultRippleAnimation;
introCoverHeight: 208px; introCoverHeight: 208px;
introCoverTopBg: #0f89d0; introCoverTopBg: #0f89d0;
introCoverBottomBg: #39b0f0; introCoverBottomBg: #39b0f0;
@ -84,7 +86,7 @@ introStepHeight: 256px;
introStepHeightAdd: 30px; introStepHeightAdd: 30px;
introStepHeightFull: 580px; introStepHeightFull: 580px;
introSlideDuration: 200; introSlideDuration: 200;
introCoverDuration: 200; introCoverDuration: 300;
introNextButton: RoundButton(defaultActiveButton) { introNextButton: RoundButton(defaultActiveButton) {
width: 300px; width: 300px;

View file

@ -47,7 +47,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
namespace Intro { namespace Intro {
Widget::Widget(QWidget *parent) : TWidget(parent) Widget::Widget(QWidget *parent) : TWidget(parent)
, _a_show(animation(this, &Widget::step_show))
, _back(this, new Ui::IconButton(this, st::introBackButton), base::lambda<void()>(), st::introSlideDuration) , _back(this, new Ui::IconButton(this, st::introBackButton), base::lambda<void()>(), st::introSlideDuration)
, _settings(this, new Ui::RoundButton(this, lang(lng_menu_settings), st::defaultBoxButton), base::lambda<void()>(), st::introCoverDuration) , _settings(this, new Ui::RoundButton(this, lang(lng_menu_settings), st::defaultBoxButton), base::lambda<void()>(), st::introCoverDuration)
, _next(this, QString(), st::introNextButton) { , _next(this, QString(), st::introNextButton) {
@ -143,7 +142,7 @@ void Widget::historyMove(Direction direction) {
if (wasStep->hasCover() != getStep()->hasCover()) { if (wasStep->hasCover() != getStep()->hasCover()) {
_nextTopFrom = wasStep->contentTop() + st::introStepHeight; _nextTopFrom = wasStep->contentTop() + st::introStepHeight;
_controlsTopFrom = wasStep->hasCover() ? st::introCoverHeight : 0; _controlsTopFrom = wasStep->hasCover() ? st::introCoverHeight : 0;
_coverShownAnimation.start([this] { updateControlsGeometry(); }, 0., 1., st::introCoverDuration, anim::easeOutCirc); _coverShownAnimation.start([this] { updateControlsGeometry(); }, 0., 1., st::introCoverDuration, wasStep->hasCover() ? anim::linear : anim::easeOutCirc);
} }
if (direction == Direction::Forward || direction == Direction::Replace) { if (direction == Direction::Forward || direction == Direction::Replace) {
@ -302,45 +301,29 @@ void Widget::hideControls() {
_back->hideFast(); _back->hideFast();
} }
void Widget::animShow(const QPixmap &bgAnimCache, bool back) { void Widget::showAnimated(const QPixmap &bgAnimCache, bool back) {
if (App::app()) App::app()->mtpPause(); _showBack = back;
(back ? _cacheOver : _cacheUnder) = bgAnimCache; (_showBack ? _cacheOver : _cacheUnder) = bgAnimCache;
_a_show.stop(); _a_show.finish();
showControls(); showControls();
(back ? _cacheUnder : _cacheOver) = myGrab(this); (_showBack ? _cacheUnder : _cacheOver) = myGrab(this);
hideControls(); hideControls();
a_coordUnder = back ? anim::ivalue(-st::slideShift, 0) : anim::ivalue(0, -st::slideShift); _a_show.start([this] { animationCallback(); }, 0., 1., st::slideDuration, Window::SlideAnimation::transition());
a_coordOver = back ? anim::ivalue(0, width()) : anim::ivalue(width(), 0);
a_shadow = back ? anim::fvalue(1, 0) : anim::fvalue(0, 1);
_a_show.start();
show(); show();
} }
void Widget::step_show(float64 ms, bool timer) { void Widget::animationCallback() {
float64 dt = ms / st::slideDuration; update();
if (dt >= 1) { if (!_a_show.animating()) {
_a_show.stop();
a_coordUnder.finish();
a_coordOver.finish();
a_shadow.finish();
_cacheUnder = _cacheOver = QPixmap(); _cacheUnder = _cacheOver = QPixmap();
showControls(); showControls();
getStep()->activate(); getStep()->activate();
if (App::app()) App::app()->mtpUnpause();
} else {
a_coordUnder.update(dt, Window::SlideAnimation::transition());
a_coordOver.update(dt, Window::SlideAnimation::transition());
a_shadow.update(dt, Window::SlideAnimation::transition());
} }
if (timer) update();
} }
void Widget::paintEvent(QPaintEvent *e) { void Widget::paintEvent(QPaintEvent *e) {
@ -356,16 +339,20 @@ void Widget::paintEvent(QPaintEvent *e) {
p.setClipRect(e->rect()); p.setClipRect(e->rect());
} }
p.fillRect(e->rect(), st::windowBg); p.fillRect(e->rect(), st::windowBg);
auto progress = _a_show.current(getms(), 1.);
if (_a_show.animating()) { if (_a_show.animating()) {
if (a_coordOver.current() > 0) { auto coordUnder = _showBack ? anim::interpolate(-st::slideShift, 0, progress) : anim::interpolate(0, -st::slideShift, progress);
p.drawPixmap(QRect(0, 0, a_coordOver.current(), height()), _cacheUnder, QRect(-a_coordUnder.current() * cRetinaFactor(), 0, a_coordOver.current() * cRetinaFactor(), height() * cRetinaFactor())); auto coordOver = _showBack ? anim::interpolate(0, width(), progress) : anim::interpolate(width(), 0, progress);
p.setOpacity(a_shadow.current()); auto shadow = _showBack ? (1. - progress) : progress;
p.fillRect(0, 0, a_coordOver.current(), height(), st::slideFadeOutBg); if (coordOver > 0) {
p.drawPixmap(QRect(0, 0, coordOver, height()), _cacheUnder, QRect(-coordUnder * cRetinaFactor(), 0, coordOver * cRetinaFactor(), height() * cRetinaFactor()));
p.setOpacity(shadow);
p.fillRect(0, 0, coordOver, height(), st::slideFadeOutBg);
p.setOpacity(1); p.setOpacity(1);
} }
p.drawPixmap(a_coordOver.current(), 0, _cacheOver); p.drawPixmap(coordOver, 0, _cacheOver);
p.setOpacity(a_shadow.current()); p.setOpacity(shadow);
st::slideShadow.fill(p, QRect(a_coordOver.current() - st::slideShadow.width(), 0, st::slideShadow.width(), height())); st::slideShadow.fill(p, QRect(coordOver - st::slideShadow.width(), 0, st::slideShadow.width(), height()));
} }
} }
@ -491,7 +478,6 @@ void Widget::Step::showFinished() {
_slideAnimation.reset(); _slideAnimation.reset();
prepareCoverMask(); prepareCoverMask();
activate(); activate();
if (App::app()) App::app()->mtpUnpause();
} }
bool Widget::Step::paintAnimated(Painter &p, QRect clip) { bool Widget::Step::paintAnimated(Painter &p, QRect clip) {
@ -519,11 +505,11 @@ bool Widget::Step::paintAnimated(Painter &p, QRect clip) {
return false; return false;
} }
auto easeOut = anim::easeOutCirc(1., dt); auto progress = (hasCover() ? anim::easeOutCirc(1., dt) : anim::linear(1., dt));
auto arrivingAlpha = easeOut; auto arrivingAlpha = progress;
auto departingAlpha = 1. - easeOut; auto departingAlpha = 1. - progress;
auto showCoverMethod = easeOut; auto showCoverMethod = progress;
auto hideCoverMethod = easeOut; auto hideCoverMethod = progress;
auto coverTop = (hasCover() ? anim::interpolate(-st::introCoverHeight, 0, showCoverMethod) : anim::interpolate(0, -st::introCoverHeight, hideCoverMethod)); auto coverTop = (hasCover() ? anim::interpolate(-st::introCoverHeight, 0, showCoverMethod) : anim::interpolate(0, -st::introCoverHeight, hideCoverMethod));
paintCover(p, coverTop); paintCover(p, coverTop);
@ -718,7 +704,6 @@ QPixmap Widget::Step::prepareSlideAnimation() {
void Widget::Step::showAnimated(Direction direction) { void Widget::Step::showAnimated(Direction direction) {
show(); show();
if (App::app()) App::app()->mtpPause();
hideChildren(); hideChildren();
if (_slideAnimation) { if (_slideAnimation) {
auto slideLeft = (direction == Direction::Back); auto slideLeft = (direction == Direction::Back);

View file

@ -39,7 +39,8 @@ class Widget : public TWidget, public RPCSender {
public: public:
Widget(QWidget *parent); Widget(QWidget *parent);
void animShow(const QPixmap &bgAnimCache, bool back = false); void showAnimated(const QPixmap &bgAnimCache, bool back = false);
void setInnerFocus(); void setInnerFocus();
~Widget(); ~Widget();
@ -205,7 +206,7 @@ public:
}; };
private: private:
void step_show(float64 ms, bool timer); void animationCallback();
void changeLanguage(int32 languageId); void changeLanguage(int32 languageId);
void updateControlsGeometry(); void updateControlsGeometry();
@ -225,10 +226,9 @@ private:
void resetDone(const MTPBool &result); void resetDone(const MTPBool &result);
bool resetFail(const RPCError &error); bool resetFail(const RPCError &error);
Animation _a_show; FloatAnimation _a_show;
bool _showBack = false;
QPixmap _cacheUnder, _cacheOver; QPixmap _cacheUnder, _cacheOver;
anim::ivalue a_coordUnder, a_coordOver;
anim::fvalue a_shadow;
QVector<Step*> _stepHistory; QVector<Step*> _stepHistory;
Step *getStep(int skip = 0) { Step *getStep(int skip = 0) {

View file

@ -453,9 +453,6 @@ void LayerStackWidget::prepareForAnimation() {
if (auto layer = currentLayer()) { if (auto layer = currentLayer()) {
layer->hide(); layer->hide();
} }
if (auto app = App::app()) {
app->mtpPause();
}
} }
void LayerStackWidget::animationDone() { void LayerStackWidget::animationDone() {
@ -477,9 +474,6 @@ void LayerStackWidget::animationDone() {
} else { } else {
showFinished(); showFinished();
} }
if (auto app = App::app()) {
app->mtpUnpause();
}
setAttribute(Qt::WA_OpaquePaintEvent, false); setAttribute(Qt::WA_OpaquePaintEvent, false);
} }
@ -613,8 +607,6 @@ LayerStackWidget::~LayerStackWidget() {
} }
MediaPreviewWidget::MediaPreviewWidget(QWidget *parent) : TWidget(parent) MediaPreviewWidget::MediaPreviewWidget(QWidget *parent) : TWidget(parent)
, a_shown(0, 0)
, _a_shown(animation(this, &MediaPreviewWidget::step_shown))
, _emojiSize(EmojiSizes[EIndex + 1] / cIntRetinaFactor()) { , _emojiSize(EmojiSizes[EIndex + 1] / cIntRetinaFactor()) {
setAttribute(Qt::WA_TransparentForMouseEvents); setAttribute(Qt::WA_TransparentForMouseEvents);
subscribe(FileDownload::ImageLoaded(), [this] { update(); }); subscribe(FileDownload::ImageLoaded(), [this] { update(); });
@ -626,8 +618,13 @@ void MediaPreviewWidget::paintEvent(QPaintEvent *e) {
auto image = currentImage(); auto image = currentImage();
int w = image.width() / cIntRetinaFactor(), h = image.height() / cIntRetinaFactor(); int w = image.width() / cIntRetinaFactor(), h = image.height() / cIntRetinaFactor();
if (_a_shown.animating()) { auto shown = _a_shown.current(getms(), _hiding ? 0. : 1.);
float64 shown = a_shown.current(); if (!_a_shown.animating()) {
if (_hiding) {
hide();
return;
}
} else {
p.setOpacity(shown); p.setOpacity(shown);
// w = qMax(qRound(w * (st::stickerPreviewMin + ((1. - st::stickerPreviewMin) * shown)) / 2.) * 2 + int(w % 2), 1); // w = qMax(qRound(w * (st::stickerPreviewMin + ((1. - st::stickerPreviewMin) * shown)) / 2.) * 2 + int(w % 2), 1);
// h = qMax(qRound(h * (st::stickerPreviewMin + ((1. - st::stickerPreviewMin) * shown)) / 2.) * 2 + int(h % 2), 1); // h = qMax(qRound(h * (st::stickerPreviewMin + ((1. - st::stickerPreviewMin) * shown)) / 2.) * 2 + int(h % 2), 1);
@ -650,18 +647,6 @@ void MediaPreviewWidget::resizeEvent(QResizeEvent *e) {
update(); update();
} }
void MediaPreviewWidget::step_shown(float64 ms, bool timer) {
float64 dt = ms / st::stickerPreviewDuration;
if (dt >= 1) {
_a_shown.stop();
a_shown.finish();
if (a_shown.current() < 0.5) hide();
} else {
a_shown.update(dt, anim::linear);
}
if (timer) update();
}
void MediaPreviewWidget::showPreview(DocumentData *document) { void MediaPreviewWidget::showPreview(DocumentData *document) {
if (!document || (!document->isAnimation() && !document->sticker())) { if (!document || (!document->isAnimation() && !document->sticker())) {
hidePreview(); hidePreview();
@ -692,8 +677,8 @@ void MediaPreviewWidget::startShow() {
_cache = QPixmap(); _cache = QPixmap();
if (isHidden() || _a_shown.animating()) { if (isHidden() || _a_shown.animating()) {
if (isHidden()) show(); if (isHidden()) show();
a_shown.start(1); _hiding = false;
_a_shown.start(); _a_shown.start([this] { update(); }, 0., 1., st::stickerPreviewDuration);
} else { } else {
update(); update();
} }
@ -704,8 +689,8 @@ void MediaPreviewWidget::hidePreview() {
return; return;
} }
if (_gif) _cache = currentImage(); if (_gif) _cache = currentImage();
a_shown.start(0); _hiding = true;
_a_shown.start(); _a_shown.start([this] { update(); }, 1., 0., st::stickerPreviewDuration);
_photo = nullptr; _photo = nullptr;
_document = nullptr; _document = nullptr;
resetGifAndCache(); resetGifAndCache();

View file

@ -144,8 +144,6 @@ public:
void paintEvent(QPaintEvent *e); void paintEvent(QPaintEvent *e);
void resizeEvent(QResizeEvent *e); void resizeEvent(QResizeEvent *e);
void step_shown(float64 ms, bool timer);
void showPreview(DocumentData *document); void showPreview(DocumentData *document);
void showPreview(PhotoData *photo); void showPreview(PhotoData *photo);
void hidePreview(); void hidePreview();
@ -159,8 +157,8 @@ private:
void fillEmojiString(); void fillEmojiString();
void resetGifAndCache(); void resetGifAndCache();
anim::fvalue a_shown; FloatAnimation _a_shown;
Animation _a_shown; bool _hiding = false;
DocumentData *_document = nullptr; DocumentData *_document = nullptr;
PhotoData *_photo = nullptr; PhotoData *_photo = nullptr;
Media::Clip::ReaderPointer _gif; Media::Clip::ReaderPointer _gif;

View file

@ -69,7 +69,6 @@ StackItemSection::~StackItemSection() {
} }
MainWidget::MainWidget(QWidget *parent) : TWidget(parent) MainWidget::MainWidget(QWidget *parent) : TWidget(parent)
, _a_show(animation(this, &MainWidget::step_show))
, _dialogsWidth(st::dialogsWidthMin) , _dialogsWidth(st::dialogsWidthMin)
, _sideShadow(this, st::shadowColor) , _sideShadow(this, st::shadowColor)
, _dialogs(this) , _dialogs(this)
@ -2231,7 +2230,7 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::Show
} }
Window::SectionSlideParams animationParams; Window::SectionSlideParams animationParams;
if (!_a_show.animating() && ((_history->isHidden() && (_wideSection || _overview)) || (Adaptive::OneColumn() && (_history->isHidden() || !peerId)) || back || (way == Ui::ShowWay::Forward))) { if (!_a_show.animating() && !App::passcoded() && ((_history->isHidden() && (_wideSection || _overview)) || (Adaptive::OneColumn() && (_history->isHidden() || !peerId)) || back || (way == Ui::ShowWay::Forward))) {
animationParams = prepareHistoryAnimation(peerId); animationParams = prepareHistoryAnimation(peerId);
} }
if (_history->peer() && _history->peer()->id != peerId && way != Ui::ShowWay::Forward) { if (_history->peer() && _history->peer()->id != peerId && way != Ui::ShowWay::Forward) {
@ -2258,7 +2257,7 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, Ui::Show
_topBar->hide(); _topBar->hide();
_history->hide(); _history->hide();
if (!_a_show.animating()) { if (!_a_show.animating()) {
if (!animationParams.oldContentCache.isNull() && !App::passcoded()) { if (!animationParams.oldContentCache.isNull()) {
_dialogs->showAnimated(back ? Window::SlideDirection::FromLeft : Window::SlideDirection::FromRight, animationParams); _dialogs->showAnimated(back ? Window::SlideDirection::FromLeft : Window::SlideDirection::FromRight, animationParams);
} else { } else {
_dialogs->showFast(); _dialogs->showFast();
@ -2408,7 +2407,7 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool
} else { } else {
_overview->fastShow(); _overview->fastShow();
} }
_history->animStop(); _history->finishAnimation();
if (back) { if (back) {
clearBotStartToken(_history->peer()); clearBotStartToken(_history->peer());
} }
@ -2537,7 +2536,7 @@ void MainWidget::showWideSectionAnimated(const Window::SectionMemento *memento,
resizeEvent(0); resizeEvent(0);
auto direction = back ? Window::SlideDirection::FromLeft : Window::SlideDirection::FromRight; auto direction = back ? Window::SlideDirection::FromLeft : Window::SlideDirection::FromRight;
_wideSection->showAnimated(direction, animationParams); _wideSection->showAnimated(direction, animationParams);
_history->animStop(); _history->finishAnimation();
_history->showHistory(0, 0); _history->showHistory(0, 0);
_history->hide(); _history->hide();
if (Adaptive::OneColumn()) _dialogs->hide(); if (Adaptive::OneColumn()) _dialogs->hide();
@ -2651,7 +2650,7 @@ QPixmap MainWidget::grabForShowAnimation(const Window::SectionSlideParams &param
void MainWidget::dlgUpdated() { void MainWidget::dlgUpdated() {
if (_peerInStack) { if (_peerInStack) {
_dialogs->dlgUpdated(App::history(_peerInStack->id), _msgIdInStack); _dialogs->dlgUpdated(_peerInStack, _msgIdInStack);
} }
} }
@ -2661,12 +2660,12 @@ void MainWidget::dlgUpdated(Dialogs::Mode list, Dialogs::Row *row) {
} }
} }
void MainWidget::dlgUpdated(History *row, MsgId msgId) { void MainWidget::dlgUpdated(PeerData *peer, MsgId msgId) {
if (!row) return; if (!peer) return;
if (msgId < 0 && -msgId < ServerMaxMsgId && row->peer->migrateFrom()) { if (msgId < 0 && -msgId < ServerMaxMsgId && peer->migrateFrom()) {
_dialogs->dlgUpdated(App::history(row->peer->migrateFrom()->id), -msgId); _dialogs->dlgUpdated(peer->migrateFrom(), -msgId);
} else { } else {
_dialogs->dlgUpdated(row, msgId); _dialogs->dlgUpdated(peer, msgId);
} }
} }
@ -2719,66 +2718,49 @@ void MainWidget::historyCleared(History *history) {
_history->historyCleared(history); _history->historyCleared(history);
} }
void MainWidget::animShow(const QPixmap &bgAnimCache, bool back) { void MainWidget::showAnimated(const QPixmap &bgAnimCache, bool back) {
if (App::app()) App::app()->mtpPause(); _showBack = back;
(_showBack ? _cacheOver : _cacheUnder) = bgAnimCache;
(back ? _cacheOver : _cacheUnder) = bgAnimCache; _a_show.finish();
_a_show.stop();
showAll(); showAll();
(back ? _cacheUnder : _cacheOver) = myGrab(this); (_showBack ? _cacheUnder : _cacheOver) = myGrab(this);
hideAll(); hideAll();
a_coordUnder = back ? anim::ivalue(-st::slideShift, 0) : anim::ivalue(0, -st::slideShift); _a_show.start([this] { animationCallback(); }, 0., 1., st::slideDuration, Window::SlideAnimation::transition());
a_coordOver = back ? anim::ivalue(0, width()) : anim::ivalue(width(), 0);
a_shadow = back ? anim::fvalue(1, 0) : anim::fvalue(0, 1);
_a_show.start();
show(); show();
} }
void MainWidget::step_show(float64 ms, bool timer) { void MainWidget::animationCallback() {
float64 dt = ms / st::slideDuration; update();
if (dt >= 1) { if (!_a_show.animating()) {
_a_show.stop();
a_coordUnder.finish();
a_coordOver.finish();
a_shadow.finish();
_cacheUnder = _cacheOver = QPixmap(); _cacheUnder = _cacheOver = QPixmap();
showAll(); showAll();
activate(); activate();
if (App::app()) App::app()->mtpUnpause();
} else {
a_coordUnder.update(dt, Window::SlideAnimation::transition());
a_coordOver.update(dt, Window::SlideAnimation::transition());
a_shadow.update(dt, Window::SlideAnimation::transition());
} }
if (timer) update();
}
void MainWidget::animStop_show() {
_a_show.stop();
} }
void MainWidget::paintEvent(QPaintEvent *e) { void MainWidget::paintEvent(QPaintEvent *e) {
if (_background) checkChatBackground(); if (_background) checkChatBackground();
Painter p(this); Painter p(this);
auto progress = _a_show.current(getms(), 1.);
if (_a_show.animating()) { if (_a_show.animating()) {
if (a_coordOver.current() > 0) { auto coordUnder = _showBack ? anim::interpolate(-st::slideShift, 0, progress) : anim::interpolate(0, -st::slideShift, progress);
p.drawPixmap(QRect(0, 0, a_coordOver.current(), height()), _cacheUnder, QRect(-a_coordUnder.current() * cRetinaFactor(), 0, a_coordOver.current() * cRetinaFactor(), height() * cRetinaFactor())); auto coordOver = _showBack ? anim::interpolate(0, width(), progress) : anim::interpolate(width(), 0, progress);
p.setOpacity(a_shadow.current()); auto shadow = _showBack ? (1. - progress) : progress;
p.fillRect(0, 0, a_coordOver.current(), height(), st::slideFadeOutBg); if (coordOver > 0) {
p.drawPixmap(QRect(0, 0, coordOver, height()), _cacheUnder, QRect(-coordUnder * cRetinaFactor(), 0, coordOver * cRetinaFactor(), height() * cRetinaFactor()));
p.setOpacity(shadow);
p.fillRect(0, 0, coordOver, height(), st::slideFadeOutBg);
p.setOpacity(1); p.setOpacity(1);
} }
p.drawPixmap(a_coordOver.current(), 0, _cacheOver); p.drawPixmap(coordOver, 0, _cacheOver);
p.setOpacity(a_shadow.current()); p.setOpacity(shadow);
st::slideShadow.fill(p, QRect(a_coordOver.current() - st::slideShadow.width(), 0, st::slideShadow.width(), height())); st::slideShadow.fill(p, QRect(coordOver - st::slideShadow.width(), 0, st::slideShadow.width(), height()));
} }
} }
@ -3048,7 +3030,7 @@ void MainWidget::onHistoryShown(History *history, MsgId atMsgId) {
_topBar->hide(); _topBar->hide();
} }
dlgUpdated(history, atMsgId); dlgUpdated(history ? history->peer : nullptr, atMsgId);
} }
void MainWidget::searchInPeer(PeerData *peer) { void MainWidget::searchInPeer(PeerData *peer) {

View file

@ -152,9 +152,7 @@ public:
int contentScrollAddToY() const; int contentScrollAddToY() const;
void animShow(const QPixmap &bgAnimCache, bool back = false); void showAnimated(const QPixmap &bgAnimCache, bool back = false);
void step_show(float64 ms, bool timer);
void animStop_show();
void start(const MTPUser &user); void start(const MTPUser &user);
@ -178,7 +176,7 @@ public:
void removeDialog(History *history); void removeDialog(History *history);
void dlgUpdated(); void dlgUpdated();
void dlgUpdated(Dialogs::Mode list, Dialogs::Row *row); void dlgUpdated(Dialogs::Mode list, Dialogs::Row *row);
void dlgUpdated(History *row, MsgId msgId); void dlgUpdated(PeerData *peer, MsgId msgId);
void windowShown(); void windowShown();
@ -483,6 +481,7 @@ protected:
void keyPressEvent(QKeyEvent *e) override; void keyPressEvent(QKeyEvent *e) override;
private: private:
void animationCallback();
void updateAdaptiveLayout(); void updateAdaptiveLayout();
void handleAudioUpdate(const AudioMsgId &audioId); void handleAudioUpdate(const AudioMsgId &audioId);
void updateMediaPlayerPosition(); void updateMediaPlayerPosition();
@ -587,10 +586,9 @@ private:
base::Observable<PeerData*> _searchInPeerChanged; base::Observable<PeerData*> _searchInPeerChanged;
base::Observable<PeerData*> _historyPeerChanged; base::Observable<PeerData*> _historyPeerChanged;
Animation _a_show; FloatAnimation _a_show;
bool _showBack = false;
QPixmap _cacheUnder, _cacheOver; QPixmap _cacheUnder, _cacheOver;
anim::ivalue a_coordUnder, a_coordOver;
anim::fvalue a_shadow;
int _dialogsWidth; int _dialogsWidth;

View file

@ -241,9 +241,9 @@ void MainWindow::clearPasscode() {
_passcode.destroy(); _passcode.destroy();
if (_intro) { if (_intro) {
_intro->animShow(bg, true); _intro->showAnimated(bg, true);
} else { } else {
_main->animShow(bg, true); _main->showAnimated(bg, true);
} }
notifyUpdateAll(); notifyUpdateAll();
updateGlobalMenu(); updateGlobalMenu();
@ -265,7 +265,7 @@ void MainWindow::setupPasscode() {
} }
if (_intro) _intro->hide(); if (_intro) _intro->hide();
if (animated) { if (animated) {
_passcode->animShow(bg); _passcode->showAnimated(bg);
} else { } else {
setInnerFocus(); setInnerFocus();
} }
@ -313,7 +313,7 @@ void MainWindow::setupIntro() {
updateControlsGeometry(); updateControlsGeometry();
if (animated) { if (animated) {
_intro->animShow(bg); _intro->showAnimated(bg);
} else { } else {
setInnerFocus(); setInnerFocus();
} }
@ -367,7 +367,7 @@ void MainWindow::setupMain(const MTPUser *self) {
updateControlsGeometry(); updateControlsGeometry();
if (animated) { if (animated) {
_main->animShow(bg); _main->showAnimated(bg);
} else { } else {
_main->activate(); _main->activate();
} }

View file

@ -991,7 +991,7 @@ void AudioPlayerFader::onTimer() {
float64 wasAudio = suppressAllGain; float64 wasAudio = suppressAllGain;
if (ms >= _suppressAllStart + notifyLengthMs || ms < _suppressAllStart) { if (ms >= _suppressAllStart + notifyLengthMs || ms < _suppressAllStart) {
_suppressAll = _suppressAllAnim = false; _suppressAll = _suppressAllAnim = false;
_suppressAllGain = anim::fvalue(1., 1.); _suppressAllGain = anim::value(1., 1.);
} else if (ms > _suppressAllStart + notifyLengthMs - AudioFadeDuration) { } else if (ms > _suppressAllStart + notifyLengthMs - AudioFadeDuration) {
if (_suppressAllGain.to() != 1.) _suppressAllGain.start(1.); if (_suppressAllGain.to() != 1.) _suppressAllGain.start(1.);
_suppressAllGain.update(1. - ((_suppressAllStart + notifyLengthMs - ms) / float64(AudioFadeDuration)), anim::linear); _suppressAllGain.update(1. - ((_suppressAllStart + notifyLengthMs - ms) / float64(AudioFadeDuration)), anim::linear);

View file

@ -257,7 +257,7 @@ private:
bool _suppressSong = false; bool _suppressSong = false;
bool _suppressSongAnim = false; bool _suppressSongAnim = false;
bool _songVolumeChanged, _videoVolumeChanged; bool _songVolumeChanged, _videoVolumeChanged;
anim::fvalue _suppressAllGain, _suppressSongGain; anim::value _suppressAllGain, _suppressSongGain;
TimeMs _suppressAllStart = 0; TimeMs _suppressAllStart = 0;
TimeMs _suppressSongStart = 0; TimeMs _suppressSongStart = 0;

View file

@ -23,17 +23,7 @@ using "basic.style";
using "ui/widgets/widgets.style"; using "ui/widgets/widgets.style";
using "overview/overview.style"; using "overview/overview.style";
MediaPlayerButton { mediaPlayerBg: windowBg;
playPosition: point;
playOuter: size;
pausePosition: point;
pauseOuter: size;
pauseStroke: pixels;
cancelPosition: point;
cancelOuter: size;
cancelStroke: pixels;
}
mediaPlayerActiveFg: windowBgActive; mediaPlayerActiveFg: windowBgActive;
mediaPlayerInactiveFg: #dfebf2; mediaPlayerInactiveFg: #dfebf2;
@ -46,6 +36,12 @@ mediaPlayerButton: MediaPlayerButton {
cancelPosition: point(1px, 1px); cancelPosition: point(1px, 1px);
cancelOuter: size(15px, 15px); cancelOuter: size(15px, 15px);
cancelStroke: 3px; cancelStroke: 3px;
rippleAreaPosition: point(0px, 5px);
rippleAreaSize: 25px;
ripple: RippleAnimation(defaultRippleAnimation) {
color: lightButtonBgOver;
}
} }
mediaPlayerButtonSize: size(25px, 30px); mediaPlayerButtonSize: size(25px, 30px);
@ -76,10 +72,20 @@ mediaPlayerRepeatButton: IconButton {
{ "player_repeat", mediaPlayerActiveFg, point(9px, 11px) } { "player_repeat", mediaPlayerActiveFg, point(9px, 11px) }
}; };
iconPosition: point(0px, 0px); iconPosition: point(0px, 0px);
rippleAreaPosition: point(3px, 5px);
rippleAreaSize: 25px;
ripple: RippleAnimation(defaultRippleAnimation) {
color: lightButtonBgOver;
}
} }
mediaPlayerRepeatDisabledIcon: icon { mediaPlayerRepeatDisabledIcon: icon {
{ "player_repeat", #c8c8c8, point(9px, 11px)} { "player_repeat", menuIconFg, point(9px, 11px)}
}; };
mediaPlayerRepeatDisabledIconOver: icon {
{ "player_repeat", menuIconFgOver, point(9px, 11px)}
};
mediaPlayerRepeatDisabledRippleBg: windowBgOver;
mediaPlayerRepeatInactiveIcon: icon { mediaPlayerRepeatInactiveIcon: icon {
{ "player_repeat", mediaPlayerInactiveFg, point(9px, 11px)} { "player_repeat", mediaPlayerInactiveFg, point(9px, 11px)}
}; };
@ -102,6 +108,12 @@ mediaPlayerVolumeToggle: IconButton {
icon: mediaPlayerVolumeIcon0; icon: mediaPlayerVolumeIcon0;
iconPosition: point(8px, 11px); iconPosition: point(8px, 11px);
rippleAreaPosition: point(3px, 5px);
rippleAreaSize: 25px;
ripple: RippleAnimation(defaultRippleAnimation) {
color: lightButtonBgOver;
}
} }
mediaPlayerVolumeMargin: 10px; mediaPlayerVolumeMargin: 10px;
mediaPlayerVolumeSize: size(27px, 100px); mediaPlayerVolumeSize: size(27px, 100px);
@ -117,6 +129,8 @@ mediaPlayerNextButton: IconButton(mediaPlayerRepeatButton) {
icon: icon { icon: icon {
{ "player_next", mediaPlayerActiveFg, mediaPlayerSkipIconPosition }, { "player_next", mediaPlayerActiveFg, mediaPlayerSkipIconPosition },
}; };
rippleAreaPosition: point(0px, 5px);
} }
mediaPlayerNextDisabledIcon: icon { mediaPlayerNextDisabledIcon: icon {
{ "player_next", mediaPlayerInactiveFg, mediaPlayerSkipIconPosition }, { "player_next", mediaPlayerInactiveFg, mediaPlayerSkipIconPosition },
@ -125,13 +139,20 @@ mediaPlayerPreviousButton: IconButton(mediaPlayerNextButton) {
icon: icon { icon: icon {
{ "player_next-flip_horizontal", mediaPlayerActiveFg, mediaPlayerSkipIconPosition }, { "player_next-flip_horizontal", mediaPlayerActiveFg, mediaPlayerSkipIconPosition },
}; };
rippleAreaPosition: point(1px, 5px);
} }
mediaPlayerPreviousDisabledIcon: icon { mediaPlayerPreviousDisabledIcon: icon {
{ "player_next-flip_horizontal", mediaPlayerInactiveFg, mediaPlayerSkipIconPosition }, { "player_next-flip_horizontal", mediaPlayerInactiveFg, mediaPlayerSkipIconPosition },
}; };
mediaPlayerClose: IconButton(mediaPlayerRepeatButton) { mediaPlayerClose: IconButton(mediaPlayerRepeatButton) {
width: 37px; width: 37px;
icon: icon {{ "player_close", #c8c8c8, point(10px, 12px) }}; icon: icon {{ "player_close", menuIconFg, point(10px, 12px) }};
iconOver: icon {{ "player_close", menuIconFgOver, point(10px, 12px) }};
rippleAreaPosition: point(3px, 5px);
ripple: RippleAnimation(defaultRippleAnimation) {
color: windowBgOver;
}
} }
mediaPlayerPlayback: FilledSlider { mediaPlayerPlayback: FilledSlider {
fullWidth: 6px; fullWidth: 6px;
@ -165,7 +186,8 @@ mediaPlayerCoverHeight: 102px;
mediaPlayerPanelClose: IconButton(mediaPlayerClose) { mediaPlayerPanelClose: IconButton(mediaPlayerClose) {
width: 43px; width: 43px;
height: 28px; height: 28px;
icon: icon {{ "player_close", #c8c8c8, point(16px, 14px) }}; icon: icon {{ "player_close", menuIconFg, point(16px, 14px) }};
iconOver: icon {{ "player_close", menuIconFgOver, point(16px, 14px) }};
} }
mediaPlayerPanelNextButton: IconButton(mediaPlayerRepeatButton) { mediaPlayerPanelNextButton: IconButton(mediaPlayerRepeatButton) {

View file

@ -21,6 +21,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "stdafx.h" #include "stdafx.h"
#include "media/player/media_player_button.h" #include "media/player/media_player_button.h"
#include "styles/style_widgets.h"
namespace Media { namespace Media {
namespace Player { namespace Player {
namespace { namespace {

View file

@ -234,7 +234,7 @@ void CoverWidget::updateLabelPositions() {
} }
void CoverWidget::updateRepeatTrackIcon() { void CoverWidget::updateRepeatTrackIcon() {
_repeatTrack->setIcon(instance()->repeatEnabled() ? nullptr : &st::mediaPlayerRepeatInactiveIcon); _repeatTrack->setIconOverride(instance()->repeatEnabled() ? nullptr : &st::mediaPlayerRepeatInactiveIcon);
} }
void CoverWidget::handleSongUpdate(const UpdatedEvent &e) { void CoverWidget::handleSongUpdate(const UpdatedEvent &e) {
@ -338,9 +338,9 @@ void CoverWidget::handlePlaylistUpdate() {
createPrevNextButtons(); createPrevNextButtons();
auto previousEnabled = (index > 0); auto previousEnabled = (index > 0);
auto nextEnabled = (index + 1 < playlist.size()); auto nextEnabled = (index + 1 < playlist.size());
_previousTrack->setIcon(previousEnabled ? nullptr : &st::mediaPlayerPanelPreviousDisabledIcon); _previousTrack->setIconOverride(previousEnabled ? nullptr : &st::mediaPlayerPanelPreviousDisabledIcon);
_previousTrack->setCursor(previousEnabled ? style::cur_pointer : style::cur_default); _previousTrack->setCursor(previousEnabled ? style::cur_pointer : style::cur_default);
_nextTrack->setIcon(nextEnabled ? nullptr : &st::mediaPlayerPanelNextDisabledIcon); _nextTrack->setIconOverride(nextEnabled ? nullptr : &st::mediaPlayerPanelNextDisabledIcon);
_nextTrack->setCursor(nextEnabled ? style::cur_pointer : style::cur_default); _nextTrack->setCursor(nextEnabled ? style::cur_pointer : style::cur_default);
} }
} }
@ -386,7 +386,7 @@ void CoverWidget::updateVolumeToggleIcon() {
} }
return nullptr; return nullptr;
}; };
_volumeToggle->setIcon(icon()); _volumeToggle->setIconOverride(icon());
} }
} // namespace Player } // namespace Player

View file

@ -25,6 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "ui/widgets/continuous_sliders.h" #include "ui/widgets/continuous_sliders.h"
#include "ui/widgets/shadow.h" #include "ui/widgets/shadow.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/effects/ripple_animation.h"
#include "media/media_audio.h" #include "media/media_audio.h"
#include "media/view/media_clip_playback.h" #include "media/view/media_clip_playback.h"
#include "media/player/media_player_button.h" #include "media/player/media_player_button.h"
@ -38,7 +39,7 @@ namespace Player {
using State = PlayButtonLayout::State; using State = PlayButtonLayout::State;
class Widget::PlayButton : public Ui::AbstractButton { class Widget::PlayButton : public Ui::RippleButton {
public: public:
PlayButton(QWidget *parent); PlayButton(QWidget *parent);
@ -52,12 +53,15 @@ public:
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
QImage prepareRippleMask() const override;
QPoint prepareRippleStartPosition() const override;
private: private:
PlayButtonLayout _layout; PlayButtonLayout _layout;
}; };
Widget::PlayButton::PlayButton(QWidget *parent) : Ui::AbstractButton(parent) Widget::PlayButton::PlayButton(QWidget *parent) : Ui::RippleButton(parent, st::mediaPlayerButton.ripple)
, _layout(st::mediaPlayerButton, [this] { update(); }) { , _layout(st::mediaPlayerButton, [this] { update(); }) {
resize(st::mediaPlayerButtonSize); resize(st::mediaPlayerButtonSize);
setCursor(style::cur_pointer); setCursor(style::cur_pointer);
@ -66,10 +70,20 @@ Widget::PlayButton::PlayButton(QWidget *parent) : Ui::AbstractButton(parent)
void Widget::PlayButton::paintEvent(QPaintEvent *e) { void Widget::PlayButton::paintEvent(QPaintEvent *e) {
Painter p(this); Painter p(this);
paintRipple(p, st::mediaPlayerButton.rippleAreaPosition.x(), st::mediaPlayerButton.rippleAreaPosition.y(), getms());
p.translate(st::mediaPlayerButtonPosition.x(), st::mediaPlayerButtonPosition.y()); p.translate(st::mediaPlayerButtonPosition.x(), st::mediaPlayerButtonPosition.y());
_layout.paint(p, st::mediaPlayerActiveFg); _layout.paint(p, st::mediaPlayerActiveFg);
} }
QImage Widget::PlayButton::prepareRippleMask() const {
auto size = QSize(st::mediaPlayerButton.rippleAreaSize, st::mediaPlayerButton.rippleAreaSize);
return Ui::RippleAnimation::ellipseMask(size);
}
QPoint Widget::PlayButton::prepareRippleStartPosition() const {
return QPoint(mapFromGlobal(QCursor::pos()) - st::mediaPlayerButton.rippleAreaPosition);
}
Widget::Widget(QWidget *parent) : TWidget(parent) Widget::Widget(QWidget *parent) : TWidget(parent)
, _nameLabel(this, st::mediaPlayerName) , _nameLabel(this, st::mediaPlayerName)
, _timeLabel(this, st::mediaPlayerTime) , _timeLabel(this, st::mediaPlayerTime)
@ -146,7 +160,7 @@ void Widget::updateVolumeToggleIcon() {
} }
return nullptr; return nullptr;
}; };
_volumeToggle->setIcon(icon()); _volumeToggle->setIconOverride(icon());
} }
void Widget::setCloseCallback(CloseCallback &&callback) { void Widget::setCloseCallback(CloseCallback &&callback) {
@ -223,7 +237,7 @@ void Widget::paintEvent(QPaintEvent *e) {
Painter p(this); Painter p(this);
auto fill = e->rect().intersected(QRect(0, 0, width(), st::mediaPlayerHeight)); auto fill = e->rect().intersected(QRect(0, 0, width(), st::mediaPlayerHeight));
if (!fill.isEmpty()) { if (!fill.isEmpty()) {
p.fillRect(fill, st::windowBg); p.fillRect(fill, st::mediaPlayerBg);
} }
} }
@ -290,7 +304,9 @@ void Widget::updateLabelsGeometry() {
} }
void Widget::updateRepeatTrackIcon() { void Widget::updateRepeatTrackIcon() {
_repeatTrack->setIcon(instance()->repeatEnabled() ? nullptr : &st::mediaPlayerRepeatDisabledIcon); auto repeating = instance()->repeatEnabled();
_repeatTrack->setIconOverride(repeating ? nullptr : &st::mediaPlayerRepeatDisabledIcon, repeating ? nullptr : &st::mediaPlayerRepeatDisabledIconOver);
_repeatTrack->setRippleColorOverride(repeating ? nullptr : &st::mediaPlayerRepeatDisabledRippleBg);
} }
void Widget::handleSongUpdate(const UpdatedEvent &e) { void Widget::handleSongUpdate(const UpdatedEvent &e) {
@ -393,9 +409,11 @@ void Widget::handlePlaylistUpdate() {
createPrevNextButtons(); createPrevNextButtons();
auto previousEnabled = (index > 0); auto previousEnabled = (index > 0);
auto nextEnabled = (index + 1 < playlist.size()); auto nextEnabled = (index + 1 < playlist.size());
_previousTrack->setIcon(previousEnabled ? nullptr : &st::mediaPlayerPreviousDisabledIcon); _previousTrack->setIconOverride(previousEnabled ? nullptr : &st::mediaPlayerPreviousDisabledIcon);
_previousTrack->setRippleColorOverride(previousEnabled ? nullptr : &st::mediaPlayerBg);
_previousTrack->setCursor(previousEnabled ? style::cur_pointer : style::cur_default); _previousTrack->setCursor(previousEnabled ? style::cur_pointer : style::cur_default);
_nextTrack->setIcon(nextEnabled ? nullptr : &st::mediaPlayerNextDisabledIcon); _nextTrack->setIconOverride(nextEnabled ? nullptr : &st::mediaPlayerNextDisabledIcon);
_nextTrack->setRippleColorOverride(nextEnabled ? nullptr : &st::mediaPlayerBg);
_nextTrack->setCursor(nextEnabled ? style::cur_pointer : style::cur_default); _nextTrack->setCursor(nextEnabled ? style::cur_pointer : style::cur_default);
} }
} }

View file

@ -118,7 +118,7 @@ void Controller::updatePlayPauseResumeState(const AudioPlaybackState &playbackSt
_showPause = showPause; _showPause = showPause;
connect(_playPauseResume, SIGNAL(clicked()), this, _showPause ? SIGNAL(pausePressed()) : SIGNAL(playPressed())); connect(_playPauseResume, SIGNAL(clicked()), this, _showPause ? SIGNAL(pausePressed()) : SIGNAL(playPressed()));
_playPauseResume->setIcon(_showPause ? &st::mediaviewPauseIcon : nullptr, _showPause ? &st::mediaviewPauseIconOver : nullptr); _playPauseResume->setIconOverride(_showPause ? &st::mediaviewPauseIcon : nullptr, _showPause ? &st::mediaviewPauseIconOver : nullptr);
} }
} }
@ -169,7 +169,7 @@ void Controller::refreshTimeTexts() {
} }
void Controller::setInFullScreen(bool inFullScreen) { void Controller::setInFullScreen(bool inFullScreen) {
_fullScreenToggle->setIcon(inFullScreen ? &st::mediaviewFullScreenOutIcon : nullptr, inFullScreen ? &st::mediaviewFullScreenOutIconOver : nullptr); _fullScreenToggle->setIconOverride(inFullScreen ? &st::mediaviewFullScreenOutIcon : nullptr, inFullScreen ? &st::mediaviewFullScreenOutIconOver : nullptr);
disconnect(_fullScreenToggle, SIGNAL(clicked()), this, SIGNAL(toFullScreenPressed())); disconnect(_fullScreenToggle, SIGNAL(clicked()), this, SIGNAL(toFullScreenPressed()));
disconnect(_fullScreenToggle, SIGNAL(clicked()), this, SIGNAL(fromFullScreenPressed())); disconnect(_fullScreenToggle, SIGNAL(clicked()), this, SIGNAL(fromFullScreenPressed()));

View file

@ -2241,7 +2241,7 @@ bool MediaView::updateOverState(OverState newState) {
if (i != _animOpacities.end()) { if (i != _animOpacities.end()) {
i->start(0); i->start(0);
} else { } else {
_animOpacities.insert(_over, anim::fvalue(1, 0)); _animOpacities.insert(_over, anim::value(1, 0));
} }
if (!_a_state.animating()) _a_state.start(); if (!_a_state.animating()) _a_state.start();
} else { } else {
@ -2254,7 +2254,7 @@ bool MediaView::updateOverState(OverState newState) {
if (i != _animOpacities.end()) { if (i != _animOpacities.end()) {
i->start(1); i->start(1);
} else { } else {
_animOpacities.insert(_over, anim::fvalue(0, 1)); _animOpacities.insert(_over, anim::value());
} }
if (!_a_state.animating()) _a_state.start(); if (!_a_state.animating()) _a_state.start();
} }
@ -2492,7 +2492,7 @@ void MediaView::setVisible(bool visible) {
if (!visible) { if (!visible) {
_controlsHideTimer.stop(); _controlsHideTimer.stop();
_controlsState = ControlsShown; _controlsState = ControlsShown;
a_cOpacity = anim::fvalue(1, 1); a_cOpacity = anim::value(1, 1);
} }
TWidget::setVisible(visible); TWidget::setVisible(visible);
if (visible) { if (visible) {

View file

@ -307,7 +307,7 @@ private:
ControlsState _controlsState = ControlsShown; ControlsState _controlsState = ControlsShown;
TimeMs _controlsAnimStarted = 0; TimeMs _controlsAnimStarted = 0;
QTimer _controlsHideTimer; QTimer _controlsHideTimer;
anim::fvalue a_cOpacity; anim::value a_cOpacity;
bool _mousePressed = false; bool _mousePressed = false;
Ui::PopupMenu *_menu = nullptr; Ui::PopupMenu *_menu = nullptr;
@ -328,14 +328,14 @@ private:
QString _saveMsgFilename; QString _saveMsgFilename;
TimeMs _saveMsgStarted = 0; TimeMs _saveMsgStarted = 0;
anim::fvalue _saveMsgOpacity = { 0 }; anim::value _saveMsgOpacity;
QRect _saveMsg; QRect _saveMsg;
QTimer _saveMsgUpdater; QTimer _saveMsgUpdater;
Text _saveMsgText; Text _saveMsgText;
typedef QMap<OverState, TimeMs> Showing; typedef QMap<OverState, TimeMs> Showing;
Showing _animations; Showing _animations;
typedef QMap<OverState, anim::fvalue> ShowingOpacities; typedef QMap<OverState, anim::value> ShowingOpacities;
ShowingOpacities _animOpacities; ShowingOpacities _animOpacities;
int _verticalWheelDelta = 0; int _verticalWheelDelta = 0;

View file

@ -358,7 +358,7 @@ namespace {
return false; return false;
} }
bool _paused = false; int PauseLevel = 0;
} // namespace } // namespace
@ -379,7 +379,20 @@ Session *getSession(ShiftedDcId shiftedDcId) {
} }
bool paused() { bool paused() {
return _paused; return PauseLevel > 0;
}
void pause() {
++PauseLevel;
}
void unpause() {
--PauseLevel;
if (_started) {
for_const (auto session, sessions) {
session->unpaused();
}
}
} }
void registerRequest(mtpRequestId requestId, int32 dcWithShift) { void registerRequest(mtpRequestId requestId, int32 dcWithShift) {
@ -685,19 +698,6 @@ void restart(int32 dcMask) {
} }
} }
void pause() {
if (!_started) return;
_paused = true;
}
void unpause() {
if (!_started) return;
_paused = false;
for (Sessions::const_iterator i = sessions.cbegin(), e = sessions.cend(); i != e; ++i) {
i.value()->unpaused();
}
}
void configure(int32 dc, int32 user) { void configure(int32 dc, int32 user) {
if (_started) return; if (_started) return;
internal::setDC(dc); internal::setDC(dc);

View file

@ -25,12 +25,13 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "core/single_timer.h" #include "core/single_timer.h"
namespace MTP { namespace MTP {
namespace internal { namespace internal {
Session *getSession(ShiftedDcId shiftedDcId); // 0 - current set dc Session *getSession(ShiftedDcId shiftedDcId); // 0 - current set dc
bool paused(); bool paused();
void pause();
void unpause();
void registerRequest(mtpRequestId requestId, int32 dc); void registerRequest(mtpRequestId requestId, int32 dc);
void unregisterRequest(mtpRequestId requestId); void unregisterRequest(mtpRequestId requestId);
@ -96,27 +97,32 @@ constexpr ShiftedDcId lgtDcId(DcId dcId) {
} }
namespace internal { namespace internal {
constexpr ShiftedDcId downloadDcId(DcId dcId, int index) {
static_assert(MTPDownloadSessionsCount < 0x10, "Too large MTPDownloadSessionsCount!"); constexpr ShiftedDcId downloadDcId(DcId dcId, int index) {
return shiftDcId(dcId, 0x10 + index); static_assert(MTPDownloadSessionsCount < 0x10, "Too large MTPDownloadSessionsCount!");
}; return shiftDcId(dcId, 0x10 + index);
} };
} // namespace internal
// send(req, callbacks, MTP::dldDcId(dc, index)) - for download shifted dc id // send(req, callbacks, MTP::dldDcId(dc, index)) - for download shifted dc id
inline ShiftedDcId dldDcId(DcId dcId, int index) { inline ShiftedDcId dldDcId(DcId dcId, int index) {
t_assert(index >= 0 && index < MTPDownloadSessionsCount); t_assert(index >= 0 && index < MTPDownloadSessionsCount);
return internal::downloadDcId(dcId, index); return internal::downloadDcId(dcId, index);
} }
constexpr bool isDldDcId(ShiftedDcId shiftedDcId) { constexpr bool isDldDcId(ShiftedDcId shiftedDcId) {
return (shiftedDcId >= internal::downloadDcId(0, 0)) && (shiftedDcId < internal::downloadDcId(0, MTPDownloadSessionsCount - 1) + DCShift); return (shiftedDcId >= internal::downloadDcId(0, 0)) && (shiftedDcId < internal::downloadDcId(0, MTPDownloadSessionsCount - 1) + DCShift);
} }
namespace internal { namespace internal {
constexpr ShiftedDcId uploadDcId(DcId dcId, int index) {
static_assert(MTPUploadSessionsCount < 0x10, "Too large MTPUploadSessionsCount!"); constexpr ShiftedDcId uploadDcId(DcId dcId, int index) {
return shiftDcId(dcId, 0x20 + index); static_assert(MTPUploadSessionsCount < 0x10, "Too large MTPUploadSessionsCount!");
}; return shiftDcId(dcId, 0x20 + index);
} };
} // namespace internal
// send(req, callbacks, MTP::uplDcId(index)) - for upload shifted dc id // send(req, callbacks, MTP::uplDcId(index)) - for upload shifted dc id
// uploading always to the main dc so bareDcId == 0 // uploading always to the main dc so bareDcId == 0
@ -124,6 +130,7 @@ inline ShiftedDcId uplDcId(int index) {
t_assert(index >= 0 && index < MTPUploadSessionsCount); t_assert(index >= 0 && index < MTPUploadSessionsCount);
return internal::uploadDcId(0, index); return internal::uploadDcId(0, index);
}; };
constexpr bool isUplDcId(ShiftedDcId shiftedDcId) { constexpr bool isUplDcId(ShiftedDcId shiftedDcId) {
return (shiftedDcId >= internal::uploadDcId(0, 0)) && (shiftedDcId < internal::uploadDcId(0, MTPUploadSessionsCount - 1) + DCShift); return (shiftedDcId >= internal::uploadDcId(0, 0)) && (shiftedDcId < internal::uploadDcId(0, MTPUploadSessionsCount - 1) + DCShift);
} }
@ -133,8 +140,29 @@ bool started();
void restart(); void restart();
void restart(int32 dcMask); void restart(int32 dcMask);
void pause(); class PauseHolder {
void unpause(); public:
PauseHolder() {
restart();
}
void restart() {
if (!base::take(_paused, true)) {
internal::pause();
}
}
void release() {
if (base::take(_paused)) {
internal::unpause();
}
}
~PauseHolder() {
release();
}
private:
bool _paused = false;
};
void configure(int32 dc, int32 user); void configure(int32 dc, int32 user);

View file

@ -132,7 +132,7 @@ protected:
} }
Ui::RadialAnimation *_radial; Ui::RadialAnimation *_radial;
anim::fvalue a_iconOver; anim::value a_iconOver;
Animation _a_iconOver; Animation _a_iconOver;
}; };

View file

@ -1878,7 +1878,6 @@ OverviewInner::~OverviewInner() {
OverviewWidget::OverviewWidget(QWidget *parent, PeerData *peer, MediaOverviewType type) : TWidget(parent) OverviewWidget::OverviewWidget(QWidget *parent, PeerData *peer, MediaOverviewType type) : TWidget(parent)
, _scroll(this, st::settingsScroll, false) , _scroll(this, st::settingsScroll, false)
, _inner(this, _scroll, peer, type) , _inner(this, _scroll, peer, type)
, _a_show(animation(this, &OverviewWidget::step_show))
, _topShadow(this, st::shadowColor) { , _topShadow(this, st::shadowColor) {
_scroll->setOwnedWidget(_inner); _scroll->setOwnedWidget(_inner);
_scroll->move(0, 0); _scroll->move(0, 0);
@ -1936,18 +1935,23 @@ void OverviewWidget::paintEvent(QPaintEvent *e) {
if (App::wnd() && App::wnd()->contentOverlapped(this, e)) return; if (App::wnd() && App::wnd()->contentOverlapped(this, e)) return;
Painter p(this); Painter p(this);
auto progress = _a_show.current(getms(), 1.);
if (_a_show.animating()) { if (_a_show.animating()) {
int retina = cIntRetinaFactor(); auto retina = cIntRetinaFactor();
int inCacheTop = st::topBarHeight; auto inCacheTop = st::topBarHeight;
if (a_coordOver.current() > 0) { auto fromLeft = (_showDirection == Window::SlideDirection::FromLeft);
p.drawPixmap(QRect(0, 0, a_coordOver.current(), height()), _cacheUnder, QRect(-a_coordUnder.current() * retina, inCacheTop * retina, a_coordOver.current() * retina, height() * retina)); auto coordUnder = fromLeft ? anim::interpolate(-st::slideShift, 0, progress) : anim::interpolate(0, -st::slideShift, progress);
p.setOpacity(a_progress.current()); auto coordOver = fromLeft ? anim::interpolate(0, width(), progress) : anim::interpolate(width(), 0, progress);
p.fillRect(0, 0, a_coordOver.current(), height(), st::slideFadeOutBg); auto shadow = fromLeft ? (1. - progress) : progress;
if (coordOver > 0) {
p.drawPixmap(QRect(0, 0, coordOver, height()), _cacheUnder, QRect(-coordUnder * retina, inCacheTop * retina, coordOver * retina, height() * retina));
p.setOpacity(shadow);
p.fillRect(0, 0, coordOver, height(), st::slideFadeOutBg);
p.setOpacity(1); p.setOpacity(1);
} }
p.drawPixmap(QRect(a_coordOver.current(), 0, _cacheOver.width() / retina, height()), _cacheOver, QRect(0, inCacheTop * retina, _cacheOver.width(), height() * retina)); p.drawPixmap(QRect(coordOver, 0, _cacheOver.width() / retina, height()), _cacheOver, QRect(0, inCacheTop * retina, _cacheOver.width(), height() * retina));
p.setOpacity(a_progress.current()); p.setOpacity(shadow);
st::slideShadow.fill(p, QRect(a_coordOver.current() - st::slideShadow.width(), 0, st::slideShadow.width(), height())); st::slideShadow.fill(p, QRect(coordOver - st::slideShadow.width(), 0, st::slideShadow.width(), height()));
return; return;
} }
@ -1972,16 +1976,21 @@ void OverviewWidget::scrollReset() {
bool OverviewWidget::paintTopBar(Painter &p, int decreaseWidth) { bool OverviewWidget::paintTopBar(Painter &p, int decreaseWidth) {
if (_a_show.animating()) { if (_a_show.animating()) {
int retina = cIntRetinaFactor(); auto progress = _a_show.current(1.);
if (a_coordOver.current() > 0) { auto retina = cIntRetinaFactor();
p.drawPixmap(QRect(0, 0, a_coordOver.current(), st::topBarHeight), _cacheUnder, QRect(-a_coordUnder.current() * retina, 0, a_coordOver.current() * retina, st::topBarHeight * retina)); auto fromLeft = (_showDirection == Window::SlideDirection::FromLeft);
p.setOpacity(a_progress.current()); auto coordUnder = fromLeft ? anim::interpolate(-st::slideShift, 0, progress) : anim::interpolate(0, -st::slideShift, progress);
p.fillRect(0, 0, a_coordOver.current(), st::topBarHeight, st::slideFadeOutBg); auto coordOver = fromLeft ? anim::interpolate(0, width(), progress) : anim::interpolate(width(), 0, progress);
auto shadow = fromLeft ? (1. - progress) : progress;
if (coordOver > 0) {
p.drawPixmap(QRect(0, 0, coordOver, st::topBarHeight), _cacheUnder, QRect(-coordUnder * retina, 0, coordOver * retina, st::topBarHeight * retina));
p.setOpacity(shadow);
p.fillRect(0, 0, coordOver, st::topBarHeight, st::slideFadeOutBg);
p.setOpacity(1); p.setOpacity(1);
} }
p.drawPixmap(QRect(a_coordOver.current(), 0, _cacheOver.width() / retina, st::topBarHeight), _cacheOver, QRect(0, 0, _cacheOver.width(), st::topBarHeight * retina)); p.drawPixmap(QRect(coordOver, 0, _cacheOver.width() / retina, st::topBarHeight), _cacheOver, QRect(0, 0, _cacheOver.width(), st::topBarHeight * retina));
p.setOpacity(a_progress.current()); p.setOpacity(shadow);
st::slideShadow.fill(p, QRect(a_coordOver.current() - st::slideShadow.width(), 0, st::slideShadow.width(), st::topBarHeight)); st::slideShadow.fill(p, QRect(coordOver - st::slideShadow.width(), 0, st::slideShadow.width(), st::topBarHeight));
return false; return false;
} }
st::topBarBack.paint(p, (st::topBarArrowPadding.left() - st::topBarBack.width()) / 2, (st::topBarHeight - st::topBarBack.height()) / 2, width()); st::topBarBack.paint(p, (st::topBarArrowPadding.left() - st::topBarBack.width()) / 2, (st::topBarHeight - st::topBarBack.height()) / 2, width());
@ -2080,8 +2089,6 @@ void OverviewWidget::fastShow(bool back, int32 lastScrollTop) {
show(); show();
_inner->activate(); _inner->activate();
doneShow(); doneShow();
if (App::app()) App::app()->mtpUnpause();
} }
void OverviewWidget::setLastScrollTop(int lastScrollTop) { void OverviewWidget::setLastScrollTop(int lastScrollTop) {
@ -2090,10 +2097,11 @@ void OverviewWidget::setLastScrollTop(int lastScrollTop) {
} }
void OverviewWidget::showAnimated(Window::SlideDirection direction, const Window::SectionSlideParams &params) { void OverviewWidget::showAnimated(Window::SlideDirection direction, const Window::SectionSlideParams &params) {
if (App::app()) App::app()->mtpPause(); _showDirection = direction;
resizeEvent(0); resizeEvent(0);
_a_show.finish();
_cacheUnder = params.oldContentCache; _cacheUnder = params.oldContentCache;
show(); show();
_topShadow->setVisible(params.withTopBarShadow ? false : true); _topShadow->setVisible(params.withTopBarShadow ? false : true);
@ -2104,47 +2112,26 @@ void OverviewWidget::showAnimated(Window::SlideDirection direction, const Window
_scrollSetAfterShow = _scroll->scrollTop(); _scrollSetAfterShow = _scroll->scrollTop();
_scroll->hide(); _scroll->hide();
int delta = st::slideShift; if (_showDirection == Window::SlideDirection::FromLeft) {
if (direction == Window::SlideDirection::FromLeft) {
a_progress = anim::fvalue(1, 0);
std::swap(_cacheUnder, _cacheOver); std::swap(_cacheUnder, _cacheOver);
a_coordUnder = anim::ivalue(-delta, 0);
a_coordOver = anim::ivalue(0, width());
} else {
a_progress = anim::fvalue(0, 1);
a_coordUnder = anim::ivalue(0, -delta);
a_coordOver = anim::ivalue(width(), 0);
} }
_a_show.start(); _a_show.start([this] { animationCallback(); }, 0., 1., st::slideDuration, Window::SlideAnimation::transition());
App::main()->topBar()->update(); App::main()->topBar()->update();
activate(); activate();
} }
void OverviewWidget::step_show(float64 ms, bool timer) { void OverviewWidget::animationCallback() {
float64 dt = ms / st::slideDuration; update();
if (dt >= 1) { App::main()->topBar()->update();
_a_show.stop(); if (!_a_show.animating()) {
_topShadow->show(); _topShadow->show();
a_coordUnder.finish();
a_coordOver.finish();
a_progress.finish();
_cacheUnder = _cacheOver = QPixmap(); _cacheUnder = _cacheOver = QPixmap();
App::main()->topBar()->stopAnim(); App::main()->topBar()->stopAnim();
doneShow(); doneShow();
if (App::app()) App::app()->mtpUnpause();
} else {
a_coordUnder.update(dt, Window::SlideAnimation::transition());
a_coordOver.update(dt, Window::SlideAnimation::transition());
a_progress.update(dt, Window::SlideAnimation::transition());
}
if (timer) {
update();
App::main()->topBar()->update();
} }
} }

View file

@ -301,7 +301,6 @@ public:
} }
void setLastScrollTop(int lastScrollTop); void setLastScrollTop(int lastScrollTop);
void showAnimated(Window::SlideDirection direction, const Window::SectionSlideParams &params); void showAnimated(Window::SlideDirection direction, const Window::SectionSlideParams &params);
void step_show(float64 ms, bool timer);
void doneShow(); void doneShow();
@ -355,16 +354,17 @@ public slots:
void onClearSelected(); void onClearSelected();
private: private:
void animationCallback();
ChildWidget<Ui::ScrollArea> _scroll; ChildWidget<Ui::ScrollArea> _scroll;
ChildWidget<OverviewInner> _inner; ChildWidget<OverviewInner> _inner;
bool _noDropResizeIndex = false; bool _noDropResizeIndex = false;
QString _header; QString _header;
Animation _a_show; FloatAnimation _a_show;
Window::SlideDirection _showDirection;
QPixmap _cacheUnder, _cacheOver; QPixmap _cacheUnder, _cacheOver;
anim::ivalue a_coordUnder, a_coordOver;
anim::fvalue a_progress;
int32 _scrollSetAfterShow = 0; int32 _scrollSetAfterShow = 0;

View file

@ -32,7 +32,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "window/window_slide_animation.h" #include "window/window_slide_animation.h"
PasscodeWidget::PasscodeWidget(QWidget *parent) : TWidget(parent) PasscodeWidget::PasscodeWidget(QWidget *parent) : TWidget(parent)
, _a_show(animation(this, &PasscodeWidget::step_show))
, _passcode(this, st::passcodeInput) , _passcode(this, st::passcodeInput)
, _submit(this, lang(lng_passcode_submit), st::passcodeSubmit) , _submit(this, lang(lng_passcode_submit), st::passcodeSubmit)
, _logout(this, lang(lng_passcode_logout)) { , _logout(this, lang(lng_passcode_logout)) {
@ -104,52 +103,30 @@ void PasscodeWidget::onChanged() {
} }
} }
void PasscodeWidget::animShow(const QPixmap &bgAnimCache, bool back) { void PasscodeWidget::showAnimated(const QPixmap &bgAnimCache, bool back) {
if (App::app()) App::app()->mtpPause(); _showBack = back;
(_showBack ? _cacheOver : _cacheUnder) = bgAnimCache;
(back ? _cacheOver : _cacheUnder) = bgAnimCache; _a_show.finish();
_a_show.stop();
showAll(); showAll();
(back ? _cacheUnder : _cacheOver) = myGrab(this); (_showBack ? _cacheUnder : _cacheOver) = myGrab(this);
hideAll(); hideAll();
a_coordUnder = back ? anim::ivalue(-st::slideShift, 0) : anim::ivalue(0, -st::slideShift); _a_show.start([this] { animationCallback(); }, 0., 1., st::slideDuration, Window::SlideAnimation::transition());
a_coordOver = back ? anim::ivalue(0, width()) : anim::ivalue(width(), 0);
a_shadow = back ? anim::fvalue(1, 0) : anim::fvalue(0, 1);
_a_show.start();
show(); show();
} }
void PasscodeWidget::step_show(float64 ms, bool timer) { void PasscodeWidget::animationCallback() {
float64 dt = ms / st::slideDuration; update();
if (dt >= 1) { if (!_a_show.animating()) {
_a_show.stop();
a_coordUnder.finish();
a_coordOver.finish();
a_shadow.finish();
_cacheUnder = _cacheOver = QPixmap();
showAll(); showAll();
if (App::wnd()) App::wnd()->setInnerFocus(); if (App::wnd()) App::wnd()->setInnerFocus();
if (App::app()) App::app()->mtpUnpause();
Ui::showChatsList(); Ui::showChatsList();
} else {
a_coordUnder.update(dt, Window::SlideAnimation::transition());
a_coordOver.update(dt, Window::SlideAnimation::transition());
a_shadow.update(dt, Window::SlideAnimation::transition());
}
if (timer) update();
}
void PasscodeWidget::stop_show() { _cacheUnder = _cacheOver = QPixmap();
_a_show.stop(); }
} }
void PasscodeWidget::showAll() { void PasscodeWidget::showAll() {
@ -173,16 +150,20 @@ void PasscodeWidget::paintEvent(QPaintEvent *e) {
p.setClipRect(e->rect()); p.setClipRect(e->rect());
} }
auto progress = _a_show.current(getms(), 1.);
if (_a_show.animating()) { if (_a_show.animating()) {
if (a_coordOver.current() > 0) { auto coordUnder = _showBack ? anim::interpolate(-st::slideShift, 0, progress) : anim::interpolate(0, -st::slideShift, progress);
p.drawPixmap(QRect(0, 0, a_coordOver.current(), height()), _cacheUnder, QRect(-a_coordUnder.current() * cRetinaFactor(), 0, a_coordOver.current() * cRetinaFactor(), height() * cRetinaFactor())); auto coordOver = _showBack ? anim::interpolate(0, width(), progress) : anim::interpolate(width(), 0, progress);
p.setOpacity(a_shadow.current()); auto shadow = _showBack ? (1. - progress) : progress;
p.fillRect(0, 0, a_coordOver.current(), height(), st::slideFadeOutBg); if (coordOver > 0) {
p.drawPixmap(QRect(0, 0, coordOver, height()), _cacheUnder, QRect(-coordUnder * cRetinaFactor(), 0, coordOver * cRetinaFactor(), height() * cRetinaFactor()));
p.setOpacity(shadow);
p.fillRect(0, 0, coordOver, height(), st::slideFadeOutBg);
p.setOpacity(1); p.setOpacity(1);
} }
p.drawPixmap(a_coordOver.current(), 0, _cacheOver); p.drawPixmap(coordOver, 0, _cacheOver);
p.setOpacity(a_shadow.current()); p.setOpacity(shadow);
st::slideShadow.fill(p, QRect(a_coordOver.current() - st::slideShadow.width(), 0, st::slideShadow.width(), height())); st::slideShadow.fill(p, QRect(coordOver - st::slideShadow.width(), 0, st::slideShadow.width(), height()));
} else { } else {
p.fillRect(rect(), st::windowBg); p.fillRect(rect(), st::windowBg);

View file

@ -34,9 +34,7 @@ public:
void setInnerFocus(); void setInnerFocus();
void animShow(const QPixmap &bgAnimCache, bool back = false); void showAnimated(const QPixmap &bgAnimCache, bool back = false);
void step_show(float64 ms, bool timer);
void stop_show();
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
@ -48,13 +46,14 @@ public slots:
void onSubmit(); void onSubmit();
private: private:
void animationCallback();
void showAll(); void showAll();
void hideAll(); void hideAll();
Animation _a_show; FloatAnimation _a_show;
bool _showBack = false;
QPixmap _cacheUnder, _cacheOver; QPixmap _cacheUnder, _cacheOver;
anim::ivalue a_coordUnder, a_coordOver;
anim::fvalue a_shadow;
ChildWidget<Ui::PasswordInput> _passcode; ChildWidget<Ui::PasswordInput> _passcode;
ChildWidget<Ui::RoundButton> _submit; ChildWidget<Ui::RoundButton> _submit;

View file

@ -89,9 +89,9 @@ void TitleWidget::onWindowStateChanged(Qt::WindowState state) {
void TitleWidget::updateMaximizeRestoreButton() { void TitleWidget::updateMaximizeRestoreButton() {
if (_maximized) { if (_maximized) {
_maximizeRestore->setIcon(&st::titleButtonRestoreIcon, &st::titleButtonRestoreIconOver); _maximizeRestore->setIconOverride(&st::titleButtonRestoreIcon, &st::titleButtonRestoreIconOver);
} else { } else {
_maximizeRestore->setIcon(nullptr, nullptr); _maximizeRestore->setIconOverride(nullptr, nullptr);
} }
} }

View file

@ -123,7 +123,7 @@ profileMemberNamePosition: point(68px, 11px);
profileMemberNameFg: #222222; profileMemberNameFg: #222222;
profileMemberStatusPosition: point(68px, 31px); profileMemberStatusPosition: point(68px, 31px);
profileMemberStatusFg: windowSubTextFg; profileMemberStatusFg: windowSubTextFg;
profileMemberStatusFgOver: windowSubTextFgOver; profileMemberStatusFgOver: #7c99b2;
profileMemberStatusFgActive: windowActiveTextFg; profileMemberStatusFgActive: windowActiveTextFg;
profileMemberAdminIcon: icon {{ "profile_admin_star", windowBgActive, point(4px, 3px) }}; profileMemberAdminIcon: icon {{ "profile_admin_star", windowBgActive, point(4px, 3px) }};
profileLimitReachedLabel: FlatLabel(defaultFlatLabel) { profileLimitReachedLabel: FlatLabel(defaultFlatLabel) {

View file

@ -63,7 +63,7 @@ void CommonGroupsWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) {
int CommonGroupsWidget::resizeGetHeight(int newWidth) { int CommonGroupsWidget::resizeGetHeight(int newWidth) {
auto result = PeerListWidget::resizeGetHeight(newWidth); auto result = PeerListWidget::resizeGetHeight(newWidth);
return _height.animating() ? _height.current() : result; return qRound(_height.current(result));
} }
void CommonGroupsWidget::paintContents(Painter &p) { void CommonGroupsWidget::paintContents(Painter &p) {

View file

@ -65,7 +65,7 @@ private:
Item *computeItem(PeerData *group); Item *computeItem(PeerData *group);
QMap<PeerData*, Item*> _dataMap; QMap<PeerData*, Item*> _dataMap;
IntAnimation _height; FloatAnimation _height;
int32 _preloadGroupId = 0; int32 _preloadGroupId = 0;
mtpRequestId _preloadRequestId = 0; mtpRequestId _preloadRequestId = 0;

View file

@ -58,13 +58,17 @@ InfoWidget::InfoWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, pe
void InfoWidget::showFinished() { void InfoWidget::showFinished() {
_showFinished = true; _showFinished = true;
if (_commonGroups && _commonGroups->isHidden() && getCommonGroupsCount() > 0) { if (_commonGroups && _commonGroups->isHidden() && getCommonGroupsCount() > 0) {
_commonGroups->show(); slideCommonGroupsDown();
refreshVisibility();
_height.start([this] { contentSizeUpdated(); }, isHidden() ? 0 : height(), resizeGetHeight(width()), st::widgetSlideDuration);
contentSizeUpdated();
} }
} }
void InfoWidget::slideCommonGroupsDown() {
_commonGroups->show();
refreshVisibility();
_height.start([this] { contentSizeUpdated(); }, isHidden() ? 0 : height(), resizeGetHeight(width()), st::widgetSlideDuration);
contentSizeUpdated();
}
void InfoWidget::restoreState(const SectionMemento *memento) { void InfoWidget::restoreState(const SectionMemento *memento) {
if (!memento->getCommonGroups().isEmpty()) { if (!memento->getCommonGroups().isEmpty()) {
onForceHideCommonGroups(); onForceHideCommonGroups();
@ -152,7 +156,7 @@ int InfoWidget::resizeGetHeight(int newWidth) {
} }
newHeight += st::profileBlockMarginBottom; newHeight += st::profileBlockMarginBottom;
return _height.animating() ? _height.current() : newHeight; return qRound(_height.current(newHeight));
} }
void InfoWidget::leaveEvent(QEvent *e) { void InfoWidget::leaveEvent(QEvent *e) {
@ -258,8 +262,7 @@ void InfoWidget::refreshCommonGroups() {
_commonGroups->setClickedCallback([this] { onShowCommonGroups(); }); _commonGroups->setClickedCallback([this] { onShowCommonGroups(); });
_commonGroups->hide(); _commonGroups->hide();
if (_showFinished) { if (_showFinished) {
_height.start([this] { contentSizeUpdated(); }, isHidden() ? 0 : height(), resizeGetHeight(width()), st::widgetSlideDuration); slideCommonGroupsDown();
contentSizeUpdated();
} }
} }
} else if (_commonGroups) { } else if (_commonGroups) {

View file

@ -68,6 +68,7 @@ private:
int getCommonGroupsCount() const; int getCommonGroupsCount() const;
void onForceHideCommonGroups(); void onForceHideCommonGroups();
void onShowCommonGroups(); void onShowCommonGroups();
void slideCommonGroupsDown();
// labelWidget may be nullptr. // labelWidget may be nullptr.
void setLabeledText(ChildWidget<Ui::FlatLabel> *labelWidget, const QString &label, void setLabeledText(ChildWidget<Ui::FlatLabel> *labelWidget, const QString &label,
@ -83,7 +84,7 @@ private:
ChildWidget<Ui::FlatLabel> _username = { nullptr }; ChildWidget<Ui::FlatLabel> _username = { nullptr };
ChildWidget<Ui::LeftOutlineButton> _commonGroups = { nullptr }; ChildWidget<Ui::LeftOutlineButton> _commonGroups = { nullptr };
IntAnimation _height; FloatAnimation _height;
bool _showFinished = false; bool _showFinished = false;
bool _forceHiddenCommonGroups = false; bool _forceHiddenCommonGroups = false;

View file

@ -21,11 +21,17 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "stdafx.h" #include "stdafx.h"
#include "profile/profile_block_peer_list.h" #include "profile/profile_block_peer_list.h"
#include "ui/effects/ripple_animation.h"
#include "styles/style_profile.h" #include "styles/style_profile.h"
#include "styles/style_widgets.h" #include "styles/style_widgets.h"
namespace Profile { namespace Profile {
PeerListWidget::Item::Item(PeerData *peer) : peer(peer) {
}
PeerListWidget::Item::~Item() = default;
PeerListWidget::PeerListWidget(QWidget *parent, PeerData *peer, const QString &title, const QString &removeText) PeerListWidget::PeerListWidget(QWidget *parent, PeerData *peer, const QString &title, const QString &removeText)
: BlockWidget(parent, peer, title) : BlockWidget(parent, peer, title)
, _removeText(removeText) , _removeText(removeText)
@ -54,38 +60,39 @@ void PeerListWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) {
} }
void PeerListWidget::paintContents(Painter &p) { void PeerListWidget::paintContents(Painter &p) {
int left = getListLeft(); auto ms = getms();
int top = getListTop(); auto left = getListLeft();
int memberRowWidth = width() - left; auto top = getListTop();
accumulate_min(memberRowWidth, st::profileBlockWideWidthMax); auto memberRowWidth = rowWidth();
int from = floorclamp(_visibleTop - top, st::profileMemberHeight, 0, _items.size()); auto from = floorclamp(_visibleTop - top, st::profileMemberHeight, 0, _items.size());
int to = ceilclamp(_visibleBottom - top, st::profileMemberHeight, 0, _items.size()); auto to = ceilclamp(_visibleBottom - top, st::profileMemberHeight, 0, _items.size());
for (int i = from; i < to; ++i) { for (auto i = from; i < to; ++i) {
int y = top + i * st::profileMemberHeight; auto y = top + i * st::profileMemberHeight;
bool selected = (i == _selected); auto selected = (_pressed >= 0) ? (i == _pressed) : (i == _selected);
bool selectedRemove = selected && _selectedRemove; auto selectedRemove = selected && _selectedRemove;
if (_pressed >= 0) { if (_pressed >= 0 && !_pressedRemove) {
if (_pressed != _selected) { selectedRemove = false;
selected = selectedRemove = false;
} else if (!_pressedRemove) {
_selectedRemove = false;
}
} }
paintItem(p, left, y, _items[i], selected, selectedRemove); paintItem(p, left, y, _items[i], selected, selectedRemove, ms);
} }
} }
void PeerListWidget::paintItem(Painter &p, int x, int y, Item *item, bool selected, bool selectedKick) { void PeerListWidget::paintItem(Painter &p, int x, int y, Item *item, bool selected, bool selectedKick, TimeMs ms) {
if (_updateItemCallback) { if (_updateItemCallback) {
_updateItemCallback(item); _updateItemCallback(item);
} }
int memberRowWidth = width() - x; auto memberRowWidth = rowWidth();
accumulate_min(memberRowWidth, st::profileBlockWideWidthMax);
if (selected) { if (selected) {
paintOutlinedRect(p, x, y, memberRowWidth, st::profileMemberHeight); paintOutlinedRect(p, x, y, memberRowWidth, st::profileMemberHeight);
} }
if (auto &ripple = item->ripple) {
ripple->paint(p, x + st::defaultLeftOutlineButton.outlineWidth, y, width(), ms);
if (ripple->empty()) {
ripple.reset();
}
}
int skip = st::profileMemberPhotoPosition.x(); int skip = st::profileMemberPhotoPosition.x();
item->peer->paintUserpicLeft(p, st::profileMemberPhotoSize, x + st::profileMemberPhotoPosition.x(), y + st::profileMemberPhotoPosition.y(), width()); item->peer->paintUserpicLeft(p, st::profileMemberPhotoSize, x + st::profileMemberPhotoPosition.x(), y + st::profileMemberPhotoPosition.y(), width());
@ -136,19 +143,36 @@ void PeerListWidget::mousePressEvent(QMouseEvent *e) {
_pressed = _selected; _pressed = _selected;
_pressedRemove = _selectedRemove; _pressedRemove = _selectedRemove;
if (_pressed >= 0 && !_pressedRemove) {
auto item = _items[_pressed];
if (!item->ripple) {
auto memberRowWidth = rowWidth();
auto mask = Ui::RippleAnimation::rectMask(QSize(memberRowWidth - st::defaultLeftOutlineButton.outlineWidth, st::profileMemberHeight));
item->ripple = std_::make_unique<Ui::RippleAnimation>(st::defaultLeftOutlineButton.ripple, std_::move(mask), [this, index = _pressed] {
repaintRow(index);
});
}
auto left = getListLeft() + st::defaultLeftOutlineButton.outlineWidth;
auto top = getListTop() + st::profileMemberHeight * _pressed;
item->ripple->add(e->pos() - QPoint(left, top));
}
} }
void PeerListWidget::mouseReleaseEvent(QMouseEvent *e) { void PeerListWidget::mouseReleaseEvent(QMouseEvent *e) {
_mousePosition = e->globalPos(); _mousePosition = e->globalPos();
updateSelection(); updateSelection();
auto pressed = _pressed; repaintRow(_pressed);
auto pressedRemove = _pressedRemove; auto pressed = base::take(_pressed, -1);
_pressed = -1; auto pressedRemove = base::take(_pressedRemove);
_pressedRemove = false; if (pressed >= 0 && pressed < _items.size()) {
if (pressed >= 0 && pressed < _items.size() && pressed == _selected && pressedRemove == _selectedRemove) { if (auto &ripple = _items[pressed]->ripple) {
if (auto &callback = (pressedRemove ? _removedCallback : _selectedCallback)) { ripple->lastStop();
callback(_items[pressed]->peer); }
if (pressed == _selected && pressedRemove == _selectedRemove) {
if (auto &callback = (pressedRemove ? _removedCallback : _selectedCallback)) {
callback(_items[pressed]->peer);
}
} }
} }
setCursor(_selectedRemove ? style::cur_pointer : style::cur_default); setCursor(_selectedRemove ? style::cur_pointer : style::cur_default);
@ -166,15 +190,14 @@ void PeerListWidget::leaveEvent(QEvent *e) {
} }
void PeerListWidget::updateSelection() { void PeerListWidget::updateSelection() {
int selected = -1; auto selected = -1;
bool selectedKick = false; auto selectedKick = false;
auto mouse = mapFromGlobal(_mousePosition); auto mouse = mapFromGlobal(_mousePosition);
if (rtl()) mouse.setX(width() - mouse.x()); if (rtl()) mouse.setX(width() - mouse.x());
int left = getListLeft(); auto left = getListLeft();
int top = getListTop(); auto top = getListTop();
int memberRowWidth = width() - left; auto memberRowWidth = rowWidth();
accumulate_min(memberRowWidth, st::profileBlockWideWidthMax);
if (mouse.x() >= left && mouse.x() < left + memberRowWidth && mouse.y() >= top) { if (mouse.x() >= left && mouse.x() < left + memberRowWidth && mouse.y() >= top) {
selected = (mouse.y() - top) / st::profileMemberHeight; selected = (mouse.y() - top) / st::profileMemberHeight;
if (selected >= _items.size()) { if (selected >= _items.size()) {
@ -214,9 +237,13 @@ void PeerListWidget::setSelected(int selected, bool selectedRemove) {
} }
void PeerListWidget::repaintSelectedRow() { void PeerListWidget::repaintSelectedRow() {
if (_selected >= 0) { repaintRow(_selected);
int left = getListLeft(); }
rtlupdate(left, getListTop() + _selected * st::profileMemberHeight, width() - left, st::profileMemberHeight);
void PeerListWidget::repaintRow(int index) {
if (index >= 0) {
auto left = getListLeft();
rtlupdate(left, getListTop() + index * st::profileMemberHeight, width() - left, st::profileMemberHeight);
} }
} }
@ -224,6 +251,10 @@ int PeerListWidget::getListLeft() const {
return st::profileBlockTitlePosition.x() - st::profileMemberPaddingLeft; return st::profileBlockTitlePosition.x() - st::profileMemberPaddingLeft;
} }
int PeerListWidget::rowWidth() const {
return qMin(width() - getListLeft(), st::profileBlockWideWidthMax);
}
void PeerListWidget::preloadPhotos() { void PeerListWidget::preloadPhotos() {
int top = getListTop(); int top = getListTop();
int preloadFor = (_visibleBottom - _visibleTop) * PreloadHeightsCount; int preloadFor = (_visibleBottom - _visibleTop) * PreloadHeightsCount;

View file

@ -22,6 +22,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "profile/profile_block_widget.h" #include "profile/profile_block_widget.h"
namespace Ui {
class RippleAnimation;
} // namespace Ui
namespace Notify { namespace Notify {
struct PeerUpdate; struct PeerUpdate;
} // namespace Notify } // namespace Notify
@ -35,14 +39,16 @@ public:
void setVisibleTopBottom(int visibleTop, int visibleBottom) override; void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
struct Item { struct Item {
explicit Item(PeerData *peer) : peer(peer) { explicit Item(PeerData *peer);
} ~Item();
PeerData * const peer; PeerData * const peer;
Text name; Text name;
QString statusText; QString statusText;
bool statusHasOnlineColor = false; bool statusHasOnlineColor = false;
bool hasAdminStar = false; bool hasAdminStar = false;
bool hasRemoveLink = false; bool hasRemoveLink = false;
std_::unique_ptr<Ui::RippleAnimation> ripple;
}; };
virtual int getListTop() const { virtual int getListTop() const {
return contentTop(); return contentTop();
@ -111,9 +117,11 @@ private:
void updateSelection(); void updateSelection();
void setSelected(int selected, bool selectedRemove); void setSelected(int selected, bool selectedRemove);
void repaintSelectedRow(); void repaintSelectedRow();
void repaintRow(int index);
void preloadPhotos(); void preloadPhotos();
int rowWidth() const;
void paintItem(Painter &p, int x, int y, Item *item, bool selected, bool selectedRemove); void paintItem(Painter &p, int x, int y, Item *item, bool selected, bool selectedRemove, TimeMs ms);
base::lambda<void()> _preloadMoreCallback; base::lambda<void()> _preloadMoreCallback;
base::lambda<void(PeerData*)> _selectedCallback; base::lambda<void(PeerData*)> _selectedCallback;

View file

@ -60,8 +60,8 @@ protected:
Window::TopBarWidget::paintUnreadCounter(p, width()); Window::TopBarWidget::paintUnreadCounter(p, width());
} }
void onStateChanged(int oldState, StateChangeSource source) override { void onStateChanged(State was, StateChangeSource source) override {
if ((_state & StateDown) && !(oldState & StateDown)) { if (isDown() && !(was & StateFlag::Down)) {
emit clicked(); emit clicked();
} }
} }

View file

@ -177,7 +177,7 @@ void EmojiColorPicker::step_appearance(float64 ms, bool timer) {
void EmojiColorPicker::hideFast() { void EmojiColorPicker::hideFast() {
clearSelection(); clearSelection();
if (_a_appearance.animating()) _a_appearance.stop(); if (_a_appearance.animating()) _a_appearance.stop();
a_opacity = anim::fvalue(0); a_opacity = anim::value();
_cache = QPixmap(); _cache = QPixmap();
hide(); hide();
emit hidden(); emit hidden();
@ -2899,7 +2899,9 @@ void EmojiPan::paintContent(Painter &p) {
paintStickerSettingsIcon(p); paintStickerSettingsIcon(p);
if (!_icons.isEmpty()) { if (!_icons.isEmpty()) {
int x = _iconsLeft, selxrel = _iconsLeft + _iconSelX.current(), selx = selxrel - _iconsX.current(); auto x = _iconsLeft;
auto selxrel = _iconsLeft + qRound(_iconSelX.current());
auto selx = selxrel - qRound(_iconsX.current());
QRect clip(x, _iconsTop, _iconsLeft + 7 * st::emojiCategory.width - x, st::emojiCategory.height); QRect clip(x, _iconsTop, _iconsLeft + 7 * st::emojiCategory.width - x, st::emojiCategory.height);
if (rtl()) clip.moveLeft(width() - x - clip.width()); if (rtl()) clip.moveLeft(width() - x - clip.width());
@ -2915,9 +2917,10 @@ void EmojiPan::paintContent(Painter &p) {
}; };
int i = 0; int i = 0;
i += _iconsX.current() / int(st::emojiCategory.width); auto iconsX = qRound(_iconsX.current());
x -= _iconsX.current() % int(st::emojiCategory.width); i += iconsX / int(st::emojiCategory.width);
selxrel -= _iconsX.current(); x -= iconsX % int(st::emojiCategory.width);
selxrel -= iconsX;
for (int l = qMin(_icons.size(), i + 8); i < l; ++i) { for (int l = qMin(_icons.size(), i + 8); i < l; ++i) {
auto &s = _icons.at(i); auto &s = _icons.at(i);
if (s.sticker) { if (s.sticker) {
@ -2938,13 +2941,13 @@ void EmojiPan::paintContent(Painter &p) {
if (rtl()) selx = width() - selx - st::emojiCategory.width; if (rtl()) selx = width() - selx - st::emojiCategory.width;
p.fillRect(selx, _iconsTop + st::emojiCategory.height - st::stickerIconPadding, st::emojiCategory.width, st::stickerIconSel, st::stickerIconSelColor); p.fillRect(selx, _iconsTop + st::emojiCategory.height - st::stickerIconPadding, st::emojiCategory.width, st::stickerIconSel, st::stickerIconSelColor);
float64 o_left = snap(float64(_iconsX.current()) / st::stickerIconLeft.width(), 0., 1.); auto o_left = snap(_iconsX.current() / st::stickerIconLeft.width(), 0., 1.);
if (o_left > 0) { if (o_left > 0) {
p.setOpacity(o_left); p.setOpacity(o_left);
st::stickerIconLeft.fill(p, rtlrect(_iconsLeft, _iconsTop, st::stickerIconLeft.width(), st::emojiCategory.height, width())); st::stickerIconLeft.fill(p, rtlrect(_iconsLeft, _iconsTop, st::stickerIconLeft.width(), st::emojiCategory.height, width()));
p.setOpacity(1.); p.setOpacity(1.);
} }
float64 o_right = snap(float64(_iconsMax - _iconsX.current()) / st::stickerIconRight.width(), 0., 1.); auto o_right = snap((_iconsMax - _iconsX.current()) / st::stickerIconRight.width(), 0., 1.);
if (o_right > 0) { if (o_right > 0) {
p.setOpacity(o_right); p.setOpacity(o_right);
st::stickerIconRight.fill(p, rtlrect(_iconsLeft + 7 * st::emojiCategory.width - st::stickerIconRight.width(), _iconsTop, st::stickerIconRight.width(), st::emojiCategory.height, width())); st::stickerIconRight.fill(p, rtlrect(_iconsLeft + 7 * st::emojiCategory.width - st::stickerIconRight.width(), _iconsTop, st::stickerIconRight.width(), st::emojiCategory.height, width()));
@ -3019,7 +3022,7 @@ void EmojiPan::mousePressEvent(QMouseEvent *e) {
} else { } else {
_iconDown = _iconOver; _iconDown = _iconOver;
_iconsMouseDown = _iconsMousePos; _iconsMouseDown = _iconsMousePos;
_iconsStartX = _iconsX.current(); _iconsStartX = qRound(_iconsX.current());
} }
} }
@ -3034,9 +3037,9 @@ void EmojiPan::mouseMoveEvent(QMouseEvent *e) {
} }
} }
if (_iconsDragging) { if (_iconsDragging) {
int32 newX = snap(_iconsStartX + (rtl() ? -1 : 1) * (_iconsMouseDown.x() - _iconsMousePos.x()), 0, _iconsMax); auto newX = snap(_iconsStartX + (rtl() ? -1 : 1) * (_iconsMouseDown.x() - _iconsMousePos.x()), 0, _iconsMax);
if (newX != _iconsX.current()) { if (newX != qRound(_iconsX.current())) {
_iconsX = anim::ivalue(newX, newX); _iconsX = anim::value(newX, newX);
_iconsStartAnim = 0; _iconsStartAnim = 0;
_a_icons.stop(); _a_icons.stop();
updateIcons(); updateIcons();
@ -3052,9 +3055,9 @@ void EmojiPan::mouseReleaseEvent(QMouseEvent *e) {
_iconsMousePos = e ? e->globalPos() : QCursor::pos(); _iconsMousePos = e ? e->globalPos() : QCursor::pos();
if (_iconsDragging) { if (_iconsDragging) {
int32 newX = snap(_iconsStartX + _iconsMouseDown.x() - _iconsMousePos.x(), 0, _iconsMax); auto newX = snap(_iconsStartX + _iconsMouseDown.x() - _iconsMousePos.x(), 0, _iconsMax);
if (newX != _iconsX.current()) { if (newX != qRound(_iconsX.current())) {
_iconsX = anim::ivalue(newX, newX); _iconsX = anim::value(newX, newX);
_iconsStartAnim = 0; _iconsStartAnim = 0;
_a_icons.stop(); _a_icons.stop();
updateIcons(); updateIcons();
@ -3065,7 +3068,7 @@ void EmojiPan::mouseReleaseEvent(QMouseEvent *e) {
updateSelected(); updateSelected();
if (wasDown == _iconOver && _iconOver >= 0 && _iconOver < _icons.size()) { if (wasDown == _iconOver && _iconOver >= 0 && _iconOver < _icons.size()) {
_iconSelX = anim::ivalue(_iconOver * st::emojiCategory.width, _iconOver * st::emojiCategory.width); _iconSelX = anim::value(_iconOver * st::emojiCategory.width, _iconOver * st::emojiCategory.width);
s_inner->showStickerSet(_icons.at(_iconOver).setId); s_inner->showStickerSet(_icons.at(_iconOver).setId);
} }
} }
@ -3080,14 +3083,14 @@ bool EmojiPan::event(QEvent *e) {
bool hor = (ev->angleDelta().x() != 0 || ev->orientation() == Qt::Horizontal); bool hor = (ev->angleDelta().x() != 0 || ev->orientation() == Qt::Horizontal);
bool ver = (ev->angleDelta().y() != 0 || ev->orientation() == Qt::Vertical); bool ver = (ev->angleDelta().y() != 0 || ev->orientation() == Qt::Vertical);
if (hor) _horizontal = true; if (hor) _horizontal = true;
int32 newX = _iconsX.current(); auto newX = qRound(_iconsX.current());
if (/*_horizontal && */hor) { if (/*_horizontal && */hor) {
newX = snap(newX - (rtl() ? -1 : 1) * (ev->pixelDelta().x() ? ev->pixelDelta().x() : ev->angleDelta().x()), 0, _iconsMax); newX = snap(newX - (rtl() ? -1 : 1) * (ev->pixelDelta().x() ? ev->pixelDelta().x() : ev->angleDelta().x()), 0, _iconsMax);
} else if (/*!_horizontal && */ver) { } else if (/*!_horizontal && */ver) {
newX = snap(newX - (ev->pixelDelta().y() ? ev->pixelDelta().y() : ev->angleDelta().y()), 0, _iconsMax); newX = snap(newX - (ev->pixelDelta().y() ? ev->pixelDelta().y() : ev->angleDelta().y()), 0, _iconsMax);
} }
if (newX != _iconsX.current()) { if (newX != qRound(_iconsX.current())) {
_iconsX = anim::ivalue(newX, newX); _iconsX = anim::value(newX, newX);
_iconsStartAnim = 0; _iconsStartAnim = 0;
_a_icons.stop(); _a_icons.stop();
updateSelected(); updateSelected();
@ -3138,7 +3141,7 @@ void EmojiPan::onRefreshIcons(bool scrollAnimation) {
_iconsMax = qMax(int((_icons.size() - 7) * st::emojiCategory.width), 0); _iconsMax = qMax(int((_icons.size() - 7) * st::emojiCategory.width), 0);
} }
if (_iconsX.current() > _iconsMax) { if (_iconsX.current() > _iconsMax) {
_iconsX = anim::ivalue(_iconsMax, _iconsMax); _iconsX = anim::value(_iconsMax, _iconsMax);
} }
updatePanelsPositions(s_panels, s_scroll->scrollTop()); updatePanelsPositions(s_panels, s_scroll->scrollTop());
updateSelected(); updateSelected();
@ -3178,7 +3181,7 @@ void EmojiPan::updateSelected() {
newOver = _icons.size(); newOver = _icons.size();
} else if (!_icons.isEmpty()) { } else if (!_icons.isEmpty()) {
if (y >= _iconsTop && y < _iconsTop + st::emojiCategory.height && x >= 0 && x < 7 * st::emojiCategory.width && x < _icons.size() * st::emojiCategory.width) { if (y >= _iconsTop && y < _iconsTop + st::emojiCategory.height && x >= 0 && x < 7 * st::emojiCategory.width && x < _icons.size() * st::emojiCategory.width) {
x += _iconsX.current(); x += qRound(_iconsX.current());
newOver = qFloor(x / st::emojiCategory.width); newOver = qFloor(x / st::emojiCategory.width);
} }
} }
@ -3329,8 +3332,8 @@ void EmojiPan::hideFinished() {
s_scroll->scrollToY(0); s_scroll->scrollToY(0);
_iconOver = _iconDown = -1; _iconOver = _iconDown = -1;
_iconSel = 0; _iconSel = 0;
_iconsX = anim::ivalue(0, 0); _iconsX = anim::value();
_iconSelX = anim::ivalue(0, 0); _iconSelX = anim::value();
_iconsStartAnim = 0; _iconsStartAnim = 0;
_a_icons.stop(); _a_icons.stop();
@ -3512,14 +3515,14 @@ void EmojiPan::onScrollEmoji() {
} }
void EmojiPan::setCurrentTabIcon(DBIEmojiTab tab) { void EmojiPan::setCurrentTabIcon(DBIEmojiTab tab) {
_recent->setIcon((tab == dbietRecent) ? &st::emojiRecentActive : nullptr); _recent->setIconOverride((tab == dbietRecent) ? &st::emojiRecentActive : nullptr);
_people->setIcon((tab == dbietPeople) ? &st::emojiPeopleActive : nullptr); _people->setIconOverride((tab == dbietPeople) ? &st::emojiPeopleActive : nullptr);
_nature->setIcon((tab == dbietNature) ? &st::emojiNatureActive : nullptr); _nature->setIconOverride((tab == dbietNature) ? &st::emojiNatureActive : nullptr);
_food->setIcon((tab == dbietFood) ? &st::emojiFoodActive : nullptr); _food->setIconOverride((tab == dbietFood) ? &st::emojiFoodActive : nullptr);
_activity->setIcon((tab == dbietActivity) ? &st::emojiActivityActive : nullptr); _activity->setIconOverride((tab == dbietActivity) ? &st::emojiActivityActive : nullptr);
_travel->setIcon((tab == dbietTravel) ? &st::emojiTravelActive : nullptr); _travel->setIconOverride((tab == dbietTravel) ? &st::emojiTravelActive : nullptr);
_objects->setIcon((tab == dbietObjects) ? &st::emojiObjectsActive : nullptr); _objects->setIconOverride((tab == dbietObjects) ? &st::emojiObjectsActive : nullptr);
_symbols->setIcon((tab == dbietSymbols) ? &st::emojiSymbolsActive : nullptr); _symbols->setIconOverride((tab == dbietSymbols) ? &st::emojiSymbolsActive : nullptr);
} }
void EmojiPan::onScrollStickers() { void EmojiPan::onScrollStickers() {
@ -3550,11 +3553,11 @@ void EmojiPan::validateSelectedIcon(ValidateIconAnimations animations) {
if (animations == ValidateIconAnimations::Full) { if (animations == ValidateIconAnimations::Full) {
_iconSelX.start(iconSelXFinal); _iconSelX.start(iconSelXFinal);
} else { } else {
_iconSelX = anim::ivalue(iconSelXFinal, iconSelXFinal); _iconSelX = anim::value(iconSelXFinal, iconSelXFinal);
} }
auto iconsXFinal = snap((2 * newSel - 7) * int(st::emojiCategory.width) / 2, 0, _iconsMax); auto iconsXFinal = snap((2 * newSel - 7) * int(st::emojiCategory.width) / 2, 0, _iconsMax);
if (animations == ValidateIconAnimations::None) { if (animations == ValidateIconAnimations::None) {
_iconsX = anim::ivalue(iconsXFinal, iconsXFinal); _iconsX = anim::value(iconsXFinal, iconsXFinal);
_a_icons.stop(); _a_icons.stop();
} else { } else {
_iconsX.start(iconsXFinal); _iconsX.start(iconsXFinal);

View file

@ -108,7 +108,7 @@ private:
bool _hiding = false; bool _hiding = false;
QPixmap _cache; QPixmap _cache;
anim::fvalue a_opacity; anim::value a_opacity;
Animation _a_appearance; Animation _a_appearance;
QTimer _hideTimer; QTimer _hideTimer;
@ -661,8 +661,8 @@ private:
int _iconsTop = 0; int _iconsTop = 0;
int _iconsStartX = 0; int _iconsStartX = 0;
int _iconsMax = 0; int _iconsMax = 0;
anim::ivalue _iconsX = { 0, 0 }; anim::value _iconsX;
anim::ivalue _iconSelX = { 0, 0 }; anim::value _iconSelX;
TimeMs _iconsStartAnim = 0; TimeMs _iconsStartAnim = 0;
bool _emojiShown = true; bool _emojiShown = true;

View file

@ -190,4 +190,10 @@ hashtagClose: IconButton {
icon: simpleCloseIcon; icon: simpleCloseIcon;
iconOver: simpleCloseIconOver; iconOver: simpleCloseIconOver;
iconPosition: point(10px, 10px); iconPosition: point(10px, 10px);
rippleAreaPosition: point(5px, 5px);
rippleAreaSize: 20px;
ripple: RippleAnimation(defaultRippleAnimation) {
color: windowBgOver;
}
} }

View file

@ -24,15 +24,14 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
namespace Ui { namespace Ui {
void AbstractButton::leaveEvent(QEvent *e) { void AbstractButton::leaveEvent(QEvent *e) {
if (_state & StateDown) return; if (_state & StateFlag::Down) return;
setOver(false, StateChangeSource::ByHover); setOver(false, StateChangeSource::ByHover);
return TWidget::leaveEvent(e); return TWidget::leaveEvent(e);
} }
void AbstractButton::enterEvent(QEvent *e) { void AbstractButton::enterEvent(QEvent *e) {
auto over = rect().marginsRemoved(getMargins()).contains(mapFromGlobal(QCursor::pos())); checkIfOver(mapFromGlobal(QCursor::pos()));
setOver(over, StateChangeSource::ByHover);
return TWidget::enterEvent(e); return TWidget::enterEvent(e);
} }
@ -40,12 +39,18 @@ void AbstractButton::setAcceptBoth(bool acceptBoth) {
_acceptBoth = acceptBoth; _acceptBoth = acceptBoth;
} }
void AbstractButton::checkIfOver(QPoint localPos) {
auto over = rect().marginsRemoved(getMargins()).contains(localPos);
setOver(over, StateChangeSource::ByHover);
}
void AbstractButton::mousePressEvent(QMouseEvent *e) { void AbstractButton::mousePressEvent(QMouseEvent *e) {
checkIfOver(e->pos());
if (_acceptBoth || (e->buttons() & Qt::LeftButton)) { if (_acceptBoth || (e->buttons() & Qt::LeftButton)) {
if ((_state & StateOver) && !(_state & StateDown)) { if ((_state & StateFlag::Over) && !(_state & StateFlag::Down)) {
int oldState = _state; auto was = _state;
_state |= StateDown; _state |= StateFlag::Down;
onStateChanged(oldState, StateChangeSource::ByPress); onStateChanged(was, StateChangeSource::ByPress);
e->accept(); e->accept();
} }
@ -61,11 +66,11 @@ void AbstractButton::mouseMoveEvent(QMouseEvent *e) {
} }
void AbstractButton::mouseReleaseEvent(QMouseEvent *e) { void AbstractButton::mouseReleaseEvent(QMouseEvent *e) {
if (_state & StateDown) { if (_state & StateFlag::Down) {
int oldState = _state; auto was = _state;
_state &= ~StateDown; _state &= ~State(StateFlag::Down);
onStateChanged(oldState, StateChangeSource::ByPress); onStateChanged(was, StateChangeSource::ByPress);
if (oldState & StateOver) { if (was & StateFlag::Over) {
_modifiers = e->modifiers(); _modifiers = e->modifiers();
if (_clickedCallback) { if (_clickedCallback) {
_clickedCallback(); _clickedCallback();
@ -73,43 +78,39 @@ void AbstractButton::mouseReleaseEvent(QMouseEvent *e) {
emit clicked(); emit clicked();
} }
} else { } else {
leaveEvent(e); setOver(false, StateChangeSource::ByHover);
} }
} }
} }
void AbstractButton::setOver(bool over, StateChangeSource source) { void AbstractButton::setOver(bool over, StateChangeSource source) {
setCursor(over ? style::cur_pointer : style::cur_default); setCursor(over ? style::cur_pointer : style::cur_default);
if (over && !(_state & StateOver)) { if (over && !(_state & StateFlag::Over)) {
int oldState = _state; auto was = _state;
_state |= StateOver; _state |= StateFlag::Over;
onStateChanged(oldState, source); onStateChanged(was, source);
} else if (!over && (_state & StateOver)) { } else if (!over && (_state & StateFlag::Over)) {
int oldState = _state; auto was = _state;
_state &= ~StateOver; _state &= ~State(StateFlag::Over);
onStateChanged(oldState, source); onStateChanged(was, source);
} }
} }
void AbstractButton::setDisabled(bool disabled) { void AbstractButton::setDisabled(bool disabled) {
int oldState = _state; auto was = _state;
if (disabled && !(_state & StateDisabled)) { if (disabled && !(_state & StateFlag::Disabled)) {
_state |= StateDisabled; _state |= StateFlag::Disabled;
onStateChanged(oldState, StateChangeSource::ByUser); onStateChanged(was, StateChangeSource::ByUser);
} else if (!disabled && (_state & StateDisabled)) { } else if (!disabled && (_state & StateFlag::Disabled)) {
_state &= ~StateDisabled; _state &= ~State(StateFlag::Disabled);
onStateChanged(oldState, StateChangeSource::ByUser); onStateChanged(was, StateChangeSource::ByUser);
} }
} }
void AbstractButton::clearState() { void AbstractButton::clearState() {
int oldState = _state; auto was = _state;
_state = StateNone; _state = StateFlag::None;
onStateChanged(oldState, StateChangeSource::ByUser); onStateChanged(was, StateChangeSource::ByUser);
}
int AbstractButton::getState() const {
return _state;
} }
} // namespace Ui } // namespace Ui

View file

@ -28,34 +28,24 @@ class AbstractButton : public TWidget {
Q_OBJECT Q_OBJECT
public: public:
enum class StateChangeSource {
ByUser = 0x00,
ByPress = 0x01,
ByHover = 0x02,
};
AbstractButton(QWidget *parent) : TWidget(parent) { AbstractButton(QWidget *parent) : TWidget(parent) {
setMouseTracking(true); setMouseTracking(true);
} }
enum {
StateNone = 0x00,
StateOver = 0x01,
StateDown = 0x02,
StateDisabled = 0x04,
};
Qt::KeyboardModifiers clickModifiers() const { Qt::KeyboardModifiers clickModifiers() const {
return _modifiers; return _modifiers;
} }
void clearState();
int getState() const;
void setDisabled(bool disabled = true); void setDisabled(bool disabled = true);
void setOver(bool over, StateChangeSource source = StateChangeSource::ByUser); void clearState();
bool disabled() const { bool isOver() const {
return (_state & StateDisabled); return _state & StateFlag::Over;
}
bool isDown() const {
return _state & StateFlag::Down;
}
bool isDisabled() {
return _state & StateFlag::Disabled;
} }
void setAcceptBoth(bool acceptBoth = true); void setAcceptBoth(bool acceptBoth = true);
@ -75,15 +65,41 @@ signals:
void clicked(); void clicked();
protected: protected:
virtual void onStateChanged(int oldState, StateChangeSource source) { enum class StateFlag {
None = 0x00,
Over = 0x01,
Down = 0x02,
Disabled = 0x04,
};
Q_DECLARE_FLAGS(State, StateFlag);
Q_DECLARE_FRIEND_OPERATORS_FOR_FLAGS(State);
State state() const {
return _state;
} }
Qt::KeyboardModifiers _modifiers; enum class StateChangeSource {
int _state = StateNone; ByUser = 0x00,
ByPress = 0x01,
ByHover = 0x02,
};
void setOver(bool over, StateChangeSource source = StateChangeSource::ByUser);
virtual void onStateChanged(State was, StateChangeSource source) {
}
private:
void checkIfOver(QPoint localPos);
State _state = StateFlag::None;
bool _acceptBoth = false; bool _acceptBoth = false;
Qt::KeyboardModifiers _modifiers;
base::lambda<void()> _clickedCallback; base::lambda<void()> _clickedCallback;
}; };
Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractButton::State);
} // namespace Ui } // namespace Ui

View file

@ -158,56 +158,6 @@ private:
}; };
using fvalue = value;
class ivalue { // int animated value
public:
using ValueType = int;
ivalue() = default;
ivalue(int from) : _cur(from), _from(float64(from)) {
}
ivalue(int from, int to) : _cur(from), _from(float64(from)), _delta(float64(to - from)) {
}
void start(int32 to) {
_from = float64(_cur);
_delta = float64(to) - _from;
}
void restart() {
_delta = _from + _delta - float64(_cur);
_from = float64(_cur);
}
int from() const {
return _from;
}
int current() const {
return _cur;
}
int to() const {
return qRound(_from + _delta);
}
void add(int delta) {
_from += delta;
_cur += delta;
}
ivalue &update(float64 dt, const transition &func) {
_cur = qRound(_from + func(_delta, dt));
return *this;
}
void finish() {
_cur = qRound(_from + _delta);
_from = _cur;
_delta = 0;
}
private:
int _cur = 0;
float64 _from = 0.;
float64 _delta = 0.;
};
void startManager(); void startManager();
void stopManager(); void stopManager();
void registerClipManager(Media::Clip::Manager *manager); void registerClipManager(Media::Clip::Manager *manager);
@ -639,7 +589,9 @@ public:
template <typename Lambda> template <typename Lambda>
void start(Lambda &&updateCallback, const ValueType &from, const ValueType &to, float64 duration, const anim::transition &transition = anim::linear) { void start(Lambda &&updateCallback, const ValueType &from, const ValueType &to, float64 duration, const anim::transition &transition = anim::linear) {
if (!_data) { if (_data) {
_data->pause.restart();
} else {
_data = std_::make_unique<Data>(from, std_::forward<Lambda>(updateCallback)); _data = std_::make_unique<Data>(from, std_::forward<Lambda>(updateCallback));
} }
_data->value.start(to); _data->value.start(to);
@ -674,6 +626,7 @@ private:
if (dt >= 1) { if (dt >= 1) {
value.finish(); value.finish();
a_animation.stop(); a_animation.stop();
pause.release();
} else { } else {
value.update(dt, transition); value.update(dt, transition);
} }
@ -685,13 +638,13 @@ private:
Callback updateCallback; Callback updateCallback;
float64 duration = 0.; float64 duration = 0.;
anim::transition transition = anim::linear; anim::transition transition = anim::linear;
MTP::PauseHolder pause;
}; };
mutable std_::unique_ptr<Data> _data; mutable std_::unique_ptr<Data> _data;
}; };
using FloatAnimation = SimpleAnimation<anim::fvalue>; using FloatAnimation = SimpleAnimation<anim::value>;
using IntAnimation = SimpleAnimation<anim::ivalue>;
class AnimationManager : public QObject { class AnimationManager : public QObject {
Q_OBJECT Q_OBJECT

View file

@ -55,8 +55,8 @@ void HistoryDownButton::paintEvent(QPaintEvent *e) {
return; return;
} }
p.setOpacity(opacity); p.setOpacity(opacity);
auto over = (_state & StateOver); auto over = isOver();
auto down = (_state & StateDown); auto down = isDown();
((over || down) ? _st.iconBelowOver : _st.iconBelow).paint(p, _st.iconPosition, width()); ((over || down) ? _st.iconBelowOver : _st.iconBelow).paint(p, _st.iconPosition, width());
paintRipple(p, _st.rippleAreaPosition.x(), _st.rippleAreaPosition.y(), ms); paintRipple(p, _st.rippleAreaPosition.x(), _st.rippleAreaPosition.y(), ms);
((over || down) ? _st.iconAboveOver : _st.iconAbove).paint(p, _st.iconPosition, width()); ((over || down) ? _st.iconAboveOver : _st.iconAbove).paint(p, _st.iconPosition, width());
@ -118,7 +118,7 @@ void HistoryDownButton::step_arrowOver(float64 ms, bool timer) {
if (timer) update(); if (timer) update();
} }
EmojiButton::EmojiButton(QWidget *parent, const style::IconButton &st) : AbstractButton(parent) EmojiButton::EmojiButton(QWidget *parent, const style::IconButton &st) : RippleButton(parent, st.ripple)
, _st(st) , _st(st)
, _a_loading(animation(this, &EmojiButton::step_loading)) { , _a_loading(animation(this, &EmojiButton::step_loading)) {
resize(_st.width, _st.height); resize(_st.width, _st.height);
@ -131,11 +131,12 @@ void EmojiButton::paintEvent(QPaintEvent *e) {
auto ms = getms(); auto ms = getms();
p.fillRect(e->rect(), st::historyComposeAreaBg); p.fillRect(e->rect(), st::historyComposeAreaBg);
paintRipple(p, _st.rippleAreaPosition.x(), _st.rippleAreaPosition.y(), ms);
auto loading = a_loading.current(ms, _loading ? 1 : 0); auto loading = a_loading.current(ms, _loading ? 1 : 0);
p.setOpacity(1 - loading); p.setOpacity(1 - loading);
auto over = (_state & StateOver); auto over = isOver();
auto icon = &(over ? _st.iconOver : _st.icon); auto icon = &(over ? _st.iconOver : _st.icon);
icon->paint(p, _st.iconPosition, width()); icon->paint(p, _st.iconPosition, width());
@ -170,11 +171,20 @@ void EmojiButton::setLoading(bool loading) {
} }
} }
void EmojiButton::onStateChanged(int oldState, StateChangeSource source) { void EmojiButton::onStateChanged(State was, StateChangeSource source) {
auto over = (_state & StateOver); RippleButton::onStateChanged(was, source);
if (over != (oldState & StateOver)) { auto wasOver = static_cast<bool>(was & StateFlag::Over);
if (isOver() != wasOver) {
update(); update();
} }
} }
QPoint EmojiButton::prepareRippleStartPosition() const {
return mapFromGlobal(QCursor::pos()) - _st.rippleAreaPosition;
}
QImage EmojiButton::prepareRippleMask() const {
return RippleAnimation::ellipseMask(QSize(_st.rippleAreaSize, _st.rippleAreaSize));
}
} // namespace Ui } // namespace Ui

View file

@ -55,7 +55,7 @@ private:
bool _shown = false; bool _shown = false;
anim::fvalue a_arrowOpacity; anim::value a_arrowOpacity;
Animation _a_arrowOver; Animation _a_arrowOver;
FloatAnimation _a_show; FloatAnimation _a_show;
@ -64,7 +64,7 @@ private:
}; };
class EmojiButton : public AbstractButton { class EmojiButton : public RippleButton {
public: public:
EmojiButton(QWidget *parent, const style::IconButton &st); EmojiButton(QWidget *parent, const style::IconButton &st);
@ -72,7 +72,10 @@ public:
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
void onStateChanged(int oldState, StateChangeSource source) override; void onStateChanged(State was, StateChangeSource source) override;
QImage prepareRippleMask() const override;
QPoint prepareRippleStartPosition() const override;
private: private:
const style::IconButton &_st; const style::IconButton &_st;

View file

@ -54,7 +54,7 @@ void NewAvatarButton::paintEvent(QPaintEvent *e) {
} }
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.setBrush((_state & StateOver) ? st::defaultActiveButton.textBgOver : st::defaultActiveButton.textBg); p.setBrush(isOver() ? st::defaultActiveButton.textBgOver : st::defaultActiveButton.textBg);
{ {
PainterHighQualityEnabler hq(p); PainterHighQualityEnabler hq(p);
p.drawEllipse(rect()); p.drawEllipse(rect());

View file

@ -25,6 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "application.h" #include "application.h"
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
#include "ui/widgets/multi_select.h" #include "ui/widgets/multi_select.h"
#include "ui/effects/ripple_animation.h"
#include "boxes/contactsbox.h" #include "boxes/contactsbox.h"
#include "countries.h" #include "countries.h"
#include "styles/style_boxes.h" #include "styles/style_boxes.h"
@ -283,6 +284,7 @@ void CountrySelectBox::Inner::paintEvent(QPaintEvent *e) {
QRect r(e->rect()); QRect r(e->rect());
p.setClipRect(r); p.setClipRect(r);
auto ms = getms();
int l = countriesNow->size(); int l = countriesNow->size();
if (l) { if (l) {
if (r.intersects(QRect(0, 0, width(), st::countriesSkip))) { if (r.intersects(QRect(0, 0, width(), st::countriesSkip))) {
@ -291,10 +293,16 @@ void CountrySelectBox::Inner::paintEvent(QPaintEvent *e) {
int32 from = floorclamp(r.y() - st::countriesSkip, _rowHeight, 0, l); int32 from = floorclamp(r.y() - st::countriesSkip, _rowHeight, 0, l);
int32 to = ceilclamp(r.y() + r.height() - st::countriesSkip, _rowHeight, 0, l); int32 to = ceilclamp(r.y() + r.height() - st::countriesSkip, _rowHeight, 0, l);
for (int32 i = from; i < to; ++i) { for (int32 i = from; i < to; ++i) {
bool sel = (i == _sel); auto selected = (i == (_pressed >= 0 ? _pressed : _selected));
int32 y = st::countriesSkip + i * _rowHeight; auto y = st::countriesSkip + i * _rowHeight;
p.fillRect(0, y, width(), _rowHeight, sel ? st::countryRowBgOver : st::countryRowBg); p.fillRect(0, y, width(), _rowHeight, selected ? st::countryRowBgOver : st::countryRowBg);
if (_ripples.size() > i && _ripples[i]) {
_ripples[i]->paint(p, 0, y, width(), ms);
if (_ripples[i]->empty()) {
_ripples[i].reset();
}
}
QString code = QString("+") + (*countriesNow)[i]->code; QString code = QString("+") + (*countriesNow)[i]->code;
int32 codeWidth = st::countryRowCodeFont->width(code); int32 codeWidth = st::countryRowCodeFont->width(code);
@ -312,7 +320,7 @@ void CountrySelectBox::Inner::paintEvent(QPaintEvent *e) {
p.drawTextLeft(st::countryRowPadding.left(), y + st::countryRowPadding.top(), width(), name); p.drawTextLeft(st::countryRowPadding.left(), y + st::countryRowPadding.top(), width(), name);
p.setFont(st::countryRowCodeFont); p.setFont(st::countryRowCodeFont);
p.setPen(sel ? st::countryRowCodeFgOver : st::countryRowCodeFg); p.setPen(selected ? st::countryRowCodeFgOver : st::countryRowCodeFg);
p.drawTextLeft(st::countryRowPadding.left() + nameWidth + st::countryRowPadding.right(), y + st::countryRowPadding.top(), width(), code); p.drawTextLeft(st::countryRowPadding.left() + nameWidth + st::countryRowPadding.right(), y + st::countryRowPadding.top(), width(), code);
} }
} else { } else {
@ -328,26 +336,49 @@ void CountrySelectBox::Inner::enterEvent(QEvent *e) {
} }
void CountrySelectBox::Inner::leaveEvent(QEvent *e) { void CountrySelectBox::Inner::leaveEvent(QEvent *e) {
_mouseSel = false; _mouseSelection = false;
setMouseTracking(false); setMouseTracking(false);
if (_sel >= 0) { if (_selected >= 0) {
updateSelectedRow(); updateSelectedRow();
_sel = -1; _selected = -1;
} }
} }
void CountrySelectBox::Inner::mouseMoveEvent(QMouseEvent *e) { void CountrySelectBox::Inner::mouseMoveEvent(QMouseEvent *e) {
_mouseSel = true; _mouseSelection = true;
_lastMousePos = e->globalPos(); updateSelected(e->pos());
updateSel();
} }
void CountrySelectBox::Inner::mousePressEvent(QMouseEvent *e) { void CountrySelectBox::Inner::mousePressEvent(QMouseEvent *e) {
_mouseSel = true; _mouseSelection = true;
_lastMousePos = e->globalPos(); updateSelected(e->pos());
updateSel();
setPressed(_selected);
if (_pressed >= 0 && _pressed < countriesNow->size()) {
if (_ripples.size() <= _pressed) {
_ripples.reserve(_pressed + 1);
while (_ripples.size() <= _pressed) {
_ripples.push_back(std_::unique_ptr<Ui::RippleAnimation>());
}
}
if (!_ripples[_pressed]) {
auto mask = Ui::RippleAnimation::rectMask(QSize(width(), _rowHeight));
_ripples[_pressed] = std_::make_unique<Ui::RippleAnimation>(st::countryRipple, std_::move(mask), [this, index = _pressed] {
updateRow(index);
});
_ripples[_pressed]->add(e->pos() - QPoint(0, st::countriesSkip + _pressed * _rowHeight));
}
}
}
void CountrySelectBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
auto pressed = _pressed;
setPressed(-1);
updateSelectedRow();
if (e->button() == Qt::LeftButton) { if (e->button() == Qt::LeftButton) {
chooseCountry(); if ((pressed >= 0) && pressed == _selected) {
chooseCountry();
}
} }
} }
@ -401,25 +432,25 @@ void CountrySelectBox::Inner::updateFilter(QString filter) {
countriesNow = &countriesFiltered; countriesNow = &countriesFiltered;
} }
refresh(); refresh();
_sel = countriesNow->isEmpty() ? -1 : 0; _selected = countriesNow->isEmpty() ? -1 : 0;
update(); update();
} }
} }
void CountrySelectBox::Inner::selectSkip(int32 dir) { void CountrySelectBox::Inner::selectSkip(int32 dir) {
_mouseSel = false; _mouseSelection = false;
int cur = (_sel >= 0) ? _sel : -1; int cur = (_selected >= 0) ? _selected : -1;
cur += dir; cur += dir;
if (cur <= 0) { if (cur <= 0) {
_sel = countriesNow->isEmpty() ? -1 : 0; _selected = countriesNow->isEmpty() ? -1 : 0;
} else if (cur >= countriesNow->size()) { } else if (cur >= countriesNow->size()) {
_sel = -1; _selected = -1;
} else { } else {
_sel = cur; _selected = cur;
} }
if (_sel >= 0) { if (_selected >= 0) {
emit mustScrollTo(st::countriesSkip + _sel * _rowHeight, st::countriesSkip + (_sel + 1) * _rowHeight); emit mustScrollTo(st::countriesSkip + _selected * _rowHeight, st::countriesSkip + (_selected + 1) * _rowHeight);
} }
update(); update();
} }
@ -433,12 +464,12 @@ void CountrySelectBox::Inner::selectSkipPage(int32 h, int32 dir) {
void CountrySelectBox::Inner::chooseCountry() { void CountrySelectBox::Inner::chooseCountry() {
QString result; QString result;
if (_filter.isEmpty()) { if (_filter.isEmpty()) {
if (_sel >= 0 && _sel < countriesAll.size()) { if (_selected >= 0 && _selected < countriesAll.size()) {
result = countriesAll[_sel]->iso2; result = countriesAll[_selected]->iso2;
} }
} else { } else {
if (_sel >= 0 && _sel < countriesFiltered.size()) { if (_selected >= 0 && _selected < countriesFiltered.size()) {
result = countriesFiltered[_sel]->iso2; result = countriesFiltered[_selected]->iso2;
} }
} }
emit countryChosen(result); emit countryChosen(result);
@ -448,22 +479,34 @@ void CountrySelectBox::Inner::refresh() {
resize(width(), countriesNow->length() ? (countriesNow->length() * _rowHeight + st::countriesSkip) : st::noContactsHeight); resize(width(), countriesNow->length() ? (countriesNow->length() * _rowHeight + st::countriesSkip) : st::noContactsHeight);
} }
void CountrySelectBox::Inner::updateSel() { void CountrySelectBox::Inner::updateSelected(QPoint localPos) {
if (!_mouseSel) return; if (!_mouseSelection) return;
QPoint p(mapFromGlobal(_lastMousePos)); auto in = parentWidget()->rect().contains(parentWidget()->mapFromGlobal(QCursor::pos()));
bool in = parentWidget()->rect().contains(parentWidget()->mapFromGlobal(_lastMousePos));
int32 newSel = (in && p.y() >= st::countriesSkip && p.y() < st::countriesSkip + countriesNow->size() * _rowHeight) ? ((p.y() - st::countriesSkip) / _rowHeight) : -1; auto selected = (in && localPos.y() >= st::countriesSkip && localPos.y() < st::countriesSkip + countriesNow->size() * _rowHeight) ? ((localPos.y() - st::countriesSkip) / _rowHeight) : -1;
if (newSel != _sel) { if (_selected != selected) {
updateSelectedRow(); updateSelectedRow();
_sel = newSel; _selected = selected;
updateSelectedRow(); updateSelectedRow();
} }
} }
void CountrySelectBox::Inner::updateSelectedRow() { void CountrySelectBox::Inner::updateSelectedRow() {
if (_sel >= 0) { updateRow(_selected);
update(0, st::countriesSkip + _sel * _rowHeight, width(), _rowHeight); }
void CountrySelectBox::Inner::updateRow(int index) {
if (index >= 0) {
update(0, st::countriesSkip + index * _rowHeight, width(), _rowHeight);
} }
} }
void CountrySelectBox::Inner::setPressed(int pressed) {
if (_pressed >= 0 && _pressed < _ripples.size() && _ripples[_pressed]) {
_ripples[_pressed]->lastStop();
}
_pressed = pressed;
}
CountrySelectBox::Inner::~Inner() = default;

View file

@ -108,29 +108,36 @@ public:
void refresh(); void refresh();
~Inner();
signals: signals:
void countryChosen(const QString &iso); void countryChosen(const QString &iso);
void mustScrollTo(int ymin, int ymax); void mustScrollTo(int ymin, int ymax);
public slots:
void updateSel();
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
void enterEvent(QEvent *e) override; void enterEvent(QEvent *e) override;
void leaveEvent(QEvent *e) override; void leaveEvent(QEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override;
void mousePressEvent(QMouseEvent *e) override; void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
private: private:
void updateSelected() {
updateSelected(mapFromGlobal(QCursor::pos()));
}
void updateSelected(QPoint localPos);
void updateSelectedRow(); void updateSelectedRow();
void updateRow(int index);
void setPressed(int pressed);
int _rowHeight; int _rowHeight;
int _sel = 0; int _selected = -1;
int _pressed = -1;
QString _filter; QString _filter;
bool _mouseSel = false; bool _mouseSelection = false;
QPoint _lastMousePos; std_::vector_of_moveable<std_::unique_ptr<Ui::RippleAnimation>> _ripples;
}; };

View file

@ -24,45 +24,45 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
namespace Ui { namespace Ui {
RadialAnimation::RadialAnimation(AnimationCallbacks &&callbacks) RadialAnimation::RadialAnimation(AnimationCallbacks &&callbacks)
: a_arcEnd(0, 0) : a_arcStart(0, FullArcLength)
, a_arcStart(0, FullArcLength)
, _animation(std_::move(callbacks)) { , _animation(std_::move(callbacks)) {
} }
void RadialAnimation::start(float64 prg) { void RadialAnimation::start(float64 prg) {
_firstStart = _lastStart = _lastTime = getms(); _firstStart = _lastStart = _lastTime = getms();
int32 iprg = qRound(qMax(prg, 0.0001) * AlmostFullArcLength), iprgstrict = qRound(prg * AlmostFullArcLength); int32 iprg = qRound(qMax(prg, 0.0001) * AlmostFullArcLength), iprgstrict = qRound(prg * AlmostFullArcLength);
a_arcEnd = anim::ivalue(iprgstrict, iprg); a_arcEnd = anim::value(iprgstrict, iprg);
_animation.start(); _animation.start();
} }
void RadialAnimation::update(float64 prg, bool finished, TimeMs ms) { void RadialAnimation::update(float64 prg, bool finished, TimeMs ms) {
int32 iprg = qRound(qMax(prg, 0.0001) * AlmostFullArcLength); auto iprg = qRound(qMax(prg, 0.0001) * AlmostFullArcLength);
if (iprg != a_arcEnd.to()) { if (iprg != qRound(a_arcEnd.to())) {
a_arcEnd.start(iprg); a_arcEnd.start(iprg);
_lastStart = _lastTime; _lastStart = _lastTime;
} }
_lastTime = ms; _lastTime = ms;
float64 dt = float64(ms - _lastStart), fulldt = float64(ms - _firstStart); auto dt = float64(ms - _lastStart);
auto fulldt = float64(ms - _firstStart);
_opacity = qMin(fulldt / st::radialDuration, 1.); _opacity = qMin(fulldt / st::radialDuration, 1.);
if (!finished) { if (!finished) {
a_arcEnd.update(1. - (st::radialDuration / (st::radialDuration + dt)), anim::linear); a_arcEnd.update(1. - (st::radialDuration / (st::radialDuration + dt)), anim::linear);
} else if (dt >= st::radialDuration) { } else if (dt >= st::radialDuration) {
a_arcEnd.update(1, anim::linear); a_arcEnd.update(1., anim::linear);
stop(); stop();
} else { } else {
float64 r = dt / st::radialDuration; auto r = dt / st::radialDuration;
a_arcEnd.update(r, anim::linear); a_arcEnd.update(r, anim::linear);
_opacity *= 1 - r; _opacity *= 1 - r;
} }
float64 fromstart = fulldt / st::radialPeriod; auto fromstart = fulldt / st::radialPeriod;
a_arcStart.update(fromstart - std::floor(fromstart), anim::linear); a_arcStart.update(fromstart - std::floor(fromstart), anim::linear);
} }
void RadialAnimation::stop() { void RadialAnimation::stop() {
_firstStart = _lastStart = _lastTime = 0; _firstStart = _lastStart = _lastTime = 0;
a_arcEnd = anim::ivalue(0, 0); a_arcEnd = anim::value();
_animation.stop(); _animation.stop();
} }
@ -79,8 +79,8 @@ void RadialAnimation::draw(Painter &p, const QRect &inner, int32 thickness, cons
pen.setCapStyle(Qt::RoundCap); pen.setCapStyle(Qt::RoundCap);
p.setPen(pen); p.setPen(pen);
int32 len = MinArcLength + a_arcEnd.current(); auto len = MinArcLength + qRound(a_arcEnd.current());
int32 from = QuarterArcLength - a_arcStart.current() - len; auto from = QuarterArcLength - qRound(a_arcStart.current()) - len;
if (rtl()) { if (rtl()) {
from = QuarterArcLength - (from - QuarterArcLength) - len; from = QuarterArcLength - (from - QuarterArcLength) - len;
if (from < 0) from += FullArcLength; if (from < 0) from += FullArcLength;

View file

@ -49,7 +49,8 @@ private:
TimeMs _lastStart = 0; TimeMs _lastStart = 0;
TimeMs _lastTime = 0; TimeMs _lastTime = 0;
float64 _opacity = 0.; float64 _opacity = 0.;
anim::ivalue a_arcEnd, a_arcStart; anim::value a_arcEnd;
anim::value a_arcStart;
Animation _animation; Animation _animation;
}; };

View file

@ -92,7 +92,7 @@ void RippleAnimation::Ripple::paint(QPainter &p, const QPixmap &mask, TimeMs ms,
return; return;
} }
if (_cache.isNull()) { if (_cache.isNull() || colorOverride != nullptr) {
auto radius = anim::interpolate(_radiusFrom, _radiusTo, _show.current(ms, 1.)); auto radius = anim::interpolate(_radiusFrom, _radiusTo, _show.current(ms, 1.));
_frame.fill(Qt::transparent); _frame.fill(Qt::transparent);
{ {
@ -110,7 +110,7 @@ void RippleAnimation::Ripple::paint(QPainter &p, const QPixmap &mask, TimeMs ms,
p.setCompositionMode(QPainter::CompositionMode_DestinationIn); p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
p.drawPixmap(0, 0, mask); p.drawPixmap(0, 0, mask);
} }
if (radius == _radiusTo) { if (radius == _radiusTo && colorOverride == nullptr) {
_cache = App::pixmapFromImageInPlace(std_::move(_frame)); _cache = App::pixmapFromImageInPlace(std_::move(_frame));
} }
} }

View file

@ -51,9 +51,9 @@ void WidgetSlideWrap<TWidget>::slideUp() {
if (_a_height.animating()) { if (_a_height.animating()) {
if (_hiding) return; if (_hiding) return;
} else { } else {
a_height = anim::ivalue(_realSize.height()); a_height = anim::value(_realSize.height());
} }
a_height.start(0); a_height.start(0.);
_hiding = true; _hiding = true;
_a_height.start(); _a_height.start();
} }
@ -70,7 +70,7 @@ void WidgetSlideWrap<TWidget>::slideDown() {
if (!_hiding) return; if (!_hiding) return;
} }
a_height.start(_realSize.height()); a_height.start(_realSize.height());
_forceHeight = a_height.current(); _forceHeight = qRound(a_height.current());
_hiding = false; _hiding = false;
_a_height.start(); _a_height.start();
} }
@ -87,7 +87,7 @@ void WidgetSlideWrap<TWidget>::showFast() {
void WidgetSlideWrap<TWidget>::hideFast() { void WidgetSlideWrap<TWidget>::hideFast() {
_a_height.stop(); _a_height.stop();
a_height = anim::ivalue(0); a_height = anim::value();
_forceHeight = 0; _forceHeight = 0;
resizeToWidth(_realSize.width()); resizeToWidth(_realSize.width());
hide(); hide();
@ -144,7 +144,7 @@ void WidgetSlideWrap<TWidget>::step_height(float64 ms, bool timer) {
if (_hiding) hide(); if (_hiding) hide();
} else { } else {
a_height.update(dt, anim::linear); a_height.update(dt, anim::linear);
_forceHeight = a_height.current(); _forceHeight = qRound(a_height.current());
} }
resizeToWidth(_realSize.width()); resizeToWidth(_realSize.width());
if (_updateCallback) { if (_updateCallback) {

View file

@ -66,7 +66,7 @@ private:
style::size _realSize; style::size _realSize;
int _forceHeight = -1; int _forceHeight = -1;
anim::ivalue a_height; anim::value a_height;
Animation _a_height; Animation _a_height;
bool _hiding = false; bool _hiding = false;

View file

@ -40,8 +40,8 @@ int LinkButton::naturalWidth() const {
void LinkButton::paintEvent(QPaintEvent *e) { void LinkButton::paintEvent(QPaintEvent *e) {
Painter p(this); Painter p(this);
auto &font = ((_state & StateOver) ? _st.overFont : _st.font); auto &font = (isOver() ? _st.overFont : _st.font);
auto &pen = ((_state & StateDown) ? _st.downColor : ((_state & StateOver) ? _st.overColor : _st.color)); auto &pen = (isDown() ? _st.downColor : (isOver() ? _st.overColor : _st.color));
p.setFont(font); p.setFont(font);
p.setPen(pen); p.setPen(pen);
if (_textWidth > width()) { if (_textWidth > width()) {
@ -58,7 +58,7 @@ void LinkButton::setText(const QString &text) {
update(); update();
} }
void LinkButton::onStateChanged(int oldState, StateChangeSource source) { void LinkButton::onStateChanged(State was, StateChangeSource source) {
update(); update();
} }
@ -95,11 +95,11 @@ void RippleButton::paintRipple(QPainter &p, int x, int y, TimeMs ms, const QColo
} }
} }
void RippleButton::onStateChanged(int oldState, StateChangeSource source) { void RippleButton::onStateChanged(State was, StateChangeSource source) {
update(); update();
auto wasDown = (oldState & StateDown); auto wasDown = static_cast<bool>(was & StateFlag::Down);
auto down = (_state & StateDown); auto down = isDown();
if (!_st.showDuration || down == wasDown || _forceRippled) { if (!_st.showDuration || down == wasDown || _forceRippled) {
return; return;
} }
@ -187,10 +187,10 @@ void FlatButton::step_appearance(float64 ms, bool timer) {
if (timer) update(); if (timer) update();
} }
void FlatButton::onStateChanged(int oldState, StateChangeSource source) { void FlatButton::onStateChanged(State was, StateChangeSource source) {
RippleButton::onStateChanged(oldState, source); RippleButton::onStateChanged(was, source);
a_over.start((_state & StateOver) ? 1. : 0.); a_over.start(isOver() ? 1. : 0.);
if (source == StateChangeSource::ByUser || source == StateChangeSource::ByPress) { if (source == StateChangeSource::ByUser || source == StateChangeSource::ByPress) {
_a_appearance.stop(); _a_appearance.stop();
a_over.finish(); a_over.finish();
@ -211,7 +211,7 @@ void FlatButton::paintEvent(QPaintEvent *e) {
auto ms = getms(); auto ms = getms();
paintRipple(p, 0, 0, ms); paintRipple(p, 0, 0, ms);
p.setFont((_state & StateOver) ? _st.overFont : _st.font); p.setFont(isOver() ? _st.overFont : _st.font);
p.setRenderHint(QPainter::TextAntialiasing); p.setRenderHint(QPainter::TextAntialiasing);
p.setPen(anim::pen(_st.color, _st.overColor, a_over.current())); p.setPen(anim::pen(_st.color, _st.overColor, a_over.current()));
@ -294,8 +294,8 @@ void RoundButton::paintEvent(QPaintEvent *e) {
} }
App::roundRect(p, myrtlrect(rounded), _st.textBg, ImageRoundRadius::Small); App::roundRect(p, myrtlrect(rounded), _st.textBg, ImageRoundRadius::Small);
auto over = (_state & StateOver); auto over = isOver();
auto down = (_state & StateDown); auto down = isDown();
if (over || down) { if (over || down) {
App::roundRect(p, myrtlrect(rounded), _st.textBgOver, ImageRoundRadius::Small); App::roundRect(p, myrtlrect(rounded), _st.textBgOver, ImageRoundRadius::Small);
} }
@ -340,21 +340,25 @@ IconButton::IconButton(QWidget *parent, const style::IconButton &st) : RippleBut
setCursor(style::cur_pointer); setCursor(style::cur_pointer);
} }
void IconButton::setIcon(const style::icon *icon, const style::icon *iconOver) { void IconButton::setIconOverride(const style::icon *iconOverride, const style::icon *iconOverOverride) {
_iconOverride = icon; _iconOverride = iconOverride;
_iconOverrideOver = iconOver; _iconOverrideOver = iconOverOverride;
update(); update();
} }
void IconButton::setRippleColorOverride(const style::color *colorOverride) {
_rippleColorOverride = colorOverride;
}
void IconButton::paintEvent(QPaintEvent *e) { void IconButton::paintEvent(QPaintEvent *e) {
Painter p(this); Painter p(this);
auto ms = getms(); auto ms = getms();
paintRipple(p, _st.rippleAreaPosition.x(), _st.rippleAreaPosition.y(), ms); paintRipple(p, _st.rippleAreaPosition.x(), _st.rippleAreaPosition.y(), ms, _rippleColorOverride ? &(*_rippleColorOverride)->c : nullptr);
auto down = (_state & StateDown); auto down = isDown();
auto overIconOpacity = (down || forceRippled()) ? 1. : _a_over.current(getms(), (_state & StateOver) ? 1. : 0.); auto overIconOpacity = (down || forceRippled()) ? 1. : _a_over.current(getms(), isOver() ? 1. : 0.);
auto overIcon = [this] { auto overIcon = [this] {
if (_iconOverrideOver) { if (_iconOverrideOver) {
return _iconOverrideOver; return _iconOverrideOver;
@ -389,11 +393,12 @@ void IconButton::paintEvent(QPaintEvent *e) {
} }
} }
void IconButton::onStateChanged(int oldState, StateChangeSource source) { void IconButton::onStateChanged(State was, StateChangeSource source) {
RippleButton::onStateChanged(oldState, source); RippleButton::onStateChanged(was, source);
auto over = (_state & StateOver); auto over = isOver();
if (over != (oldState & StateOver)) { auto wasOver = static_cast<bool>(was & StateFlag::Over);
if (over != wasOver) {
if (_st.duration) { if (_st.duration) {
auto from = over ? 0. : 1.; auto from = over ? 0. : 1.;
auto to = over ? 1. : 0.; auto to = over ? 1. : 0.;
@ -443,7 +448,8 @@ int LeftOutlineButton::resizeGetHeight(int newWidth) {
void LeftOutlineButton::paintEvent(QPaintEvent *e) { void LeftOutlineButton::paintEvent(QPaintEvent *e) {
Painter p(this); Painter p(this);
bool over = (_state & StateOver), down = (_state & StateDown); auto over = isOver();
auto down = isDown();
if (width() > _st.outlineWidth) { if (width() > _st.outlineWidth) {
p.fillRect(rtlrect(_st.outlineWidth, 0, width() - _st.outlineWidth, height(), width()), (over || down) ? _st.textBgOver : _st.textBg); p.fillRect(rtlrect(_st.outlineWidth, 0, width() - _st.outlineWidth, height(), width()), (over || down) ? _st.textBgOver : _st.textBg);
paintRipple(p, 0, 0, getms()); paintRipple(p, 0, 0, getms());
@ -492,7 +498,7 @@ void CrossButton::paintEvent(QPaintEvent *e) {
Painter p(this); Painter p(this);
auto ms = getms(); auto ms = getms();
auto over = (_state & StateOver); auto over = isOver();
auto shown = _a_show.current(ms, _shown ? 1. : 0.); auto shown = _a_show.current(ms, _shown ? 1. : 0.);
p.setOpacity(shown); p.setOpacity(shown);
@ -501,11 +507,12 @@ void CrossButton::paintEvent(QPaintEvent *e) {
CrossAnimation::paint(p, _st.cross, over ? _st.crossFgOver : _st.crossFg, _st.crossPosition.x(), _st.crossPosition.y(), width(), shown); CrossAnimation::paint(p, _st.cross, over ? _st.crossFgOver : _st.crossFg, _st.crossPosition.x(), _st.crossPosition.y(), width(), shown);
} }
void CrossButton::onStateChanged(int oldState, StateChangeSource source) { void CrossButton::onStateChanged(State was, StateChangeSource source) {
RippleButton::onStateChanged(oldState, source); RippleButton::onStateChanged(was, source);
auto over = (_state & StateOver); auto over = isOver();
if (over != (oldState & StateOver)) { auto wasOver = static_cast<bool>(was & StateFlag::Over);
if (over != wasOver) {
update(); update();
} }
} }

View file

@ -23,6 +23,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "ui/abstract_button.h" #include "ui/abstract_button.h"
#include "styles/style_widgets.h" #include "styles/style_widgets.h"
#include <memory>
namespace Ui { namespace Ui {
class RippleAnimation; class RippleAnimation;
@ -38,7 +40,7 @@ public:
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
void onStateChanged(int oldState, StateChangeSource source) override; void onStateChanged(State was, StateChangeSource source) override;
private: private:
QString _text; QString _text;
@ -66,7 +68,7 @@ public:
protected: protected:
void paintRipple(QPainter &p, int x, int y, TimeMs ms, const QColor *colorOverride = nullptr); void paintRipple(QPainter &p, int x, int y, TimeMs ms, const QColor *colorOverride = nullptr);
void onStateChanged(int oldState, StateChangeSource source) override; void onStateChanged(State was, StateChangeSource source) override;
virtual QImage prepareRippleMask() const; virtual QImage prepareRippleMask() const;
virtual QPoint prepareRippleStartPosition() const; virtual QPoint prepareRippleStartPosition() const;
@ -98,7 +100,7 @@ public:
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
void onStateChanged(int oldState, StateChangeSource source) override; void onStateChanged(State was, StateChangeSource source) override;
private: private:
void setOpacity(float64 o); void setOpacity(float64 o);
@ -109,7 +111,7 @@ private:
const style::FlatButton &_st; const style::FlatButton &_st;
anim::fvalue a_over; anim::value a_over;
Animation _a_appearance; Animation _a_appearance;
float64 _opacity = 1.; float64 _opacity = 1.;
@ -162,12 +164,13 @@ public:
IconButton(QWidget *parent, const style::IconButton &st); IconButton(QWidget *parent, const style::IconButton &st);
// Pass nullptr to restore the default icon. // Pass nullptr to restore the default icon.
void setIcon(const style::icon *icon, const style::icon *iconOver = nullptr); void setIconOverride(const style::icon *iconOverride, const style::icon *iconOverOverride = nullptr);
void setRippleColorOverride(const style::color *colorOverride);
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
void onStateChanged(int oldState, StateChangeSource source) override; void onStateChanged(State was, StateChangeSource source) override;
QImage prepareRippleMask() const override; QImage prepareRippleMask() const override;
QPoint prepareRippleStartPosition() const override; QPoint prepareRippleStartPosition() const override;
@ -176,6 +179,7 @@ private:
const style::IconButton &_st; const style::IconButton &_st;
const style::icon *_iconOverride = nullptr; const style::icon *_iconOverride = nullptr;
const style::icon *_iconOverrideOver = nullptr; const style::icon *_iconOverrideOver = nullptr;
const style::color *_rippleColorOverride = nullptr;
FloatAnimation _a_over; FloatAnimation _a_over;
@ -215,7 +219,7 @@ public:
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
void onStateChanged(int oldState, StateChangeSource source) override; void onStateChanged(State was, StateChangeSource source) override;
QImage prepareRippleMask() const override; QImage prepareRippleMask() const override;
QPoint prepareRippleStartPosition() const override; QPoint prepareRippleStartPosition() const override;

View file

@ -163,16 +163,16 @@ void Checkbox::paintEvent(QPaintEvent *e) {
} }
void Checkbox::onClicked() { void Checkbox::onClicked() {
if (_state & StateDisabled) return; if (isDisabled()) return;
setChecked(!checked()); setChecked(!checked());
} }
void Checkbox::onStateChanged(int oldState, StateChangeSource source) { void Checkbox::onStateChanged(State was, StateChangeSource source) {
RippleButton::onStateChanged(oldState, source); RippleButton::onStateChanged(was, source);
if ((_state & StateDisabled) && !(oldState & StateDisabled)) { if (isDisabled() && !(was & StateFlag::Disabled)) {
setCursor(style::cur_default); setCursor(style::cur_default);
} else if (!(_state & StateDisabled) && (oldState & StateDisabled)) { } else if (!isDisabled() && (was & StateFlag::Disabled)) {
setCursor(style::cur_pointer); setCursor(style::cur_pointer);
} }
} }
@ -284,16 +284,16 @@ void Radiobutton::paintEvent(QPaintEvent *e) {
} }
void Radiobutton::onClicked() { void Radiobutton::onClicked() {
if (_state & StateDisabled) return; if (isDisabled()) return;
setChecked(!checked()); setChecked(!checked());
} }
void Radiobutton::onStateChanged(int oldState, StateChangeSource source) { void Radiobutton::onStateChanged(State was, StateChangeSource source) {
RippleButton::onStateChanged(oldState, source); RippleButton::onStateChanged(was, source);
if ((_state & StateDisabled) && !(oldState & StateDisabled)) { if (isDisabled() && !(was & StateFlag::Disabled)) {
setCursor(style::cur_default); setCursor(style::cur_default);
} else if (!(_state & StateDisabled) && (oldState & StateDisabled)) { } else if (!isDisabled() && (was & StateFlag::Disabled)) {
setCursor(style::cur_pointer); setCursor(style::cur_pointer);
} }
} }

View file

@ -48,7 +48,7 @@ public:
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
void onStateChanged(int oldState, StateChangeSource source) override; void onStateChanged(State was, StateChangeSource source) override;
int resizeGetHeight(int newWidth) override; int resizeGetHeight(int newWidth) override;
QImage prepareRippleMask() const override; QImage prepareRippleMask() const override;
@ -95,7 +95,7 @@ public:
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
void onStateChanged(int oldState, StateChangeSource source) override; void onStateChanged(State was, StateChangeSource source) override;
int resizeGetHeight(int newWidth) override; int resizeGetHeight(int newWidth) override;
QImage prepareRippleMask() const override; QImage prepareRippleMask() const override;

View file

@ -65,7 +65,7 @@ void ContinuousSlider::setValue(float64 value, bool animated) {
a_value.start(value); a_value.start(value);
_a_value.start(); _a_value.start();
} else { } else {
a_value = anim::fvalue(value, value); a_value = anim::value(value, value);
_a_value.stop(); _a_value.stop();
} }
update(); update();
@ -116,7 +116,7 @@ void ContinuousSlider::mouseReleaseEvent(QMouseEvent *e) {
if (_changeFinishedCallback) { if (_changeFinishedCallback) {
_changeFinishedCallback(_downValue); _changeFinishedCallback(_downValue);
} }
a_value = anim::fvalue(_downValue, _downValue); a_value = anim::value(_downValue, _downValue);
_a_value.stop(); _a_value.stop();
update(); update();
} }

View file

@ -107,7 +107,7 @@ private:
bool _over = false; bool _over = false;
FloatAnimation _a_over; FloatAnimation _a_over;
anim::fvalue a_value = { 0., 0. }; anim::value a_value;
Animation _a_value; Animation _a_value;
bool _mouseDown = false; bool _mouseDown = false;

View file

@ -1716,11 +1716,6 @@ InputArea::InputArea(QWidget *parent, const style::InputArea &st, const QString
, _placeholderFull(ph) , _placeholderFull(ph)
, _placeholderVisible(val.isEmpty()) , _placeholderVisible(val.isEmpty())
, a_placeholderLeft(_placeholderVisible ? 0 : st.placeholderShift)
, a_placeholderOpacity(_placeholderVisible ? 1 : 0)
, a_placeholderFgActive(0)
, _a_placeholderFg(animation(this, &InputArea::step_placeholderFg))
, _a_placeholderShift(animation(this, &InputArea::step_placeholderShift))
, a_borderOpacityActive(0) , a_borderOpacityActive(0)
, a_borderFgActive(0) , a_borderFgActive(0)
@ -1878,21 +1873,21 @@ void InputArea::paintEvent(QPaintEvent *e) {
p.setOpacity(1); p.setOpacity(1);
} }
bool drawPlaceholder = _placeholderVisible; auto ms = getms();
if (_a_placeholderShift.animating()) { auto placeholderOpacity = _a_placeholderVisible.current(ms, _placeholderVisible ? 1. : 0.);
p.setOpacity(a_placeholderOpacity.current()); if (placeholderOpacity > 0.) {
drawPlaceholder = true; p.setOpacity(placeholderOpacity);
}
if (drawPlaceholder) {
p.save(); p.save();
p.setClipRect(r); p.setClipRect(r);
auto placeholderLeft = anim::interpolate(_st.placeholderShift, 0, placeholderOpacity);
QRect r(rect().marginsRemoved(_st.textMargins + _st.placeholderMargins)); QRect r(rect().marginsRemoved(_st.textMargins + _st.placeholderMargins));
r.moveLeft(r.left() + a_placeholderLeft.current()); r.moveLeft(r.left() + placeholderLeft);
if (rtl()) r.moveLeft(width() - r.left() - r.width()); if (rtl()) r.moveLeft(width() - r.left() - r.width());
p.setFont(_st.font); p.setFont(_st.font);
p.setPen(anim::pen(_st.placeholderFg, _st.placeholderFgActive, a_placeholderFgActive.current())); p.setPen(anim::pen(_st.placeholderFg, _st.placeholderFgActive, _a_placeholderFocused.current(ms, hasFocus() ? 1. : 0.)));
p.drawText(r, _placeholder, _st.placeholderAlign); p.drawText(r, _placeholder, _st.placeholderAlign);
p.restore(); p.restore();
@ -1929,8 +1924,7 @@ void InputArea::focusInInner() {
if (!_focused) { if (!_focused) {
_focused = true; _focused = true;
a_placeholderFgActive.start(1.); _a_placeholderFocused.start([this] { update(); }, 0., 1., _st.duration);
_a_placeholderFg.start();
startBorderAnimation(); startBorderAnimation();
} }
@ -1946,8 +1940,7 @@ void InputArea::focusOutInner() {
if (_focused) { if (_focused) {
_focused = false; _focused = false;
a_placeholderFgActive.start(0.); _a_placeholderFocused.start([this] { update(); }, 1., 0., _st.duration);
_a_placeholderFg.start();
startBorderAnimation(); startBorderAnimation();
} }
@ -2273,30 +2266,6 @@ void InputArea::onRedoAvailable(bool avail) {
if (App::wnd()) App::wnd()->updateGlobalMenu(); if (App::wnd()) App::wnd()->updateGlobalMenu();
} }
void InputArea::step_placeholderFg(float64 ms, bool timer) {
float64 dt = ms / _st.duration;
if (dt >= 1) {
_a_placeholderFg.stop();
a_placeholderFgActive.finish();
} else {
a_placeholderFgActive.update(dt, anim::linear);
}
if (timer) update();
}
void InputArea::step_placeholderShift(float64 ms, bool timer) {
float64 dt = ms / _st.duration;
if (dt >= 1) {
_a_placeholderShift.stop();
a_placeholderLeft.finish();
a_placeholderOpacity.finish();
} else {
a_placeholderLeft.update(dt, anim::linear);
a_placeholderOpacity.update(dt, anim::linear);
}
if (timer) update();
}
void InputArea::step_border(float64 ms, bool timer) { void InputArea::step_border(float64 ms, bool timer) {
float64 dt = ms / _st.duration; float64 dt = ms / _st.duration;
bool res = true; bool res = true;
@ -2314,13 +2283,10 @@ void InputArea::step_border(float64 ms, bool timer) {
} }
void InputArea::updatePlaceholder() { void InputArea::updatePlaceholder() {
bool placeholderVisible = _oldtext.isEmpty(); auto placeholderVisible = _oldtext.isEmpty();
if (placeholderVisible != _placeholderVisible) { if (_placeholderVisible != placeholderVisible) {
_placeholderVisible = placeholderVisible; _placeholderVisible = placeholderVisible;
_a_placeholderVisible.start([this] { update(); }, _placeholderVisible ? 0. : 1., _placeholderVisible ? 1. : 0., _st.duration);
a_placeholderLeft.start(_placeholderVisible ? 0 : _st.placeholderShift);
a_placeholderOpacity.start(_placeholderVisible ? 1 : 0);
_a_placeholderShift.start();
} }
} }
@ -2445,11 +2411,6 @@ InputField::InputField(QWidget *parent, const style::InputField &st, const QStri
, _placeholderFull(ph) , _placeholderFull(ph)
, _placeholderVisible(val.isEmpty()) , _placeholderVisible(val.isEmpty())
, a_placeholderLeft(_placeholderVisible ? 0 : st.placeholderShift)
, a_placeholderOpacity(_placeholderVisible ? 1 : 0)
, a_placeholderFgActive(0)
, _a_placeholderFg(animation(this, &InputField::step_placeholderFg))
, _a_placeholderShift(animation(this, &InputField::step_placeholderShift))
, a_borderOpacityActive(0) , a_borderOpacityActive(0)
, a_borderFgActive(0) , a_borderFgActive(0)
@ -2571,13 +2532,6 @@ void InputField::paintEvent(QPaintEvent *e) {
Painter p(this); Painter p(this);
auto ms = getms(); auto ms = getms();
if (_a_placeholderShift.animating()) {
_a_placeholderShift.step(ms);
}
if (_a_placeholderFg.animating()) {
_a_placeholderFg.step(ms);
}
QRect r(rect().intersected(e->rect())); QRect r(rect().intersected(e->rect()));
if (_st.textBg->c.alphaF() > 0.) { if (_st.textBg->c.alphaF() > 0.) {
p.fillRect(r, _st.textBg); p.fillRect(r, _st.textBg);
@ -2593,21 +2547,21 @@ void InputField::paintEvent(QPaintEvent *e) {
p.setOpacity(1); p.setOpacity(1);
} }
bool drawPlaceholder = _placeholderVisible; auto placeholderOpacity = _a_placeholderVisible.current(ms, _placeholderVisible ? 1. : 0.);
if (_a_placeholderShift.animating()) { if (placeholderOpacity > 0.) {
p.setOpacity(a_placeholderOpacity.current()); p.setOpacity(placeholderOpacity);
drawPlaceholder = true;
}
if (drawPlaceholder) {
p.save(); p.save();
p.setClipRect(r); p.setClipRect(r);
auto placeholderLeft = anim::interpolate(_st.placeholderShift, 0, placeholderOpacity);
QRect r(rect().marginsRemoved(_st.textMargins + _st.placeholderMargins)); QRect r(rect().marginsRemoved(_st.textMargins + _st.placeholderMargins));
r.moveLeft(r.left() + a_placeholderLeft.current()); r.moveLeft(r.left() + placeholderLeft);
if (rtl()) r.moveLeft(width() - r.left() - r.width()); if (rtl()) r.moveLeft(width() - r.left() - r.width());
p.setFont(_st.font); p.setFont(_st.font);
p.setPen(anim::pen(_st.placeholderFg, _st.placeholderFgActive, a_placeholderFgActive.current())); p.setPen(anim::pen(_st.placeholderFg, _st.placeholderFgActive, _a_placeholderFocused.current(ms, hasFocus() ? 1. : 0.)));
p.drawText(r, _placeholder, _st.placeholderAlign); p.drawText(r, _placeholder, _st.placeholderAlign);
p.restore(); p.restore();
@ -2644,8 +2598,7 @@ void InputField::focusInInner() {
if (!_focused) { if (!_focused) {
_focused = true; _focused = true;
a_placeholderFgActive.start(1.); _a_placeholderFocused.start([this] { update(); }, 0., 1., _st.duration);
_a_placeholderFg.start();
startBorderAnimation(); startBorderAnimation();
} }
@ -2661,8 +2614,7 @@ void InputField::focusOutInner() {
if (_focused) { if (_focused) {
_focused = false; _focused = false;
a_placeholderFgActive.start(0.); _a_placeholderFocused.start([this] { update(); }, 1., 0., _st.duration);
_a_placeholderFg.start();
startBorderAnimation(); startBorderAnimation();
} }
@ -3019,32 +2971,9 @@ void InputField::selectAll() {
_inner.setTextCursor(c); _inner.setTextCursor(c);
} }
void InputField::step_placeholderFg(float64 ms, bool timer) {
float64 dt = ms / _st.duration;
if (dt >= 1) {
_a_placeholderFg.stop();
a_placeholderFgActive.finish();
} else {
a_placeholderFgActive.update(dt, anim::linear);
}
if (timer) update();
}
void InputField::step_placeholderShift(float64 ms, bool timer) {
float64 dt = ms / _st.duration;
if (dt >= 1) {
finishPlaceholderAnimation();
} else {
a_placeholderLeft.update(dt, anim::linear);
a_placeholderOpacity.update(dt, anim::linear);
}
if (timer) update();
}
void InputField::finishPlaceholderAnimation() { void InputField::finishPlaceholderAnimation() {
_a_placeholderShift.stop(); _a_placeholderVisible.finish();
a_placeholderLeft.finish(); _a_placeholderFocused.finish();
a_placeholderOpacity.finish();
update(); update();
} }
@ -3064,13 +2993,10 @@ void InputField::step_border(float64 ms, bool timer) {
} }
void InputField::updatePlaceholder() { void InputField::updatePlaceholder() {
bool placeholderVisible = _oldtext.isEmpty() && !_forcePlaceholderHidden; auto placeholderVisible = _oldtext.isEmpty();
if (placeholderVisible != _placeholderVisible) { if (_placeholderVisible != placeholderVisible) {
_placeholderVisible = placeholderVisible; _placeholderVisible = placeholderVisible;
_a_placeholderVisible.start([this] { update(); }, _placeholderVisible ? 0. : 1., _placeholderVisible ? 1. : 0., _st.duration);
a_placeholderLeft.start(_placeholderVisible ? 0 : _st.placeholderShift);
a_placeholderOpacity.start(_placeholderVisible ? 1 : 0);
_a_placeholderShift.start();
} }
} }
@ -3198,11 +3124,6 @@ MaskedInputField::MaskedInputField(QWidget *parent, const style::InputField &st,
, _placeholderFull(placeholder) , _placeholderFull(placeholder)
, _placeholderVisible(val.isEmpty()) , _placeholderVisible(val.isEmpty())
, _placeholderFast(false) , _placeholderFast(false)
, a_placeholderLeft(_placeholderVisible ? 0 : st.placeholderShift)
, a_placeholderOpacity(_placeholderVisible ? 1 : 0)
, a_placeholderFgActive(0)
, _a_placeholderFg(animation(this, &MaskedInputField::step_placeholderFg))
, _a_placeholderShift(animation(this, &MaskedInputField::step_placeholderShift))
, a_borderOpacityActive(0) , a_borderOpacityActive(0)
, a_borderFgActive(0) , a_borderFgActive(0)
@ -3345,7 +3266,7 @@ void MaskedInputField::paintEvent(QPaintEvent *e) {
} }
p.setClipRect(r); p.setClipRect(r);
paintPlaceholder(p); paintPlaceholder(p, getms());
QLineEdit::paintEvent(e); QLineEdit::paintEvent(e);
} }
@ -3361,8 +3282,7 @@ void MaskedInputField::focusInEvent(QFocusEvent *e) {
if (!_focused) { if (!_focused) {
_focused = true; _focused = true;
a_placeholderFgActive.start(1.); _a_placeholderFocused.start([this] { update(); }, 0., 1., _st.duration);
_a_placeholderFg.start();
startBorderAnimation(); startBorderAnimation();
} }
@ -3374,8 +3294,7 @@ void MaskedInputField::focusOutEvent(QFocusEvent *e) {
if (_focused) { if (_focused) {
_focused = false; _focused = false;
a_placeholderFgActive.start(0.); _a_placeholderFocused.start([this] { update(); }, 1., 0., _st.duration);
_a_placeholderFg.start();
startBorderAnimation(); startBorderAnimation();
} }
@ -3416,30 +3335,6 @@ QSize MaskedInputField::minimumSizeHint() const {
return geometry().size(); return geometry().size();
} }
void MaskedInputField::step_placeholderFg(float64 ms, bool timer) {
float64 dt = ms / _st.duration;
if (dt >= 1) {
_a_placeholderFg.stop();
a_placeholderFgActive.finish();
} else {
a_placeholderFgActive.update(dt, anim::linear);
}
if (timer) update();
}
void MaskedInputField::step_placeholderShift(float64 ms, bool timer) {
float64 dt = ms / _st.duration;
if (dt >= 1) {
_a_placeholderShift.stop();
a_placeholderLeft.finish();
a_placeholderOpacity.finish();
} else {
a_placeholderLeft.update(dt, anim::linear);
a_placeholderOpacity.update(dt, anim::linear);
}
if (timer) update();
}
void MaskedInputField::step_border(float64 ms, bool timer) { void MaskedInputField::step_border(float64 ms, bool timer) {
float64 dt = ms / _st.duration; float64 dt = ms / _st.duration;
if (dt >= 1) { if (dt >= 1) {
@ -3467,25 +3362,18 @@ bool MaskedInputField::setPlaceholder(const QString &placeholder) {
void MaskedInputField::setPlaceholderFast(bool fast) { void MaskedInputField::setPlaceholderFast(bool fast) {
_placeholderFast = fast; _placeholderFast = fast;
if (_placeholderFast) { if (_placeholderFast) {
a_placeholderLeft = anim::ivalue(_placeholderVisible ? 0 : _st.placeholderShift, _placeholderVisible ? 0 : _st.placeholderShift); _a_placeholderVisible.finish();
a_placeholderOpacity = anim::fvalue(_placeholderVisible ? 1 : 0, _placeholderVisible ? 1 : 0);
update(); update();
} }
} }
void MaskedInputField::updatePlaceholder() { void MaskedInputField::updatePlaceholder() {
bool placeholderVisible = _oldtext.isEmpty(); auto placeholderVisible = _oldtext.isEmpty();
if (placeholderVisible != _placeholderVisible) { if (_placeholderVisible != placeholderVisible) {
_placeholderVisible = placeholderVisible; _placeholderVisible = placeholderVisible;
_a_placeholderVisible.start([this] { update(); }, _placeholderVisible ? 0. : 1., _placeholderVisible ? 1. : 0., _st.duration);
if (_placeholderFast) { if (_placeholderFast) {
a_placeholderLeft = anim::ivalue(_placeholderVisible ? 0 : _st.placeholderShift, _placeholderVisible ? 0 : _st.placeholderShift); _a_placeholderVisible.finish();
a_placeholderOpacity = anim::fvalue(_placeholderVisible ? 1 : 0, _placeholderVisible ? 1 : 0);
update();
} else {
a_placeholderLeft.start(_placeholderVisible ? 0 : _st.placeholderShift);
a_placeholderOpacity.start(_placeholderVisible ? 1 : 0);
_a_placeholderShift.start();
} }
} }
} }
@ -3498,29 +3386,28 @@ QRect MaskedInputField::placeholderRect() const {
return rect().marginsRemoved(_st.textMargins + _st.placeholderMargins); return rect().marginsRemoved(_st.textMargins + _st.placeholderMargins);
} }
void MaskedInputField::paintPlaceholder(Painter &p) { void MaskedInputField::paintPlaceholder(Painter &p, TimeMs ms) {
bool drawPlaceholder = _placeholderVisible; auto placeholderOpacity = _a_placeholderVisible.current(ms, _placeholderVisible ? 1. : 0.);
if (_a_placeholderShift.animating()) { if (placeholderOpacity > 0.) {
p.setOpacity(a_placeholderOpacity.current()); p.setOpacity(placeholderOpacity);
drawPlaceholder = true;
}
if (drawPlaceholder) {
p.save(); p.save();
auto placeholderLeft = anim::interpolate(_st.placeholderShift, 0, placeholderOpacity);
QRect phRect(placeholderRect()); QRect phRect(placeholderRect());
phRect.moveLeft(phRect.left() + a_placeholderLeft.current()); phRect.moveLeft(phRect.left() + placeholderLeft);
if (rtl()) phRect.moveLeft(width() - phRect.left() - phRect.width()); if (rtl()) phRect.moveLeft(width() - phRect.left() - phRect.width());
placeholderPreparePaint(p); placeholderPreparePaint(p, ms);
p.drawText(phRect, _placeholder, _st.placeholderAlign); p.drawText(phRect, _placeholder, _st.placeholderAlign);
p.restore(); p.restore();
} }
} }
void MaskedInputField::placeholderPreparePaint(Painter &p) { void MaskedInputField::placeholderPreparePaint(Painter &p, TimeMs ms) {
p.setFont(_st.font); p.setFont(_st.font);
p.setPen(anim::pen(_st.placeholderFg, _st.placeholderFgActive, a_placeholderFgActive.current())); p.setPen(anim::pen(_st.placeholderFg, _st.placeholderFgActive, _a_placeholderFocused.current(ms, hasFocus() ? 1. : 0.)));
} }
void MaskedInputField::keyPressEvent(QKeyEvent *e) { void MaskedInputField::keyPressEvent(QKeyEvent *e) {
@ -3648,7 +3535,7 @@ void CountryCodeInput::correctValue(const QString &was, int32 wasCursor, QString
PhonePartInput::PhonePartInput(QWidget *parent, const style::InputField &st) : MaskedInputField(parent, st, lang(lng_phone_ph)) { PhonePartInput::PhonePartInput(QWidget *parent, const style::InputField &st) : MaskedInputField(parent, st, lang(lng_phone_ph)) {
} }
void PhonePartInput::paintPlaceholder(Painter &p) { void PhonePartInput::paintPlaceholder(Painter &p, TimeMs ms) {
auto t = getLastText(); auto t = getLastText();
if (!_pattern.isEmpty() && !t.isEmpty()) { if (!_pattern.isEmpty() && !t.isEmpty()) {
auto ph = placeholder().mid(t.size()); auto ph = placeholder().mid(t.size());
@ -3658,12 +3545,12 @@ void PhonePartInput::paintPlaceholder(Painter &p) {
int tw = phFont()->width(t); int tw = phFont()->width(t);
if (tw < phRect.width()) { if (tw < phRect.width()) {
phRect.setLeft(phRect.left() + tw); phRect.setLeft(phRect.left() + tw);
placeholderPreparePaint(p); placeholderPreparePaint(p, ms);
p.drawText(phRect, ph, style::al_topleft); p.drawText(phRect, ph, style::al_topleft);
} }
} }
} else { } else {
MaskedInputField::paintPlaceholder(p); MaskedInputField::paintPlaceholder(p, ms);
} }
} }
@ -3812,9 +3699,9 @@ _linkPlaceholder(isLink ? qsl("telegram.me/") : QString()) {
} }
} }
void UsernameInput::paintPlaceholder(Painter &p) { void UsernameInput::paintPlaceholder(Painter &p, TimeMs ms) {
if (_linkPlaceholder.isEmpty()) { if (_linkPlaceholder.isEmpty()) {
MaskedInputField::paintPlaceholder(p); MaskedInputField::paintPlaceholder(p, ms);
} else { } else {
p.setFont(_st.font); p.setFont(_st.font);
p.setPen(_st.placeholderFg); p.setPen(_st.placeholderFg);
@ -3872,7 +3759,7 @@ void PhoneInput::clearText() {
correctValue(QString(), 0, phone, pos); correctValue(QString(), 0, phone, pos);
} }
void PhoneInput::paintPlaceholder(Painter &p) { void PhoneInput::paintPlaceholder(Painter &p, TimeMs ms) {
auto t = getLastText(); auto t = getLastText();
if (!_pattern.isEmpty() && !t.isEmpty()) { if (!_pattern.isEmpty() && !t.isEmpty()) {
auto ph = placeholder().mid(t.size()); auto ph = placeholder().mid(t.size());
@ -3882,12 +3769,12 @@ void PhoneInput::paintPlaceholder(Painter &p) {
int tw = phFont()->width(t); int tw = phFont()->width(t);
if (tw < phRect.width()) { if (tw < phRect.width()) {
phRect.setLeft(phRect.left() + tw); phRect.setLeft(phRect.left() + tw);
placeholderPreparePaint(p); placeholderPreparePaint(p, ms);
p.drawText(phRect, ph, style::al_topleft); p.drawText(phRect, ph, style::al_topleft);
} }
} }
} else { } else {
MaskedInputField::paintPlaceholder(p); MaskedInputField::paintPlaceholder(p, ms);
} }
} }

View file

@ -347,8 +347,6 @@ public:
} }
void updatePlaceholder(); void updatePlaceholder();
void step_placeholderFg(float64 ms, bool timer);
void step_placeholderShift(float64 ms, bool timer);
void step_border(float64 ms, bool timer); void step_border(float64 ms, bool timer);
QSize sizeHint() const override; QSize sizeHint() const override;
@ -470,14 +468,12 @@ private:
QString _placeholder, _placeholderFull; QString _placeholder, _placeholderFull;
bool _placeholderVisible; bool _placeholderVisible;
anim::ivalue a_placeholderLeft; FloatAnimation _a_placeholderFocused;
anim::fvalue a_placeholderOpacity; FloatAnimation _a_placeholderVisible;
anim::fvalue a_placeholderFgActive;
Animation _a_placeholderFg, _a_placeholderShift;
anim::fvalue a_borderOpacityActive; anim::value a_borderOpacityActive;
anim::fvalue a_borderFgActive; anim::value a_borderFgActive;
anim::fvalue a_borderFgError; anim::value a_borderFgError;
Animation _a_border; Animation _a_border;
bool _focused, _error; bool _focused, _error;
@ -511,8 +507,6 @@ public:
void setPlaceholderHidden(bool forcePlaceholderHidden); void setPlaceholderHidden(bool forcePlaceholderHidden);
void finishPlaceholderAnimation(); void finishPlaceholderAnimation();
void step_placeholderFg(float64 ms, bool timer);
void step_placeholderShift(float64 ms, bool timer);
void step_border(float64 ms, bool timer); void step_border(float64 ms, bool timer);
QSize sizeHint() const override; QSize sizeHint() const override;
@ -640,14 +634,12 @@ private:
QString _placeholder, _placeholderFull; QString _placeholder, _placeholderFull;
bool _placeholderVisible; bool _placeholderVisible;
anim::ivalue a_placeholderLeft; FloatAnimation _a_placeholderFocused;
anim::fvalue a_placeholderOpacity; FloatAnimation _a_placeholderVisible;
anim::fvalue a_placeholderFgActive;
Animation _a_placeholderFg, _a_placeholderShift;
anim::fvalue a_borderOpacityActive; anim::value a_borderOpacityActive;
anim::fvalue a_borderFgActive; anim::value a_borderFgActive;
anim::fvalue a_borderFgError; anim::value a_borderFgError;
Animation _a_border; Animation _a_border;
bool _focused, _error; bool _focused, _error;
@ -676,8 +668,6 @@ public:
QRect getTextRect() const; QRect getTextRect() const;
void step_placeholderFg(float64 ms, bool timer);
void step_placeholderShift(float64 ms, bool timer);
void step_border(float64 ms, bool timer); void step_border(float64 ms, bool timer);
QSize sizeHint() const override; QSize sizeHint() const override;
@ -736,13 +726,13 @@ protected:
} }
void setCorrectedText(QString &now, int &nowCursor, const QString &newText, int newPos); void setCorrectedText(QString &now, int &nowCursor, const QString &newText, int newPos);
virtual void paintPlaceholder(Painter &p); virtual void paintPlaceholder(Painter &p, TimeMs ms);
style::font phFont() { style::font phFont() {
return _st.font; return _st.font;
} }
void placeholderPreparePaint(Painter &p); void placeholderPreparePaint(Painter &p, TimeMs ms);
const QString &placeholder() const; const QString &placeholder() const;
QRect placeholderRect() const; QRect placeholderRect() const;
@ -764,14 +754,12 @@ private:
QString _placeholder, _placeholderFull; QString _placeholder, _placeholderFull;
bool _placeholderVisible, _placeholderFast; bool _placeholderVisible, _placeholderFast;
anim::ivalue a_placeholderLeft; FloatAnimation _a_placeholderFocused;
anim::fvalue a_placeholderOpacity; FloatAnimation _a_placeholderVisible;
anim::fvalue a_placeholderFgActive;
Animation _a_placeholderFg, _a_placeholderShift;
anim::fvalue a_borderOpacityActive; anim::value a_borderOpacityActive;
anim::fvalue a_borderFgActive; anim::value a_borderFgActive;
anim::fvalue a_borderFgError; anim::value a_borderFgError;
Animation _a_border; Animation _a_border;
bool _focused, _error; bool _focused, _error;
@ -822,7 +810,7 @@ protected:
void keyPressEvent(QKeyEvent *e) override; void keyPressEvent(QKeyEvent *e) override;
void correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) override; void correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) override;
void paintPlaceholder(Painter &p) override; void paintPlaceholder(Painter &p, TimeMs ms) override;
private: private:
QVector<int> _pattern; QVector<int> _pattern;
@ -850,7 +838,7 @@ public:
protected: protected:
void correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) override; void correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) override;
void paintPlaceholder(Painter &p) override; void paintPlaceholder(Painter &p, TimeMs ms) override;
private: private:
QString _linkPlaceholder; QString _linkPlaceholder;
@ -867,7 +855,7 @@ protected:
void focusInEvent(QFocusEvent *e) override; void focusInEvent(QFocusEvent *e) override;
void correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) override; void correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) override;
void paintPlaceholder(Painter &p) override; void paintPlaceholder(Painter &p, TimeMs ms) override;
private: private:
QString _defaultPlaceholder; QString _defaultPlaceholder;

View file

@ -95,7 +95,7 @@ private:
, y(y) { , y(y) {
x.start(updateCallback, fromX, toX, duration); x.start(updateCallback, fromX, toX, duration);
} }
IntAnimation x; FloatAnimation x;
int fromX, toX; int fromX, toX;
int y; int y;
}; };
@ -143,7 +143,7 @@ void MultiSelect::Inner::Item::paint(Painter &p, int outerWidth, TimeMs ms) {
paintOnce(p, _x, _y, outerWidth, ms); paintOnce(p, _x, _y, outerWidth, ms);
} else { } else {
for (auto i = _copies.begin(), e = _copies.end(); i != e;) { for (auto i = _copies.begin(), e = _copies.end(); i != e;) {
auto x = i->x.current(getms(), _x); auto x = qRound(i->x.current(getms(), _x));
auto y = i->y; auto y = i->y;
auto animating = i->x.animating(); auto animating = i->x.animating();
if (animating || (y == _y)) { if (animating || (y == _y)) {
@ -748,7 +748,7 @@ void MultiSelect::Inner::updateItemsGeometry() {
} }
void MultiSelect::Inner::updateHeightStep() { void MultiSelect::Inner::updateHeightStep() {
auto newHeight = _height.current(_newHeight); auto newHeight = qRound(_height.current(_newHeight));
if (auto heightDelta = newHeight - height()) { if (auto heightDelta = newHeight - height()) {
resize(width(), newHeight); resize(width(), newHeight);
if (_resizedCallback) { if (_resizedCallback) {

Some files were not shown because too many files have changed in this diff Show more