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_no_media" = "No media in this conversation.";
"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_header" = "Videos overview";
"lng_profile_videos_header" = "Videos";
"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_header" = "Files overview";
"lng_profile_files_header" = "Files";
"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_header" = "Shared links overview";
"lng_profile_shared_links_header" = "Shared links";
"lng_profile_copy_phone" = "Copy Phone Number";
"lng_profile_copy_fullname" = "Copy Name";
"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
FILEVERSION 0,10,19,11
PRODUCTVERSION 0,10,19,11
FILEVERSION 0,10,19,12
PRODUCTVERSION 0,10,19,12
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -51,10 +51,10 @@ BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileVersion", "0.10.19.11"
VALUE "FileVersion", "0.10.19.12"
VALUE "LegalCopyright", "Copyright (C) 2014-2016"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "0.10.19.11"
VALUE "ProductVersion", "0.10.19.12"
END
END
BLOCK "VarFileInfo"

View file

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

View file

@ -1246,7 +1246,7 @@ namespace {
if (auto history = App::historyLoaded(peer)) {
history->outboxRead(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();

View file

@ -711,8 +711,6 @@ AppClass::AppClass() : QObject() {
cChangeTimeFormat(QLocale::system().timeFormat(QLocale::ShortFormat));
connect(&_mtpUnpauseTimer, SIGNAL(timeout()), this, SLOT(doMtpUnpause()));
connect(&killDownloadSessionsTimer, SIGNAL(timeout()), this, SLOT(killDownloadSessions()));
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) {
if (!App::self()) return;
App::self()->setPhoto(result);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -178,7 +178,7 @@ private:
QPoint _lastMousePos;
QString _goodTextLink;
anim::fvalue a_goodOpacity;
anim::value a_goodOpacity;
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/scroll_area.h"
#include "ui/effects/widget_slide_wrap.h"
#include "ui/effects/ripple_animation.h"
#include "boxes/photocropbox.h"
#include "boxes/confirmbox.h"
#include "observer_peer.h"
@ -546,10 +547,14 @@ bool ContactsBox::creationFail(const RPCError &error) {
return false;
}
ContactsBox::Inner::ContactData::ContactData() = default;
ContactsBox::Inner::ContactData::ContactData(PeerData *peer, const base::lambda_copy<void()> &updateCallback)
: 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)
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
, _creating(creating)
@ -924,16 +929,16 @@ ContactsBox::Inner::ContactData *ContactsBox::Inner::contactData(Dialogs::Row *r
return data;
}
void ContactsBox::Inner::paintDialog(Painter &p, TimeMs ms, PeerData *peer, ContactData *data, bool sel) {
UserData *user = peer->asUser();
void ContactsBox::Inner::paintDialog(Painter &p, TimeMs ms, PeerData *peer, ContactData *data, bool selected) {
auto user = peer->asUser();
if (_chat && _membersFilter == MembersFilter::Admins) {
if (_allAdmins->checked() || peer->id == peerFromUser(_chat->creator) || _saving) {
sel = false;
selected = false;
}
} else {
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.;
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) {
paintDisabledCheckUserpic(p, peer, st::contactsPadding.left(), st::contactsPadding.top(), width());
} else if (usingMultiSelect()) {
@ -979,14 +990,14 @@ void ContactsBox::Inner::paintDialog(Painter &p, TimeMs ms, PeerData *peer, Cont
int32 secondw = st::contactsStatusFont->width(second);
p.setPen(st::contactsStatusFgOnline);
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);
}
} else {
if ((user && (uname || data->statusHasOnlineColor)) || (peer->isChannel() && uname)) {
p.setPen(st::contactsStatusFgOnline);
} 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);
}
@ -1064,7 +1075,8 @@ void ContactsBox::Inner::paintEvent(QPaintEvent *e) {
if ((*i)->pos() * _rowHeight >= yTo) {
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);
}
yFrom -= _contacts->size() * _rowHeight;
@ -1080,11 +1092,12 @@ void ContactsBox::Inner::paintEvent(QPaintEvent *e) {
yTo -= st::searchedBarHeight;
p.translate(0, st::searchedBarHeight);
int32 from = floorclamp(yFrom, _rowHeight, 0, _byUsername.size());
int32 to = ceilclamp(yTo, _rowHeight, 0, _byUsername.size());
auto from = floorclamp(yFrom, _rowHeight, 0, _byUsername.size());
auto to = ceilclamp(yTo, _rowHeight, 0, _byUsername.size());
p.translate(0, from * _rowHeight);
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);
}
}
@ -1130,7 +1143,8 @@ void ContactsBox::Inner::paintEvent(QPaintEvent *e) {
int32 to = ceilclamp(yTo, _rowHeight, 0, _filtered.size());
p.translate(0, from * _rowHeight);
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);
}
}
@ -1147,7 +1161,8 @@ void ContactsBox::Inner::paintEvent(QPaintEvent *e) {
int32 to = ceilclamp(yTo, _rowHeight, 0, _byUsernameFiltered.size());
p.translate(0, from * _rowHeight);
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);
}
}
@ -1161,16 +1176,16 @@ void ContactsBox::Inner::enterEvent(QEvent *e) {
int ContactsBox::Inner::getSelectedRowTop() const {
if (_filter.isEmpty()) {
if (_sel) {
return _aboutHeight + (_sel->pos() * _rowHeight);
} else if (_byUsernameSel >= 0) {
return _aboutHeight + (_contacts->size() * _rowHeight) + st::searchedBarHeight + (_byUsernameSel * _rowHeight);
if (_selected) {
return _aboutHeight + (_selected->pos() * _rowHeight);
} else if (_searchedSelected >= 0) {
return _aboutHeight + (_contacts->size() * _rowHeight) + st::searchedBarHeight + (_searchedSelected * _rowHeight);
}
} else {
if (_filteredSel >= 0) {
return (_filteredSel * _rowHeight);
} else if (_byUsernameSel >= 0) {
return (_filtered.size() * _rowHeight + st::searchedBarHeight + _byUsernameSel * _rowHeight);
if (_filteredSelected >= 0) {
return (_filteredSelected * _rowHeight);
} else if (_searchedSelected >= 0) {
return (_filtered.size() * _rowHeight + st::searchedBarHeight + _searchedSelected * _rowHeight);
}
}
return -1;
@ -1222,53 +1237,130 @@ void ContactsBox::Inner::updateRowWithPeer(PeerData *peer) {
}
void ContactsBox::Inner::leaveEvent(QEvent *e) {
_mouseSel = false;
_mouseSelection = false;
setMouseTracking(false);
if (_sel || _filteredSel >= 0 || _byUsernameSel >= 0) {
if (_selected || _filteredSelected >= 0 || _searchedSelected >= 0) {
updateSelectedRow();
_sel = 0;
_filteredSel = _byUsernameSel = -1;
_selected = nullptr;
_filteredSelected = _searchedSelected = -1;
}
}
void ContactsBox::Inner::mouseMoveEvent(QMouseEvent *e) {
_mouseSel = true;
_mouseSelection = true;
_lastMousePos = e->globalPos();
updateSelection();
}
void ContactsBox::Inner::mousePressEvent(QMouseEvent *e) {
_mouseSel = true;
_mouseSelection = true;
_lastMousePos = e->globalPos();
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() {
if (_saving) return;
bool addingAdmin = (_channel && _membersFilter == MembersFilter::Admins);
if (!addingAdmin && usingMultiSelect()) {
_time = unixtime();
if (_filter.isEmpty()) {
if (_byUsernameSel >= 0 && _byUsernameSel < _byUsername.size()) {
auto data = d_byUsername[_byUsernameSel];
auto peer = _byUsername[_byUsernameSel];
if (_searchedSelected >= 0 && _searchedSelected < _byUsername.size()) {
auto data = d_byUsername[_searchedSelected];
auto peer = _byUsername[_searchedSelected];
if (data->disabledChecked) return;
changeCheckState(data, peer);
} else if (_sel) {
auto data = contactData(_sel);
auto peer = _sel->history()->peer;
} else if (_selected) {
auto data = contactData(_selected);
auto peer = _selected->history()->peer;
if (data->disabledChecked) return;
changeCheckState(_sel);
changeCheckState(_selected);
}
} else {
if (_byUsernameSel >= 0 && _byUsernameSel < _byUsernameFiltered.size()) {
auto data = d_byUsernameFiltered[_byUsernameSel];
auto peer = _byUsernameFiltered[_byUsernameSel];
if (_searchedSelected >= 0 && _searchedSelected < _byUsernameFiltered.size()) {
auto data = d_byUsernameFiltered[_searchedSelected];
auto peer = _byUsernameFiltered[_searchedSelected];
if (data->disabledChecked) return;
int i = 0, l = d_byUsername.size();
@ -1291,9 +1383,9 @@ void ContactsBox::Inner::chooseParticipant() {
}
changeCheckState(data, peer);
} else if (_filteredSel >= 0 && _filteredSel < _filtered.size()) {
auto data = contactData(_filtered[_filteredSel]);
auto peer = _filtered[_filteredSel]->history()->peer;
} else if (_filteredSelected >= 0 && _filteredSelected < _filtered.size()) {
auto data = contactData(_filtered[_filteredSelected]);
auto peer = _filtered[_filteredSelected]->history()->peer;
if (data->disabledChecked) return;
changeCheckState(data, peer);
@ -1302,17 +1394,17 @@ void ContactsBox::Inner::chooseParticipant() {
} else {
PeerData *peer = 0;
if (_filter.isEmpty()) {
if (_byUsernameSel >= 0 && _byUsernameSel < _byUsername.size()) {
peer = _byUsername[_byUsernameSel];
} else if (_sel) {
peer = _sel->history()->peer;
if (_searchedSelected >= 0 && _searchedSelected < _byUsername.size()) {
peer = _byUsername[_searchedSelected];
} else if (_selected) {
peer = _selected->history()->peer;
}
} else {
if (_byUsernameSel >= 0 && _byUsernameSel < _byUsernameFiltered.size()) {
peer = _byUsernameFiltered[_byUsernameSel];
if (_searchedSelected >= 0 && _searchedSelected < _byUsernameFiltered.size()) {
peer = _byUsernameFiltered[_searchedSelected];
} else {
if (_filteredSel < 0 || _filteredSel >= _filtered.size()) return;
peer = _filtered[_filteredSel]->history()->peer;
if (_filteredSelected < 0 || _filteredSelected >= _filtered.size()) return;
peer = _filtered[_filteredSelected]->history()->peer;
}
}
if (peer) {
@ -1408,31 +1500,35 @@ int32 ContactsBox::Inner::selectedCount() const {
}
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));
if (_filter.isEmpty()) {
_filteredSelected = -1;
setFilteredPressed(-1);
if (_aboutHeight) {
p.setY(p.y() - _aboutHeight);
}
Dialogs::Row *newSel = (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;
if (byUsernameSel >= _byUsername.size()) byUsernameSel = -1;
if (newSel != _sel || byUsernameSel != _byUsernameSel) {
auto selected = (in && (p.y() >= 0) && (p.y() < _contacts->size() * _rowHeight)) ? _contacts->rowAtY(p.y(), _rowHeight) : nullptr;
auto searchedSelected = (in && p.y() >= _contacts->size() * _rowHeight + st::searchedBarHeight) ? ((p.y() - _contacts->size() * _rowHeight - st::searchedBarHeight) / _rowHeight) : -1;
if (searchedSelected >= _byUsername.size()) searchedSelected = -1;
if (_selected != selected || _searchedSelected != searchedSelected) {
updateSelectedRow();
_sel = newSel;
_byUsernameSel = byUsernameSel;
_selected = selected;
_searchedSelected = searchedSelected;
updateSelectedRow();
}
} else {
int32 newFilteredSel = (in && p.y() >= 0 && p.y() < _filtered.size() * _rowHeight) ? (p.y() / _rowHeight) : -1;
int32 byUsernameSel = (in && p.y() >= _filtered.size() * _rowHeight + st::searchedBarHeight) ? ((p.y() - _filtered.size() * _rowHeight - st::searchedBarHeight) / _rowHeight) : -1;
if (byUsernameSel >= _byUsernameFiltered.size()) byUsernameSel = -1;
if (newFilteredSel != _filteredSel || byUsernameSel != _byUsernameSel) {
_selected = nullptr;
setPressed(nullptr);
auto filteredSelected = (in && p.y() >= 0 && p.y() < _filtered.size() * _rowHeight) ? (p.y() / _rowHeight) : -1;
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();
_filteredSel = newFilteredSel;
_byUsernameSel = byUsernameSel;
_filteredSelected = filteredSelected;
_searchedSelected = searchedSelected;
updateSelectedRow();
}
}
@ -1461,13 +1557,15 @@ void ContactsBox::Inner::updateFilter(QString filter) {
_byUsernameFiltered.clear();
d_byUsernameFiltered.clear();
for (int i = 0, l = _byUsernameDatas.size(); i < l; ++i) {
delete _byUsernameDatas[i];
}
_byUsernameDatas.clear();
clearSearchedContactDatas();
_selected = nullptr;
setPressed(nullptr);
_filteredSelected = -1;
setFilteredPressed(-1);
_searchedSelected = -1;
setSearchedPressed(-1);
if (_filter.isEmpty()) {
_sel = 0;
refresh();
} else {
if (!_addContactLnk->isHidden()) _addContactLnk->hide();
@ -1534,21 +1632,19 @@ void ContactsBox::Inner::updateFilter(QString filter) {
}
}
}
_filteredSel = -1;
if (!_filtered.isEmpty()) {
for (_filteredSel = 0; (_filteredSel < _filtered.size()) && contactData(_filtered[_filteredSel])->disabledChecked;) {
++_filteredSel;
for (_filteredSelected = 0; (_filteredSelected < _filtered.size()) && contactData(_filtered[_filteredSelected])->disabledChecked;) {
++_filteredSelected;
}
if (_filteredSel == _filtered.size()) _filteredSel = -1;
if (_filteredSelected == _filtered.size()) _filteredSelected = -1;
}
_byUsernameSel = -1;
if (_filteredSel < 0 && !_byUsernameFiltered.isEmpty()) {
for (_byUsernameSel = 0; (_byUsernameSel < _byUsernameFiltered.size()) && d_byUsernameFiltered[_byUsernameSel]->disabledChecked;) {
++_byUsernameSel;
if (_filteredSelected < 0 && !_byUsernameFiltered.isEmpty()) {
for (_searchedSelected = 0; (_searchedSelected < _byUsernameFiltered.size()) && d_byUsernameFiltered[_searchedSelected]->disabledChecked;) {
++_searchedSelected;
}
if (_byUsernameSel == _byUsernameFiltered.size()) _byUsernameSel = -1;
if (_searchedSelected == _byUsernameFiltered.size()) _searchedSelected = -1;
}
_mouseSel = false;
_mouseSelection = false;
refresh();
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) {
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 (newRow) {
*i = newRow;
@ -1575,18 +1677,21 @@ void ContactsBox::Inner::onDialogRowReplaced(Dialogs::Row *oldRow, Dialogs::Row
++i;
}
}
if (_filteredSel >= _filtered.size()) {
_filteredSel = -1;
if (_filteredSelected >= _filtered.size()) {
_filteredSelected = -1;
}
if (_filteredPressed >= _filtered.size()) {
_filteredPressed = -1;
}
} else {
if (_sel == oldRow) {
_sel = newRow;
if (_selected == oldRow) {
_selected = newRow;
}
if (_pressed == oldRow) {
setPressed(newRow);
}
}
_mouseSel = false;
int cnt = (_filter.isEmpty() ? _contacts->size() : _filtered.size());
int newh = cnt ? (cnt * _rowHeight) : st::noContactsHeight;
resize(width(), newh);
refresh();
}
void ContactsBox::Inner::peopleReceived(const QString &query, const QVector<MTPPeer> &people) {
@ -1707,6 +1812,10 @@ ContactsBox::Inner::~Inner() {
for (auto contactData : base::take(_contactsData)) {
delete contactData;
}
clearSearchedContactDatas();
for (auto data : base::take(d_byUsername)) {
delete data;
}
if (_bot) {
if (auto &info = _bot->botInfo) {
info->startGroupToken = QString();
@ -1722,127 +1831,127 @@ void ContactsBox::Inner::resizeEvent(QResizeEvent *e) {
void ContactsBox::Inner::selectSkip(int32 dir) {
_time = unixtime();
_mouseSel = false;
_mouseSelection = false;
if (_filter.isEmpty()) {
int cur = 0;
if (_sel) {
for (auto i = _contacts->cbegin(); *i != _sel; ++i) {
if (_selected) {
for (auto i = _contacts->cbegin(); *i != _selected; ++i) {
++cur;
}
} else if (_byUsernameSel >= 0) {
cur = (_contacts->size() + _byUsernameSel);
} else if (_searchedSelected >= 0) {
cur = (_contacts->size() + _searchedSelected);
} else {
cur = -1;
}
cur += dir;
if (cur <= 0) {
_sel = (!_contacts->isEmpty()) ? *_contacts->cbegin() : nullptr;
_byUsernameSel = (_contacts->isEmpty() && !_byUsername.isEmpty()) ? 0 : -1;
_selected = (!_contacts->isEmpty()) ? *_contacts->cbegin() : nullptr;
_searchedSelected = (_contacts->isEmpty() && !_byUsername.isEmpty()) ? 0 : -1;
} else if (cur >= _contacts->size()) {
if (_byUsername.isEmpty()) {
_sel = _contacts->isEmpty() ? nullptr : *(_contacts->cend() - 1);
_byUsernameSel = -1;
_selected = _contacts->isEmpty() ? nullptr : *(_contacts->cend() - 1);
_searchedSelected = -1;
} else {
_sel = nullptr;
_byUsernameSel = cur - _contacts->size();
if (_byUsernameSel >= _byUsername.size()) _byUsernameSel = _byUsername.size() - 1;
_selected = nullptr;
_searchedSelected = cur - _contacts->size();
if (_searchedSelected >= _byUsername.size()) _searchedSelected = _byUsername.size() - 1;
}
} else {
for (auto i = _contacts->cbegin(); ; ++i) {
_sel = *i;
_selected = *i;
if (!cur) {
break;
} else {
--cur;
}
}
_byUsernameSel = -1;
_searchedSelected = -1;
}
if (dir > 0) {
for (auto i = _contacts->cfind(_sel), end = _contacts->cend(); i != end && contactData(*i)->disabledChecked; ++i) {
_sel = *i;
for (auto i = _contacts->cfind(_selected), end = _contacts->cend(); i != end && contactData(*i)->disabledChecked; ++i) {
_selected = *i;
}
if (_sel && contactData(_sel)->disabledChecked) {
_sel = nullptr;
if (_selected && contactData(_selected)->disabledChecked) {
_selected = nullptr;
}
if (!_sel) {
if (!_selected) {
if (!_byUsername.isEmpty()) {
if (_byUsernameSel < 0) _byUsernameSel = 0;
for (; _byUsernameSel < _byUsername.size() && d_byUsername[_byUsernameSel]->disabledChecked;) {
++_byUsernameSel;
if (_searchedSelected < 0) _searchedSelected = 0;
for (; _searchedSelected < _byUsername.size() && d_byUsername[_searchedSelected]->disabledChecked;) {
++_searchedSelected;
}
if (_byUsernameSel == _byUsername.size()) _byUsernameSel = -1;
if (_searchedSelected == _byUsername.size()) _searchedSelected = -1;
}
}
} else {
while (_byUsernameSel >= 0 && d_byUsername[_byUsernameSel]->disabledChecked) {
--_byUsernameSel;
while (_searchedSelected >= 0 && d_byUsername[_searchedSelected]->disabledChecked) {
--_searchedSelected;
}
if (_byUsernameSel < 0) {
if (_searchedSelected < 0) {
if (!_contacts->isEmpty()) {
if (!_sel) _sel = *(_contacts->cend() - 1);
if (_sel) {
for (auto i = _contacts->cfind(_sel), b = _contacts->cbegin(); i != b && contactData(*i)->disabledChecked; --i) {
_sel = *i;
if (!_selected) _selected = *(_contacts->cend() - 1);
if (_selected) {
for (auto i = _contacts->cfind(_selected), b = _contacts->cbegin(); i != b && contactData(*i)->disabledChecked; --i) {
_selected = *i;
}
if (contactData(_sel)->disabledChecked) {
_sel = nullptr;
if (contactData(_selected)->disabledChecked) {
_selected = nullptr;
}
}
}
}
}
if (_sel) {
emit mustScrollTo(_aboutHeight + _sel->pos() * _rowHeight, _aboutHeight + (_sel->pos() + 1) * _rowHeight);
} else if (_byUsernameSel >= 0) {
emit mustScrollTo(_aboutHeight + (_contacts->size() + _byUsernameSel) * _rowHeight + st::searchedBarHeight, _aboutHeight + (_contacts->size() + _byUsernameSel + 1) * _rowHeight + st::searchedBarHeight);
if (_selected) {
emit mustScrollTo(_aboutHeight + _selected->pos() * _rowHeight, _aboutHeight + (_selected->pos() + 1) * _rowHeight);
} else if (_searchedSelected >= 0) {
emit mustScrollTo(_aboutHeight + (_contacts->size() + _searchedSelected) * _rowHeight + st::searchedBarHeight, _aboutHeight + (_contacts->size() + _searchedSelected + 1) * _rowHeight + st::searchedBarHeight);
}
} 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;
if (cur <= 0) {
_filteredSel = _filtered.isEmpty() ? -1 : 0;
_byUsernameSel = (_filtered.isEmpty() && !_byUsernameFiltered.isEmpty()) ? 0 : -1;
_filteredSelected = _filtered.isEmpty() ? -1 : 0;
_searchedSelected = (_filtered.isEmpty() && !_byUsernameFiltered.isEmpty()) ? 0 : -1;
} else if (cur >= _filtered.size()) {
_filteredSel = -1;
_byUsernameSel = cur - _filtered.size();
if (_byUsernameSel >= _byUsernameFiltered.size()) _byUsernameSel = _byUsernameFiltered.size() - 1;
_filteredSelected = -1;
_searchedSelected = cur - _filtered.size();
if (_searchedSelected >= _byUsernameFiltered.size()) _searchedSelected = _byUsernameFiltered.size() - 1;
} else {
_filteredSel = cur;
_byUsernameSel = -1;
_filteredSelected = cur;
_searchedSelected = -1;
}
if (dir > 0) {
while (_filteredSel >= 0 && _filteredSel < _filtered.size() && contactData(_filtered[_filteredSel])->disabledChecked) {
++_filteredSel;
while (_filteredSelected >= 0 && _filteredSelected < _filtered.size() && contactData(_filtered[_filteredSelected])->disabledChecked) {
++_filteredSelected;
}
if (_filteredSel < 0 || _filteredSel >= _filtered.size()) {
_filteredSel = -1;
if (_filteredSelected < 0 || _filteredSelected >= _filtered.size()) {
_filteredSelected = -1;
if (!_byUsernameFiltered.isEmpty()) {
if (_byUsernameSel < 0) _byUsernameSel = 0;
for (; _byUsernameSel < _byUsernameFiltered.size() && d_byUsernameFiltered[_byUsernameSel]->disabledChecked;) {
++_byUsernameSel;
if (_searchedSelected < 0) _searchedSelected = 0;
for (; _searchedSelected < _byUsernameFiltered.size() && d_byUsernameFiltered[_searchedSelected]->disabledChecked;) {
++_searchedSelected;
}
if (_byUsernameSel == _byUsernameFiltered.size()) _byUsernameSel = -1;
if (_searchedSelected == _byUsernameFiltered.size()) _searchedSelected = -1;
}
}
} else {
while (_byUsernameSel >= 0 && d_byUsernameFiltered[_byUsernameSel]->disabledChecked) {
--_byUsernameSel;
while (_searchedSelected >= 0 && d_byUsernameFiltered[_searchedSelected]->disabledChecked) {
--_searchedSelected;
}
if (_byUsernameSel < 0) {
if (_searchedSelected < 0) {
if (!_filtered.isEmpty()) {
if (_filteredSel < 0) _filteredSel = _filtered.size() - 1;
for (; _filteredSel >= 0 && contactData(_filtered[_filteredSel])->disabledChecked;) {
--_filteredSel;
if (_filteredSelected < 0) _filteredSelected = _filtered.size() - 1;
for (; _filteredSelected >= 0 && contactData(_filtered[_filteredSelected])->disabledChecked;) {
--_filteredSelected;
}
}
}
}
if (_filteredSel >= 0) {
emit mustScrollTo(_filteredSel * _rowHeight, (_filteredSel + 1) * _rowHeight);
} else if (_byUsernameSel >= 0) {
if (_filteredSelected >= 0) {
emit mustScrollTo(_filteredSelected * _rowHeight, (_filteredSelected + 1) * _rowHeight);
} else if (_searchedSelected >= 0) {
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();

View file

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

View file

@ -44,8 +44,8 @@ void MembersAddButton::paintEvent(QPaintEvent *e) {
Painter p(this);
auto ms = getms();
auto over = (_state & StateOver);
auto down = (_state & StateDown);
auto over = isOver();
auto down = isDown();
((over || down) ? _st.iconBelowOver : _st.iconBelow).paint(p, _st.iconPosition, width());
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() {
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();
if (_terminateBox) _terminateBox->deleteLater();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -59,20 +59,21 @@ void paintRowDate(Painter &p, const QDateTime &date, QRect &rectForName, bool ac
}
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) {
QRect fullRect(0, 0, w, st::dialogsRowHeight);
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, fullWidth, st::dialogsRowHeight);
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;
PeerData *userpicPeer = (history->peer->migrateTo() ? history->peer->migrateTo() : history->peer);
userpicPeer->paintUserpicLeft(p, st::dialogsPhotoSize, st::dialogsPadding.x(), st::dialogsPadding.y(), w);
auto userpicPeer = (history->peer->migrateTo() ? history->peer->migrateTo() : history->peer);
userpicPeer->paintUserpicLeft(p, st::dialogsPhotoSize, st::dialogsPadding.x(), st::dialogsPadding.y(), fullWidth);
int32 nameleft = st::dialogsPadding.x() + st::dialogsPhotoSize + st::dialogsPhotoPadding;
int32 namewidth = w - nameleft - st::dialogsPadding.x();
auto nameleft = st::dialogsPadding.x() + st::dialogsPhotoSize + st::dialogsPhotoPadding;
auto namewidth = fullWidth - nameleft - st::dialogsPadding.x();
QRect rectForName(nameleft, st::dialogsPadding.y() + st::dialogsNameTop, namewidth, st::msgNameFont->height);
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);
}
@ -82,7 +83,7 @@ void paintRow(Painter &p, History *history, HistoryItem *item, Data::Draft *draf
p.setFont(st::dialogsTextFont);
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()) {
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));
@ -96,7 +97,7 @@ void paintRow(Painter &p, History *history, HistoryItem *item, Data::Draft *draf
} else if (!item) {
auto &color = active ? st::dialogsTextFgServiceActive : (selected ? st::dialogsTextFgServiceOver : st::dialogsTextFgService);
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.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) {
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()) {
auto icon = &(active ? st::dialogsVerifiedIconActive : (selected ? st::dialogsVerifiedIconOver : st::dialogsVerifiedIcon));
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));
@ -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);
}
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 item = history->lastMsg;
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) {
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 texttop = st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip;
if (unreadCount) {
auto counter = QString::number(unreadCount);
auto mutedCounter = history->mute();
int unreadRight = w - st::dialogsPadding.x();
int unreadTop = texttop + st::dialogsTextFont->ascent - st::dialogsUnreadFont->ascent - (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2;
int unreadWidth = 0;
auto unreadRight = fullWidth - st::dialogsPadding.x();
auto unreadTop = texttop + st::dialogsTextFont->ascent - st::dialogsUnreadFont->ascent - (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2;
auto unreadWidth = 0;
UnreadBadgeStyle st;
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;
}
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);
}
});
}
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 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;
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);
}
void paintImportantSwitch(Painter &p, Mode current, int w, bool selected, bool onlyBackground) {
p.fillRect(0, 0, w, st::dialogsImportantBarHeight, selected ? st::dialogsBgOver : st::dialogsBg);
void paintImportantSwitch(Painter &p, Mode current, int fullWidth, bool selected, bool onlyBackground) {
p.fillRect(0, 0, fullWidth, st::dialogsImportantBarHeight, selected ? st::dialogsBgOver : st::dialogsBg);
if (onlyBackground) {
return;
}
@ -323,7 +324,7 @@ void paintImportantSwitch(Painter &p, Mode current, int w, bool selected, bool o
if (mutedHidden) {
if (int32 unread = App::histories().unreadMutedCount()) {
int unreadRight = w - st::dialogsPadding.x();
int unreadRight = fullWidth - st::dialogsPadding.x();
UnreadBadgeStyle st;
st.muted = true;
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 {
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 FakeRow *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 fullWidth, bool active, bool selected, bool onlyBackground, TimeMs ms);
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 {
UnreadBadgeInDialogs = 0,

View file

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

View file

@ -22,9 +22,37 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "dialogs/dialogs_row.h"
#include "styles/style_dialogs.h"
#include "ui/effects/ripple_animation.h"
#include "mainwidget.h"
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) {
}

View file

@ -25,13 +25,32 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
class History;
class HistoryItem;
namespace Ui {
class RippleAnimation;
} // namespace Ui
namespace Dialogs {
namespace Layout {
class RowPainter;
} // 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 Row {
class Row : public RippleRow {
public:
Row(History *history, Row *prev, Row *next, int pos)
: _history(history)
@ -57,7 +76,7 @@ private:
};
class FakeRow {
class FakeRow : public RippleRow {
public:
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 addSavedPeersAfter(const QDateTime &date);
void addAllSavedPeers();
bool searchReceived(const QVector<MTPMessage> &messages, DialogsSearchRequestType type, int32 fullCount);
void peopleReceived(const QString &query, const QVector<MTPPeer> &people);
bool searchReceived(const QVector<MTPMessage> &result, DialogsSearchRequestType type, int32 fullCount);
void peerSearchReceived(const QString &query, const QVector<MTPPeer> &result);
void showMore(int32 pixels);
void activate();
void contactsReceived(const QVector<MTPContact> &contacts);
void contactsReceived(const QVector<MTPContact> &result);
void selectSkip(int32 direction);
void selectSkipPage(int32 pixels, int32 direction);
void createDialog(History *history);
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 dragLeft();
void loadPeerPhotos(int32 yFrom);
void clearFilter();
void refresh(bool toTop = false);
@ -88,21 +87,14 @@ public:
void peerAfter(const PeerData *inPeer, MsgId inMsg, PeerData *&outPeer, MsgId &outMsg) const;
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 *dialogsList();
FilteredDialogs &filteredList();
PeopleResults &peopleList();
SearchResults &searchList();
int32 lastSearchDate() const;
PeerData *lastSearchPeer() const;
MsgId lastSearchId() const;
MsgId lastSearchMigratedId() const;
void setMouseSel(bool msel, bool toTop = false);
void setMouseSelection(bool mouseSelection, bool toTop = false);
enum State {
DefaultState = 0,
@ -120,7 +112,10 @@ public:
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_historyMuteUpdated(History *history);
@ -128,7 +123,6 @@ public:
~DialogsInner();
public slots:
void onUpdateSelected(bool force = false);
void onParentGeometryChanged();
void onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars);
void onPeerPhotoChanged(PeerData *peer);
@ -149,67 +143,109 @@ protected:
void paintRegion(Painter &p, const QRegion &region, bool paintingOther) override;
void mouseMoveEvent(QMouseEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
void enterEvent(QEvent *e) override;
void leaveEvent(QEvent *e) override;
void contextMenuEvent(QContextMenuEvent *e) override;
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);
enum class UpdateRowSection {
Default = 0x01,
Filtered = 0x02,
GlobalSearch = 0x04,
PeerSearch = 0x04,
MessageSearch = 0x08,
All = 0x0F,
};
Q_DECLARE_FLAGS(UpdateRowSections, UpdateRowSection);
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 filteredOffset() const;
int peopleOffset() const;
int peerSearchOffset() const;
int searchedOffset() const;
void peopleResultPaint(PeerData *peer, Painter &p, int32 w, bool active, bool selected, bool onlyBackground) const;
void searchInPeerPaint(Painter &p, int32 w, bool onlyBackground) const;
void paintDialog(QPainter &p, Dialogs::Row *dialog);
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 clearSearchResults(bool clearPeople = true);
void clearSearchResults(bool clearPeerSearchResults = true);
void updateSelectedRow(PeerData *peer = 0);
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 importantDialogs;
DialogsList _dialogs;
DialogsList _dialogsImportant;
DialogsList contactsNoDialogs;
DialogsList contacts;
DialogsList _contactsNoDialogs;
DialogsList _contacts;
bool _importantSwitchSel = false;
Dialogs::Row *_sel = nullptr;
bool _selByMouse = false;
bool _mouseSelection = false;
Qt::MouseButton _pressButton = Qt::LeftButton;
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;
QStringList _hashtagResults;
int _hashtagSel = -1;
HashtagResults _hashtagResults;
int _hashtagSelected = -1;
int _hashtagPressed = -1;
bool _hashtagDeleteSelected = false;
bool _hashtagDeletePressed = false;
FilteredDialogs _filterResults;
int _filteredSel = -1;
int _filteredSelected = -1;
int _filteredPressed = -1;
QString _peerSearchQuery;
PeerSearchResults _peerSearchResults;
int _peerSearchSelected = -1;
int _peerSearchPressed = -1;
SearchResults _searchResults;
int _searchedCount = 0;
int _searchedMigratedCount = 0;
int _searchedSel = -1;
QString _peopleQuery;
PeopleResults _peopleResults;
int _peopleSel = -1;
int _searchedSelected = -1;
int _searchedPressed = -1;
int _lastSearchDate = 0;
PeerData *_lastSearchPeer = nullptr;
@ -218,21 +254,17 @@ private:
State _state = DefaultState;
QPoint lastMousePos;
void paintDialog(QPainter &p, Dialogs::Row *dialog);
ChildWidget<Ui::LinkButton> _addContactLnk;
ChildWidget<Ui::IconButton> _cancelSearchInPeer;
bool _overDelete = false;
PeerData *_searchInPeer = nullptr;
PeerData *_searchInMigrated = nullptr;
PeerData *_menuPeer = nullptr;
Ui::PopupMenu *_menu = nullptr;
base::lambda<void()> _loadMoreCallback;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(DialogsInner::UpdateRowSections);
@ -243,27 +275,14 @@ class DialogsWidget : public TWidget, public RPCSender, private base::Subscriber
public:
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 resizeEvent(QResizeEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
void paintEvent(QPaintEvent *e) override;
void searchInPeer(PeerData *peer);
void loadDialogs();
void createDialog(History *history);
void dlgUpdated(Dialogs::Mode list, Dialogs::Row *row);
void dlgUpdated(History *row, MsgId msgId);
void dlgUpdated(PeerData *peer, MsgId msgId);
void dialogsToUp();
@ -272,7 +291,6 @@ public:
}
void showAnimated(Window::SlideDirection direction, const Window::SectionSlideParams &params);
void showFast();
void step_show(float64 ms, bool timer);
void destroyData();
@ -321,7 +339,22 @@ private slots:
void onCheckUpdateStatus();
#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:
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 showMainMenu();
void updateLockUnlockVisibility();
@ -354,31 +387,34 @@ private:
ChildWidget<DialogsInner> _inner;
ChildWidget<Ui::FlatButton> _updateTelegram = { nullptr };
Animation _a_show;
FloatAnimation _a_show;
Window::SlideDirection _showDirection;
QPixmap _cacheUnder, _cacheOver;
anim::ivalue a_coordUnder, a_coordOver;
anim::fvalue a_progress;
PeerData *_searchInPeer = nullptr;
PeerData *_searchInMigrated = nullptr;
QTimer _searchTimer;
QString _searchQuery, _peopleQuery;
QString _peerSearchQuery;
bool _peerSearchFull = false;
mtpRequestId _peerSearchRequest = 0;
QString _searchQuery;
bool _searchFull = false;
bool _searchFullMigrated = false;
bool _peopleFull = false;
mtpRequestId _searchRequest, _peopleRequest;
mtpRequestId _searchRequest = 0;
typedef QMap<QString, MTPmessages_Messages> SearchCache;
using SearchCache = QMap<QString, MTPmessages_Messages>;
SearchCache _searchCache;
typedef QMap<mtpRequestId, QString> SearchQueries;
using SearchQueries = QMap<mtpRequestId, QString>;
SearchQueries _searchQueries;
typedef QMap<QString, MTPcontacts_Found> PeopleCache;
PeopleCache _peopleCache;
using PeerSearchCache = QMap<QString, MTPcontacts_Found>;
PeerSearchCache _peerSearchCache;
typedef QMap<mtpRequestId, QString> PeopleQueries;
PeopleQueries _peopleQueries;
using PeerSearchQueries = QMap<mtpRequestId, QString>;
PeerSearchQueries _peerSearchQueries;
};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2329,7 +2329,7 @@ bool HistoryService::updateDependentText() {
history()->textCachedFor = 0;
}
if (App::main()) {
App::main()->dlgUpdated(history(), id);
App::main()->dlgUpdated(history()->peer, id);
}
App::historyUpdateDependent(this);
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/inner_dropdown.h"
#include "ui/widgets/dropdown_menu.h"
#include "ui/effects/ripple_animation.h"
#include "inline_bots/inline_bot_result.h"
#include "data/data_drafts.h"
#include "history/history_service_layout.h"
@ -2971,7 +2972,7 @@ void SilentToggle::mouseMoveEvent(QMouseEvent *e) {
void SilentToggle::setChecked(bool checked) {
if (_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)
, _silent(this)
, _field(this, st::historyComposeField, lang(lng_message_ph))
, _a_record(animation(this, &HistoryWidget::step_record))
, _a_recording(animation(this, &HistoryWidget::step_recording))
, a_recordCancelActive(0, 0)
, _recordCancelWidth(st::historyRecordFont->width(lang(lng_record_cancel)))
, _kbScroll(this, st::botKbScroll)
, _keyboard(this)
@ -3061,7 +3060,6 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
, _attachDragDocument(this)
, _attachDragPhoto(this)
, _fileLoader(this, FileLoaderQueueStopTimeout)
, _a_show(animation(this, &HistoryWidget::step_show))
, _topShadow(this, st::shadowColor) {
setAcceptDrops(true);
@ -3318,10 +3316,8 @@ void HistoryWidget::onTextChange() {
_send->show();
}
updateMouseTracking();
_a_record.stop();
_a_recordActive.finish();
_inRecord = _inField = false;
a_recordDown = anim::fvalue(0, 0);
a_recordCancelActive = anim::fvalue(0, 0);
}
}
if (updateCmdStartShown()) {
@ -4197,7 +4193,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
historyLoaded();
}
App::main()->dlgUpdated(wasHistory, wasMsgId);
App::main()->dlgUpdated(wasHistory ? wasHistory->peer : nullptr, wasMsgId);
emit historyShown(_history, _showAtMsgId);
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()));
App::main()->dlgUpdated(wasHistory, wasMsgId);
App::main()->dlgUpdated(wasHistory ? wasHistory->peer : nullptr, wasMsgId);
emit historyShown(_history, _showAtMsgId);
App::main()->historyPeerChanged().notify(_peer, true);
@ -4650,7 +4646,7 @@ void HistoryWidget::updateControlsVisibility() {
} else {
_send->show();
}
_a_record.stop();
_a_recordActive.finish();
_inRecord = _inField = false;
}
if (_recording) {
@ -5441,9 +5437,9 @@ PeerData *HistoryWidget::peer() const {
void HistoryWidget::setMsgId(MsgId showAtMsgId) { // sometimes _showAtMsgId is set directly
if (_showAtMsgId != showAtMsgId) {
MsgId wasMsgId = _showAtMsgId;
auto wasMsgId = _showAtMsgId;
_showAtMsgId = showAtMsgId;
App::main()->dlgUpdated(_history, wasMsgId);
App::main()->dlgUpdated(_history ? _history->peer : nullptr, wasMsgId);
emit historyShown(_history, _showAtMsgId);
}
}
@ -5453,7 +5449,9 @@ MsgId HistoryWidget::msgId() const {
}
void HistoryWidget::showAnimated(Window::SlideDirection direction, const Window::SectionSlideParams &params) {
if (App::app()) App::app()->mtpPause();
_showDirection = direction;
_a_show.finish();
_cacheUnder = params.oldContentCache;
show();
@ -5487,47 +5485,26 @@ void HistoryWidget::showAnimated(Window::SlideDirection direction, const Window:
_pinnedBar->cancel->hide();
}
int delta = st::slideShift;
if (direction == Window::SlideDirection::FromLeft) {
a_progress = anim::fvalue(1, 0);
if (_showDirection == Window::SlideDirection::FromLeft) {
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();
activate();
}
void HistoryWidget::step_show(float64 ms, bool timer) {
float64 dt = ms / st::slideDuration;
if (dt >= 1) {
_a_show.stop();
void HistoryWidget::animationCallback() {
update();
App::main()->topBar()->update();
if (!_a_show.animating()) {
_topShadow->setVisible(_peer ? true : false);
_historyToEnd->finishAnimation();
a_coordUnder.finish();
a_coordOver.finish();
a_progress.finish();
_cacheUnder = _cacheOver = QPixmap();
App::main()->topBar()->stopAnim();
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;
_a_show.stop();
_a_show.finish();
_topShadow->setVisible(_peer ? true : false);
_historyToEnd->finishAnimation();
}
void HistoryWidget::step_record(float64 ms, bool timer) {
float64 dt = ms / st::historyComposeButton.duration;
if (dt >= 1 || !_send->isHidden() || (_inlineBotCancel && !_inlineBotCancel->isHidden()) || isBotStart() || isBlocked()) {
_a_record.stop();
a_recordDown.finish();
a_recordCancelActive.finish();
void HistoryWidget::recordActiveCallback() {
if (_recording) {
updateField();
} else {
a_recordDown.update(dt, anim::linear);
a_recordCancelActive.update(dt, anim::linear);
update(_send->geometry());
}
if (timer) {
if (_recording) {
updateField();
} else {
update(_send->geometry());
}
if (!_send->isHidden() || (_inlineBotCancel && !_inlineBotCancel->isHidden()) || isBotStart() || isBlocked()) {
_a_recordActive.finish();
}
}
@ -5665,9 +5634,7 @@ void HistoryWidget::mouseMoveEvent(QMouseEvent *e) {
}
if (inField != _inField && _recording) {
_inField = inField;
a_recordDown.start(_inField ? 1 : 0);
a_recordCancelActive.start(_inField ? 0. : 1.);
_a_record.start();
_a_recordActive.start([this] { recordActiveCallback(); }, _inField ? 0. : 1., _inField ? 1. : 0., st::historyComposeButton.duration);
}
_inReplyEdit = inReplyEdit;
_inPinnedMsg = inPinnedMsg;
@ -5698,7 +5665,7 @@ void HistoryWidget::mouseReleaseEvent(QMouseEvent *e) {
void HistoryWidget::stopRecording(bool send) {
emit audioCapture()->stop(send);
a_recordingLevel = anim::ivalue(0, 0);
a_recordingLevel = anim::value();
_a_recording.stop();
_recording = false;
@ -5712,9 +5679,13 @@ void HistoryWidget::stopRecording(bool send) {
updateField();
a_recordDown.start(0);
a_recordCancelActive = anim::fvalue(0., 0.);
_a_record.start();
if (_inField) {
_a_recordActive.start([this] { recordActiveCallback(); }, 1., 0., st::historyComposeButton.duration);
}
if (_recordRipple) {
_recordRipple->lastStop();
}
}
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) {
if (_a_show.animating()) {
int retina = cIntRetinaFactor();
if (a_coordOver.current() > 0) {
p.drawPixmap(QRect(0, 0, a_coordOver.current(), st::topBarHeight), _cacheUnder, QRect(-a_coordUnder.current() * retina, 0, a_coordOver.current() * retina, st::topBarHeight * retina));
p.setOpacity(a_progress.current());
p.fillRect(0, 0, a_coordOver.current(), st::topBarHeight, st::slideFadeOutBg);
auto progress = _a_show.current(1.);
auto retina = cIntRetinaFactor();
auto fromLeft = (_showDirection == Window::SlideDirection::FromLeft);
auto coordUnder = fromLeft ? anim::interpolate(-st::slideShift, 0, progress) : anim::interpolate(0, -st::slideShift, progress);
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.drawPixmap(QRect(a_coordOver.current(), 0, _cacheOver.width() / retina, st::topBarHeight), _cacheOver, QRect(0, 0, _cacheOver.width(), st::topBarHeight * retina));
p.setOpacity(a_progress.current());
st::slideShadow.fill(p, QRect(a_coordOver.current() - st::slideShadow.width(), 0, st::slideShadow.width(), st::topBarHeight));
p.drawPixmap(QRect(coordOver, 0, _cacheOver.width() / retina, st::topBarHeight), _cacheOver, QRect(0, 0, _cacheOver.width(), st::topBarHeight * retina));
p.setOpacity(shadow);
st::slideShadow.fill(p, QRect(coordOver - st::slideShadow.width(), 0, st::slideShadow.width(), st::topBarHeight));
return false;
}
@ -6481,14 +6457,14 @@ void HistoryWidget::onCheckFieldAutocomplete() {
void HistoryWidget::updateFieldPlaceholder() {
if (_editMsgId) {
_field->setPlaceholder(lang(lng_edit_message_text));
_send->setIcon(&st::historyEditSaveIcon, &st::historyEditSaveIconOver);
_send->setIconOverride(&st::historyEditSaveIcon, &st::historyEditSaveIconOver);
} else {
if (_inlineBot && _inlineBot != Ui::LookingUpInlineBot) {
_field->setPlaceholder(_inlineBot->botInfo->inlinePlaceholder.mid(1), _inlineBot->username.size() + 2);
} else {
_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();
a_recordDown.start(1);
_a_record.start();
_a_recordActive.start([this] { recordActiveCallback(); }, 0., 1., st::historyComposeButton.duration);
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) {
Ui::showPeerHistory(_peer, _editMsgId ? _editMsgId : replyToId());
} else if (_inPinnedMsg) {
@ -8582,7 +8563,7 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
Text *from = 0, *text = 0;
bool serviceColor = false, hasForward = readyToForward();
ImagePtr preview;
HistoryItem *drawMsgText = (_editMsgId || _replyToId) ? _replyEditMsg : _kbReplyTo;
auto drawMsgText = (_editMsgId || _replyToId) ? _replyEditMsg : _kbReplyTo;
if (_editMsgId || _replyToId || (!hasForward && _kbReplyTo)) {
if (!_editMsgId && drawMsgText && drawMsgText->author()->nameVersion > _replyToNameVersion) {
updateReplyToName();
@ -8718,10 +8699,16 @@ void HistoryWidget::paintEditHeader(Painter &p, const QRect &rect, int left, int
}
}
void HistoryWidget::drawRecordButton(Painter &p) {
auto down = a_recordDown.current();
auto fastIcon = [down, this] {
if (down == 1.) {
void HistoryWidget::drawRecordButton(Painter &p, float64 recordActive, TimeMs ms) {
if (_recordRipple) {
auto rippleColor = anim::color(st::historyAttachEmoji.ripple.color, st::historyRecordVoiceRippleBgActive, recordActive);
_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;
} else if (_inRecord) {
return &st::historyRecordVoiceOver;
@ -8729,19 +8716,19 @@ void HistoryWidget::drawRecordButton(Painter &p) {
return &st::historyRecordVoice;
};
fastIcon()->paintInCenter(p, _send->geometry());
if (down > 0. && down < 1.) {
p.setOpacity(down);
if (recordActive > 0. && recordActive < 1.) {
p.setOpacity(recordActive);
st::historyRecordVoiceActive.paintInCenter(p, _send->geometry());
p.setOpacity(1.);
}
}
void HistoryWidget::drawRecording(Painter &p) {
void HistoryWidget::drawRecording(Painter &p, float64 recordActive) {
p.setPen(Qt::NoPen);
p.setBrush(st::historyRecordSignalColor);
float64 delta = qMin(float64(a_recordingLevel.current()) / 0x4000, 1.);
int32 d = 2 * qRound(st::historyRecordSignalMin + (delta * (st::historyRecordSignalMax - st::historyRecordSignalMin)));
auto delta = qMin(a_recordingLevel.current() / 0x4000, 1.);
auto d = 2 * qRound(st::historyRecordSignalMin + (delta * (st::historyRecordSignalMax - st::historyRecordSignalMin)));
{
PainterHighQualityEnabler hq(p);
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 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));
}
@ -8809,18 +8796,24 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
}
bool hasTopBar = !App::main()->topBar()->isHidden();
auto ms = getms();
auto progress = _a_show.current(ms, 1.);
if (_a_show.animating()) {
int retina = cIntRetinaFactor();
int inCacheTop = hasTopBar ? st::topBarHeight : 0;
if (a_coordOver.current() > 0) {
p.drawPixmap(QRect(0, 0, a_coordOver.current(), height()), _cacheUnder, QRect(-a_coordUnder.current() * retina, inCacheTop * retina, a_coordOver.current() * retina, height() * retina));
p.setOpacity(a_progress.current());
p.fillRect(0, 0, a_coordOver.current(), height(), st::slideFadeOutBg);
auto retina = cIntRetinaFactor();
auto inCacheTop = hasTopBar ? st::topBarHeight : 0;
auto fromLeft = (_showDirection == Window::SlideDirection::FromLeft);
auto coordUnder = fromLeft ? anim::interpolate(-st::slideShift, 0, progress) : anim::interpolate(0, -st::slideShift, progress);
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, 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.drawPixmap(QRect(a_coordOver.current(), 0, _cacheOver.width() / retina, height()), _cacheOver, QRect(0, inCacheTop * retina, _cacheOver.width(), height() * retina));
p.setOpacity(a_progress.current());
st::slideShadow.fill(p, QRect(a_coordOver.current() - st::slideShadow.width(), 0, st::slideShadow.width(), height()));
p.drawPixmap(QRect(coordOver, 0, _cacheOver.width() / retina, height()), _cacheOver, QRect(0, inCacheTop * retina, _cacheOver.width(), height() * retina));
p.setOpacity(shadow);
st::slideShadow.fill(p, QRect(coordOver - st::slideShadow.width(), 0, st::slideShadow.width(), height()));
return;
}
@ -8854,8 +8847,9 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
if (!_field->isHidden() || _recording) {
drawField(p, r);
if (_send->isHidden() && (!_inlineBotCancel || _inlineBotCancel->isHidden())) {
drawRecordButton(p);
if (_recording) drawRecording(p);
auto recordActive = _a_recordActive.current(ms, _inField ? 1. : 0.);
drawRecordButton(p, recordActive, ms);
if (_recording) drawRecording(p, recordActive);
}
}
if (_pinnedBar && !_pinnedBar->cancel->isHidden()) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -234,7 +234,7 @@ void CoverWidget::updateLabelPositions() {
}
void CoverWidget::updateRepeatTrackIcon() {
_repeatTrack->setIcon(instance()->repeatEnabled() ? nullptr : &st::mediaPlayerRepeatInactiveIcon);
_repeatTrack->setIconOverride(instance()->repeatEnabled() ? nullptr : &st::mediaPlayerRepeatInactiveIcon);
}
void CoverWidget::handleSongUpdate(const UpdatedEvent &e) {
@ -338,9 +338,9 @@ void CoverWidget::handlePlaylistUpdate() {
createPrevNextButtons();
auto previousEnabled = (index > 0);
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);
_nextTrack->setIcon(nextEnabled ? nullptr : &st::mediaPlayerPanelNextDisabledIcon);
_nextTrack->setIconOverride(nextEnabled ? nullptr : &st::mediaPlayerPanelNextDisabledIcon);
_nextTrack->setCursor(nextEnabled ? style::cur_pointer : style::cur_default);
}
}
@ -386,7 +386,7 @@ void CoverWidget::updateVolumeToggleIcon() {
}
return nullptr;
};
_volumeToggle->setIcon(icon());
_volumeToggle->setIconOverride(icon());
}
} // 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/shadow.h"
#include "ui/widgets/buttons.h"
#include "ui/effects/ripple_animation.h"
#include "media/media_audio.h"
#include "media/view/media_clip_playback.h"
#include "media/player/media_player_button.h"
@ -38,7 +39,7 @@ namespace Player {
using State = PlayButtonLayout::State;
class Widget::PlayButton : public Ui::AbstractButton {
class Widget::PlayButton : public Ui::RippleButton {
public:
PlayButton(QWidget *parent);
@ -52,12 +53,15 @@ public:
protected:
void paintEvent(QPaintEvent *e) override;
QImage prepareRippleMask() const override;
QPoint prepareRippleStartPosition() const override;
private:
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(); }) {
resize(st::mediaPlayerButtonSize);
setCursor(style::cur_pointer);
@ -66,10 +70,20 @@ Widget::PlayButton::PlayButton(QWidget *parent) : Ui::AbstractButton(parent)
void Widget::PlayButton::paintEvent(QPaintEvent *e) {
Painter p(this);
paintRipple(p, st::mediaPlayerButton.rippleAreaPosition.x(), st::mediaPlayerButton.rippleAreaPosition.y(), getms());
p.translate(st::mediaPlayerButtonPosition.x(), st::mediaPlayerButtonPosition.y());
_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)
, _nameLabel(this, st::mediaPlayerName)
, _timeLabel(this, st::mediaPlayerTime)
@ -146,7 +160,7 @@ void Widget::updateVolumeToggleIcon() {
}
return nullptr;
};
_volumeToggle->setIcon(icon());
_volumeToggle->setIconOverride(icon());
}
void Widget::setCloseCallback(CloseCallback &&callback) {
@ -223,7 +237,7 @@ void Widget::paintEvent(QPaintEvent *e) {
Painter p(this);
auto fill = e->rect().intersected(QRect(0, 0, width(), st::mediaPlayerHeight));
if (!fill.isEmpty()) {
p.fillRect(fill, st::windowBg);
p.fillRect(fill, st::mediaPlayerBg);
}
}
@ -290,7 +304,9 @@ void Widget::updateLabelsGeometry() {
}
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) {
@ -393,9 +409,11 @@ void Widget::handlePlaylistUpdate() {
createPrevNextButtons();
auto previousEnabled = (index > 0);
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);
_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);
}
}

View file

@ -118,7 +118,7 @@ void Controller::updatePlayPauseResumeState(const AudioPlaybackState &playbackSt
_showPause = showPause;
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) {
_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(fromFullScreenPressed()));

View file

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

View file

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

View file

@ -358,7 +358,7 @@ namespace {
return false;
}
bool _paused = false;
int PauseLevel = 0;
} // namespace
@ -379,7 +379,20 @@ Session *getSession(ShiftedDcId shiftedDcId) {
}
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) {
@ -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) {
if (_started) return;
internal::setDC(dc);

View file

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

View file

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

View file

@ -1878,7 +1878,6 @@ OverviewInner::~OverviewInner() {
OverviewWidget::OverviewWidget(QWidget *parent, PeerData *peer, MediaOverviewType type) : TWidget(parent)
, _scroll(this, st::settingsScroll, false)
, _inner(this, _scroll, peer, type)
, _a_show(animation(this, &OverviewWidget::step_show))
, _topShadow(this, st::shadowColor) {
_scroll->setOwnedWidget(_inner);
_scroll->move(0, 0);
@ -1936,18 +1935,23 @@ void OverviewWidget::paintEvent(QPaintEvent *e) {
if (App::wnd() && App::wnd()->contentOverlapped(this, e)) return;
Painter p(this);
auto progress = _a_show.current(getms(), 1.);
if (_a_show.animating()) {
int retina = cIntRetinaFactor();
int inCacheTop = st::topBarHeight;
if (a_coordOver.current() > 0) {
p.drawPixmap(QRect(0, 0, a_coordOver.current(), height()), _cacheUnder, QRect(-a_coordUnder.current() * retina, inCacheTop * retina, a_coordOver.current() * retina, height() * retina));
p.setOpacity(a_progress.current());
p.fillRect(0, 0, a_coordOver.current(), height(), st::slideFadeOutBg);
auto retina = cIntRetinaFactor();
auto inCacheTop = st::topBarHeight;
auto fromLeft = (_showDirection == Window::SlideDirection::FromLeft);
auto coordUnder = fromLeft ? anim::interpolate(-st::slideShift, 0, progress) : anim::interpolate(0, -st::slideShift, progress);
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, 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.drawPixmap(QRect(a_coordOver.current(), 0, _cacheOver.width() / retina, height()), _cacheOver, QRect(0, inCacheTop * retina, _cacheOver.width(), height() * retina));
p.setOpacity(a_progress.current());
st::slideShadow.fill(p, QRect(a_coordOver.current() - st::slideShadow.width(), 0, st::slideShadow.width(), height()));
p.drawPixmap(QRect(coordOver, 0, _cacheOver.width() / retina, height()), _cacheOver, QRect(0, inCacheTop * retina, _cacheOver.width(), height() * retina));
p.setOpacity(shadow);
st::slideShadow.fill(p, QRect(coordOver - st::slideShadow.width(), 0, st::slideShadow.width(), height()));
return;
}
@ -1972,16 +1976,21 @@ void OverviewWidget::scrollReset() {
bool OverviewWidget::paintTopBar(Painter &p, int decreaseWidth) {
if (_a_show.animating()) {
int retina = cIntRetinaFactor();
if (a_coordOver.current() > 0) {
p.drawPixmap(QRect(0, 0, a_coordOver.current(), st::topBarHeight), _cacheUnder, QRect(-a_coordUnder.current() * retina, 0, a_coordOver.current() * retina, st::topBarHeight * retina));
p.setOpacity(a_progress.current());
p.fillRect(0, 0, a_coordOver.current(), st::topBarHeight, st::slideFadeOutBg);
auto progress = _a_show.current(1.);
auto retina = cIntRetinaFactor();
auto fromLeft = (_showDirection == Window::SlideDirection::FromLeft);
auto coordUnder = fromLeft ? anim::interpolate(-st::slideShift, 0, progress) : anim::interpolate(0, -st::slideShift, progress);
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.drawPixmap(QRect(a_coordOver.current(), 0, _cacheOver.width() / retina, st::topBarHeight), _cacheOver, QRect(0, 0, _cacheOver.width(), st::topBarHeight * retina));
p.setOpacity(a_progress.current());
st::slideShadow.fill(p, QRect(a_coordOver.current() - st::slideShadow.width(), 0, st::slideShadow.width(), st::topBarHeight));
p.drawPixmap(QRect(coordOver, 0, _cacheOver.width() / retina, st::topBarHeight), _cacheOver, QRect(0, 0, _cacheOver.width(), st::topBarHeight * retina));
p.setOpacity(shadow);
st::slideShadow.fill(p, QRect(coordOver - st::slideShadow.width(), 0, st::slideShadow.width(), st::topBarHeight));
return false;
}
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();
_inner->activate();
doneShow();
if (App::app()) App::app()->mtpUnpause();
}
void OverviewWidget::setLastScrollTop(int lastScrollTop) {
@ -2090,10 +2097,11 @@ void OverviewWidget::setLastScrollTop(int lastScrollTop) {
}
void OverviewWidget::showAnimated(Window::SlideDirection direction, const Window::SectionSlideParams &params) {
if (App::app()) App::app()->mtpPause();
_showDirection = direction;
resizeEvent(0);
_a_show.finish();
_cacheUnder = params.oldContentCache;
show();
_topShadow->setVisible(params.withTopBarShadow ? false : true);
@ -2104,47 +2112,26 @@ void OverviewWidget::showAnimated(Window::SlideDirection direction, const Window
_scrollSetAfterShow = _scroll->scrollTop();
_scroll->hide();
int delta = st::slideShift;
if (direction == Window::SlideDirection::FromLeft) {
a_progress = anim::fvalue(1, 0);
if (_showDirection == Window::SlideDirection::FromLeft) {
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();
activate();
}
void OverviewWidget::step_show(float64 ms, bool timer) {
float64 dt = ms / st::slideDuration;
if (dt >= 1) {
_a_show.stop();
void OverviewWidget::animationCallback() {
update();
App::main()->topBar()->update();
if (!_a_show.animating()) {
_topShadow->show();
a_coordUnder.finish();
a_coordOver.finish();
a_progress.finish();
_cacheUnder = _cacheOver = QPixmap();
App::main()->topBar()->stopAnim();
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 showAnimated(Window::SlideDirection direction, const Window::SectionSlideParams &params);
void step_show(float64 ms, bool timer);
void doneShow();
@ -355,16 +354,17 @@ public slots:
void onClearSelected();
private:
void animationCallback();
ChildWidget<Ui::ScrollArea> _scroll;
ChildWidget<OverviewInner> _inner;
bool _noDropResizeIndex = false;
QString _header;
Animation _a_show;
FloatAnimation _a_show;
Window::SlideDirection _showDirection;
QPixmap _cacheUnder, _cacheOver;
anim::ivalue a_coordUnder, a_coordOver;
anim::fvalue a_progress;
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"
PasscodeWidget::PasscodeWidget(QWidget *parent) : TWidget(parent)
, _a_show(animation(this, &PasscodeWidget::step_show))
, _passcode(this, st::passcodeInput)
, _submit(this, lang(lng_passcode_submit), st::passcodeSubmit)
, _logout(this, lang(lng_passcode_logout)) {
@ -104,52 +103,30 @@ void PasscodeWidget::onChanged() {
}
}
void PasscodeWidget::animShow(const QPixmap &bgAnimCache, bool back) {
if (App::app()) App::app()->mtpPause();
void PasscodeWidget::showAnimated(const QPixmap &bgAnimCache, bool back) {
_showBack = back;
(_showBack ? _cacheOver : _cacheUnder) = bgAnimCache;
(back ? _cacheOver : _cacheUnder) = bgAnimCache;
_a_show.stop();
_a_show.finish();
showAll();
(back ? _cacheUnder : _cacheOver) = myGrab(this);
(_showBack ? _cacheUnder : _cacheOver) = myGrab(this);
hideAll();
a_coordUnder = back ? anim::ivalue(-st::slideShift, 0) : anim::ivalue(0, -st::slideShift);
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();
_a_show.start([this] { animationCallback(); }, 0., 1., st::slideDuration, Window::SlideAnimation::transition());
show();
}
void PasscodeWidget::step_show(float64 ms, bool timer) {
float64 dt = ms / st::slideDuration;
if (dt >= 1) {
_a_show.stop();
a_coordUnder.finish();
a_coordOver.finish();
a_shadow.finish();
_cacheUnder = _cacheOver = QPixmap();
void PasscodeWidget::animationCallback() {
update();
if (!_a_show.animating()) {
showAll();
if (App::wnd()) App::wnd()->setInnerFocus();
if (App::app()) App::app()->mtpUnpause();
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() {
_a_show.stop();
_cacheUnder = _cacheOver = QPixmap();
}
}
void PasscodeWidget::showAll() {
@ -173,16 +150,20 @@ void PasscodeWidget::paintEvent(QPaintEvent *e) {
p.setClipRect(e->rect());
}
auto progress = _a_show.current(getms(), 1.);
if (_a_show.animating()) {
if (a_coordOver.current() > 0) {
p.drawPixmap(QRect(0, 0, a_coordOver.current(), height()), _cacheUnder, QRect(-a_coordUnder.current() * cRetinaFactor(), 0, a_coordOver.current() * cRetinaFactor(), height() * cRetinaFactor()));
p.setOpacity(a_shadow.current());
p.fillRect(0, 0, a_coordOver.current(), height(), st::slideFadeOutBg);
auto coordUnder = _showBack ? anim::interpolate(-st::slideShift, 0, progress) : anim::interpolate(0, -st::slideShift, progress);
auto coordOver = _showBack ? anim::interpolate(0, width(), progress) : anim::interpolate(width(), 0, progress);
auto shadow = _showBack ? (1. - progress) : progress;
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.drawPixmap(a_coordOver.current(), 0, _cacheOver);
p.setOpacity(a_shadow.current());
st::slideShadow.fill(p, QRect(a_coordOver.current() - st::slideShadow.width(), 0, st::slideShadow.width(), height()));
p.drawPixmap(coordOver, 0, _cacheOver);
p.setOpacity(shadow);
st::slideShadow.fill(p, QRect(coordOver - st::slideShadow.width(), 0, st::slideShadow.width(), height()));
} else {
p.fillRect(rect(), st::windowBg);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -21,11 +21,17 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "stdafx.h"
#include "profile/profile_block_peer_list.h"
#include "ui/effects/ripple_animation.h"
#include "styles/style_profile.h"
#include "styles/style_widgets.h"
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)
: BlockWidget(parent, peer, title)
, _removeText(removeText)
@ -54,38 +60,39 @@ void PeerListWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) {
}
void PeerListWidget::paintContents(Painter &p) {
int left = getListLeft();
int top = getListTop();
int memberRowWidth = width() - left;
accumulate_min(memberRowWidth, st::profileBlockWideWidthMax);
auto ms = getms();
auto left = getListLeft();
auto top = getListTop();
auto memberRowWidth = rowWidth();
int from = floorclamp(_visibleTop - top, st::profileMemberHeight, 0, _items.size());
int to = ceilclamp(_visibleBottom - top, st::profileMemberHeight, 0, _items.size());
for (int i = from; i < to; ++i) {
int y = top + i * st::profileMemberHeight;
bool selected = (i == _selected);
bool selectedRemove = selected && _selectedRemove;
if (_pressed >= 0) {
if (_pressed != _selected) {
selected = selectedRemove = false;
} else if (!_pressedRemove) {
_selectedRemove = false;
}
auto from = floorclamp(_visibleTop - top, st::profileMemberHeight, 0, _items.size());
auto to = ceilclamp(_visibleBottom - top, st::profileMemberHeight, 0, _items.size());
for (auto i = from; i < to; ++i) {
auto y = top + i * st::profileMemberHeight;
auto selected = (_pressed >= 0) ? (i == _pressed) : (i == _selected);
auto selectedRemove = selected && _selectedRemove;
if (_pressed >= 0 && !_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) {
_updateItemCallback(item);
}
int memberRowWidth = width() - x;
accumulate_min(memberRowWidth, st::profileBlockWideWidthMax);
auto memberRowWidth = rowWidth();
if (selected) {
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();
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;
_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) {
_mousePosition = e->globalPos();
updateSelection();
auto pressed = _pressed;
auto pressedRemove = _pressedRemove;
_pressed = -1;
_pressedRemove = false;
if (pressed >= 0 && pressed < _items.size() && pressed == _selected && pressedRemove == _selectedRemove) {
if (auto &callback = (pressedRemove ? _removedCallback : _selectedCallback)) {
callback(_items[pressed]->peer);
repaintRow(_pressed);
auto pressed = base::take(_pressed, -1);
auto pressedRemove = base::take(_pressedRemove);
if (pressed >= 0 && pressed < _items.size()) {
if (auto &ripple = _items[pressed]->ripple) {
ripple->lastStop();
}
if (pressed == _selected && pressedRemove == _selectedRemove) {
if (auto &callback = (pressedRemove ? _removedCallback : _selectedCallback)) {
callback(_items[pressed]->peer);
}
}
}
setCursor(_selectedRemove ? style::cur_pointer : style::cur_default);
@ -166,15 +190,14 @@ void PeerListWidget::leaveEvent(QEvent *e) {
}
void PeerListWidget::updateSelection() {
int selected = -1;
bool selectedKick = false;
auto selected = -1;
auto selectedKick = false;
auto mouse = mapFromGlobal(_mousePosition);
if (rtl()) mouse.setX(width() - mouse.x());
int left = getListLeft();
int top = getListTop();
int memberRowWidth = width() - left;
accumulate_min(memberRowWidth, st::profileBlockWideWidthMax);
auto left = getListLeft();
auto top = getListTop();
auto memberRowWidth = rowWidth();
if (mouse.x() >= left && mouse.x() < left + memberRowWidth && mouse.y() >= top) {
selected = (mouse.y() - top) / st::profileMemberHeight;
if (selected >= _items.size()) {
@ -214,9 +237,13 @@ void PeerListWidget::setSelected(int selected, bool selectedRemove) {
}
void PeerListWidget::repaintSelectedRow() {
if (_selected >= 0) {
int left = getListLeft();
rtlupdate(left, getListTop() + _selected * st::profileMemberHeight, width() - left, st::profileMemberHeight);
repaintRow(_selected);
}
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;
}
int PeerListWidget::rowWidth() const {
return qMin(width() - getListLeft(), st::profileBlockWideWidthMax);
}
void PeerListWidget::preloadPhotos() {
int top = getListTop();
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"
namespace Ui {
class RippleAnimation;
} // namespace Ui
namespace Notify {
struct PeerUpdate;
} // namespace Notify
@ -35,14 +39,16 @@ public:
void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
struct Item {
explicit Item(PeerData *peer) : peer(peer) {
}
explicit Item(PeerData *peer);
~Item();
PeerData * const peer;
Text name;
QString statusText;
bool statusHasOnlineColor = false;
bool hasAdminStar = false;
bool hasRemoveLink = false;
std_::unique_ptr<Ui::RippleAnimation> ripple;
};
virtual int getListTop() const {
return contentTop();
@ -111,9 +117,11 @@ private:
void updateSelection();
void setSelected(int selected, bool selectedRemove);
void repaintSelectedRow();
void repaintRow(int index);
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(PeerData*)> _selectedCallback;

View file

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

View file

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

View file

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

View file

@ -190,4 +190,10 @@ hashtagClose: IconButton {
icon: simpleCloseIcon;
iconOver: simpleCloseIconOver;
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 {
void AbstractButton::leaveEvent(QEvent *e) {
if (_state & StateDown) return;
if (_state & StateFlag::Down) return;
setOver(false, StateChangeSource::ByHover);
return TWidget::leaveEvent(e);
}
void AbstractButton::enterEvent(QEvent *e) {
auto over = rect().marginsRemoved(getMargins()).contains(mapFromGlobal(QCursor::pos()));
setOver(over, StateChangeSource::ByHover);
checkIfOver(mapFromGlobal(QCursor::pos()));
return TWidget::enterEvent(e);
}
@ -40,12 +39,18 @@ void AbstractButton::setAcceptBoth(bool acceptBoth) {
_acceptBoth = acceptBoth;
}
void AbstractButton::checkIfOver(QPoint localPos) {
auto over = rect().marginsRemoved(getMargins()).contains(localPos);
setOver(over, StateChangeSource::ByHover);
}
void AbstractButton::mousePressEvent(QMouseEvent *e) {
checkIfOver(e->pos());
if (_acceptBoth || (e->buttons() & Qt::LeftButton)) {
if ((_state & StateOver) && !(_state & StateDown)) {
int oldState = _state;
_state |= StateDown;
onStateChanged(oldState, StateChangeSource::ByPress);
if ((_state & StateFlag::Over) && !(_state & StateFlag::Down)) {
auto was = _state;
_state |= StateFlag::Down;
onStateChanged(was, StateChangeSource::ByPress);
e->accept();
}
@ -61,11 +66,11 @@ void AbstractButton::mouseMoveEvent(QMouseEvent *e) {
}
void AbstractButton::mouseReleaseEvent(QMouseEvent *e) {
if (_state & StateDown) {
int oldState = _state;
_state &= ~StateDown;
onStateChanged(oldState, StateChangeSource::ByPress);
if (oldState & StateOver) {
if (_state & StateFlag::Down) {
auto was = _state;
_state &= ~State(StateFlag::Down);
onStateChanged(was, StateChangeSource::ByPress);
if (was & StateFlag::Over) {
_modifiers = e->modifiers();
if (_clickedCallback) {
_clickedCallback();
@ -73,43 +78,39 @@ void AbstractButton::mouseReleaseEvent(QMouseEvent *e) {
emit clicked();
}
} else {
leaveEvent(e);
setOver(false, StateChangeSource::ByHover);
}
}
}
void AbstractButton::setOver(bool over, StateChangeSource source) {
setCursor(over ? style::cur_pointer : style::cur_default);
if (over && !(_state & StateOver)) {
int oldState = _state;
_state |= StateOver;
onStateChanged(oldState, source);
} else if (!over && (_state & StateOver)) {
int oldState = _state;
_state &= ~StateOver;
onStateChanged(oldState, source);
if (over && !(_state & StateFlag::Over)) {
auto was = _state;
_state |= StateFlag::Over;
onStateChanged(was, source);
} else if (!over && (_state & StateFlag::Over)) {
auto was = _state;
_state &= ~State(StateFlag::Over);
onStateChanged(was, source);
}
}
void AbstractButton::setDisabled(bool disabled) {
int oldState = _state;
if (disabled && !(_state & StateDisabled)) {
_state |= StateDisabled;
onStateChanged(oldState, StateChangeSource::ByUser);
} else if (!disabled && (_state & StateDisabled)) {
_state &= ~StateDisabled;
onStateChanged(oldState, StateChangeSource::ByUser);
auto was = _state;
if (disabled && !(_state & StateFlag::Disabled)) {
_state |= StateFlag::Disabled;
onStateChanged(was, StateChangeSource::ByUser);
} else if (!disabled && (_state & StateFlag::Disabled)) {
_state &= ~State(StateFlag::Disabled);
onStateChanged(was, StateChangeSource::ByUser);
}
}
void AbstractButton::clearState() {
int oldState = _state;
_state = StateNone;
onStateChanged(oldState, StateChangeSource::ByUser);
}
int AbstractButton::getState() const {
return _state;
auto was = _state;
_state = StateFlag::None;
onStateChanged(was, StateChangeSource::ByUser);
}
} // namespace Ui

View file

@ -28,34 +28,24 @@ class AbstractButton : public TWidget {
Q_OBJECT
public:
enum class StateChangeSource {
ByUser = 0x00,
ByPress = 0x01,
ByHover = 0x02,
};
AbstractButton(QWidget *parent) : TWidget(parent) {
setMouseTracking(true);
}
enum {
StateNone = 0x00,
StateOver = 0x01,
StateDown = 0x02,
StateDisabled = 0x04,
};
Qt::KeyboardModifiers clickModifiers() const {
return _modifiers;
}
void clearState();
int getState() const;
void setDisabled(bool disabled = true);
void setOver(bool over, StateChangeSource source = StateChangeSource::ByUser);
bool disabled() const {
return (_state & StateDisabled);
void clearState();
bool isOver() const {
return _state & StateFlag::Over;
}
bool isDown() const {
return _state & StateFlag::Down;
}
bool isDisabled() {
return _state & StateFlag::Disabled;
}
void setAcceptBoth(bool acceptBoth = true);
@ -75,15 +65,41 @@ signals:
void clicked();
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;
int _state = StateNone;
enum class StateChangeSource {
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;
Qt::KeyboardModifiers _modifiers;
base::lambda<void()> _clickedCallback;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractButton::State);
} // 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 stopManager();
void registerClipManager(Media::Clip::Manager *manager);
@ -639,7 +589,9 @@ public:
template <typename Lambda>
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->value.start(to);
@ -674,6 +626,7 @@ private:
if (dt >= 1) {
value.finish();
a_animation.stop();
pause.release();
} else {
value.update(dt, transition);
}
@ -685,13 +638,13 @@ private:
Callback updateCallback;
float64 duration = 0.;
anim::transition transition = anim::linear;
MTP::PauseHolder pause;
};
mutable std_::unique_ptr<Data> _data;
};
using FloatAnimation = SimpleAnimation<anim::fvalue>;
using IntAnimation = SimpleAnimation<anim::ivalue>;
using FloatAnimation = SimpleAnimation<anim::value>;
class AnimationManager : public QObject {
Q_OBJECT

View file

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

View file

@ -55,7 +55,7 @@ private:
bool _shown = false;
anim::fvalue a_arrowOpacity;
anim::value a_arrowOpacity;
Animation _a_arrowOver;
FloatAnimation _a_show;
@ -64,7 +64,7 @@ private:
};
class EmojiButton : public AbstractButton {
class EmojiButton : public RippleButton {
public:
EmojiButton(QWidget *parent, const style::IconButton &st);
@ -72,7 +72,10 @@ public:
protected:
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:
const style::IconButton &_st;

View file

@ -54,7 +54,7 @@ void NewAvatarButton::paintEvent(QPaintEvent *e) {
}
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);
p.drawEllipse(rect());

View file

@ -25,6 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "application.h"
#include "ui/widgets/scroll_area.h"
#include "ui/widgets/multi_select.h"
#include "ui/effects/ripple_animation.h"
#include "boxes/contactsbox.h"
#include "countries.h"
#include "styles/style_boxes.h"
@ -283,6 +284,7 @@ void CountrySelectBox::Inner::paintEvent(QPaintEvent *e) {
QRect r(e->rect());
p.setClipRect(r);
auto ms = getms();
int l = countriesNow->size();
if (l) {
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 to = ceilclamp(r.y() + r.height() - st::countriesSkip, _rowHeight, 0, l);
for (int32 i = from; i < to; ++i) {
bool sel = (i == _sel);
int32 y = st::countriesSkip + i * _rowHeight;
auto selected = (i == (_pressed >= 0 ? _pressed : _selected));
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;
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.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);
}
} else {
@ -328,26 +336,49 @@ void CountrySelectBox::Inner::enterEvent(QEvent *e) {
}
void CountrySelectBox::Inner::leaveEvent(QEvent *e) {
_mouseSel = false;
_mouseSelection = false;
setMouseTracking(false);
if (_sel >= 0) {
if (_selected >= 0) {
updateSelectedRow();
_sel = -1;
_selected = -1;
}
}
void CountrySelectBox::Inner::mouseMoveEvent(QMouseEvent *e) {
_mouseSel = true;
_lastMousePos = e->globalPos();
updateSel();
_mouseSelection = true;
updateSelected(e->pos());
}
void CountrySelectBox::Inner::mousePressEvent(QMouseEvent *e) {
_mouseSel = true;
_lastMousePos = e->globalPos();
updateSel();
_mouseSelection = true;
updateSelected(e->pos());
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) {
chooseCountry();
if ((pressed >= 0) && pressed == _selected) {
chooseCountry();
}
}
}
@ -401,25 +432,25 @@ void CountrySelectBox::Inner::updateFilter(QString filter) {
countriesNow = &countriesFiltered;
}
refresh();
_sel = countriesNow->isEmpty() ? -1 : 0;
_selected = countriesNow->isEmpty() ? -1 : 0;
update();
}
}
void CountrySelectBox::Inner::selectSkip(int32 dir) {
_mouseSel = false;
_mouseSelection = false;
int cur = (_sel >= 0) ? _sel : -1;
int cur = (_selected >= 0) ? _selected : -1;
cur += dir;
if (cur <= 0) {
_sel = countriesNow->isEmpty() ? -1 : 0;
_selected = countriesNow->isEmpty() ? -1 : 0;
} else if (cur >= countriesNow->size()) {
_sel = -1;
_selected = -1;
} else {
_sel = cur;
_selected = cur;
}
if (_sel >= 0) {
emit mustScrollTo(st::countriesSkip + _sel * _rowHeight, st::countriesSkip + (_sel + 1) * _rowHeight);
if (_selected >= 0) {
emit mustScrollTo(st::countriesSkip + _selected * _rowHeight, st::countriesSkip + (_selected + 1) * _rowHeight);
}
update();
}
@ -433,12 +464,12 @@ void CountrySelectBox::Inner::selectSkipPage(int32 h, int32 dir) {
void CountrySelectBox::Inner::chooseCountry() {
QString result;
if (_filter.isEmpty()) {
if (_sel >= 0 && _sel < countriesAll.size()) {
result = countriesAll[_sel]->iso2;
if (_selected >= 0 && _selected < countriesAll.size()) {
result = countriesAll[_selected]->iso2;
}
} else {
if (_sel >= 0 && _sel < countriesFiltered.size()) {
result = countriesFiltered[_sel]->iso2;
if (_selected >= 0 && _selected < countriesFiltered.size()) {
result = countriesFiltered[_selected]->iso2;
}
}
emit countryChosen(result);
@ -448,22 +479,34 @@ void CountrySelectBox::Inner::refresh() {
resize(width(), countriesNow->length() ? (countriesNow->length() * _rowHeight + st::countriesSkip) : st::noContactsHeight);
}
void CountrySelectBox::Inner::updateSel() {
if (!_mouseSel) return;
void CountrySelectBox::Inner::updateSelected(QPoint localPos) {
if (!_mouseSelection) return;
QPoint p(mapFromGlobal(_lastMousePos));
bool in = parentWidget()->rect().contains(parentWidget()->mapFromGlobal(_lastMousePos));
auto in = parentWidget()->rect().contains(parentWidget()->mapFromGlobal(QCursor::pos()));
int32 newSel = (in && p.y() >= st::countriesSkip && p.y() < st::countriesSkip + countriesNow->size() * _rowHeight) ? ((p.y() - st::countriesSkip) / _rowHeight) : -1;
if (newSel != _sel) {
auto selected = (in && localPos.y() >= st::countriesSkip && localPos.y() < st::countriesSkip + countriesNow->size() * _rowHeight) ? ((localPos.y() - st::countriesSkip) / _rowHeight) : -1;
if (_selected != selected) {
updateSelectedRow();
_sel = newSel;
_selected = selected;
updateSelectedRow();
}
}
void CountrySelectBox::Inner::updateSelectedRow() {
if (_sel >= 0) {
update(0, st::countriesSkip + _sel * _rowHeight, width(), _rowHeight);
updateRow(_selected);
}
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();
~Inner();
signals:
void countryChosen(const QString &iso);
void mustScrollTo(int ymin, int ymax);
public slots:
void updateSel();
protected:
void paintEvent(QPaintEvent *e) override;
void enterEvent(QEvent *e) override;
void leaveEvent(QEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
private:
void updateSelected() {
updateSelected(mapFromGlobal(QCursor::pos()));
}
void updateSelected(QPoint localPos);
void updateSelectedRow();
void updateRow(int index);
void setPressed(int pressed);
int _rowHeight;
int _sel = 0;
int _selected = -1;
int _pressed = -1;
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 {
RadialAnimation::RadialAnimation(AnimationCallbacks &&callbacks)
: a_arcEnd(0, 0)
, a_arcStart(0, FullArcLength)
: a_arcStart(0, FullArcLength)
, _animation(std_::move(callbacks)) {
}
void RadialAnimation::start(float64 prg) {
_firstStart = _lastStart = _lastTime = getms();
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();
}
void RadialAnimation::update(float64 prg, bool finished, TimeMs ms) {
int32 iprg = qRound(qMax(prg, 0.0001) * AlmostFullArcLength);
if (iprg != a_arcEnd.to()) {
auto iprg = qRound(qMax(prg, 0.0001) * AlmostFullArcLength);
if (iprg != qRound(a_arcEnd.to())) {
a_arcEnd.start(iprg);
_lastStart = _lastTime;
}
_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.);
if (!finished) {
a_arcEnd.update(1. - (st::radialDuration / (st::radialDuration + dt)), anim::linear);
} else if (dt >= st::radialDuration) {
a_arcEnd.update(1, anim::linear);
a_arcEnd.update(1., anim::linear);
stop();
} else {
float64 r = dt / st::radialDuration;
auto r = dt / st::radialDuration;
a_arcEnd.update(r, anim::linear);
_opacity *= 1 - r;
}
float64 fromstart = fulldt / st::radialPeriod;
auto fromstart = fulldt / st::radialPeriod;
a_arcStart.update(fromstart - std::floor(fromstart), anim::linear);
}
void RadialAnimation::stop() {
_firstStart = _lastStart = _lastTime = 0;
a_arcEnd = anim::ivalue(0, 0);
a_arcEnd = anim::value();
_animation.stop();
}
@ -79,8 +79,8 @@ void RadialAnimation::draw(Painter &p, const QRect &inner, int32 thickness, cons
pen.setCapStyle(Qt::RoundCap);
p.setPen(pen);
int32 len = MinArcLength + a_arcEnd.current();
int32 from = QuarterArcLength - a_arcStart.current() - len;
auto len = MinArcLength + qRound(a_arcEnd.current());
auto from = QuarterArcLength - qRound(a_arcStart.current()) - len;
if (rtl()) {
from = QuarterArcLength - (from - QuarterArcLength) - len;
if (from < 0) from += FullArcLength;

View file

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

View file

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

View file

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

View file

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

View file

@ -40,8 +40,8 @@ int LinkButton::naturalWidth() const {
void LinkButton::paintEvent(QPaintEvent *e) {
Painter p(this);
auto &font = ((_state & StateOver) ? _st.overFont : _st.font);
auto &pen = ((_state & StateDown) ? _st.downColor : ((_state & StateOver) ? _st.overColor : _st.color));
auto &font = (isOver() ? _st.overFont : _st.font);
auto &pen = (isDown() ? _st.downColor : (isOver() ? _st.overColor : _st.color));
p.setFont(font);
p.setPen(pen);
if (_textWidth > width()) {
@ -58,7 +58,7 @@ void LinkButton::setText(const QString &text) {
update();
}
void LinkButton::onStateChanged(int oldState, StateChangeSource source) {
void LinkButton::onStateChanged(State was, StateChangeSource source) {
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();
auto wasDown = (oldState & StateDown);
auto down = (_state & StateDown);
auto wasDown = static_cast<bool>(was & StateFlag::Down);
auto down = isDown();
if (!_st.showDuration || down == wasDown || _forceRippled) {
return;
}
@ -187,10 +187,10 @@ void FlatButton::step_appearance(float64 ms, bool timer) {
if (timer) update();
}
void FlatButton::onStateChanged(int oldState, StateChangeSource source) {
RippleButton::onStateChanged(oldState, source);
void FlatButton::onStateChanged(State was, StateChangeSource 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) {
_a_appearance.stop();
a_over.finish();
@ -211,7 +211,7 @@ void FlatButton::paintEvent(QPaintEvent *e) {
auto ms = getms();
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.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);
auto over = (_state & StateOver);
auto down = (_state & StateDown);
auto over = isOver();
auto down = isDown();
if (over || down) {
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);
}
void IconButton::setIcon(const style::icon *icon, const style::icon *iconOver) {
_iconOverride = icon;
_iconOverrideOver = iconOver;
void IconButton::setIconOverride(const style::icon *iconOverride, const style::icon *iconOverOverride) {
_iconOverride = iconOverride;
_iconOverrideOver = iconOverOverride;
update();
}
void IconButton::setRippleColorOverride(const style::color *colorOverride) {
_rippleColorOverride = colorOverride;
}
void IconButton::paintEvent(QPaintEvent *e) {
Painter p(this);
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 overIconOpacity = (down || forceRippled()) ? 1. : _a_over.current(getms(), (_state & StateOver) ? 1. : 0.);
auto down = isDown();
auto overIconOpacity = (down || forceRippled()) ? 1. : _a_over.current(getms(), isOver() ? 1. : 0.);
auto overIcon = [this] {
if (_iconOverrideOver) {
return _iconOverrideOver;
@ -389,11 +393,12 @@ void IconButton::paintEvent(QPaintEvent *e) {
}
}
void IconButton::onStateChanged(int oldState, StateChangeSource source) {
RippleButton::onStateChanged(oldState, source);
void IconButton::onStateChanged(State was, StateChangeSource source) {
RippleButton::onStateChanged(was, source);
auto over = (_state & StateOver);
if (over != (oldState & StateOver)) {
auto over = isOver();
auto wasOver = static_cast<bool>(was & StateFlag::Over);
if (over != wasOver) {
if (_st.duration) {
auto from = over ? 0. : 1.;
auto to = over ? 1. : 0.;
@ -443,7 +448,8 @@ int LeftOutlineButton::resizeGetHeight(int newWidth) {
void LeftOutlineButton::paintEvent(QPaintEvent *e) {
Painter p(this);
bool over = (_state & StateOver), down = (_state & StateDown);
auto over = isOver();
auto down = isDown();
if (width() > _st.outlineWidth) {
p.fillRect(rtlrect(_st.outlineWidth, 0, width() - _st.outlineWidth, height(), width()), (over || down) ? _st.textBgOver : _st.textBg);
paintRipple(p, 0, 0, getms());
@ -492,7 +498,7 @@ void CrossButton::paintEvent(QPaintEvent *e) {
Painter p(this);
auto ms = getms();
auto over = (_state & StateOver);
auto over = isOver();
auto shown = _a_show.current(ms, _shown ? 1. : 0.);
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);
}
void CrossButton::onStateChanged(int oldState, StateChangeSource source) {
RippleButton::onStateChanged(oldState, source);
void CrossButton::onStateChanged(State was, StateChangeSource source) {
RippleButton::onStateChanged(was, source);
auto over = (_state & StateOver);
if (over != (oldState & StateOver)) {
auto over = isOver();
auto wasOver = static_cast<bool>(was & StateFlag::Over);
if (over != wasOver) {
update();
}
}

View file

@ -23,6 +23,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "ui/abstract_button.h"
#include "styles/style_widgets.h"
#include <memory>
namespace Ui {
class RippleAnimation;
@ -38,7 +40,7 @@ public:
protected:
void paintEvent(QPaintEvent *e) override;
void onStateChanged(int oldState, StateChangeSource source) override;
void onStateChanged(State was, StateChangeSource source) override;
private:
QString _text;
@ -66,7 +68,7 @@ public:
protected:
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 QPoint prepareRippleStartPosition() const;
@ -98,7 +100,7 @@ public:
protected:
void paintEvent(QPaintEvent *e) override;
void onStateChanged(int oldState, StateChangeSource source) override;
void onStateChanged(State was, StateChangeSource source) override;
private:
void setOpacity(float64 o);
@ -109,7 +111,7 @@ private:
const style::FlatButton &_st;
anim::fvalue a_over;
anim::value a_over;
Animation _a_appearance;
float64 _opacity = 1.;
@ -162,12 +164,13 @@ public:
IconButton(QWidget *parent, const style::IconButton &st);
// 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:
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;
@ -176,6 +179,7 @@ private:
const style::IconButton &_st;
const style::icon *_iconOverride = nullptr;
const style::icon *_iconOverrideOver = nullptr;
const style::color *_rippleColorOverride = nullptr;
FloatAnimation _a_over;
@ -215,7 +219,7 @@ public:
protected:
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;

View file

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

View file

@ -48,7 +48,7 @@ public:
protected:
void paintEvent(QPaintEvent *e) override;
void onStateChanged(int oldState, StateChangeSource source) override;
void onStateChanged(State was, StateChangeSource source) override;
int resizeGetHeight(int newWidth) override;
QImage prepareRippleMask() const override;
@ -95,7 +95,7 @@ public:
protected:
void paintEvent(QPaintEvent *e) override;
void onStateChanged(int oldState, StateChangeSource source) override;
void onStateChanged(State was, StateChangeSource source) override;
int resizeGetHeight(int newWidth) 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();
} else {
a_value = anim::fvalue(value, value);
a_value = anim::value(value, value);
_a_value.stop();
}
update();
@ -116,7 +116,7 @@ void ContinuousSlider::mouseReleaseEvent(QMouseEvent *e) {
if (_changeFinishedCallback) {
_changeFinishedCallback(_downValue);
}
a_value = anim::fvalue(_downValue, _downValue);
a_value = anim::value(_downValue, _downValue);
_a_value.stop();
update();
}

View file

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

View file

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

View file

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

View file

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

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