Using cute userpic checkbox Ui::RoundImageCheckbox in ContactsBox.

This commit is contained in:
John Preston 2016-10-20 16:41:46 +03:00
parent 763b347a8f
commit 2bd561821a
10 changed files with 323 additions and 207 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

After

Width:  |  Height:  |  Size: 84 KiB

View file

@ -1354,10 +1354,7 @@ contactsStatusFg: #999999;
contactsStatusFgOver: #7c99b2;
contactsStatusFgOnline: #3b8dcc;
contactsBgOver: overBg;
contactsBgActive: #6f9cbd;
contactsCheckPosition: point(8px, 16px);
contactsCheckIcon: sprite(187px, 61px, 18px, 14px);
contactsCheckActiveIcon: sprite(187px, 75px, 18px, 14px);
contactsNewItemHeight: 53px;
contactsNewItemIcon: sprite(307px, 248px, 22px, 16px);
contactsNewItemIconPosition: point(29px, 19px);

View file

@ -68,14 +68,9 @@ aboutRevokePublicLabel: flatLabel(labelDefFlat) {
textFg: windowTextFg;
}
localStorageBoxSkip: 10px;
shareRowsTop: 12px;
shareRowHeight: 108px;
sharePhotoTop: 6px;
sharePhotoCheckbox: RoundImageCheckbox {
imageRadius: 28px;
imageSmallRadius: 24px;
contactsPhotoCheckbox: RoundImageCheckbox {
imageRadius: 21px;
imageSmallRadius: 18px;
selectWidth: 2px;
selectFg: windowActiveBg;
selectDuration: 150;
@ -85,6 +80,18 @@ sharePhotoCheckbox: RoundImageCheckbox {
checkSmallRadius: 3px;
checkIcon: icon {{ "default_checkbox_check", windowBg, point(3px, 6px) }};
}
contactsPhotoDisabledCheckFg: #bbbbbb;
contactsNameCheckedFg: #2b88b8;
localStorageBoxSkip: 10px;
shareRowsTop: 12px;
shareRowHeight: 108px;
sharePhotoTop: 6px;
sharePhotoCheckbox: RoundImageCheckbox(contactsPhotoCheckbox) {
imageRadius: 28px;
imageSmallRadius: 24px;
}
shareNameFont: font(11px);
shareNameFg: windowTextFg;
shareNameActiveFg: btnYesColor;

View file

@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "dialogs/dialogs_indexed_list.h"
#include "styles/style_dialogs.h"
#include "styles/style_boxes.h"
#include "lang.h"
#include "boxes/addcontactbox.h"
#include "mainwidget.h"
@ -38,6 +39,14 @@ QString cantInviteError() {
return lng_cant_invite_not_contact(lt_more_info, textcmdLink(qsl("https://telegram.me/spambot"), lang(lng_cant_more_info)));
}
ContactsInner::ContactData::ContactData() : name(st::boxWideWidth) {
}
ContactsInner::ContactData::ContactData(PeerData *peer, Ui::RoundImageCheckbox::UpdateCallback &&updateCallback)
: checkbox(std_::make_unique<Ui::RoundImageCheckbox>(st::contactsPhotoCheckbox, std_::move(updateCallback), PaintUserpicCallback(peer)))
, name(st::boxWideWidth) {
}
ContactsInner::ContactsInner(CreatingGroupType creating) : TWidget()
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
, _newItemHeight(creating == CreatingGroupNone ? st::contactsNewItemHeight : 0)
@ -71,7 +80,7 @@ ContactsInner::ContactsInner(ChatData *chat, MembersFilter membersFilter) : TWid
, _chat(chat)
, _membersFilter(membersFilter)
, _allAdmins(this, lang(lng_chat_all_members_admins), !_chat->adminsEnabled(), st::contactsAdminCheckbox)
, _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.right() - st::contactsCheckPosition.x() * 2 - st::contactsCheckIcon.pxWidth())
, _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.right())
, _aboutAllAdmins(st::boxTextFont, lang(lng_chat_about_all_admins), _defaultOptions, _aboutWidth)
, _aboutAdmins(st::boxTextFont, lang(lng_chat_about_admins), _defaultOptions, _aboutWidth)
, _customList((membersFilter == MembersFilterRecent) ? std_::unique_ptr<Dialogs::IndexedList>() : std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Add))
@ -149,7 +158,7 @@ void ContactsInner::init() {
}
void ContactsInner::initList() {
if (!_chat || _membersFilter != MembersFilterAdmins) return;
if (!usingMultiSelect()) return;
QList<UserData*> admins, others;
admins.reserve(_chat->admins.size() + 1);
@ -370,41 +379,37 @@ ContactsInner::ContactData *ContactsInner::contactData(Dialogs::Row *row) {
PeerData *peer = row->history()->peer;
ContactsData::const_iterator i = _contactsData.constFind(peer);
if (i == _contactsData.cend()) {
_contactsData.insert(peer, data = new ContactData());
data = usingMultiSelect() ? new ContactData(peer, [this, peer] { updateRowWithPeer(peer); }) : new ContactData();
_contactsData.insert(peer, data);
if (peer->isUser()) {
if (_chat) {
if (_membersFilter == MembersFilterRecent) {
data->inchat = _chat->participants.contains(peer->asUser());
} else {
data->inchat = false;
data->disabledChecked = _chat->participants.contains(peer->asUser());
}
} else if (_creating == CreatingGroupGroup) {
data->inchat = (peerToUser(peer->id) == MTP::authedId());
data->disabledChecked = (peerToUser(peer->id) == MTP::authedId());
} else if (_channel) {
data->inchat = (peerToUser(peer->id) == MTP::authedId()) || _already.contains(peer->asUser());
} else {
data->inchat = false;
data->disabledChecked = (peerToUser(peer->id) == MTP::authedId()) || _already.contains(peer->asUser());
}
} else {
data->inchat = false;
}
data->onlineColor = false;
data->check = _checkedContacts.contains(peer);
if (usingMultiSelect() && _checkedContacts.contains(peer)) {
data->checkbox->setChecked(true, Ui::RoundImageCheckbox::SetStyle::Fast);
}
data->name.setText(st::contactsNameFont, peer->name, _textNameOptions);
if (peer->isUser()) {
data->online = App::onlineText(peer->asUser(), _time);
data->onlineColor = App::onlineColorUse(peer->asUser(), _time);
data->statusText = App::onlineText(peer->asUser(), _time);
data->statusHasOnlineColor = App::onlineColorUse(peer->asUser(), _time);
} else if (peer->isChat()) {
ChatData *chat = peer->asChat();
if (!chat->amIn()) {
data->online = lang(lng_chat_status_unaccessible);
data->statusText = lang(lng_chat_status_unaccessible);
} else {
data->online = lng_chat_status_members(lt_count, chat->count);
data->statusText = lng_chat_status_members(lt_count, chat->count);
}
} else if (peer->isMegagroup()) {
data->online = lang(lng_group_status);
data->statusText = lang(lng_group_status);
} else if (peer->isChannel()) {
data->online = lang(lng_channel_status);
data->statusText = lang(lng_channel_status);
}
} else {
data = i.value();
@ -417,49 +422,58 @@ ContactsInner::ContactData *ContactsInner::contactData(Dialogs::Row *row) {
void ContactsInner::paintDialog(Painter &p, PeerData *peer, ContactData *data, bool sel) {
UserData *user = peer->asUser();
bool inverse = data->inchat || data->check;
if (_chat && _membersFilter == MembersFilterAdmins) {
inverse = false;
if (_allAdmins.checked() || peer->id == peerFromUser(_chat->creator) || _saving) {
sel = false;
}
} else {
if (data->inchat || data->check || selectedCount() >= Global::MegagroupSizeMax()) {
if (data->disabledChecked || selectedCount() >= Global::MegagroupSizeMax()) {
sel = false;
}
}
p.fillRect(0, 0, width(), _rowHeight, inverse ? st::contactsBgActive : (sel ? st::contactsBgOver : st::white));
p.setPen(inverse ? st::white : st::black);
peer->paintUserpicLeft(p, st::contactsPhotoSize, st::contactsPadding.left(), st::contactsPadding.top(), width());
int32 namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left();
int32 iconw = (_chat || _creating != CreatingGroupNone) ? (st::contactsCheckPosition.x() * 2 + st::contactsCheckIcon.pxWidth()) : 0;
int32 namew = width() - namex - st::contactsPadding.right() - iconw;
auto paintDisabledCheck = data->disabledChecked;
if (_chat && _membersFilter == MembersFilterAdmins) {
if (peer->id == peerFromUser(_chat->creator) || _allAdmins.checked()) {
paintDisabledCheck = true;
}
}
auto checkedRatio = 0.;
p.fillRect(0, 0, width(), _rowHeight, sel ? st::contactsBgOver : st::white);
if (paintDisabledCheck) {
paintDisabledCheckUserpic(p, peer, st::contactsPadding.left(), st::contactsPadding.top(), width());
} else if (usingMultiSelect()) {
checkedRatio = data->checkbox->checkedAnimationRatio();
data->checkbox->paint(p, st::contactsPadding.left(), st::contactsPadding.top(), width());
} else {
peer->paintUserpicLeft(p, st::contactsPhotoSize, st::contactsPadding.left(), st::contactsPadding.top(), width());
}
int namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left();
int namew = width() - namex - st::contactsPadding.right();
if (peer->isVerified()) {
auto icon = &st::dialogsVerifiedIcon;
namew -= icon->width();
icon->paint(p, namex + qMin(data->name.maxWidth(), namew), st::contactsPadding.top() + st::contactsNameTop, width());
}
if (checkedRatio > 0) {
if (checkedRatio < 1) {
p.setPen(style::interpolate(st::black, st::contactsNameCheckedFg, checkedRatio));
} else {
p.setPen(st::contactsNameCheckedFg);
}
} else {
p.setPen(st::black);
}
data->name.drawLeftElided(p, namex, st::contactsPadding.top() + st::contactsNameTop, namew, width());
if (_chat || (_creating != CreatingGroupNone && (!_channel || _membersFilter != MembersFilterAdmins))) {
if (_chat && _membersFilter == MembersFilterAdmins) {
if (sel || data->check || peer->id == peerFromUser(_chat->creator) || _allAdmins.checked()) {
if (!data->check || peer->id == peerFromUser(_chat->creator) || _allAdmins.checked()) p.setOpacity(0.5);
p.drawSpriteRight(st::contactsPadding.right() + st::contactsCheckPosition.x(), st::contactsPadding.top() + st::contactsCheckPosition.y(), width(), st::contactsCheckIcon);
if (!data->check || peer->id == peerFromUser(_chat->creator) || _allAdmins.checked()) p.setOpacity(1);
}
} else if (sel || data->check) {
p.drawSpriteRight(st::contactsPadding.right() + st::contactsCheckPosition.x(), st::contactsPadding.top() + st::contactsCheckPosition.y(), width(), (data->check ? st::contactsCheckActiveIcon : st::contactsCheckIcon));
}
}
bool uname = (user || peer->isChannel()) && (data->online.at(0) == '@');
bool uname = (user || peer->isChannel()) && (data->statusText.at(0) == '@');
p.setFont(st::contactsStatusFont->f);
if (uname && !data->inchat && !data->check && !_lastQuery.isEmpty() && peer->userName().startsWith(_lastQuery, Qt::CaseInsensitive)) {
int32 availw = width() - namex - st::contactsPadding.right() - iconw;
if (uname && !_lastQuery.isEmpty() && peer->userName().startsWith(_lastQuery, Qt::CaseInsensitive)) {
int availw = width() - namex - st::contactsPadding.right();
QString first = '@' + peer->userName().mid(0, _lastQuery.size()), second = peer->userName().mid(_lastQuery.size());
int32 w = st::contactsStatusFont->width(first);
int w = st::contactsStatusFont->width(first);
if (w >= availw || second.isEmpty()) {
p.setPen(st::contactsStatusFgOnline);
p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width(), st::contactsStatusFont->elided(first, availw));
@ -472,24 +486,57 @@ void ContactsInner::paintDialog(Painter &p, PeerData *peer, ContactData *data, b
p.drawTextLeft(namex + w, st::contactsPadding.top() + st::contactsStatusTop, width() + w, second);
}
} else {
if (inverse) {
p.setPen(st::white);
} else if ((user && (uname || data->onlineColor)) || (peer->isChannel() && uname)) {
if ((user && (uname || data->statusHasOnlineColor)) || (peer->isChannel() && uname)) {
p.setPen(st::contactsStatusFgOnline);
} else {
p.setPen(sel ? st::contactsStatusFgOver : st::contactsStatusFg);
}
p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width(), data->online);
p.drawTextLeft(namex, st::contactsPadding.top() + st::contactsStatusTop, width(), data->statusText);
}
}
// Emulates Ui::RoundImageCheckbox::paint() in a checked state.
void ContactsInner::paintDisabledCheckUserpic(Painter &p, PeerData *peer, int x, int y, int outerWidth) const {
auto userpicRadius = st::contactsPhotoCheckbox.imageSmallRadius;
auto userpicShift = st::contactsPhotoCheckbox.imageRadius - userpicRadius;
auto userpicDiameter = st::contactsPhotoCheckbox.imageRadius * 2;
auto userpicLeft = x + userpicShift;
auto userpicTop = y + userpicShift;
auto userpicEllipse = rtlrect(x, y, userpicDiameter, userpicDiameter, outerWidth);
auto userpicBorderPen = st::contactsPhotoDisabledCheckFg->p;
userpicBorderPen.setWidth(st::contactsPhotoCheckbox.selectWidth);
auto iconDiameter = 2 * st::contactsPhotoCheckbox.checkRadius;
auto iconLeft = x + userpicDiameter + st::contactsPhotoCheckbox.selectWidth - iconDiameter;
auto iconTop = y + userpicDiameter + st::contactsPhotoCheckbox.selectWidth - iconDiameter;
auto iconEllipse = rtlrect(iconLeft, iconTop, iconDiameter, iconDiameter, outerWidth);
auto iconBorderPen = st::contactsPhotoCheckbox.checkBorder->p;
iconBorderPen.setWidth(st::contactsPhotoCheckbox.selectWidth);
peer->paintUserpicLeft(p, userpicRadius * 2, userpicLeft, userpicTop, width());
p.setRenderHint(QPainter::HighQualityAntialiasing, true);
p.setPen(userpicBorderPen);
p.setBrush(Qt::NoBrush);
p.drawEllipse(userpicEllipse);
p.setPen(iconBorderPen);
p.setBrush(st::contactsPhotoDisabledCheckFg);
p.drawEllipse(iconEllipse);
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
st::contactsPhotoCheckbox.checkIcon.paint(p, iconEllipse.topLeft(), outerWidth);
}
void ContactsInner::paintEvent(QPaintEvent *e) {
QRect r(e->rect());
Painter p(this);
p.setClipRect(r);
_time = unixtime();
p.fillRect(r, st::white->b);
p.fillRect(r, st::white);
int32 yFrom = r.y(), yTo = r.y() + r.height();
if (_filter.isEmpty()) {
@ -500,8 +547,7 @@ void ContactsInner::paintEvent(QPaintEvent *e) {
p.fillRect(0, _newItemHeight - st::contactsPadding.bottom() - st::lineWidth, width(), st::lineWidth, st::shadowColor);
p.setPen(st::black);
p.drawTextLeft(st::contactsPadding.left(), st::contactsNewItemTop, width(), lang(lng_chat_all_members_admins));
int32 iconw = st::contactsCheckPosition.x() * 2 + st::contactsCheckIcon.pxWidth();
int32 aboutw = width() - st::contactsPadding.left() - st::contactsPadding.right() - iconw;
int aboutw = width() - st::contactsPadding.left() - st::contactsPadding.right();
(_allAdmins.checked() ? _aboutAllAdmins : _aboutAdmins).draw(p, st::contactsPadding.left(), st::contactsNewItemHeight + st::contactsAboutTop, aboutw);
} else {
p.fillRect(0, 0, width(), st::contactsNewItemHeight, (_newItemSel ? st::contactsBgOver : st::white)->b);
@ -556,8 +602,7 @@ void ContactsInner::paintEvent(QPaintEvent *e) {
p.fillRect(0, _newItemHeight - st::contactsPadding.bottom() - st::lineWidth, width(), st::lineWidth, st::shadowColor);
p.setPen(st::black);
p.drawTextLeft(st::contactsPadding.left(), st::contactsNewItemTop, width(), lang(lng_chat_all_members_admins));
int32 iconw = st::contactsCheckPosition.x() * 2 + st::contactsCheckIcon.pxWidth();
int32 aboutw = width() - st::contactsPadding.left() - st::contactsPadding.right() - iconw;
int aboutw = width() - st::contactsPadding.left() - st::contactsPadding.right();
(_allAdmins.checked() ? _aboutAllAdmins : _aboutAdmins).draw(p, st::contactsPadding.left(), st::contactsNewItemHeight + st::contactsAboutTop, aboutw);
p.translate(0, _newItemHeight);
} else if (cContactsReceived() && !_searching) {
@ -618,27 +663,72 @@ void ContactsInner::enterEvent(QEvent *e) {
setMouseTracking(true);
}
void ContactsInner::updateSelectedRow() {
int ContactsInner::getSelectedRowTop() const {
if (_filter.isEmpty()) {
if (_newItemSel) {
update(0, 0, width(), st::contactsNewItemHeight);
}
if (_sel) {
update(0, _newItemHeight + _sel->pos() * _rowHeight, width(), _rowHeight);
}
if (_byUsernameSel >= 0) {
update(0, _newItemHeight + _contacts->size() * _rowHeight + st::searchedBarHeight + _byUsernameSel * _rowHeight, width(), _rowHeight);
return _newItemHeight + (_sel->pos() * _rowHeight);
} else if (_byUsernameSel >= 0) {
return _newItemHeight + (_contacts->size() * _rowHeight) + st::searchedBarHeight + (_byUsernameSel * _rowHeight);
}
} else {
if (_filteredSel >= 0) {
update(0, _filteredSel * _rowHeight, width(), _rowHeight);
return (_filteredSel * _rowHeight);
} else if (_byUsernameSel >= 0) {
return (_filtered.size() * _rowHeight + st::searchedBarHeight + _byUsernameSel * _rowHeight);
}
if (_byUsernameSel >= 0) {
update(0, _filtered.size() * _rowHeight + st::searchedBarHeight + _byUsernameSel * _rowHeight, width(), _rowHeight);
}
return -1;
}
void ContactsInner::updateSelectedRow() {
if (_filter.isEmpty() && _newItemSel) {
update(0, 0, width(), st::contactsNewItemHeight);
} else {
auto rowTop = getSelectedRowTop();
if (rowTop >= 0) {
updateRowWithTop(rowTop);
}
}
}
void ContactsInner::updateRowWithTop(int rowTop) {
update(0, rowTop, width(), _rowHeight);
}
int ContactsInner::getRowTopWithPeer(PeerData *peer) const {
if (_filter.isEmpty()) {
for (auto i = _contacts->cbegin(), end = _contacts->cend(); i != end; ++i) {
if ((*i)->history()->peer == peer) {
return _newItemHeight + ((*i)->pos() * _rowHeight);
}
}
for (auto i = 0, count = _byUsername.size(); i != count; ++i) {
if (_byUsername[i] == peer) {
return _newItemHeight + (_contacts->size() * _rowHeight) + st::searchedBarHeight + (i * _rowHeight);
}
}
} else {
for (auto i = 0, count = _filtered.size(); i != count; ++i) {
if (_filtered[i]->history()->peer == peer) {
return (i * _rowHeight);
}
}
for (auto i = 0, count = _byUsernameFiltered.size(); i != count; ++i) {
if (_byUsernameFiltered[i] == peer) {
return (_contacts->size() * _rowHeight) + st::searchedBarHeight + (i * _rowHeight);
}
}
}
return -1;
}
void ContactsInner::updateRowWithPeer(PeerData *peer) {
auto rowTop = getRowTopWithPeer(peer);
if (rowTop >= 0) {
updateRowWithTop(rowTop);
}
}
void ContactsInner::leaveEvent(QEvent *e) {
_mouseSel = false;
setMouseTracking(false);
@ -668,19 +758,19 @@ void ContactsInner::mousePressEvent(QMouseEvent *e) {
void ContactsInner::chooseParticipant() {
if (_saving) return;
bool addingAdmin = (_channel && _membersFilter == MembersFilterAdmins);
if (!addingAdmin && (_chat || _creating != CreatingGroupNone)) {
if (!addingAdmin && usingMultiSelect()) {
_time = unixtime();
if (_filter.isEmpty()) {
if (_byUsernameSel >= 0 && _byUsernameSel < _byUsername.size()) {
if (d_byUsername[_byUsernameSel]->inchat) return;
if (d_byUsername[_byUsernameSel]->disabledChecked) return;
changeCheckState(d_byUsername[_byUsernameSel], _byUsername[_byUsernameSel]);
} else {
if (!_sel || contactData(_sel)->inchat) return;
if (!_sel || contactData(_sel)->disabledChecked) return;
changeCheckState(_sel);
}
} else {
if (_byUsernameSel >= 0 && _byUsernameSel < _byUsernameFiltered.size()) {
if (d_byUsernameFiltered[_byUsernameSel]->inchat) return;
if (d_byUsernameFiltered[_byUsernameSel]->disabledChecked) return;
changeCheckState(d_byUsernameFiltered[_byUsernameSel], _byUsernameFiltered[_byUsernameSel]);
ContactData *moving = d_byUsernameFiltered[_byUsernameSel];
@ -703,7 +793,7 @@ void ContactsInner::chooseParticipant() {
}
}
} else {
if (_filteredSel < 0 || _filteredSel >= _filtered.size() || contactData(_filtered[_filteredSel])->inchat) return;
if (_filteredSel < 0 || _filteredSel >= _filtered.size() || contactData(_filtered[_filteredSel])->disabledChecked) return;
changeCheckState(_filtered[_filteredSel]);
}
emit selectAllQuery();
@ -770,13 +860,15 @@ void ContactsInner::changeCheckState(Dialogs::Row *row) {
}
void ContactsInner::changeCheckState(ContactData *data, PeerData *peer) {
t_assert(usingMultiSelect());
int32 cnt = _selCount;
if (data->check) {
data->check = false;
if (data->checkbox->checked()) {
data->checkbox->setChecked(false);
_checkedContacts.remove(peer);
--_selCount;
} else if (selectedCount() < ((_channel && _channel->isMegagroup()) ? Global::MegagroupSizeMax() : Global::ChatSizeMax())) {
data->check = true;
data->checkbox->setChecked(true);
_checkedContacts.insert(peer, true);
++_selCount;
} else if (_channel && !_channel->isMegagroup()) {
@ -933,14 +1025,14 @@ void ContactsInner::updateFilter(QString filter) {
}
_filteredSel = -1;
if (!_filtered.isEmpty()) {
for (_filteredSel = 0; (_filteredSel < _filtered.size()) && contactData(_filtered[_filteredSel])->inchat;) {
for (_filteredSel = 0; (_filteredSel < _filtered.size()) && contactData(_filtered[_filteredSel])->disabledChecked;) {
++_filteredSel;
}
if (_filteredSel == _filtered.size()) _filteredSel = -1;
}
_byUsernameSel = -1;
if (_filteredSel < 0 && !_byUsernameFiltered.isEmpty()) {
for (_byUsernameSel = 0; (_byUsernameSel < _byUsernameFiltered.size()) && d_byUsernameFiltered[_byUsernameSel]->inchat;) {
for (_byUsernameSel = 0; (_byUsernameSel < _byUsernameFiltered.size()) && d_byUsernameFiltered[_byUsernameSel]->disabledChecked;) {
++_byUsernameSel;
}
if (_byUsernameSel == _byUsernameFiltered.size()) _byUsernameSel = -1;
@ -993,20 +1085,20 @@ void ContactsInner::peopleReceived(const QString &query, const QVector<MTPPeer>
_byUsernameFiltered.reserve(already + people.size());
d_byUsernameFiltered.reserve(already + people.size());
for (QVector<MTPPeer>::const_iterator i = people.cbegin(), e = people.cend(); i != e; ++i) {
PeerId peerId = peerFromMTP(*i);
int32 j = 0;
auto peerId = peerFromMTP(*i);
int j = 0;
for (; j < already; ++j) {
if (_byUsernameFiltered[j]->id == peerId) break;
}
if (j == already) {
PeerData *p = App::peer(peerId);
if (!p) continue;
auto peer = App::peer(peerId);
if (!peer) continue;
if (_channel || _chat || _creating != CreatingGroupNone) {
if (p->isUser()) {
if (p->asUser()->botInfo) {
if (peer->isUser()) {
if (peer->asUser()->botInfo) {
if (_chat || _creating == CreatingGroupGroup) { // skip bot's that can't be invited to groups
if (p->asUser()->botInfo->cantJoinGroups) continue;
if (peer->asUser()->botInfo->cantJoinGroups) continue;
}
if (_channel) {
if (!_channel->isMegagroup() && _membersFilter != MembersFilterAdmins) continue;
@ -1016,25 +1108,27 @@ void ContactsInner::peopleReceived(const QString &query, const QVector<MTPPeer>
continue; // skip
}
} else if (sharingBotGame()) {
if (!p->canWrite()) {
if (!peer->canWrite()) {
continue;
}
if (auto channel = p->asChannel()) {
if (auto channel = peer->asChannel()) {
if (channel->isBroadcast()) {
continue;
}
}
}
ContactData *d = new ContactData();
_byUsernameDatas.push_back(d);
d->inchat = _chat ? _chat->participants.contains(p->asUser()) : ((_creating == CreatingGroupGroup || _channel) ? (p == App::self()) : false);
d->check = _checkedContacts.contains(p);
d->name.setText(st::contactsNameFont, p->name, _textNameOptions);
d->online = '@' + p->userName();
auto data = usingMultiSelect() ? new ContactData(peer, [this, peer] { updateRowWithPeer(peer); }) : new ContactData();
_byUsernameDatas.push_back(data);
data->disabledChecked = _chat ? _chat->participants.contains(peer->asUser()) : ((_creating == CreatingGroupGroup || _channel) ? (peer == App::self()) : false);
if (usingMultiSelect() && _checkedContacts.contains(peer)) {
data->checkbox->setChecked(true, Ui::RoundImageCheckbox::SetStyle::Fast);
}
data->name.setText(st::contactsNameFont, peer->name, _textNameOptions);
data->statusText = '@' + peer->userName();
_byUsernameFiltered.push_back(p);
d_byUsernameFiltered.push_back(d);
_byUsernameFiltered.push_back(peer);
d_byUsernameFiltered.push_back(data);
}
}
_searching = false;
@ -1160,33 +1254,33 @@ void ContactsInner::selectSkip(int32 dir) {
_byUsernameSel = -1;
}
if (dir > 0) {
for (auto i = _contacts->cfind(_sel), end = _contacts->cend(); i != end && contactData(*i)->inchat; ++i) {
for (auto i = _contacts->cfind(_sel), end = _contacts->cend(); i != end && contactData(*i)->disabledChecked; ++i) {
_sel = *i;
}
if (_sel && contactData(_sel)->inchat) {
if (_sel && contactData(_sel)->disabledChecked) {
_sel = nullptr;
}
if (!_sel) {
if (!_byUsername.isEmpty()) {
if (_byUsernameSel < 0) _byUsernameSel = 0;
for (; _byUsernameSel < _byUsername.size() && d_byUsername[_byUsernameSel]->inchat;) {
for (; _byUsernameSel < _byUsername.size() && d_byUsername[_byUsernameSel]->disabledChecked;) {
++_byUsernameSel;
}
if (_byUsernameSel == _byUsername.size()) _byUsernameSel = -1;
}
}
} else {
while (_byUsernameSel >= 0 && d_byUsername[_byUsernameSel]->inchat) {
while (_byUsernameSel >= 0 && d_byUsername[_byUsernameSel]->disabledChecked) {
--_byUsernameSel;
}
if (_byUsernameSel < 0) {
if (!_contacts->isEmpty()) {
if (!_newItemSel && !_sel) _sel = *(_contacts->cend() - 1);
if (_sel) {
for (auto i = _contacts->cfind(_sel), b = _contacts->cbegin(); i != b && contactData(*i)->inchat; --i) {
for (auto i = _contacts->cfind(_sel), b = _contacts->cbegin(); i != b && contactData(*i)->disabledChecked; --i) {
_sel = *i;
}
if (contactData(_sel)->inchat) {
if (contactData(_sel)->disabledChecked) {
_sel = nullptr;
}
}
@ -1215,27 +1309,27 @@ void ContactsInner::selectSkip(int32 dir) {
_byUsernameSel = -1;
}
if (dir > 0) {
while (_filteredSel >= 0 && _filteredSel < _filtered.size() && contactData(_filtered[_filteredSel])->inchat) {
while (_filteredSel >= 0 && _filteredSel < _filtered.size() && contactData(_filtered[_filteredSel])->disabledChecked) {
++_filteredSel;
}
if (_filteredSel < 0 || _filteredSel >= _filtered.size()) {
_filteredSel = -1;
if (!_byUsernameFiltered.isEmpty()) {
if (_byUsernameSel < 0) _byUsernameSel = 0;
for (; _byUsernameSel < _byUsernameFiltered.size() && d_byUsernameFiltered[_byUsernameSel]->inchat;) {
for (; _byUsernameSel < _byUsernameFiltered.size() && d_byUsernameFiltered[_byUsernameSel]->disabledChecked;) {
++_byUsernameSel;
}
if (_byUsernameSel == _byUsernameFiltered.size()) _byUsernameSel = -1;
}
}
} else {
while (_byUsernameSel >= 0 && d_byUsernameFiltered[_byUsernameSel]->inchat) {
while (_byUsernameSel >= 0 && d_byUsernameFiltered[_byUsernameSel]->disabledChecked) {
--_byUsernameSel;
}
if (_byUsernameSel < 0) {
if (!_filtered.isEmpty()) {
if (_filteredSel < 0) _filteredSel = _filtered.size() - 1;
for (; _filteredSel >= 0 && contactData(_filtered[_filteredSel])->inchat;) {
for (; _filteredSel >= 0 && contactData(_filtered[_filteredSel])->disabledChecked;) {
--_filteredSel;
}
}
@ -1259,6 +1353,10 @@ void ContactsInner::selectSkipPage(int32 h, int32 dir) {
QVector<UserData*> ContactsInner::selected() {
QVector<UserData*> result;
if (!usingMultiSelect()) {
return result;
}
for_const (auto row, *_contacts) {
if (_checkedContacts.contains(row->history()->peer)) {
contactData(row); // fill _contactsData
@ -1266,12 +1364,12 @@ QVector<UserData*> ContactsInner::selected() {
}
result.reserve(_contactsData.size());
for (ContactsData::const_iterator i = _contactsData.cbegin(), e = _contactsData.cend(); i != e; ++i) {
if (i.value()->check && i.key()->isUser()) {
if (i.value()->checkbox->checked() && i.key()->isUser()) {
result.push_back(i.key()->asUser());
}
}
for (int32 i = 0, l = _byUsername.size(); i < l; ++i) {
if (d_byUsername[i]->check && _byUsername[i]->isUser()) {
if (d_byUsername[i]->checkbox->checked() && _byUsername[i]->isUser()) {
result.push_back(_byUsername[i]->asUser());
}
}
@ -1280,6 +1378,10 @@ QVector<UserData*> ContactsInner::selected() {
QVector<MTPInputUser> ContactsInner::selectedInputs() {
QVector<MTPInputUser> result;
if (!usingMultiSelect()) {
return result;
}
for_const (auto row, *_contacts) {
if (_checkedContacts.contains(row->history()->peer)) {
contactData(row); // fill _contactsData
@ -1287,46 +1389,25 @@ QVector<MTPInputUser> ContactsInner::selectedInputs() {
}
result.reserve(_contactsData.size());
for (ContactsData::const_iterator i = _contactsData.cbegin(), e = _contactsData.cend(); i != e; ++i) {
if (i.value()->check && i.key()->isUser()) {
if (i.value()->checkbox->checked() && i.key()->isUser()) {
result.push_back(i.key()->asUser()->inputUser);
}
}
for (int32 i = 0, l = _byUsername.size(); i < l; ++i) {
if (d_byUsername[i]->check && _byUsername[i]->isUser()) {
if (d_byUsername[i]->checkbox->checked() && _byUsername[i]->isUser()) {
result.push_back(_byUsername[i]->asUser()->inputUser);
}
}
return result;
}
PeerData *ContactsInner::selectedUser() {
for_const (auto row, *_contacts) {
if (_checkedContacts.contains(row->history()->peer)) {
contactData(row); // fill _contactsData
}
}
for (ContactsData::const_iterator i = _contactsData.cbegin(), e = _contactsData.cend(); i != e; ++i) {
if (i.value()->check) {
return i.key();
}
}
for (int32 i = 0, l = _byUsername.size(); i < l; ++i) {
if (d_byUsername[i]->check) {
return _byUsername[i];
}
}
return 0;
}
ContactsBox::ContactsBox() : ItemListBox(st::contactsScroll)
, _inner(CreatingGroupNone)
, _filter(this, st::boxSearchField, lang(lng_participant_filter))
, _filterCancel(this, st::boxSearchCancel)
, _next(this, lang(lng_create_group_next), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
, _topShadow(this)
, _bottomShadow(0)
, _saveRequestId(0) {
, _topShadow(this) {
init();
}
@ -1337,8 +1418,6 @@ ContactsBox::ContactsBox(const QString &name, const QImage &photo) : ItemListBox
, _next(this, lang(lng_create_group_create), st::defaultBoxButton)
, _cancel(this, lang(lng_create_group_back), st::cancelBoxButton)
, _topShadow(this)
, _bottomShadow(0)
, _saveRequestId(0)
, _creationName(name)
, _creationPhoto(photo) {
init();
@ -1350,9 +1429,7 @@ ContactsBox::ContactsBox(ChannelData *channel) : ItemListBox(st::boxScroll)
, _filterCancel(this, st::boxSearchCancel)
, _next(this, lang(lng_participant_invite), st::defaultBoxButton)
, _cancel(this, lang(lng_create_group_skip), st::cancelBoxButton)
, _topShadow(this)
, _bottomShadow(0)
, _saveRequestId(0) {
, _topShadow(this) {
init();
}
@ -1362,9 +1439,7 @@ ContactsBox::ContactsBox(ChannelData *channel, MembersFilter filter, const Membe
, _filterCancel(this, st::boxSearchCancel)
, _next(this, lang(lng_participant_invite), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
, _topShadow(this)
, _bottomShadow(0)
, _saveRequestId(0) {
, _topShadow(this) {
init();
}
@ -1374,9 +1449,7 @@ ContactsBox::ContactsBox(ChatData *chat, MembersFilter filter) : ItemListBox(st:
, _filterCancel(this, st::boxSearchCancel)
, _next(this, lang((filter == MembersFilterAdmins) ? lng_settings_save : lng_participant_invite), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
, _topShadow(this)
, _bottomShadow(0)
, _saveRequestId(0) {
, _topShadow(this) {
init();
}
@ -1386,9 +1459,7 @@ ContactsBox::ContactsBox(UserData *bot) : ItemListBox(st::contactsScroll)
, _filterCancel(this, st::boxSearchCancel)
, _next(this, lang(lng_create_group_next), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
, _topShadow(this)
, _bottomShadow(0)
, _saveRequestId(0) {
, _topShadow(this) {
init();
}

View file

@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "abstractbox.h"
#include "core/single_timer.h"
#include "ui/effects/round_image_checkbox.h"
namespace Dialogs {
class Row;
@ -51,7 +52,6 @@ public:
void init();
void initList();
void paintDialog(Painter &p, PeerData *peer, ContactData *data, bool sel);
void updateFilter(QString filter = QString());
void selectSkip(int32 dir);
@ -59,7 +59,6 @@ public:
QVector<UserData*> selected();
QVector<MTPInputUser> selectedInputs();
PeerData *selectedUser();
bool allAdmins() const {
return _allAdmins.checked();
}
@ -120,13 +119,24 @@ protected:
void resizeEvent(QResizeEvent *e) override;
private:
void updateRowWithTop(int rowTop);
int getSelectedRowTop() const;
void updateSelectedRow();
int getRowTopWithPeer(PeerData *peer) const;
void updateRowWithPeer(PeerData *peer);
void addAdminDone(const MTPUpdates &result, mtpRequestId req);
bool addAdminFail(const RPCError &error, mtpRequestId req);
void paintDialog(Painter &p, PeerData *peer, ContactData *data, bool sel);
void paintDisabledCheckUserpic(Painter &p, PeerData *peer, int x, int y, int outerWidth) const;
template <typename FilterCallback>
void addDialogsToList(FilterCallback callback);
bool usingMultiSelect() const {
return (_chat != nullptr) || (_creating != CreatingGroupNone && (!_channel || _membersFilter != MembersFilterAdmins));
}
int32 _rowHeight;
int _newItemHeight = 0;
bool _newItemSel = false;
@ -161,11 +171,14 @@ private:
int _selCount = 0;
struct ContactData {
ContactData();
ContactData(PeerData *peer, Ui::RoundImageCheckbox::UpdateCallback &&updateCallback);
std_::unique_ptr<Ui::RoundImageCheckbox> checkbox;
Text name;
QString online;
bool onlineColor;
bool inchat;
bool check;
QString statusText;
bool statusHasOnlineColor = false;
bool disabledChecked = false;
};
typedef QMap<PeerData*, ContactData*> ContactsData;
ContactsData _contactsData;
@ -239,7 +252,8 @@ private:
BoxButton _next, _cancel;
MembersFilter _membersFilter;
ScrollableBoxShadow _topShadow, *_bottomShadow;
ScrollableBoxShadow _topShadow;
ScrollableBoxShadow *_bottomShadow = nullptr;
void peopleReceived(const MTPcontacts_Found &result, mtpRequestId req);
bool peopleFailed(const RPCError &error, mtpRequestId req);
@ -255,7 +269,7 @@ private:
typedef QMap<mtpRequestId, QString> PeopleQueries;
PeopleQueries _peopleQueries;
int32 _saveRequestId;
mtpRequestId _saveRequestId = 0;
// saving admins
void saveAdminsDone(const MTPUpdates &result);
@ -419,3 +433,9 @@ private:
SingleTimer _loadTimer;
};
inline Ui::RoundImageCheckbox::PaintRoundImage PaintUserpicCallback(PeerData *peer) {
return [peer](Painter &p, int x, int y, int outerWidth, int size) {
peer->paintUserpicLeft(p, size, x, y, outerWidth);
};
}

View file

@ -33,16 +33,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "apiwrap.h"
#include "ui/toast/toast.h"
#include "history/history_media_types.h"
namespace {
Ui::RoundImageCheckbox::PaintRoundImage paintUserpicCallback(PeerData *peer) {
return [peer](Painter &p, int x, int y, int outerWidth, int size) {
peer->paintUserpicLeft(p, size, x, y, outerWidth);
};
}
} // namespace
#include "boxes/contactsbox.h"
ShareBox::ShareBox(CopyCallback &&copyCallback, SubmitCallback &&submitCallback, FilterCallback &&filterCallback) : ItemListBox(st::boxScroll)
, _copyCallback(std_::move(copyCallback))
@ -485,7 +476,7 @@ void ShareInner::paintChat(Painter &p, Chat *chat, int index) {
ShareInner::Chat::Chat(PeerData *peer, Ui::RoundImageCheckbox::UpdateCallback &&updateCallback)
: peer(peer)
, checkbox(st::sharePhotoCheckbox, std_::move(updateCallback), paintUserpicCallback(peer))
, checkbox(st::sharePhotoCheckbox, std_::move(updateCallback), PaintUserpicCallback(peer))
, name(st::sharePhotoCheckbox.imageRadius * 2) {
}
@ -604,14 +595,14 @@ void ShareInner::changeCheckState(Chat *chat) {
row = _chatsIndexed->addToEnd(App::history(chat->peer)).value(0);
}
chat = getChat(row);
if (!chat->checkbox.selected()) {
if (!chat->checkbox.checked()) {
_chatsIndexed->moveToTop(chat->peer);
}
emit filterCancel();
}
chat->checkbox.toggleSelected();
if (chat->checkbox.selected()) {
chat->checkbox.setChecked(!chat->checkbox.checked());
if (chat->checkbox.checked()) {
_selected.insert(chat->peer);
setActive(chatIndex(chat->peer));
} else {
@ -754,7 +745,7 @@ QVector<PeerData*> ShareInner::selected() const {
QVector<PeerData*> result;
result.reserve(_dataMap.size());
for_const (auto chat, _dataMap) {
if (chat->checkbox.selected()) {
if (chat->checkbox.checked()) {
result.push_back(chat->peer);
}
}

View file

@ -152,7 +152,6 @@ private:
int displayedChatsCount() const;
static constexpr int kWideCacheScale = Ui::kWideRoundImageCheckboxScale;
struct Chat {
Chat(PeerData *peer, Ui::RoundImageCheckbox::UpdateCallback &&updateCallback);

View file

@ -24,10 +24,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
namespace Ui {
namespace {
static constexpr int kWideScale = 4;
void prepareCheckCaches(const style::RoundImageCheckbox *st, QPixmap &checkBgCache, QPixmap &checkFullCache) {
auto size = st->checkRadius * 2;
auto wideSize = size * kWideRoundImageCheckboxScale;
QImage cache(wideSize * cIntRetinaFactor(), wideSize * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
auto wideSize = size * kWideScale;
auto cache = QImage(wideSize * cIntRetinaFactor(), wideSize * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
cache.setDevicePixelRatio(cRetinaFactor());
{
Painter p(&cache);
@ -42,7 +44,7 @@ void prepareCheckCaches(const style::RoundImageCheckbox *st, QPixmap &checkBgCac
auto ellipse = QRect((wideSize - size) / 2, (wideSize - size) / 2, size, size);
p.drawEllipse(ellipse);
}
QImage cacheIcon = cache;
auto cacheIcon = cache;
{
Painter p(&cacheIcon);
auto ellipse = QRect((wideSize - size) / 2, (wideSize - size) / 2, size, size);
@ -80,13 +82,13 @@ RoundImageCheckbox::RoundImageCheckbox(const style::RoundImageCheckbox &st, Upda
}
void RoundImageCheckbox::paint(Painter &p, int x, int y, int outerWidth) {
auto selectionLevel = _selection.current(_selected ? 1. : 0.);
auto selectionLevel = _selection.current(_checked ? 1. : 0.);
if (_selection.animating()) {
p.setRenderHint(QPainter::SmoothPixmapTransform, true);
auto userpicRadius = qRound(kWideRoundImageCheckboxScale * (_st.imageRadius + (_st.imageSmallRadius - _st.imageRadius) * selectionLevel));
auto userpicShift = kWideRoundImageCheckboxScale * _st.imageRadius - userpicRadius;
auto userpicLeft = x - (kWideRoundImageCheckboxScale - 1) * _st.imageRadius + userpicShift;
auto userpicTop = y - (kWideRoundImageCheckboxScale - 1) * _st.imageRadius + userpicShift;
auto userpicRadius = qRound(kWideScale * (_st.imageRadius + (_st.imageSmallRadius - _st.imageRadius) * selectionLevel));
auto userpicShift = kWideScale * _st.imageRadius - userpicRadius;
auto userpicLeft = x - (kWideScale - 1) * _st.imageRadius + userpicShift;
auto userpicTop = y - (kWideScale - 1) * _st.imageRadius + userpicShift;
auto to = QRect(userpicLeft, userpicTop, userpicRadius * 2, userpicRadius * 2);
auto from = QRect(QPoint(0, 0), _wideCache.size());
p.drawPixmapLeft(to, outerWidth, _wideCache, from);
@ -95,7 +97,7 @@ void RoundImageCheckbox::paint(Painter &p, int x, int y, int outerWidth) {
if (!_wideCache.isNull()) {
_wideCache = QPixmap();
}
auto userpicRadius = _selected ? _st.imageSmallRadius : _st.imageRadius;
auto userpicRadius = _checked ? _st.imageSmallRadius : _st.imageRadius;
auto userpicShift = _st.imageRadius - userpicRadius;
auto userpicLeft = x + userpicShift;
auto userpicTop = y + userpicShift;
@ -106,7 +108,7 @@ void RoundImageCheckbox::paint(Painter &p, int x, int y, int outerWidth) {
p.setRenderHint(QPainter::HighQualityAntialiasing, true);
p.setOpacity(snap(selectionLevel, 0., 1.));
p.setBrush(Qt::NoBrush);
QPen pen = _st.selectFg;
auto pen = _st.selectFg->p;
pen.setWidth(_st.selectWidth);
p.setPen(pen);
p.drawEllipse(rtlrect(x, y, _st.imageRadius * 2, _st.imageRadius * 2, outerWidth));
@ -119,10 +121,10 @@ void RoundImageCheckbox::paint(Painter &p, int x, int y, int outerWidth) {
for (auto &icon : _icons) {
auto fadeIn = icon.fadeIn.current(1.);
auto fadeOut = icon.fadeOut.current(1.);
auto iconRadius = qRound(kWideRoundImageCheckboxScale * (_st.checkSmallRadius + fadeOut * (_st.checkRadius - _st.checkSmallRadius)));
auto iconShift = kWideRoundImageCheckboxScale * _st.checkRadius - iconRadius;
auto iconLeft = x + 2 * _st.imageRadius + _st.selectWidth - 2 * _st.checkRadius - (kWideRoundImageCheckboxScale - 1) * _st.checkRadius + iconShift;
auto iconTop = y + 2 * _st.imageRadius + _st.selectWidth - 2 * _st.checkRadius - (kWideRoundImageCheckboxScale - 1) * _st.checkRadius + iconShift;
auto iconRadius = qRound(kWideScale * (_st.checkSmallRadius + fadeOut * (_st.checkRadius - _st.checkSmallRadius)));
auto iconShift = kWideScale * _st.checkRadius - iconRadius;
auto iconLeft = x + 2 * _st.imageRadius + _st.selectWidth - 2 * _st.checkRadius - (kWideScale - 1) * _st.checkRadius + iconShift;
auto iconTop = y + 2 * _st.imageRadius + _st.selectWidth - 2 * _st.checkRadius - (kWideScale - 1) * _st.checkRadius + iconShift;
auto to = QRect(iconLeft, iconTop, iconRadius * 2, iconRadius * 2);
auto from = QRect(QPoint(0, 0), _wideCheckFullCache.size());
auto opacity = fadeIn * fadeOut;
@ -130,7 +132,7 @@ void RoundImageCheckbox::paint(Painter &p, int x, int y, int outerWidth) {
if (fadeOut < 1.) {
p.drawPixmapLeft(to, outerWidth, icon.wideCheckCache, from);
} else {
auto divider = qRound((kWideRoundImageCheckboxScale - 2) * _st.checkRadius + fadeIn * 3 * _st.checkRadius);
auto divider = qRound((kWideScale - 2) * _st.checkRadius + fadeIn * 3 * _st.checkRadius);
p.drawPixmapLeft(QRect(iconLeft, iconTop, divider, iconRadius * 2), outerWidth, _wideCheckFullCache, QRect(0, 0, divider * cIntRetinaFactor(), _wideCheckFullCache.height()));
p.drawPixmapLeft(QRect(iconLeft + divider, iconTop, iconRadius * 2 - divider, iconRadius * 2), outerWidth, _wideCheckBgCache, QRect(divider * cIntRetinaFactor(), 0, _wideCheckBgCache.width() - divider * cIntRetinaFactor(), _wideCheckBgCache.height()));
}
@ -139,25 +141,50 @@ void RoundImageCheckbox::paint(Painter &p, int x, int y, int outerWidth) {
p.setOpacity(1.);
}
void RoundImageCheckbox::toggleSelected() {
_selected = !_selected;
if (_selected) {
float64 RoundImageCheckbox::checkedAnimationRatio() const {
return snap(_selection.current(_checked ? 1. : 0.), 0., 1.);
}
void RoundImageCheckbox::setChecked(bool checked, SetStyle speed) {
if (_checked == checked) {
if (speed != SetStyle::Animated) {
if (!_icons.isEmpty()) {
_icons.back().fadeIn.finish();
_icons.back().fadeOut.finish();
}
_selection.finish();
}
return;
}
_checked = checked;
if (_checked) {
_icons.push_back(Icon());
_icons.back().fadeIn.start(UpdateCallback(_updateCallback), 0, 1, _st.selectDuration);
if (speed != SetStyle::Animated) {
_icons.back().fadeIn.finish();
}
} else {
prepareWideCheckIconCache(&_icons.back());
_icons.back().fadeOut.start([this] {
_updateCallback();
removeFadeOutedIcons(); // this call can destroy current lambda
}, 1, 0, _st.selectDuration);
if (speed == SetStyle::Animated) {
prepareWideCheckIconCache(&_icons.back());
} else {
_icons.back().fadeOut.finish();
}
}
if (speed == SetStyle::Animated) {
prepareWideCache();
_selection.start(UpdateCallback(_updateCallback), _checked ? 0 : 1, _checked ? 1 : 0, _st.selectDuration, anim_bumpy<125>);
} else {
_selection.finish();
}
prepareWideCache();
_selection.start(UpdateCallback(_updateCallback), _selected ? 0 : 1, _selected ? 1 : 0, _st.selectDuration, anim_bumpy<125>);
}
void RoundImageCheckbox::removeFadeOutedIcons() {
while (!_icons.empty() && !_icons.front().fadeIn.animating() && !_icons.front().fadeOut.animating()) {
if (_icons.size() > 1 || !_selected) {
if (_icons.size() > 1 || !_checked) {
_icons.erase(_icons.begin());
} else {
break;
@ -168,7 +195,7 @@ void RoundImageCheckbox::removeFadeOutedIcons() {
void RoundImageCheckbox::prepareWideCache() {
if (_wideCache.isNull()) {
auto size = _st.imageRadius * 2;
auto wideSize = size * kWideRoundImageCheckboxScale;
auto wideSize = size * kWideScale;
QImage cache(wideSize * cIntRetinaFactor(), wideSize * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
cache.setDevicePixelRatio(cRetinaFactor());
{
@ -190,8 +217,8 @@ void RoundImageCheckbox::prepareWideCheckIconCache(Icon *icon) {
{
Painter p(&wideCache);
p.setCompositionMode(QPainter::CompositionMode_Source);
auto iconRadius = kWideRoundImageCheckboxScale * _st.checkRadius;
auto divider = qRound((kWideRoundImageCheckboxScale - 2) * _st.checkRadius + icon->fadeIn.current(1.) * (kWideRoundImageCheckboxScale - 1) * _st.checkRadius);
auto iconRadius = kWideScale * _st.checkRadius;
auto divider = qRound((kWideScale - 2) * _st.checkRadius + icon->fadeIn.current(1.) * (kWideScale - 1) * _st.checkRadius);
p.drawPixmapLeft(QRect(0, 0, divider, iconRadius * 2), cacheWidth, _wideCheckFullCache, QRect(0, 0, divider * cIntRetinaFactor(), _wideCheckFullCache.height()));
p.drawPixmapLeft(QRect(divider, 0, iconRadius * 2 - divider, iconRadius * 2), cacheWidth, _wideCheckBgCache, QRect(divider * cIntRetinaFactor(), 0, _wideCheckBgCache.width() - divider * cIntRetinaFactor(), _wideCheckBgCache.height()));
}

View file

@ -24,7 +24,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
namespace Ui {
static constexpr int kWideRoundImageCheckboxScale = 4;
class RoundImageCheckbox {
public:
using PaintRoundImage = base::lambda_unique<void(Painter &p, int x, int y, int outerWidth, int size)>;
@ -32,11 +31,16 @@ public:
RoundImageCheckbox(const style::RoundImageCheckbox &st, UpdateCallback &&updateCallback, PaintRoundImage &&paintRoundImage);
void paint(Painter &p, int x, int y, int outerWidth);
float64 checkedAnimationRatio() const;
void toggleSelected();
bool selected() const {
return _selected;
bool checked() const {
return _checked;
}
enum class SetStyle {
Animated,
Fast,
};
void setChecked(bool checked, SetStyle speed = SetStyle::Animated);
private:
struct Icon {
@ -52,7 +56,7 @@ private:
UpdateCallback _updateCallback;
PaintRoundImage _paintRoundImage;
bool _selected = false;
bool _checked = false;
QPixmap _wideCache;
FloatAnimation _selection;
std_::vector_of_moveable<Icon> _icons;