fast dialogs, emoji pan etc done

This commit is contained in:
John Preston 2015-10-01 17:05:05 +03:00
parent 01374e6dc5
commit fe8567e909
32 changed files with 851 additions and 440 deletions

View File

@ -90,6 +90,7 @@ void AbstractBox::animStep(float64 ms) {
if (ms >= 1) { if (ms >= 1) {
a_opacity.finish(); a_opacity.finish();
_cache = QPixmap(); _cache = QPixmap();
setAttribute(Qt::WA_OpaquePaintEvent);
if (!_hiding) { if (!_hiding) {
showAll(); showAll();
showDone(); showDone();
@ -129,6 +130,7 @@ void AbstractBox::startHide() {
hideAll(); hideAll();
} }
a_opacity.start(0); a_opacity.start(0);
setAttribute(Qt::WA_OpaquePaintEvent, false);
} }
ScrollableBox::ScrollableBox(const style::flatScroll &scroll) : AbstractBox(), ScrollableBox::ScrollableBox(const style::flatScroll &scroll) : AbstractBox(),

View File

@ -150,8 +150,12 @@ bool ContactsInner::addAdminFail(const RPCError &error, mtpRequestId req) {
if (req != _addAdminRequestId) return true; if (req != _addAdminRequestId) return true;
_addAdminRequestId = 0; _addAdminRequestId = 0;
if (_addAdminBox) _addAdminBox->onClose(); if (error.type() == "USERS_TOO_MUCH") {
emit adminAdded(); App::wnd()->replaceLayer(new MaxInviteBox(_channel->invitationUrl));
} else {
if (_addAdminBox) _addAdminBox->onClose();
emit adminAdded();
}
return true; return true;
} }
@ -173,23 +177,29 @@ void ContactsInner::peerUpdated(PeerData *peer) {
} }
} }
} }
update();
} else { } else {
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
ContactsData::iterator i = _contactsData.find(peer); ContactsData::iterator i = _contactsData.find(peer);
if (i != _contactsData.cend()) { if (i != _contactsData.cend()) {
for (DialogRow *row = _contacts->list.begin; row->next; row = row->next) { for (DialogRow *row = _contacts->list.begin; row->next; row = row->next) {
if (row->attached == i.value()) row->attached = 0; if (row->attached == i.value()) {
row->attached = 0;
update(0, rh * row->pos, width(), rh);
}
} }
if (!_filter.isEmpty()) { if (!_filter.isEmpty()) {
for (int32 j = 0, s = _filtered.size(); j < s; ++j) { for (int32 j = 0, s = _filtered.size(); j < s; ++j) {
if (_filtered[j]->attached == i.value()) _filtered[j]->attached = 0; if (_filtered[j]->attached == i.value()) {
_filtered[j]->attached = 0;
update(0, rh * j, width(), rh);
}
} }
} }
delete i.value(); delete i.value();
_contactsData.erase(i); _contactsData.erase(i);
} }
} }
parentWidget()->update();
} }
void ContactsInner::loadProfilePhotos(int32 yFrom) { void ContactsInner::loadProfilePhotos(int32 yFrom) {
@ -338,10 +348,11 @@ void ContactsInner::paintEvent(QPaintEvent *e) {
QRect r(e->rect()); QRect r(e->rect());
Painter p(this); Painter p(this);
p.setClipRect(r);
_time = unixtime(); _time = unixtime();
p.fillRect(r, st::white->b); p.fillRect(r, st::white->b);
int32 yFrom = r.top(), yTo = r.bottom(); int32 yFrom = r.y(), yTo = r.y() + r.height();
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
if (_filter.isEmpty()) { if (_filter.isEmpty()) {
if (_contacts->list.count || !_byUsername.isEmpty()) { if (_contacts->list.count || !_byUsername.isEmpty()) {
@ -365,16 +376,12 @@ void ContactsInner::paintEvent(QPaintEvent *e) {
yFrom -= _contacts->list.count * rh + st::searchedBarHeight; yFrom -= _contacts->list.count * rh + st::searchedBarHeight;
yTo -= _contacts->list.count * rh + st::searchedBarHeight; yTo -= _contacts->list.count * rh + st::searchedBarHeight;
int32 from = (yFrom >= 0) ? (yFrom / rh) : 0; int32 from = floorclamp(yFrom, rh, 0, _byUsername.size());
if (from < _byUsername.size()) { int32 to = ceilclamp(yTo, rh, 0, _byUsername.size());
int32 to = (yTo / rh) + 1; p.translate(0, from * rh);
if (to > _byUsername.size()) to = _byUsername.size(); for (; from < to; ++from) {
paintDialog(p, _byUsername[from], d_byUsername[from], (_byUsernameSel == from));
p.translate(0, from * rh); p.translate(0, rh);
for (; from < to; ++from) {
paintDialog(p, _byUsername[from], d_byUsername[from], (_byUsernameSel == from));
p.translate(0, rh);
}
} }
} }
} else { } else {
@ -405,16 +412,12 @@ void ContactsInner::paintEvent(QPaintEvent *e) {
p.drawText(QRect(0, 0, width(), st::noContactsHeight), text, style::al_center); p.drawText(QRect(0, 0, width(), st::noContactsHeight), text, style::al_center);
} else { } else {
if (!_filtered.isEmpty()) { if (!_filtered.isEmpty()) {
int32 from = (yFrom >= 0) ? (yFrom / rh) : 0; int32 from = floorclamp(yFrom, rh, 0, _filtered.size());
if (from < _filtered.size()) { int32 to = ceilclamp(yTo, rh, 0, _filtered.size());
int32 to = (yTo / rh) + 1; p.translate(0, from * rh);
if (to > _filtered.size()) to = _filtered.size(); for (; from < to; ++from) {
paintDialog(p, _filtered[from]->history->peer, contactData(_filtered[from]), (_filteredSel == from));
p.translate(0, from * rh); p.translate(0, rh);
for (; from < to; ++from) {
paintDialog(p, _filtered[from]->history->peer, contactData(_filtered[from]), (_filteredSel == from));
p.translate(0, rh);
}
} }
} }
if (!_byUsernameFiltered.isEmpty()) { if (!_byUsernameFiltered.isEmpty()) {
@ -426,16 +429,12 @@ void ContactsInner::paintEvent(QPaintEvent *e) {
yFrom -= _filtered.size() * rh + st::searchedBarHeight; yFrom -= _filtered.size() * rh + st::searchedBarHeight;
yTo -= _filtered.size() * rh + st::searchedBarHeight; yTo -= _filtered.size() * rh + st::searchedBarHeight;
int32 from = (yFrom >= 0) ? (yFrom / rh) : 0; int32 from = floorclamp(yFrom, rh, 0, _byUsernameFiltered.size());
if (from < _byUsernameFiltered.size()) { int32 to = ceilclamp(yTo, rh, 0, _byUsernameFiltered.size());
int32 to = (yTo / rh) + 1; p.translate(0, from * rh);
if (to > _byUsernameFiltered.size()) to = _byUsernameFiltered.size(); for (; from < to; ++from) {
paintDialog(p, _byUsernameFiltered[from], d_byUsernameFiltered[from], (_byUsernameSel == from));
p.translate(0, from * rh); p.translate(0, rh);
for (; from < to; ++from) {
paintDialog(p, _byUsernameFiltered[from], d_byUsernameFiltered[from], (_byUsernameSel == from));
p.translate(0, rh);
}
} }
} }
} }
@ -446,12 +445,31 @@ void ContactsInner::enterEvent(QEvent *e) {
setMouseTracking(true); setMouseTracking(true);
} }
void ContactsInner::updateSelectedRow() {
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
if (_filter.isEmpty()) {
if (_sel) {
update(0, _sel->pos * rh, width(), rh);
}
if (_byUsernameSel >= 0) {
update(0, _contacts->list.count * rh + st::searchedBarHeight + _byUsernameSel * rh, width(), rh);
}
} else {
if (_filteredSel >= 0) {
update(0, _filteredSel * rh, width(), rh);
}
if (_byUsernameSel >= 0) {
update(0, _filtered.size() * rh + st::searchedBarHeight + _byUsernameSel * rh, width(), rh);
}
}
}
void ContactsInner::leaveEvent(QEvent *e) { void ContactsInner::leaveEvent(QEvent *e) {
setMouseTracking(false); setMouseTracking(false);
if (_sel || _filteredSel >= 0 || _byUsernameSel >= 0) { if (_sel || _filteredSel >= 0 || _byUsernameSel >= 0) {
updateSelectedRow();
_sel = 0; _sel = 0;
_filteredSel = _byUsernameSel = -1; _filteredSel = _byUsernameSel = -1;
parentWidget()->update();
} }
} }
@ -554,7 +572,7 @@ void ContactsInner::chooseParticipant() {
} }
} }
} }
parentWidget()->update(); update();
} }
void ContactsInner::changeCheckState(DialogRow *row) { void ContactsInner::changeCheckState(DialogRow *row) {
@ -596,18 +614,20 @@ void ContactsInner::updateSel() {
int32 byUsernameSel = (in && p.y() >= _contacts->list.count * rh + st::searchedBarHeight) ? ((p.y() - _contacts->list.count * rh - st::searchedBarHeight) / rh) : -1; int32 byUsernameSel = (in && p.y() >= _contacts->list.count * rh + st::searchedBarHeight) ? ((p.y() - _contacts->list.count * rh - st::searchedBarHeight) / rh) : -1;
if (byUsernameSel >= _byUsername.size()) byUsernameSel = -1; if (byUsernameSel >= _byUsername.size()) byUsernameSel = -1;
if (newSel != _sel || byUsernameSel != _byUsernameSel) { if (newSel != _sel || byUsernameSel != _byUsernameSel) {
updateSelectedRow();
_sel = newSel; _sel = newSel;
_byUsernameSel = byUsernameSel; _byUsernameSel = byUsernameSel;
parentWidget()->update(); updateSelectedRow();
} }
} else { } else {
int32 newFilteredSel = (in && p.y() >= 0 && p.y() < _filtered.size() * rh) ? (p.y() / rh) : -1; int32 newFilteredSel = (in && p.y() >= 0 && p.y() < _filtered.size() * rh) ? (p.y() / rh) : -1;
int32 byUsernameSel = (in && p.y() >= _filtered.size() * rh + st::searchedBarHeight) ? ((p.y() - _filtered.size() * rh - st::searchedBarHeight) / rh) : -1; int32 byUsernameSel = (in && p.y() >= _filtered.size() * rh + st::searchedBarHeight) ? ((p.y() - _filtered.size() * rh - st::searchedBarHeight) / rh) : -1;
if (byUsernameSel >= _byUsernameFiltered.size()) byUsernameSel = -1; if (byUsernameSel >= _byUsernameFiltered.size()) byUsernameSel = -1;
if (newFilteredSel != _filteredSel || byUsernameSel != _byUsernameSel) { if (newFilteredSel != _filteredSel || byUsernameSel != _byUsernameSel) {
updateSelectedRow();
_filteredSel = newFilteredSel; _filteredSel = newFilteredSel;
_byUsernameSel = byUsernameSel; _byUsernameSel = byUsernameSel;
parentWidget()->update(); updateSelectedRow();
} }
} }
} }
@ -745,7 +765,7 @@ void ContactsInner::updateFilter(QString filter) {
emit searchByUsername(); emit searchByUsername();
} }
} }
if (parentWidget()) parentWidget()->update(); update();
loadProfilePhotos(0); loadProfilePhotos(0);
} }
} }
@ -984,7 +1004,7 @@ void ContactsInner::selectSkip(int32 dir) {
emit mustScrollTo(skip + _byUsernameSel * rh, skip + (_byUsernameSel + 1) * rh); emit mustScrollTo(skip + _byUsernameSel * rh, skip + (_byUsernameSel + 1) * rh);
} }
} }
parentWidget()->update(); update();
} }
void ContactsInner::selectSkipPage(int32 h, int32 dir) { void ContactsInner::selectSkipPage(int32 h, int32 dir) {
@ -1441,7 +1461,7 @@ void MembersInner::paintEvent(QPaintEvent *e) {
_time = unixtime(); _time = unixtime();
p.fillRect(r, st::white->b); p.fillRect(r, st::white->b);
int32 yFrom = r.top(), yTo = r.bottom(); int32 yFrom = r.y() - st::membersPadding.top(), yTo = r.y() + r.height() - st::membersPadding.top();
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2; int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
p.translate(0, st::membersPadding.top()); p.translate(0, st::membersPadding.top());
@ -1450,19 +1470,15 @@ void MembersInner::paintEvent(QPaintEvent *e) {
p.setPen(st::noContactsColor->p); p.setPen(st::noContactsColor->p);
p.drawText(QRect(0, 0, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center); p.drawText(QRect(0, 0, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center);
} else { } else {
int32 from = (yFrom >= 0) ? (yFrom / rh) : 0; int32 from = floorclamp(yFrom, rh, 0, _rows.size());
if (from < _rows.size()) { int32 to = ceilclamp(yTo, rh, 0, _rows.size());
int32 to = (yTo / rh) + 1; p.translate(0, from * rh);
if (to > _rows.size()) to = _rows.size(); for (; from < to; ++from) {
bool sel = (from == _sel);
p.translate(0, from * rh); bool kickSel = (from == _kickSel && (_kickDown < 0 || from == _kickDown));
for (; from < to; ++from) { bool kickDown = kickSel && (from == _kickDown);
bool sel = (from == _sel); paintDialog(p, _rows[from], data(from), sel, kickSel, kickDown);
bool kickSel = (from == _kickSel && (_kickDown < 0 || from == _kickDown)); p.translate(0, rh);
bool kickDown = kickSel && (from == _kickDown);
paintDialog(p, _rows[from], data(from), sel, kickSel, kickDown);
p.translate(0, rh);
}
} }
} }
} }
@ -1474,8 +1490,8 @@ void MembersInner::enterEvent(QEvent *e) {
void MembersInner::leaveEvent(QEvent *e) { void MembersInner::leaveEvent(QEvent *e) {
setMouseTracking(false); setMouseTracking(false);
if (_sel >= 0) { if (_sel >= 0) {
updateSelectedRow();
_sel = -1; _sel = -1;
parentWidget()->update();
} }
} }
@ -1581,7 +1597,7 @@ void MembersInner::selectSkip(int32 dir) {
emit mustScrollTo(_sel * rh, (_sel + 1) * rh); emit mustScrollTo(_sel * rh, (_sel + 1) * rh);
} }
parentWidget()->update(); update();
} }
void MembersInner::selectSkipPage(int32 h, int32 dir) { void MembersInner::selectSkipPage(int32 h, int32 dir) {
@ -1700,23 +1716,32 @@ void MembersInner::updateSel() {
newKickSel = -1; newKickSel = -1;
} }
if (newSel != _sel || newKickSel != _kickSel) { if (newSel != _sel || newKickSel != _kickSel) {
updateSelectedRow();
_sel = newSel; _sel = newSel;
_kickSel = newKickSel; _kickSel = newKickSel;
parentWidget()->update(); updateSelectedRow();
setCursor(_kickSel >= 0 ? style::cur_pointer : style::cur_default); setCursor(_kickSel >= 0 ? style::cur_pointer : style::cur_default);
} }
} }
void MembersInner::peerUpdated(PeerData *peer) { void MembersInner::peerUpdated(PeerData *peer) {
parentWidget()->update(); update();
}
void MembersInner::updateSelectedRow() {
if (_sel >= 0) {
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
update(0, st::membersPadding.top() + _sel * rh, width(), rh);
}
} }
void MembersInner::onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) { void MembersInner::onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) {
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
for (int32 i = 0, l = _rows.size(); i < l; ++i) { for (int32 i = 0, l = _rows.size(); i < l; ++i) {
if (_rows.at(i) == peer) { if (_rows.at(i) == peer) {
if (_datas.at(i)) { if (_datas.at(i)) {
_datas.at(i)->name.setText(st::profileListNameFont, peer->name, _textNameOptions); _datas.at(i)->name.setText(st::profileListNameFont, peer->name, _textNameOptions);
parentWidget()->update(); update(0, st::membersPadding.top() + i * rh, width(), rh);
} else { } else {
break; break;
} }

View File

@ -108,6 +108,7 @@ public slots:
private: private:
void updateSelectedRow();
void addAdminDone(const MTPBool &result, mtpRequestId req); void addAdminDone(const MTPBool &result, mtpRequestId req);
bool addAdminFail(const RPCError &error, mtpRequestId req); bool addAdminFail(const RPCError &error, mtpRequestId req);
@ -296,6 +297,7 @@ public slots:
private: private:
void updateSelectedRow();
void clearSel(); void clearSel();
MemberData *data(int32 index); MemberData *data(int32 index);

View File

@ -38,30 +38,28 @@ void SessionsInner::paintEvent(QPaintEvent *e) {
p.setFont(st::linkFont->f); p.setFont(st::linkFont->f);
int32 x = st::sessionPadding.left(), xact = st::sessionTerminateSkip + st::sessionTerminate.iconPos.x();// st::sessionTerminateSkip + st::sessionTerminate.width + st::sessionTerminateSkip; int32 x = st::sessionPadding.left(), xact = st::sessionTerminateSkip + st::sessionTerminate.iconPos.x();// st::sessionTerminateSkip + st::sessionTerminate.width + st::sessionTerminateSkip;
int32 w = width(); int32 w = width();
int32 from = (r.top() >= 0) ? qFloor(r.top() / st::sessionHeight) : 0, count = _list->size(); int32 count = _list->size();
if (from < count) { int32 from = floorclamp(r.y(), st::sessionHeight, 0, count);
int32 to = (r.bottom() >= 0 ? qFloor(r.bottom() / st::sessionHeight) : 0) + 1; int32 to = ceilclamp(r.y() + r.height(), st::sessionHeight, 0, count);
if (to > count) to = count; p.translate(0, from * st::sessionHeight);
p.translate(0, from * st::sessionHeight); for (int32 i = from; i < to; ++i) {
for (int32 i = from; i < to; ++i) { const SessionData &auth(_list->at(i));
const SessionData &auth(_list->at(i));
p.setFont(st::sessionNameFont->f); p.setFont(st::sessionNameFont->f);
p.setPen(st::black->p); p.setPen(st::black->p);
p.drawTextLeft(x, st::sessionPadding.top(), w, auth.name, auth.nameWidth); p.drawTextLeft(x, st::sessionPadding.top(), w, auth.name, auth.nameWidth);
p.setFont(st::sessionActiveFont->f); p.setFont(st::sessionActiveFont->f);
p.setPen(st::sessionActiveColor->p); p.setPen(st::sessionActiveColor->p);
p.drawTextRight(xact, st::sessionPadding.top(), w, auth.active, auth.activeWidth); p.drawTextRight(xact, st::sessionPadding.top(), w, auth.active, auth.activeWidth);
p.setFont(st::sessionInfoFont->f); p.setFont(st::sessionInfoFont->f);
p.setPen(st::black->p); p.setPen(st::black->p);
p.drawTextLeft(x, st::sessionPadding.top() + st::sessionNameFont->height, w, auth.info, auth.infoWidth); p.drawTextLeft(x, st::sessionPadding.top() + st::sessionNameFont->height, w, auth.info, auth.infoWidth);
p.setPen(st::sessionInfoColor->p); p.setPen(st::sessionInfoColor->p);
p.drawTextLeft(x, st::sessionPadding.top() + st::sessionNameFont->height + st::sessionInfoFont->height, w, auth.ip, auth.ipWidth); p.drawTextLeft(x, st::sessionPadding.top() + st::sessionNameFont->height + st::sessionInfoFont->height, w, auth.ip, auth.ipWidth);
p.translate(0, st::sessionHeight); p.translate(0, st::sessionHeight);
}
} }
} }

View File

@ -26,9 +26,14 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "localstorage.h" #include "localstorage.h"
void StickerSetPanel::paintEvent(QPaintEvent *e) {
Painter p(this);
p.fillRect(e->rect(), st::emojiPanHeaderBg->b);
}
StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) :
_loaded(false), _setId(0), _setAccess(0), _setCount(0), _setHash(0), _setFlags(0), _bottom(0), _loaded(false), _setId(0), _setAccess(0), _setCount(0), _setHash(0), _setFlags(0), _bottom(0),
_input(set), _installRequest(0) { _input(set), _installRequest(0), _panel(0) {
switch (set.type()) { switch (set.type()) {
case mtpc_inputStickerSetID: _setId = set.c_inputStickerSetID().vid.v; _setAccess = set.c_inputStickerSetID().vaccess_hash.v; break; case mtpc_inputStickerSetID: _setId = set.c_inputStickerSetID().vid.v; _setAccess = set.c_inputStickerSetID().vaccess_hash.v; break;
case mtpc_inputStickerSetShortName: _setShortName = qs(set.c_inputStickerSetShortName().vshort_name); break; case mtpc_inputStickerSetShortName: _setShortName = qs(set.c_inputStickerSetShortName().vshort_name); break;
@ -68,6 +73,9 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) {
} else { } else {
int32 rows = _pack.size() / StickerPanPerRow + ((_pack.size() % StickerPanPerRow) ? 1 : 0); int32 rows = _pack.size() / StickerPanPerRow + ((_pack.size() % StickerPanPerRow) ? 1 : 0);
resize(st::stickersPadding + StickerPanPerRow * st::stickersSize.width(), rows * st::stickersSize.height() + st::stickersAddOrShare); resize(st::stickersPadding + StickerPanPerRow * st::stickersSize.width(), rows * st::stickersSize.height() + st::stickersAddOrShare);
_panel = new StickerSetPanel(parentWidget());
_panel->setGeometry(0, parentWidget()->height() - st::stickersAddOrShare, width(), st::stickersAddOrShare);
_panel->show();
} }
_loaded = true; _loaded = true;
@ -178,16 +186,12 @@ void StickerSetInner::paintEvent(QPaintEvent *e) {
} }
} }
} }
p.fillRect(0, _bottom - st::stickersAddOrShare, width(), st::stickersAddOrShare, st::emojiPanHeaderBg->b);
} }
void StickerSetInner::setScrollBottom(int32 bottom) { void StickerSetInner::setScrollBottom(int32 bottom) {
if (bottom == _bottom) return; if (bottom == _bottom) return;
QRegion upd = QRect(0, _bottom - st::stickersAddOrShare, width(), st::stickersAddOrShare);
_bottom = bottom; _bottom = bottom;
upd += QRect(0, _bottom - st::stickersAddOrShare, width(), st::stickersAddOrShare);
repaint(upd);
} }
bool StickerSetInner::loaded() const { bool StickerSetInner::loaded() const {

View File

@ -19,7 +19,16 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "abstractbox.h" #include "abstractbox.h"
class StickerSetInner : public QWidget, public RPCSender { class StickerSetPanel : public TWidget {
public:
StickerSetPanel(QWidget *parent) : TWidget(parent) {
}
void paintEvent(QPaintEvent *e);
};
class StickerSetInner : public TWidget, public RPCSender {
Q_OBJECT Q_OBJECT
public: public:
@ -64,6 +73,8 @@ private:
MTPInputStickerSet _input; MTPInputStickerSet _input;
mtpRequestId _installRequest; mtpRequestId _installRequest;
StickerSetPanel *_panel;
}; };
class StickerSetBox : public ScrollableBox, public RPCSender { class StickerSetBox : public ScrollableBox, public RPCSender {

View File

@ -69,11 +69,14 @@ int32 DialogsInner::searchedOffset() const {
} }
void DialogsInner::paintRegion(Painter &p, const QRegion &region, bool paintingOther) { void DialogsInner::paintRegion(Painter &p, const QRegion &region, bool paintingOther) {
QRegion original(rtl() ? region.translated(-otherWidth(), 0) : region);
if (App::wnd() && App::wnd()->contentOverlapped(this, original)) return;
if (!App::main()) return; if (!App::main()) return;
QRect r(region.boundingRect()); QRect r(region.boundingRect());
if (!paintingOther && !r.contains(rect())) { if (!paintingOther) {
p.setClipRect(rect().intersected(r)); p.setClipRect(r);
} }
if (_state == DefaultState) { if (_state == DefaultState) {
@ -94,16 +97,12 @@ void DialogsInner::paintRegion(Painter &p, const QRegion &region, bool paintingO
} }
} else if (_state == FilteredState || _state == SearchedState) { } else if (_state == FilteredState || _state == SearchedState) {
if (!hashtagResults.isEmpty()) { if (!hashtagResults.isEmpty()) {
int32 from = r.top() / int32(st::mentionHeight); int32 from = floorclamp(r.y(), st::mentionHeight, 0, hashtagResults.size());
if (from < 0) { int32 to = ceilclamp(r.y() + r.height(), st::mentionHeight, 0, hashtagResults.size());
from = 0;
} else if (from > hashtagResults.size()) {
from = hashtagResults.size();
}
p.translate(0, from * st::mentionHeight); p.translate(0, from * st::mentionHeight);
if (from < hashtagResults.size()) { if (from < hashtagResults.size()) {
int32 to = (r.bottom() / int32(st::mentionHeight)) + 1, w = fullWidth(), htagwidth = w - st::dlgPaddingHor * 2; int32 w = fullWidth(), htagwidth = w - st::dlgPaddingHor * 2;
if (to > hashtagResults.size()) to = hashtagResults.size();
p.setFont(st::mentionFont->f); p.setFont(st::mentionFont->f);
p.setPen(st::black->p); p.setPen(st::black->p);
for (; from < to; ++from) { for (; from < to; ++from) {
@ -142,16 +141,11 @@ void DialogsInner::paintRegion(Painter &p, const QRegion &region, bool paintingO
} }
if (!filterResults.isEmpty()) { if (!filterResults.isEmpty()) {
int32 skip = filteredOffset(); int32 skip = filteredOffset();
int32 from = (r.top() - skip) / int32(st::dlgHeight); int32 from = floorclamp(r.y() - skip, st::dlgHeight, 0, filterResults.size());
if (from < 0) { int32 to = ceilclamp(r.y() + r.height() - skip, st::dlgHeight, 0, filterResults.size());
from = 0;
} else if (from > filterResults.size()) {
from = filterResults.size();
}
p.translate(0, from * st::dlgHeight); p.translate(0, from * st::dlgHeight);
if (from < filterResults.size()) { if (from < filterResults.size()) {
int32 to = (r.bottom() / int32(st::dlgHeight)) + 1, w = fullWidth(); int32 w = fullWidth();
if (to > filterResults.size()) to = filterResults.size();
for (; from < to; ++from) { for (; from < to; ++from) {
bool active = (filterResults[from]->history->peer == App::main()->activePeer() && !App::main()->activeMsgId()); bool active = (filterResults[from]->history->peer == App::main()->activePeer() && !App::main()->activeMsgId());
bool selected = (from == filteredSel); bool selected = (from == filteredSel);
@ -171,16 +165,11 @@ void DialogsInner::paintRegion(Painter &p, const QRegion &region, bool paintingO
p.translate(0, st::searchedBarHeight); p.translate(0, st::searchedBarHeight);
int32 skip = peopleOffset(); int32 skip = peopleOffset();
int32 from = (r.top() - skip) / int32(st::dlgHeight); int32 from = floorclamp(r.y() - skip, st::dlgHeight, 0, peopleResults.size());
if (from < 0) { int32 to = ceilclamp(r.y() + r.height() - skip, st::dlgHeight, 0, peopleResults.size());
from = 0;
} else if (from > peopleResults.size()) {
from = peopleResults.size();
}
p.translate(0, from * st::dlgHeight); p.translate(0, from * st::dlgHeight);
if (from < peopleResults.size()) { if (from < peopleResults.size()) {
int32 to = ((r.bottom() - skip) / int32(st::dlgHeight)) + 1, w = fullWidth(); int32 w = fullWidth();
if (to > peopleResults.size()) to = peopleResults.size();
for (; from < to; ++from) { for (; from < to; ++from) {
bool active = (peopleResults[from] == App::main()->activePeer() && !App::main()->activeMsgId()); bool active = (peopleResults[from] == App::main()->activePeer() && !App::main()->activeMsgId());
bool selected = (from == peopleSel); bool selected = (from == peopleSel);
@ -215,16 +204,11 @@ void DialogsInner::paintRegion(Painter &p, const QRegion &region, bool paintingO
p.translate(0, st::searchedBarHeight); p.translate(0, st::searchedBarHeight);
int32 skip = searchedOffset(); int32 skip = searchedOffset();
int32 from = (r.top() - skip) / int32(st::dlgHeight); int32 from = floorclamp(r.y() - skip, st::dlgHeight, 0, searchResults.size());
if (from < 0) { int32 to = ceilclamp(r.y() + r.height() - skip, st::dlgHeight, 0, searchResults.size());
from = 0;
} else if (from > searchResults.size()) {
from = searchResults.size();
}
p.translate(0, from * st::dlgHeight); p.translate(0, from * st::dlgHeight);
if (from < searchResults.size()) { if (from < searchResults.size()) {
int32 to = ((r.bottom() - skip) / int32(st::dlgHeight)) + 1, w = fullWidth(); int32 w = fullWidth();
if (to > searchResults.size()) to = searchResults.size();
for (; from < to; ++from) { for (; from < to; ++from) {
bool active = (searchResults[from]->_item->history()->peer == App::main()->activePeer() && searchResults[from]->_item->id == App::main()->activeMsgId()); bool active = (searchResults[from]->_item->history()->peer == App::main()->activePeer() && searchResults[from]->_item->id == App::main()->activeMsgId());
bool selected = (from == searchedSel); bool selected = (from == searchedSel);
@ -941,7 +925,7 @@ void DialogsInner::refresh(bool toTop) {
h = searchedOffset() + (searchResults.count() * st::dlgHeight); h = searchedOffset() + (searchResults.count() * st::dlgHeight);
} }
} }
setHeight(h ); setHeight(h);
if (toTop) { if (toTop) {
emit mustScrollTo(0, 0); emit mustScrollTo(0, 0);
loadPeerPhotos(0); loadPeerPhotos(0);
@ -2192,6 +2176,8 @@ void DialogsWidget::keyPressEvent(QKeyEvent *e) {
} }
void DialogsWidget::paintEvent(QPaintEvent *e) { void DialogsWidget::paintEvent(QPaintEvent *e) {
if (App::wnd() && App::wnd()->contentOverlapped(this, e)) return;
QPainter p(this); QPainter p(this);
QRect r(e->rect()); QRect r(e->rect());
if (r != rect()) { if (r != rect()) {

View File

@ -444,7 +444,7 @@ bool DragArea::animStep(float64 ms) {
return res; return res;
} }
EmojiColorPicker::EmojiColorPicker(QWidget *parent) : TWidget(parent), EmojiColorPicker::EmojiColorPicker() :
_ignoreShow(false), _selected(-1), _pressedSel(-1), _hiding(false), a_opacity(0), _shadow(st::dropdownDef.shadow) { _ignoreShow(false), _selected(-1), _pressedSel(-1), _hiding(false), a_opacity(0), _shadow(st::dropdownDef.shadow) {
memset(_variants, 0, sizeof(_variants)); memset(_variants, 0, sizeof(_variants));
memset(_hovers, 0, sizeof(_hovers)); memset(_hovers, 0, sizeof(_hovers));
@ -484,13 +484,16 @@ void EmojiColorPicker::paintEvent(QPaintEvent *e) {
if (!_cache.isNull()) { if (!_cache.isNull()) {
p.setOpacity(a_opacity.current()); p.setOpacity(a_opacity.current());
} }
if (e->rect() != rect()) {
p.setClipRect(e->rect());
}
int32 w = st::dropdownDef.shadow.pxWidth(), h = st::dropdownDef.shadow.pxHeight(); int32 w = st::dropdownDef.shadow.pxWidth(), h = st::dropdownDef.shadow.pxHeight();
QRect r = QRect(w, h, width() - 2 * w, height() - 2 * h); QRect r = QRect(w, h, width() - 2 * w, height() - 2 * h);
_shadow.paint(p, r, st::dropdownDef.shadowShift); _shadow.paint(p, r, st::dropdownDef.shadowShift);
if (_cache.isNull()) { if (_cache.isNull()) {
p.fillRect(r, st::white->b); p.fillRect(e->rect().intersected(r), st::white->b);
int32 x = w + 2 * st::emojiColorsPadding + st::emojiPanSize.width(); int32 x = w + 2 * st::emojiColorsPadding + st::emojiPanSize.width();
if (rtl()) x = width() - x - st::emojiColorsSep; if (rtl()) x = width() - x - st::emojiColorsSep;
@ -541,7 +544,7 @@ void EmojiColorPicker::mouseMoveEvent(QMouseEvent *e) {
} }
bool EmojiColorPicker::animStep(float64 ms) { bool EmojiColorPicker::animStep(float64 ms) {
bool res1 = true, res2 = true; bool res1 = false, res2 = false;
if (!_cache.isNull()) { if (!_cache.isNull()) {
float64 dt = ms / st::dropdownDef.duration; float64 dt = ms / st::dropdownDef.duration;
if (dt >= 1) { if (dt >= 1) {
@ -554,13 +557,15 @@ bool EmojiColorPicker::animStep(float64 ms) {
_lastMousePos = QCursor::pos(); _lastMousePos = QCursor::pos();
updateSelected(); updateSelected();
} }
res1 = false;
} else { } else {
a_opacity.update(dt, anim::linear); a_opacity.update(dt, anim::linear);
res1 = true;
} }
update();
} }
if (!_emojiAnimations.isEmpty()) { if (!_emojiAnimations.isEmpty()) {
uint64 now = getms(); uint64 now = getms();
QRegion toUpdate;
for (EmojiAnimations::iterator i = _emojiAnimations.begin(); i != _emojiAnimations.end();) { for (EmojiAnimations::iterator i = _emojiAnimations.begin(); i != _emojiAnimations.end();) {
int index = qAbs(i.key()) - 1; int index = qAbs(i.key()) - 1;
float64 dt = float64(now - i.value()) / st::emojiPanDuration; float64 dt = float64(now - i.value()) / st::emojiPanDuration;
@ -571,10 +576,11 @@ bool EmojiColorPicker::animStep(float64 ms) {
_hovers[index] = (i.key() > 0) ? dt : (1 - dt); _hovers[index] = (i.key() > 0) ? dt : (1 - dt);
++i; ++i;
} }
toUpdate += QRect(st::dropdownDef.shadow.pxWidth() + st::emojiColorsPadding + index * st::emojiPanSize.width() + (index ? 2 * st::emojiColorsPadding + st::emojiColorsSep : 0), st::dropdownDef.shadow.pxHeight() + st::emojiColorsPadding, st::emojiPanSize.width(), st::emojiPanSize.height());
} }
res2 = !_emojiAnimations.isEmpty(); res2 = !_emojiAnimations.isEmpty();
rtlupdate(toUpdate.boundingRect());
} }
update();
return res1 || res2; return res1 || res2;
} }
@ -684,13 +690,13 @@ void EmojiColorPicker::drawVariant(Painter &p, int variant) {
p.drawPixmapLeft(w.x() + (st::emojiPanSize.width() - (esize / cIntRetinaFactor())) / 2, w.y() + (st::emojiPanSize.height() - (esize / cIntRetinaFactor())) / 2, width(), App::emojisLarge(), QRect(_variants[variant]->x * esize, _variants[variant]->y * esize, esize, esize)); p.drawPixmapLeft(w.x() + (st::emojiPanSize.width() - (esize / cIntRetinaFactor())) / 2, w.y() + (st::emojiPanSize.height() - (esize / cIntRetinaFactor())) / 2, width(), App::emojisLarge(), QRect(_variants[variant]->x * esize, _variants[variant]->y * esize, esize, esize));
} }
EmojiPanInner::EmojiPanInner(QWidget *parent) : TWidget(parent), _maxHeight(int(st::emojiPanMaxHeight)), EmojiPanInner::EmojiPanInner() : _maxHeight(int(st::emojiPanMaxHeight)),
_top(0), _selected(-1), _pressedSel(-1), _pickerSel(-1), _picker(this), _top(0), _selected(-1), _pressedSel(-1), _pickerSel(-1) {
_switcherHover(0), _stickersWidth(st::emojiPanHeaderFont->m.width(lang(lng_switch_stickers))) { resize(st::emojiPanWidth - st::emojiScroll.width, countHeight());
resize(st::emojiPanWidth, countHeight());
setMouseTracking(true); setMouseTracking(true);
setFocusPolicy(Qt::NoFocus); setFocusPolicy(Qt::NoFocus);
setAttribute(Qt::WA_OpaquePaintEvent);
_picker.hide(); _picker.hide();
@ -712,16 +718,13 @@ _switcherHover(0), _stickersWidth(st::emojiPanHeaderFont->m.width(lang(lng_switc
void EmojiPanInner::setMaxHeight(int32 h) { void EmojiPanInner::setMaxHeight(int32 h) {
_maxHeight = h; _maxHeight = h;
resize(st::emojiPanWidth, countHeight()); resize(st::emojiPanWidth - st::emojiScroll.width, countHeight());
} }
void EmojiPanInner::setScrollTop(int top) { void EmojiPanInner::setScrollTop(int top) {
if (top == _top) return; if (top == _top) return;
QRegion upd = QRect(0, _top, width(), st::emojiPanHeader);
_top = top; _top = top;
upd += QRect(0, _top, width(), st::emojiPanHeader);
repaint(upd);
updateSelected(); updateSelected();
} }
@ -743,6 +746,14 @@ void EmojiPanInner::paintEvent(QPaintEvent *e) {
} }
p.fillRect(r, st::white->b); p.fillRect(r, st::white->b);
int32 fromcol = floorclamp(r.x() - st::emojiPanPadding, st::emojiPanSize.width(), 0, EmojiPanPerRow);
int32 tocol = ceilclamp(r.x() + r.width() - st::emojiPanPadding, st::emojiPanSize.width(), 0, EmojiPanPerRow);
if (rtl()) {
qSwap(fromcol, tocol);
fromcol = EmojiPanPerRow - fromcol;
tocol = EmojiPanPerRow - tocol;
}
int32 y, tilly = 0; int32 y, tilly = 0;
for (int c = 0; c < emojiTabCount; ++c) { for (int c = 0; c < emojiTabCount; ++c) {
y = tilly; y = tilly;
@ -752,14 +763,6 @@ void EmojiPanInner::paintEvent(QPaintEvent *e) {
if (r.top() >= tilly) continue; if (r.top() >= tilly) continue;
y += st::emojiPanHeader; y += st::emojiPanHeader;
if (r.bottom() <= y) {
p.setFont(st::emojiPanHeaderFont->f);
p.setPen(st::emojiPanHeaderColor->p);
p.drawTextLeft(st::emojiPanHeaderLeft, qMax(y - int(st::emojiPanHeader), _top) + st::emojiPanHeaderTop, width(), lang(LangKey(lng_emoji_category0 + c)));
break;
}
if (_emojis[c].isEmpty()) { if (_emojis[c].isEmpty()) {
_emojis[c] = emojiPack(emojiTabAtIndex(c)); _emojis[c] = emojiPack(emojiTabAtIndex(c));
if (emojiTabAtIndex(c) != dbietRecent) { if (emojiTabAtIndex(c) != dbietRecent) {
@ -779,9 +782,10 @@ void EmojiPanInner::paintEvent(QPaintEvent *e) {
} }
} }
int32 fromrow = (r.top() <= y) ? 0 : qMax(qFloor((r.top() - y) / st::emojiPanSize.height()), 0), torow = qMin(qCeil((r.bottom() - y) / st::emojiPanSize.height()) + 1, rows); int32 fromrow = floorclamp(r.y() - y, st::emojiPanSize.height(), 0, rows);
int32 torow = ceilclamp(r.y() + r.height() - y, st::emojiPanSize.height(), 0, rows);
for (int32 i = fromrow; i < torow; ++i) { for (int32 i = fromrow; i < torow; ++i) {
for (int32 j = 0; j < EmojiPanPerRow; ++j) { for (int32 j = fromcol; j < tocol; ++j) {
int32 index = i * EmojiPanPerRow + j; int32 index = i * EmojiPanPerRow + j;
if (index >= size) break; if (index >= size) break;
@ -798,34 +802,32 @@ void EmojiPanInner::paintEvent(QPaintEvent *e) {
p.drawPixmapLeft(w.x() + (st::emojiPanSize.width() - (_esize / cIntRetinaFactor())) / 2, w.y() + (st::emojiPanSize.height() - (_esize / cIntRetinaFactor())) / 2, width(), App::emojisLarge(), QRect(_emojis[c][index]->x * _esize, _emojis[c][index]->y * _esize, _esize, _esize)); p.drawPixmapLeft(w.x() + (st::emojiPanSize.width() - (_esize / cIntRetinaFactor())) / 2, w.y() + (st::emojiPanSize.height() - (_esize / cIntRetinaFactor())) / 2, width(), App::emojisLarge(), QRect(_emojis[c][index]->x * _esize, _emojis[c][index]->y * _esize, _esize, _esize));
} }
} }
if (y - int(st::emojiPanHeader) < _top) {
p.fillRect(QRect(0, qMin(_top, tilly - int(st::emojiPanHeader)), width(), st::emojiPanHeader), st::emojiPanHeaderBg->b);
}
p.setFont(st::emojiPanHeaderFont->f);
p.setPen(st::emojiPanHeaderColor->p);
p.drawTextLeft(st::emojiPanHeaderLeft, qMin(qMax(y - int(st::emojiPanHeader), _top), tilly - int(st::emojiPanHeader)) + st::emojiPanHeaderTop, width(), lang(LangKey(lng_emoji_category0 + c)));
} }
}
p.setFont(st::emojiPanHeaderFont->f); bool EmojiPanInner::checkPickerHide() {
p.setPen(st::emojiSwitchColor->p); if (!_picker.isHidden() && _selected == _pickerSel) {
p.drawTextRight(st::emojiSwitchSkip, _top + st::emojiPanHeaderTop, width(), lang(lng_switch_stickers), _stickersWidth); _picker.hideStart();
p.drawSpriteRight(QPoint(st::emojiSwitchImgSkip - st::emojiSwitchStickers.pxWidth(), _top + (st::emojiPanHeader - st::emojiSwitchStickers.pxHeight()) / 2), width(), st::emojiSwitchStickers); _pickerSel = -1;
updateSelected();
return true;
}
return false;
} }
void EmojiPanInner::mousePressEvent(QMouseEvent *e) { void EmojiPanInner::mousePressEvent(QMouseEvent *e) {
_lastMousePos = e->globalPos(); _lastMousePos = e->globalPos();
updateSelected(); updateSelected();
if (!_picker.isHidden() && _selected == _pickerSel) { if (checkPickerHide()) {
_picker.hideStart();
return; return;
} }
_pressedSel = _selected; _pressedSel = _selected;
if (_selected >= 0 && _selected != SwitcherSelected) { if (_selected >= 0) {
int tab = (_selected / MatrixRowShift), sel = _selected % MatrixRowShift; int tab = (_selected / MatrixRowShift), sel = _selected % MatrixRowShift;
if (tab < emojiTabCount && sel < _emojis[tab].size() && _emojis[tab][sel]->color) { if (tab < emojiTabCount && sel < _emojis[tab].size() && _emojis[tab][sel]->color) {
_pickerSel = _selected; _pickerSel = _selected;
setCursor(style::cur_default);
if (cEmojiVariants().constFind(_emojis[tab][sel]->code) == cEmojiVariants().cend()) { if (cEmojiVariants().constFind(_emojis[tab][sel]->code) == cEmojiVariants().cend()) {
onShowPicker(); onShowPicker();
} else { } else {
@ -848,6 +850,7 @@ void EmojiPanInner::mouseReleaseEvent(QMouseEvent *e) {
if (tab < emojiTabCount && sel < _emojis[tab].size() && _emojis[tab][sel]->color) { if (tab < emojiTabCount && sel < _emojis[tab].size() && _emojis[tab][sel]->color) {
if (cEmojiVariants().constFind(_emojis[tab][sel]->code) != cEmojiVariants().cend()) { if (cEmojiVariants().constFind(_emojis[tab][sel]->code) != cEmojiVariants().cend()) {
_picker.hideStart(); _picker.hideStart();
_pickerSel = -1;
} }
} }
} }
@ -861,10 +864,6 @@ void EmojiPanInner::mouseReleaseEvent(QMouseEvent *e) {
} }
if (_selected < 0 || _selected != pressed) return; if (_selected < 0 || _selected != pressed) return;
if (_selected == SwitcherSelected) {
emit switchToStickers();
return;
}
if (_selected >= emojiTabCount * MatrixRowShift) { if (_selected >= emojiTabCount * MatrixRowShift) {
return; return;
@ -930,8 +929,8 @@ void EmojiPanInner::onShowPicker() {
int32 size = (c == tab) ? (sel - (sel % EmojiPanPerRow)) : _counts[c], rows = (size / EmojiPanPerRow) + ((size % EmojiPanPerRow) ? 1 : 0); int32 size = (c == tab) ? (sel - (sel % EmojiPanPerRow)) : _counts[c], rows = (size / EmojiPanPerRow) + ((size % EmojiPanPerRow) ? 1 : 0);
y += st::emojiPanHeader + (rows * st::emojiPanSize.height()); y += st::emojiPanHeader + (rows * st::emojiPanSize.height());
} }
y -= _picker.height() - st::msgRadius; y -= _picker.height() - st::msgRadius + _top;
if (y < _top) { if (y < 0) {
y += _picker.height() - st::msgRadius + st::emojiPanSize.height() - st::msgRadius; y += _picker.height() - st::msgRadius + st::emojiPanSize.height() - st::msgRadius;
} }
int xmax = width() - _picker.width(); int xmax = width() - _picker.width();
@ -953,6 +952,23 @@ void EmojiPanInner::onPickerHidden() {
updateSelected(); updateSelected();
} }
QRect EmojiPanInner::emojiRect(int tab, int sel) {
int x = 0, y = 0;
for (int i = 0; i < emojiTabCount; ++i) {
if (i == tab) {
int rows = (sel / EmojiPanPerRow);
y += st::emojiPanHeader + rows * st::emojiPanSize.height();
x = st::emojiPanPadding + ((sel % EmojiPanPerRow) * st::emojiPanSize.width());
break;
} else {
int cnt = emojiPackCount(emojiTabAtIndex(i));
int rows = (cnt / EmojiPanPerRow) + ((cnt % EmojiPanPerRow) ? 1 : 0);
y += st::emojiPanHeader + rows * st::emojiPanSize.height();
}
}
return QRect(x, y, st::emojiPanSize.width(), st::emojiPanSize.height());
}
void EmojiPanInner::onColorSelected(EmojiPtr emoji) { void EmojiPanInner::onColorSelected(EmojiPtr emoji) {
if (emoji->color) { if (emoji->color) {
cRefEmojiVariants().insert(emoji->code, emojiKey(emoji)); cRefEmojiVariants().insert(emoji->code, emojiKey(emoji));
@ -961,7 +977,7 @@ void EmojiPanInner::onColorSelected(EmojiPtr emoji) {
int tab = (_pickerSel / MatrixRowShift), sel = _pickerSel % MatrixRowShift; int tab = (_pickerSel / MatrixRowShift), sel = _pickerSel % MatrixRowShift;
if (tab >= 0 && tab < emojiTabCount) { if (tab >= 0 && tab < emojiTabCount) {
_emojis[tab][sel] = emoji; _emojis[tab][sel] = emoji;
update(); rtlupdate(emojiRect(tab, sel));
} }
} }
selectEmoji(emoji); selectEmoji(emoji);
@ -998,9 +1014,17 @@ void EmojiPanInner::clearSelection(bool fast) {
if (fast) { if (fast) {
for (Animations::const_iterator i = _animations.cbegin(); i != _animations.cend(); ++i) { for (Animations::const_iterator i = _animations.cbegin(); i != _animations.cend(); ++i) {
int index = qAbs(i.key()) - 1, tab = (index / MatrixRowShift), sel = index % MatrixRowShift; int index = qAbs(i.key()) - 1, tab = (index / MatrixRowShift), sel = index % MatrixRowShift;
(index == SwitcherSelected ? _switcherHover : _hovers[tab][sel]) = 0; _hovers[tab][sel] = 0;
} }
_animations.clear(); _animations.clear();
if (_selected >= 0) {
int index = qAbs(_selected), tab = (index / MatrixRowShift), sel = index % MatrixRowShift;
_hovers[tab][sel] = 0;
}
if (_pressedSel >= 0) {
int index = qAbs(_pressedSel), tab = (index / MatrixRowShift), sel = index % MatrixRowShift;
_hovers[tab][sel] = 0;
}
_selected = _pressedSel = -1; _selected = _pressedSel = -1;
anim::stop(this); anim::stop(this);
} else { } else {
@ -1025,6 +1049,7 @@ void EmojiPanInner::hideFinish() {
if (!_picker.isHidden()) { if (!_picker.isHidden()) {
_picker.hideStart(true); _picker.hideStart(true);
_pickerSel = -1; _pickerSel = -1;
clearSelection(true);
} }
} }
@ -1034,7 +1059,42 @@ void EmojiPanInner::refreshRecent() {
if (_hovers[0].size() != _counts[0]) _hovers[0] = QVector<float64>(_counts[0], 0); if (_hovers[0].size() != _counts[0]) _hovers[0] = QVector<float64>(_counts[0], 0);
_emojis[0] = emojiPack(dbietRecent); _emojis[0] = emojiPack(dbietRecent);
int32 h = countHeight(); int32 h = countHeight();
if (h != height()) resize(width(), h); if (h != height()) {
resize(width(), h);
emit needRefreshPanels();
}
}
void EmojiPanInner::fillPanels(QVector<EmojiPanel*> &panels) {
if (_picker.parentWidget() != parentWidget()) {
_picker.setParent(parentWidget());
}
for (int32 i = 0; i < panels.size(); ++i) {
panels.at(i)->hide();
panels.at(i)->deleteLater();
}
panels.clear();
int y = 0;
panels.reserve(emojiTabCount);
for (int c = 0; c < emojiTabCount; ++c) {
panels.push_back(new EmojiPanel(parentWidget(), lang(LangKey(lng_emoji_category0 + c)), NoneStickerSetId, true, y));
connect(panels.back(), SIGNAL(mousePressed()), this, SLOT(checkPickerHide()));
int cnt = emojiPackCount(emojiTabAtIndex(c)), rows = (cnt / EmojiPanPerRow) + ((cnt % EmojiPanPerRow) ? 1 : 0);
panels.back()->show();
y += st::emojiPanHeader + rows * st::emojiPanSize.height();
}
}
void EmojiPanInner::refreshPanels(QVector<EmojiPanel*> &panels) {
if (panels.size() != emojiTabCount) return fillPanels(panels);
int32 y = 0;
for (int c = 0; c < emojiTabCount; ++c) {
panels.at(c)->setWantedY(y);
int cnt = emojiPackCount(emojiTabAtIndex(c)), rows = (cnt / EmojiPanPerRow) + ((cnt % EmojiPanPerRow) ? 1 : 0);
y += st::emojiPanHeader + rows * st::emojiPanSize.height();
}
} }
void EmojiPanInner::updateSelected() { void EmojiPanInner::updateSelected() {
@ -1042,33 +1102,25 @@ void EmojiPanInner::updateSelected() {
int32 selIndex = -1; int32 selIndex = -1;
QPoint p(mapFromGlobal(_lastMousePos)); QPoint p(mapFromGlobal(_lastMousePos));
if (p.y() < _top + st::emojiPanHeader) { int y, ytill = 0, sx = (rtl() ? width() - p.x() : p.x()) - st::emojiPanPadding;
bool upon1 = rtl() && p.x() >= 0 && p.x() < st::emojiSwitchSkip + _stickersWidth + (st::emojiSwitchSkip - st::emojiSwitchImgSkip); for (int c = 0; c < emojiTabCount; ++c) {
bool upon2 = !rtl() && p.x() < width() && p.x() >= width() - st::emojiSwitchSkip - _stickersWidth - (st::emojiSwitchSkip - st::emojiSwitchImgSkip); int cnt = _counts[c];
if (upon1 || upon2) { y = ytill;
selIndex = SwitcherSelected; ytill = y + st::emojiPanHeader + ((cnt / EmojiPanPerRow) + ((cnt % EmojiPanPerRow) ? 1 : 0)) * st::emojiPanSize.height();
} if (p.y() >= y && p.y() < ytill) {
} else { y += st::emojiPanHeader;
int y, ytill = 0, sx = (rtl() ? width() - p.x() : p.x()) - st::emojiPanPadding; if (p.y() >= y && sx >= 0 && sx < EmojiPanPerRow * st::emojiPanSize.width()) {
for (int c = 0; c < emojiTabCount; ++c) { selIndex = qFloor((p.y() - y) / st::emojiPanSize.height()) * EmojiPanPerRow + qFloor(sx / st::emojiPanSize.width());
int cnt = _counts[c]; if (selIndex >= _emojis[c].size()) {
y = ytill; selIndex = -1;
ytill = y + st::emojiPanHeader + ((cnt / EmojiPanPerRow) + ((cnt % EmojiPanPerRow) ? 1 : 0)) * st::emojiPanSize.height(); } else {
if (p.y() >= y && p.y() < ytill) { selIndex += c * MatrixRowShift;
y += st::emojiPanHeader;
if (p.y() >= y && sx >= 0 && sx < EmojiPanPerRow * st::emojiPanSize.width()) {
selIndex = qFloor((p.y() - y) / st::emojiPanSize.height()) * EmojiPanPerRow + qFloor(sx / st::emojiPanSize.width());
if (selIndex >= _emojis[c].size()) {
selIndex = -1;
} else {
selIndex += c * MatrixRowShift;
}
} }
break;
} }
break;
} }
} }
bool startanim = false; bool startanim = false;
int oldSel = _selected, newSel = selIndex; int oldSel = _selected, newSel = selIndex;
@ -1103,18 +1155,20 @@ void EmojiPanInner::updateSelected() {
bool EmojiPanInner::animStep(float64 ms) { bool EmojiPanInner::animStep(float64 ms) {
uint64 now = getms(); uint64 now = getms();
QRegion toUpdate;
for (Animations::iterator i = _animations.begin(); i != _animations.end();) { for (Animations::iterator i = _animations.begin(); i != _animations.end();) {
int index = qAbs(i.key()) - 1, tab = (index / MatrixRowShift), sel = index % MatrixRowShift; int index = qAbs(i.key()) - 1, tab = (index / MatrixRowShift), sel = index % MatrixRowShift;
float64 dt = float64(now - i.value()) / st::emojiPanDuration; float64 dt = float64(now - i.value()) / st::emojiPanDuration;
if (dt >= 1) { if (dt >= 1) {
(index == SwitcherSelected ? _switcherHover : _hovers[tab][sel]) = (i.key() > 0) ? 1 : 0; _hovers[tab][sel] = (i.key() > 0) ? 1 : 0;
i = _animations.erase(i); i = _animations.erase(i);
} else { } else {
(index == SwitcherSelected ? _switcherHover : _hovers[tab][sel]) = (i.key() > 0) ? dt : (1 - dt); _hovers[tab][sel] = (i.key() > 0) ? dt : (1 - dt);
++i; ++i;
} }
toUpdate += emojiRect(tab, sel);
} }
update(); rtlupdate(toUpdate.boundingRect());
return !_animations.isEmpty(); return !_animations.isEmpty();
} }
@ -1137,13 +1191,13 @@ void EmojiPanInner::showEmojiPack(DBIEmojiTab packIndex) {
update(); update();
} }
StickerPanInner::StickerPanInner(QWidget *parent) : TWidget(parent), _maxHeight(st::emojiPanMaxHeight), StickerPanInner::StickerPanInner() : _maxHeight(st::emojiPanMaxHeight),
_top(0), _selected(-1), _pressedSel(-1), _top(0), _selected(-1), _pressedSel(-1) {
_switcherHover(0), _emojiWidth(st::emojiPanHeaderFont->m.width(lang(lng_switch_emoji))) { resize(st::emojiPanWidth - st::emojiScroll.width, countHeight());
resize(st::emojiPanWidth, countHeight());
setMouseTracking(true); setMouseTracking(true);
setFocusPolicy(Qt::NoFocus); setFocusPolicy(Qt::NoFocus);
setAttribute(Qt::WA_OpaquePaintEvent);
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update()));
@ -1152,16 +1206,13 @@ _switcherHover(0), _emojiWidth(st::emojiPanHeaderFont->m.width(lang(lng_switch_e
void StickerPanInner::setMaxHeight(int32 h) { void StickerPanInner::setMaxHeight(int32 h) {
_maxHeight = h; _maxHeight = h;
resize(st::emojiPanWidth, countHeight()); resize(st::emojiPanWidth - st::emojiScroll.width, countHeight());
} }
void StickerPanInner::setScrollTop(int top) { void StickerPanInner::setScrollTop(int top) {
if (top == _top) return; if (top == _top) return;
QRegion upd = QRect(0, _top, width(), st::emojiPanHeader);
_top = top; _top = top;
upd += QRect(0, _top, width(), st::emojiPanHeader);
repaint(upd);
updateSelected(); updateSelected();
} }
@ -1176,6 +1227,23 @@ int StickerPanInner::countHeight() {
return result + st::stickerPanPadding; return result + st::stickerPanPadding;
} }
QRect StickerPanInner::stickerRect(int tab, int sel) {
int x = 0, y = 0;
for (int i = 0; i < _sets.size(); ++i) {
if (i == tab) {
int rows = (((sel >= _sets.at(i).pack.size()) ? (sel - _sets.at(i).pack.size()) : sel) / StickerPanPerRow);
y += st::emojiPanHeader + rows * st::stickerPanSize.height();
x = st::stickerPanPadding + ((sel % StickerPanPerRow) * st::stickerPanSize.width());
break;
} else {
int cnt = _sets.at(i).pack.size();
int rows = (cnt / StickerPanPerRow) + ((cnt % StickerPanPerRow) ? 1 : 0);
y += st::emojiPanHeader + rows * st::stickerPanSize.height();
}
}
return QRect(x, y, st::stickerPanSize.width(), st::stickerPanSize.height());
}
void StickerPanInner::paintEvent(QPaintEvent *e) { void StickerPanInner::paintEvent(QPaintEvent *e) {
Painter p(this); Painter p(this);
QRect r = e ? e->rect() : rect(); QRect r = e ? e->rect() : rect();
@ -1183,6 +1251,15 @@ void StickerPanInner::paintEvent(QPaintEvent *e) {
p.setClipRect(r); p.setClipRect(r);
} }
p.fillRect(r, st::white->b); p.fillRect(r, st::white->b);
int32 fromcol = floorclamp(r.x() - st::stickerPanPadding, st::stickerPanSize.width(), 0, StickerPanPerRow);
int32 tocol = ceilclamp(r.x() + r.width() - st::stickerPanPadding, st::stickerPanSize.width(), 0, StickerPanPerRow);
if (rtl()) {
qSwap(fromcol, tocol);
fromcol = StickerPanPerRow - fromcol;
tocol = StickerPanPerRow - tocol;
}
int32 y, tilly = 0; int32 y, tilly = 0;
for (int c = 0, l = _sets.size(); c < l; ++c) { for (int c = 0, l = _sets.size(); c < l; ++c) {
y = tilly; y = tilly;
@ -1194,22 +1271,10 @@ void StickerPanInner::paintEvent(QPaintEvent *e) {
bool special = (_sets[c].flags & MTPDstickerSet_flag_official); bool special = (_sets[c].flags & MTPDstickerSet_flag_official);
y += st::emojiPanHeader; y += st::emojiPanHeader;
QString title = _sets[c].title; int32 fromrow = floorclamp(r.y() - y, st::stickerPanSize.height(), 0, rows);
if (r.bottom() <= y) { int32 torow = ceilclamp(r.y() + r.height() - y, st::stickerPanSize.height(), 0, rows);
p.setFont(st::emojiPanHeaderFont->f);
p.setPen(st::emojiPanHeaderColor->p);
p.drawTextLeft(st::emojiPanHeaderLeft, qMax(y - int(st::emojiPanHeader), _top) + st::emojiPanHeaderTop, width(), title);
if (!special && y >= _top + 2 * st::emojiPanHeader) {
p.setOpacity(st::stickerPanDeleteOpacity + (1 - st::stickerPanDeleteOpacity) * _sets[c].hovers[size]);
p.drawSpriteRight(QPoint(st::emojiPanHeaderLeft, y - (st::emojiPanHeader + st::notifyClose.icon.pxHeight()) / 2), width(), st::notifyClose.icon);
p.setOpacity(1);
}
break;
}
int32 fromrow = (r.top() <= y) ? 0 : qMax(qFloor((r.top() - y) / st::stickerPanSize.height()), 0), torow = qMin(qCeil((r.bottom() - y) / st::stickerPanSize.height()) + 1, rows);
for (int32 i = fromrow; i < torow; ++i) { for (int32 i = fromrow; i < torow; ++i) {
for (int32 j = 0; j < StickerPanPerRow; ++j) { for (int32 j = fromcol; j < tocol; ++j) {
int32 index = i * StickerPanPerRow + j; int32 index = i * StickerPanPerRow + j;
if (index >= size) break; if (index >= size) break;
@ -1266,24 +1331,7 @@ void StickerPanInner::paintEvent(QPaintEvent *e) {
} }
} }
} }
if (y - st::emojiPanHeader < _top) {
p.fillRect(QRect(0, qMin(_top, tilly - int(st::emojiPanHeader)), width(), st::emojiPanHeader), st::emojiPanHeaderBg->b);
} else if (!special && y >= _top + 2 * st::emojiPanHeader) {
p.setOpacity(st::stickerPanDeleteOpacity + (1 - st::stickerPanDeleteOpacity) * _sets[c].hovers[size]);
p.drawSpriteRight(QPoint(st::emojiPanHeaderLeft, y - (st::emojiPanHeader + st::notifyClose.icon.pxHeight()) / 2), width(), st::notifyClose.icon);
p.setOpacity(1);
}
p.setFont(st::emojiPanHeaderFont->f);
p.setPen(st::emojiPanHeaderColor->p);
p.drawTextLeft(st::emojiPanHeaderLeft, qMin(qMax(y - int(st::emojiPanHeader), _top), tilly - int(st::emojiPanHeader)) + st::emojiPanHeaderTop, width(), title);
} }
p.setFont(st::emojiPanHeaderFont->f);
p.setPen(st::emojiSwitchColor->p);
p.drawTextRight(st::emojiSwitchImgSkip - st::emojiSwitchEmoji.pxWidth(), _top + st::emojiPanHeaderTop, width(), lang(lng_switch_emoji), _emojiWidth);
p.drawSpriteRight(QPoint(st::emojiSwitchSkip + _emojiWidth - st::emojiSwitchEmoji.pxWidth(), _top + (st::emojiPanHeader - st::emojiSwitchEmoji.pxHeight()) / 2), width(), st::emojiSwitchEmoji);
} }
void StickerPanInner::mousePressEvent(QMouseEvent *e) { void StickerPanInner::mousePressEvent(QMouseEvent *e) {
@ -1301,10 +1349,6 @@ void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) {
updateSelected(); updateSelected();
if (_selected < 0 || _selected != pressed) return; if (_selected < 0 || _selected != pressed) return;
if (_selected == SwitcherSelected) {
emit switchToEmoji();
return;
}
if (_selected >= MatrixRowShift * _sets.size()) { if (_selected >= MatrixRowShift * _sets.size()) {
return; return;
} }
@ -1347,8 +1391,6 @@ void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) {
} }
if (sel < _sets[tab].pack.size()) { if (sel < _sets[tab].pack.size()) {
emit selected(_sets[tab].pack[sel]); emit selected(_sets[tab].pack[sel]);
} else if (sel == _sets[tab].pack.size()) {
emit removing(_sets[tab].id);
} }
} }
@ -1375,9 +1417,25 @@ void StickerPanInner::clearSelection(bool fast) {
if (fast) { if (fast) {
for (Animations::const_iterator i = _animations.cbegin(); i != _animations.cend(); ++i) { for (Animations::const_iterator i = _animations.cbegin(); i != _animations.cend(); ++i) {
int index = qAbs(i.key()) - 1, tab = (index / MatrixRowShift), sel = index % MatrixRowShift; int index = qAbs(i.key()) - 1, tab = (index / MatrixRowShift), sel = index % MatrixRowShift;
(index == SwitcherSelected ? _switcherHover : _sets[tab].hovers[sel]) = 0; _sets[tab].hovers[sel] = 0;
} }
_animations.clear(); _animations.clear();
if (_selected >= 0) {
int index = qAbs(_selected), tab = (index / MatrixRowShift), sel = index % MatrixRowShift;
if (index >= 0 && tab < _sets.size() && _sets[tab].id == RecentStickerSetId && sel >= tab * MatrixRowShift + _sets[tab].pack.size()) {
_sets[tab].hovers[sel] = 0;
sel -= _sets[tab].pack.size();
}
_sets[tab].hovers[sel] = 0;
}
if (_pressedSel >= 0) {
int index = qAbs(_pressedSel), tab = (index / MatrixRowShift), sel = index % MatrixRowShift;
if (index >= 0 && tab < _sets.size() && _sets[tab].id == RecentStickerSetId && sel >= tab * MatrixRowShift + _sets[tab].pack.size()) {
_sets[tab].hovers[sel] = 0;
sel -= _sets[tab].pack.size();
}
_sets[tab].hovers[sel] = 0;
}
_selected = _pressedSel = -1; _selected = _pressedSel = -1;
anim::stop(this); anim::stop(this);
} else { } else {
@ -1457,9 +1515,7 @@ void StickerPanInner::appendSet(uint64 setId) {
for (int32 i = 0, l = it->stickers.size(); i < l; ++i) { for (int32 i = 0, l = it->stickers.size(); i < l; ++i) {
pack.push_back(it->stickers.at(i)); pack.push_back(it->stickers.at(i));
} }
int32 availw = width() - st::emojiPanHeaderLeft - st::emojiSwitchSkip - _emojiWidth - (st::emojiSwitchSkip - st::emojiSwitchImgSkip); _sets.push_back(DisplayedSet(it->id, it->flags, it->title, pack.size() + 1, pack));
QString title = st::emojiPanHeaderFont->m.elidedText(it->title, Qt::ElideRight, availw);
_sets.push_back(DisplayedSet(it->id, it->flags, title, pack.size() + 1, pack));
} }
void StickerPanInner::refreshRecent(bool performResize) { void StickerPanInner::refreshRecent(bool performResize) {
@ -1501,7 +1557,10 @@ void StickerPanInner::refreshRecent(bool performResize) {
if (performResize) { if (performResize) {
int32 h = countHeight(); int32 h = countHeight();
if (h != height()) resize(width(), h); if (h != height()) {
resize(width(), h);
emit needRefreshPanels();
}
updateSelected(); updateSelected();
} }
@ -1532,49 +1591,71 @@ void StickerPanInner::fillIcons(QVector<StickerIcon> &icons) {
} }
} }
void StickerPanInner::fillPanels(QVector<EmojiPanel*> &panels) {
for (int32 i = 0; i < panels.size(); ++i) {
panels.at(i)->hide();
panels.at(i)->deleteLater();
}
panels.clear();
if (_sets.isEmpty()) return;
int y = 0;
panels.reserve(_sets.size());
for (int32 i = 0, l = _sets.size(); i < l; ++i) {
bool special = (_sets.at(i).flags & MTPDstickerSet_flag_official);
panels.push_back(new EmojiPanel(parentWidget(), _sets.at(i).title, _sets.at(i).id, special, y));
panels.back()->show();
connect(panels.back(), SIGNAL(deleteClicked(quint64)), this, SIGNAL(removing(quint64)));
int cnt = _sets.at(i).pack.size(), rows = (cnt / StickerPanPerRow) + ((cnt % StickerPanPerRow) ? 1 : 0);
int h = st::emojiPanHeader + rows * st::stickerPanSize.height();
y += h;
}
}
void StickerPanInner::refreshPanels(QVector<EmojiPanel*> &panels) {
if (panels.size() != _sets.size()) return fillPanels(panels);
int32 y = 0;
for (int32 i = 0, l = _sets.size(); i < l; ++i) {
panels.at(i)->setWantedY(y);
int cnt = _sets.at(i).pack.size(), rows = (cnt / StickerPanPerRow) + ((cnt % StickerPanPerRow) ? 1 : 0);
int h = st::emojiPanHeader + rows * st::stickerPanSize.height();
y += h;
}
}
void StickerPanInner::updateSelected() { void StickerPanInner::updateSelected() {
if (_pressedSel >= 0) return; if (_pressedSel >= 0) return;
int32 selIndex = -1; int32 selIndex = -1;
QPoint p(mapFromGlobal(_lastMousePos)); QPoint p(mapFromGlobal(_lastMousePos));
if (p.y() < _top + st::emojiPanHeader) { int y, ytill = 0, sx = (rtl() ? width() - p.x() : p.x()) - st::stickerPanPadding;
bool upon1 = rtl() && p.x() >= 0 && p.x() < st::emojiSwitchSkip + _emojiWidth + (st::emojiSwitchSkip - st::emojiSwitchImgSkip); for (int c = 0, l = _sets.size(); c < l; ++c) {
bool upon2 = !rtl() && p.x() < width() && p.x() >= width() - st::emojiSwitchSkip - _emojiWidth - (st::emojiSwitchSkip - st::emojiSwitchImgSkip); const DisplayedSet &set(_sets.at(c));
if (upon1 || upon2) { int cnt = set.pack.size();
selIndex = SwitcherSelected; bool special = (set.flags & MTPDstickerSet_flag_official);
}
} else {
int y, ytill = 0, sx = (rtl() ? width() - p.x() : p.x()) - st::stickerPanPadding;
for (int c = 0, l = _sets.size(); c < l; ++c) {
const DisplayedSet &set(_sets.at(c));
int cnt = set.pack.size();
bool special = (set.flags & MTPDstickerSet_flag_official);
y = ytill; y = ytill;
ytill = y + st::emojiPanHeader + ((cnt / StickerPanPerRow) + ((cnt % StickerPanPerRow) ? 1 : 0)) * st::stickerPanSize.height(); ytill = y + st::emojiPanHeader + ((cnt / StickerPanPerRow) + ((cnt % StickerPanPerRow) ? 1 : 0)) * st::stickerPanSize.height();
if (p.y() >= y && p.y() < ytill) { if (p.y() >= y && p.y() < ytill) {
if (!special && p.y() >= y && p.y() < y + st::emojiPanHeader && sx + st::stickerPanPadding >= width() - st::emojiPanHeaderLeft - st::notifyClose.icon.pxWidth() && sx + st::stickerPanPadding < width() - st::emojiPanHeaderLeft) { y += st::emojiPanHeader;
selIndex = c * MatrixRowShift + set.pack.size(); if (p.y() >= y && sx >= 0 && sx < StickerPanPerRow * st::stickerPanSize.width()) {
selIndex = qFloor((p.y() - y) / st::stickerPanSize.height()) * StickerPanPerRow + qFloor(sx / st::stickerPanSize.width());
if (selIndex >= set.pack.size()) {
selIndex = -1;
} else { } else {
y += st::emojiPanHeader; if (set.id == RecentStickerSetId && _custom[selIndex]) {
if (p.y() >= y && sx >= 0 && sx < StickerPanPerRow * st::stickerPanSize.width()) { int32 inx = sx - (selIndex % StickerPanPerRow) * st::stickerPanSize.width(), iny = p.y() - y - ((selIndex / StickerPanPerRow) * st::stickerPanSize.height());
selIndex = qFloor((p.y() - y) / st::stickerPanSize.height()) * StickerPanPerRow + qFloor(sx / st::stickerPanSize.width()); if (inx >= st::stickerPanSize.width() - st::stickerPanDelete.pxWidth() && iny < st::stickerPanDelete.pxHeight()) {
if (selIndex >= set.pack.size()) { selIndex += set.pack.size();
selIndex = -1;
} else {
if (set.id == RecentStickerSetId && _custom[selIndex]) {
int32 inx = sx - (selIndex % StickerPanPerRow) * st::stickerPanSize.width(), iny = p.y() - y - ((selIndex / StickerPanPerRow) * st::stickerPanSize.height());
if (inx >= st::stickerPanSize.width() - st::stickerPanDelete.pxWidth() && iny < st::stickerPanDelete.pxHeight()) {
selIndex += set.pack.size();
}
}
selIndex += c * MatrixRowShift;
} }
} }
selIndex += c * MatrixRowShift;
} }
break;
} }
break;
} }
} }
@ -1627,18 +1708,20 @@ void StickerPanInner::updateSelected() {
bool StickerPanInner::animStep(float64 ms) { bool StickerPanInner::animStep(float64 ms) {
uint64 now = getms(); uint64 now = getms();
QRegion toUpdate;
for (Animations::iterator i = _animations.begin(); i != _animations.end();) { for (Animations::iterator i = _animations.begin(); i != _animations.end();) {
int index = qAbs(i.key()) - 1, tab = (index / MatrixRowShift), sel = index % MatrixRowShift; int index = qAbs(i.key()) - 1, tab = (index / MatrixRowShift), sel = index % MatrixRowShift;
float64 dt = float64(now - i.value()) / st::emojiPanDuration; float64 dt = float64(now - i.value()) / st::emojiPanDuration;
if (dt >= 1) { if (dt >= 1) {
(index == SwitcherSelected ? _switcherHover : _sets[tab].hovers[sel]) = (i.key() > 0) ? 1 : 0; _sets[tab].hovers[sel] = (i.key() > 0) ? 1 : 0;
i = _animations.erase(i); i = _animations.erase(i);
} else { } else {
(index == SwitcherSelected ? _switcherHover : _sets[tab].hovers[sel]) = (i.key() > 0) ? dt : (1 - dt); _sets[tab].hovers[sel] = (i.key() > 0) ? dt : (1 - dt);
++i; ++i;
} }
toUpdate += stickerRect(tab, sel);
} }
update(); rtlupdate(toUpdate.boundingRect());
return !_animations.isEmpty(); return !_animations.isEmpty();
} }
@ -1659,6 +1742,89 @@ void StickerPanInner::showStickerSet(uint64 setId) {
update(); update();
} }
EmojiPanel::EmojiPanel(QWidget *parent, const QString &text, uint64 setId, bool special, int32 wantedY) : TWidget(parent),
_wantedY(wantedY), _setId(setId), _special(special), _deleteVisible(false), _delete(special ? 0 : new IconedButton(this, st::notifyClose)) { // NoneStickerSetId if in emoji
resize(st::emojiPanWidth, st::emojiPanHeader);
setMouseTracking(true);
setFocusPolicy(Qt::NoFocus);
setText(text);
if (_delete) {
_delete->hide();
_delete->moveToRight(st::emojiPanHeaderLeft - ((_delete->width() - st::notifyClose.icon.pxWidth()) / 2), (st::emojiPanHeader - _delete->height()) / 2, width());
connect(_delete, SIGNAL(clicked()), this, SLOT(onDelete()));
}
}
void EmojiPanel::onDelete() {
emit deleteClicked(_setId);
}
void EmojiPanel::setText(const QString &text) {
_fullText = text;
updateText();
}
void EmojiPanel::updateText() {
int32 availw = st::emojiPanWidth - st::emojiPanHeaderLeft * 2;
if (_deleteVisible) {
if (!_special && _setId != NoneStickerSetId) {
availw -= st::notifyClose.icon.pxWidth() + st::emojiPanHeaderLeft;
}
} else {
QString switchText = lang((_setId != NoneStickerSetId) ? lng_switch_emoji : lng_switch_stickers);
availw -= st::emojiSwitchSkip + st::emojiPanHeaderFont->m.width(switchText);
}
_text = st::emojiPanHeaderFont->m.elidedText(_fullText, Qt::ElideRight, availw);
update();
}
void EmojiPanel::setDeleteVisible(bool isVisible) {
if (_deleteVisible != isVisible) {
_deleteVisible = isVisible;
updateText();
if (_delete) {
_delete->setVisible(_deleteVisible);
}
}
}
void EmojiPanel::mousePressEvent(QMouseEvent *e) {
emit mousePressed();
}
void EmojiPanel::paintEvent(QPaintEvent *e) {
Painter p(this);
if (!_deleteVisible) {
p.fillRect(0, 0, width(), st::emojiPanHeader, st::emojiPanHeaderBg->b);
}
p.setFont(st::emojiPanHeaderFont->f);
p.setPen(st::emojiPanHeaderColor->p);
p.drawTextLeft(st::emojiPanHeaderLeft, st::emojiPanHeaderTop, width(), _text);
}
EmojiSwitchButton::EmojiSwitchButton(QWidget *parent, bool toStickers) : Button(parent),
_toStickers(toStickers), _text(lang(_toStickers ? lng_switch_stickers : lng_switch_emoji)),
_textWidth(st::emojiPanHeaderFont->m.width(_text)) {
int32 w = st::emojiSwitchSkip + _textWidth + (st::emojiSwitchSkip - st::emojiSwitchImgSkip);
setCursor(style::cur_pointer);
resize(w, st::emojiPanHeader);
}
void EmojiSwitchButton::paintEvent(QPaintEvent *e) {
Painter p(this);
p.setFont(st::emojiPanHeaderFont->f);
p.setPen(st::emojiSwitchColor->p);
if (_toStickers) {
p.drawTextRight(st::emojiSwitchSkip, st::emojiPanHeaderTop, width(), _text, _textWidth);
p.drawSpriteRight(QPoint(st::emojiSwitchImgSkip - st::emojiSwitchStickers.pxWidth(), (st::emojiPanHeader - st::emojiSwitchStickers.pxHeight()) / 2), width(), st::emojiSwitchStickers);
} else {
p.drawTextRight(st::emojiSwitchImgSkip - st::emojiSwitchEmoji.pxWidth(), st::emojiPanHeaderTop, width(), lang(lng_switch_emoji), _textWidth);
p.drawSpriteRight(QPoint(st::emojiSwitchSkip + _textWidth - st::emojiSwitchEmoji.pxWidth(), (st::emojiPanHeader - st::emojiSwitchEmoji.pxHeight()) / 2), width(), st::emojiSwitchEmoji);
}
}
EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent), _maxHeight(st::emojiPanMaxHeight), EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent), _maxHeight(st::emojiPanMaxHeight),
_horizontal(false), _noTabUpdate(false), _hiding(false), a_opacity(0), _shadow(st::dropdownDef.shadow), _horizontal(false), _noTabUpdate(false), _hiding(false), a_opacity(0), _shadow(st::dropdownDef.shadow),
_recent(this , qsl("emoji_group"), dbietRecent , QString(), true , st::rbEmojiRecent), _recent(this , qsl("emoji_group"), dbietRecent , QString(), true , st::rbEmojiRecent),
@ -1673,7 +1839,8 @@ _iconOver(-1), _iconSel(0), _iconDown(-1), _iconsDragging(false),
_iconAnim(animFunc(this, &EmojiPan::iconAnim)), _iconAnim(animFunc(this, &EmojiPan::iconAnim)),
_iconsLeft(0), _iconsTop(0), _iconsStartX(0), _iconsMax(0), _iconsX(0, 0), _iconSelX(0, 0), _iconsStartAnim(0), _iconsLeft(0), _iconsTop(0), _iconsStartX(0), _iconsMax(0), _iconsX(0, 0), _iconSelX(0, 0), _iconsStartAnim(0),
_stickersShown(false), _moveStart(0), _stickersShown(false), _moveStart(0),
e_scroll(this, st::emojiScroll), e_inner(), s_scroll(this, st::emojiScroll), s_inner(), _removingSetId(0) { e_scroll(this, st::emojiScroll), e_inner(), e_switch(&e_scroll, true),
s_scroll(this, st::emojiScroll), s_inner(), s_switch(&s_scroll, false), _removingSetId(0) {
setFocusPolicy(Qt::NoFocus); setFocusPolicy(Qt::NoFocus);
e_scroll.setFocusPolicy(Qt::NoFocus); e_scroll.setFocusPolicy(Qt::NoFocus);
e_scroll.viewport()->setFocusPolicy(Qt::NoFocus); e_scroll.viewport()->setFocusPolicy(Qt::NoFocus);
@ -1692,10 +1859,8 @@ e_scroll(this, st::emojiScroll), e_inner(), s_scroll(this, st::emojiScroll), s_i
s_scroll.move(st::dropdownDef.padding.left(), st::dropdownDef.padding.top()); s_scroll.move(st::dropdownDef.padding.left(), st::dropdownDef.padding.top());
s_scroll.setWidget(&s_inner); s_scroll.setWidget(&s_inner);
e_inner.setAttribute(Qt::WA_OpaquePaintEvent); e_inner.moveToLeft(0, 0, e_scroll.width());
e_scroll.setAutoFillBackground(true); s_inner.moveToLeft(0, 0, s_scroll.width());
s_inner.setAttribute(Qt::WA_OpaquePaintEvent);
s_scroll.setAutoFillBackground(true);
int32 left = _iconsLeft = st::dropdownDef.padding.left() + (st::emojiPanWidth - 8 * st::rbEmoji.width) / 2; int32 left = _iconsLeft = st::dropdownDef.padding.left() + (st::emojiPanWidth - 8 * st::rbEmoji.width) / 2;
int32 top = _iconsTop = st::dropdownDef.padding.top() + _maxHeight - st::rbEmoji.height; int32 top = _iconsTop = st::dropdownDef.padding.top() + _maxHeight - st::rbEmoji.height;
@ -1707,6 +1872,8 @@ e_scroll(this, st::emojiScroll), e_inner(), s_scroll(this, st::emojiScroll), s_i
prepareTab(left, top, _width, _activity); prepareTab(left, top, _width, _activity);
prepareTab(left, top, _width, _travel); prepareTab(left, top, _width, _travel);
prepareTab(left, top, _width, _objects); prepareTab(left, top, _width, _objects);
e_inner.fillPanels(e_panels);
updatePanelsPositions(e_panels, 0);
_hideTimer.setSingleShot(true); _hideTimer.setSingleShot(true);
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideStart())); connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideStart()));
@ -1722,11 +1889,15 @@ e_scroll(this, st::emojiScroll), e_inner(), s_scroll(this, st::emojiScroll), s_i
connect(&e_inner, SIGNAL(selected(EmojiPtr)), this, SIGNAL(emojiSelected(EmojiPtr))); connect(&e_inner, SIGNAL(selected(EmojiPtr)), this, SIGNAL(emojiSelected(EmojiPtr)));
connect(&s_inner, SIGNAL(selected(DocumentData*)), this, SIGNAL(stickerSelected(DocumentData*))); connect(&s_inner, SIGNAL(selected(DocumentData*)), this, SIGNAL(stickerSelected(DocumentData*)));
connect(&e_inner, SIGNAL(switchToStickers()), this, SLOT(onSwitch())); connect(&s_switch, SIGNAL(clicked()), this, SLOT(onSwitch()));
connect(&s_inner, SIGNAL(switchToEmoji()), this, SLOT(onSwitch())); connect(&e_switch, SIGNAL(clicked()), this, SLOT(onSwitch()));
s_switch.moveToRight(0, 0, st::emojiPanWidth);
e_switch.moveToRight(0, 0, st::emojiPanWidth);
connect(&s_inner, SIGNAL(removing(uint64)), this, SLOT(onRemoveSet(uint64))); connect(&s_inner, SIGNAL(removing(quint64)), this, SLOT(onRemoveSet(quint64)));
connect(&s_inner, SIGNAL(refreshIcons()), this, SLOT(onRefreshIcons())); connect(&s_inner, SIGNAL(refreshIcons()), this, SLOT(onRefreshIcons()));
connect(&e_inner, SIGNAL(needRefreshPanels()), this, SLOT(onRefreshPanels()));
connect(&s_inner, SIGNAL(needRefreshPanels()), this, SLOT(onRefreshPanels()));
if (cPlatform() == dbipMac) { if (cPlatform() == dbipMac) {
connect(App::wnd()->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWndActiveChanged())); connect(App::wnd()->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWndActiveChanged()));
@ -1798,6 +1969,7 @@ void EmojiPan::paintEvent(QPaintEvent *e) {
if (_toCache.isNull()) { if (_toCache.isNull()) {
if (_cache.isNull()) { if (_cache.isNull()) {
p.fillRect(rtlrect(r.x() + r.width() - st::emojiScroll.width, r.y(), st::emojiScroll.width, e_scroll.height(), width()), st::white->b);
if (_stickersShown) { if (_stickersShown) {
p.fillRect(r.left(), _iconsTop, r.width(), st::rbEmoji.height, st::emojiPanCategories->b); p.fillRect(r.left(), _iconsTop, r.width(), st::rbEmoji.height, st::emojiPanCategories->b);
if (!_icons.isEmpty()) { if (!_icons.isEmpty()) {
@ -2028,6 +2200,7 @@ void EmojiPan::onRefreshIcons() {
_iconHovers.clear(); _iconHovers.clear();
_iconAnimations.clear(); _iconAnimations.clear();
s_inner.fillIcons(_icons); s_inner.fillIcons(_icons);
s_inner.fillPanels(s_panels);
_iconsX = anim::ivalue(0, 0); _iconsX = anim::ivalue(0, 0);
_iconSelX.finish(); _iconSelX.finish();
_iconsStartAnim = 0; _iconsStartAnim = 0;
@ -2038,11 +2211,21 @@ void EmojiPan::onRefreshIcons() {
_iconHovers = QVector<float64>(_icons.size(), 0); _iconHovers = QVector<float64>(_icons.size(), 0);
_iconsMax = qMax(int((_icons.size() - 8) * st::rbEmoji.width), 0); _iconsMax = qMax(int((_icons.size() - 8) * st::rbEmoji.width), 0);
} }
updatePanelsPositions(s_panels, s_scroll.scrollTop());
updateSelected(); updateSelected();
updateIcons(); updateIcons();
} }
void EmojiPan::onRefreshPanels() {
s_inner.refreshPanels(s_panels);
e_inner.refreshPanels(e_panels);
if (_stickersShown) {
updatePanelsPositions(s_panels, s_scroll.scrollTop());
} else {
updatePanelsPositions(e_panels, e_scroll.scrollTop());
}
}
void EmojiPan::leaveToChildEvent(QEvent *e) { void EmojiPan::leaveToChildEvent(QEvent *e) {
if (!_stickersShown) return; if (!_stickersShown) return;
_iconsMousePos = QCursor::pos(); _iconsMousePos = QCursor::pos();
@ -2334,10 +2517,23 @@ void EmojiPan::onTabChange() {
e_inner.showEmojiPack(newTab); e_inner.showEmojiPack(newTab);
} }
void EmojiPan::updatePanelsPositions(const QVector<EmojiPanel*> &panels, int32 st) {
for (int32 i = 0, l = panels.size(); i < l; ++i) {
int32 y = panels.at(i)->wantedY() - st;
if (y < 0) {
y = (i + 1 < l) ? qMin(panels.at(i + 1)->wantedY() - st - int(st::emojiPanHeader), 0) : 0;
}
panels.at(i)->move(0, y);
panels.at(i)->setDeleteVisible(y >= st::emojiPanHeader);
}
}
void EmojiPan::onScroll() { void EmojiPan::onScroll() {
int top = e_scroll.scrollTop(); int st = e_scroll.scrollTop();
if (!_stickersShown) { if (!_stickersShown) {
DBIEmojiTab tab = e_inner.currentTab(top); updatePanelsPositions(e_panels, st);
DBIEmojiTab tab = e_inner.currentTab(st);
FlatRadiobutton *check = 0; FlatRadiobutton *check = 0;
switch (tab) { switch (tab) {
case dbietRecent : check = &_recent ; break; case dbietRecent : check = &_recent ; break;
@ -2355,11 +2551,13 @@ void EmojiPan::onScroll() {
_noTabUpdate = false; _noTabUpdate = false;
} }
} }
e_inner.setScrollTop(top); e_inner.setScrollTop(st);
top = s_scroll.scrollTop(); st = s_scroll.scrollTop();
if (_stickersShown) { if (_stickersShown) {
uint64 setId = s_inner.currentSet(top); updatePanelsPositions(s_panels, st);
uint64 setId = s_inner.currentSet(st);
int32 newSel = 0; int32 newSel = 0;
for (int32 i = 0, l = _icons.size(); i < l; ++i) { for (int32 i = 0, l = _icons.size(); i < l; ++i) {
if (_icons.at(i).setId == setId) { if (_icons.at(i).setId == setId) {
@ -2377,7 +2575,7 @@ void EmojiPan::onScroll() {
updateIcons(); updateIcons();
} }
} }
s_inner.setScrollTop(top); s_inner.setScrollTop(st);
} }
void EmojiPan::onSwitch() { void EmojiPan::onSwitch() {
@ -2398,6 +2596,10 @@ void EmojiPan::onSwitch() {
hideAll(); hideAll();
_moveStart = getms(); _moveStart = getms();
if (_stickersShown) {
e_inner.hideFinish();
}
a_toCoord = (_stickersShown != rtl()) ? anim::ivalue(st::emojiPanWidth, 0) : anim::ivalue(-st::emojiPanWidth, 0); a_toCoord = (_stickersShown != rtl()) ? anim::ivalue(st::emojiPanWidth, 0) : anim::ivalue(-st::emojiPanWidth, 0);
a_toAlpha = anim::fvalue(0, 1); a_toAlpha = anim::fvalue(0, 1);
a_fromCoord = (_stickersShown != rtl()) ? anim::ivalue(0, -st::emojiPanWidth) : anim::ivalue(0, st::emojiPanWidth); a_fromCoord = (_stickersShown != rtl()) ? anim::ivalue(0, -st::emojiPanWidth) : anim::ivalue(0, st::emojiPanWidth);
@ -2407,7 +2609,7 @@ void EmojiPan::onSwitch() {
update(); update();
} }
void EmojiPan::onRemoveSet(uint64 setId) { void EmojiPan::onRemoveSet(quint64 setId) {
StickerSets::const_iterator it = cStickerSets().constFind(setId); StickerSets::const_iterator it = cStickerSets().constFind(setId);
if (it != cStickerSets().cend() && !(it->flags & MTPDstickerSet_flag_official)) { if (it != cStickerSets().cend() && !(it->flags & MTPDstickerSet_flag_official)) {
_removingSetId = it->id; _removingSetId = it->id;
@ -2677,8 +2879,9 @@ void MentionsInner::leaveEvent(QEvent *e) {
} }
void MentionsInner::setSel(int sel, bool scroll) { void MentionsInner::setSel(int sel, bool scroll) {
if (_sel >= 0) update(0, _sel * st::mentionHeight, width(), st::mentionHeight);
_sel = sel; _sel = sel;
parentWidget()->update(); if (_sel >= 0) update(0, _sel * st::mentionHeight, width(), st::mentionHeight);
int32 maxSel = _rows->isEmpty() ? (_hrows->isEmpty() ? _crows->size() : _hrows->size()) : _rows->size(); int32 maxSel = _rows->isEmpty() ? (_hrows->isEmpty() ? _crows->size() : _hrows->size()) : _rows->size();
if (scroll && _sel >= 0 && _sel < maxSel) emit mustScrollTo(_sel * st::mentionHeight, (_sel + 1) * st::mentionHeight); if (scroll && _sel >= 0 && _sel < maxSel) emit mustScrollTo(_sel * st::mentionHeight, (_sel + 1) * st::mentionHeight);
} }
@ -2936,6 +3139,7 @@ void MentionsDropdown::hideStart() {
_scroll.hide(); _scroll.hide();
_hiding = true; _hiding = true;
a_opacity.start(0); a_opacity.start(0);
setAttribute(Qt::WA_OpaquePaintEvent, false);
anim::start(this); anim::start(this);
} }
} }
@ -2959,6 +3163,7 @@ void MentionsDropdown::showStart() {
_hiding = false; _hiding = false;
show(); show();
a_opacity.start(1); a_opacity.start(1);
setAttribute(Qt::WA_OpaquePaintEvent, false);
anim::start(this); anim::start(this);
} }
@ -2968,6 +3173,7 @@ bool MentionsDropdown::animStep(float64 ms) {
if (dt >= 1) { if (dt >= 1) {
a_opacity.finish(); a_opacity.finish();
_cache = QPixmap(); _cache = QPixmap();
setAttribute(Qt::WA_OpaquePaintEvent);
if (_hiding) { if (_hiding) {
hideFinish(); hideFinish();
} else { } else {

View File

@ -47,6 +47,16 @@ public:
bool eventFilter(QObject *obj, QEvent *e); bool eventFilter(QObject *obj, QEvent *e);
bool overlaps(const QRect &globalRect) {
if (isHidden() || animating()) return false;
return QRect(_st.padding.left(),
_st.padding.top(),
_width - _st.padding.left() - _st.padding.right(),
_height - _st.padding.top() - _st.padding.bottom()
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
}
signals: signals:
void hiding(); void hiding();
@ -108,6 +118,16 @@ public:
bool animStep(float64 ms); bool animStep(float64 ms);
bool overlaps(const QRect &globalRect) {
if (isHidden() || animating()) return false;
return QRect(st::dragPadding.left(),
st::dragPadding.top(),
width() - st::dragPadding.left() - st::dragPadding.right(),
height() - st::dragPadding.top() - st::dragPadding.bottom()
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
}
signals: signals:
void dropped(const QMimeData *data); void dropped(const QMimeData *data);
@ -132,6 +152,7 @@ private:
}; };
class EmojiPanel;
static const int EmojiColorsCount = 5; static const int EmojiColorsCount = 5;
class EmojiColorPicker : public TWidget, public Animated { class EmojiColorPicker : public TWidget, public Animated {
@ -139,7 +160,7 @@ class EmojiColorPicker : public TWidget, public Animated {
public: public:
EmojiColorPicker(QWidget *parent); EmojiColorPicker();
void showEmoji(uint32 code); void showEmoji(uint32 code);
@ -193,14 +214,12 @@ private:
}; };
static const int32 SwitcherSelected = (INT_MAX / 2);
class EmojiPanInner : public TWidget, public Animated { class EmojiPanInner : public TWidget, public Animated {
Q_OBJECT Q_OBJECT
public: public:
EmojiPanInner(QWidget *parent = 0); EmojiPanInner();
void setMaxHeight(int32 h); void setMaxHeight(int32 h);
void paintEvent(QPaintEvent *e); void paintEvent(QPaintEvent *e);
@ -224,6 +243,9 @@ public:
void refreshRecent(); void refreshRecent();
void setScrollTop(int top); void setScrollTop(int top);
void fillPanels(QVector<EmojiPanel*> &panels);
void refreshPanels(QVector<EmojiPanel*> &panels);
public slots: public slots:
@ -234,6 +256,8 @@ public slots:
void onPickerHidden(); void onPickerHidden();
void onColorSelected(EmojiPtr emoji); void onColorSelected(EmojiPtr emoji);
bool checkPickerHide();
signals: signals:
void selected(EmojiPtr emoji); void selected(EmojiPtr emoji);
@ -243,6 +267,8 @@ signals:
void scrollToY(int y); void scrollToY(int y);
void disableScroll(bool dis); void disableScroll(bool dis);
void needRefreshPanels();
private: private:
int32 _maxHeight; int32 _maxHeight;
@ -250,6 +276,8 @@ private:
int32 countHeight(); int32 countHeight();
void selectEmoji(EmojiPtr emoji); void selectEmoji(EmojiPtr emoji);
QRect emojiRect(int tab, int sel);
typedef QMap<int32, uint64> Animations; // index - showing, -index - hiding typedef QMap<int32, uint64> Animations; // index - showing, -index - hiding
Animations _animations; Animations _animations;
@ -267,9 +295,6 @@ private:
EmojiColorPicker _picker; EmojiColorPicker _picker;
QTimer _showPickerTimer; QTimer _showPickerTimer;
float64 _switcherHover;
int32 _stickersWidth;
}; };
struct StickerIcon { struct StickerIcon {
@ -287,7 +312,7 @@ class StickerPanInner : public TWidget, public Animated {
public: public:
StickerPanInner(QWidget *parent = 0); StickerPanInner();
void setMaxHeight(int32 h); void setMaxHeight(int32 h);
void paintEvent(QPaintEvent *e); void paintEvent(QPaintEvent *e);
@ -309,6 +334,8 @@ public:
void refreshRecent(bool resize = true); void refreshRecent(bool resize = true);
void fillIcons(QVector<StickerIcon> &icons); void fillIcons(QVector<StickerIcon> &icons);
void fillPanels(QVector<EmojiPanel*> &panels);
void refreshPanels(QVector<EmojiPanel*> &panels);
void setScrollTop(int top); void setScrollTop(int top);
void preloadImages(); void preloadImages();
@ -322,7 +349,7 @@ public slots:
signals: signals:
void selected(DocumentData *sticker); void selected(DocumentData *sticker);
void removing(uint64 setId); void removing(quint64 setId);
void refreshIcons(); void refreshIcons();
@ -330,6 +357,7 @@ signals:
void scrollToY(int y); void scrollToY(int y);
void disableScroll(bool dis); void disableScroll(bool dis);
void needRefreshPanels();
private: private:
@ -339,6 +367,7 @@ private:
int32 countHeight(); int32 countHeight();
void selectEmoji(EmojiPtr emoji); void selectEmoji(EmojiPtr emoji);
QRect stickerRect(int tab, int sel);
typedef QMap<int32, uint64> Animations; // index - showing, -index - hiding typedef QMap<int32, uint64> Animations; // index - showing, -index - hiding
Animations _animations; Animations _animations;
@ -359,9 +388,62 @@ private:
int32 _selected, _pressedSel; int32 _selected, _pressedSel;
QPoint _lastMousePos; QPoint _lastMousePos;
};
class EmojiPanel : public TWidget {
Q_OBJECT
public:
EmojiPanel(QWidget *parent, const QString &text, uint64 setId, bool special, int32 wantedY); // NoneStickerSetId if in emoji
void setText(const QString &text);
void setDeleteVisible(bool isVisible);
void paintEvent(QPaintEvent *e);
void mousePressEvent(QMouseEvent *e);
int32 wantedY() const {
return _wantedY;
}
void setWantedY(int32 y) {
_wantedY = y;
}
signals:
void deleteClicked(quint64 setId);
void mousePressed();
public slots:
void onDelete();
private:
void updateText();
int32 _wantedY;
QString _text, _fullText;
uint64 _setId;
bool _special, _deleteVisible;
IconedButton *_delete;
};
class EmojiSwitchButton : public Button {
Q_OBJECT
public:
EmojiSwitchButton(QWidget *parent, bool toStickers); // otherwise toEmoji
void paintEvent(QPaintEvent *e);
protected:
bool _toStickers;
QString _text;
int32 _textWidth;
float64 _switcherHover;
int32 _emojiWidth;
}; };
class EmojiPan : public TWidget, public Animated { class EmojiPan : public TWidget, public Animated {
@ -397,6 +479,16 @@ public:
bool eventFilter(QObject *obj, QEvent *e); bool eventFilter(QObject *obj, QEvent *e);
void stickersInstalled(uint64 setId); void stickersInstalled(uint64 setId);
bool overlaps(const QRect &globalRect) {
if (isHidden() || !_cache.isNull()) return false;
return QRect(st::dropdownDef.padding.left(),
st::dropdownDef.padding.top(),
_width - st::dropdownDef.padding.left() - st::dropdownDef.padding.right(),
_height - st::dropdownDef.padding.top() - st::dropdownDef.padding.bottom()
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
}
public slots: public slots:
void refreshStickers(); void refreshStickers();
@ -411,11 +503,12 @@ public slots:
void onScroll(); void onScroll();
void onSwitch(); void onSwitch();
void onRemoveSet(uint64 setId); void onRemoveSet(quint64 setId);
void onRemoveSetSure(); void onRemoveSetSure();
void onDelayedHide(); void onDelayedHide();
void onRefreshIcons(); void onRefreshIcons();
void onRefreshPanels();
signals: signals:
@ -434,6 +527,7 @@ private:
void updateIcons(); void updateIcons();
void prepareTab(int32 &left, int32 top, int32 _width, FlatRadiobutton &tab); void prepareTab(int32 &left, int32 top, int32 _width, FlatRadiobutton &tab);
void updatePanelsPositions(const QVector<EmojiPanel*> &panels, int32 st);
void showAll(); void showAll();
void hideAll(); void hideAll();
@ -472,8 +566,12 @@ private:
ScrollArea e_scroll; ScrollArea e_scroll;
EmojiPanInner e_inner; EmojiPanInner e_inner;
QVector<EmojiPanel*> e_panels;
EmojiSwitchButton e_switch;
ScrollArea s_scroll; ScrollArea s_scroll;
StickerPanInner s_inner; StickerPanInner s_inner;
QVector<EmojiPanel*> s_panels;
EmojiSwitchButton s_switch;
uint64 _removingSetId; uint64 _removingSetId;
@ -557,6 +655,12 @@ public:
bool eventFilter(QObject *obj, QEvent *e); bool eventFilter(QObject *obj, QEvent *e);
QString getSelected() const; QString getSelected() const;
bool overlaps(const QRect &globalRect) {
if (isHidden() || !testAttribute(Qt::WA_OpaquePaintEvent)) return false;
return rect().contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
}
~MentionsDropdown(); ~MentionsDropdown();
signals: signals:

View File

@ -304,11 +304,8 @@ void CountryList::paintEvent(QPaintEvent *e) {
int l = countriesNow->size(); int l = countriesNow->size();
if (l) { if (l) {
int from = (r.top() > _st.verticalMargin) ? (r.top() - _st.verticalMargin) / _st.rowHeight : 0, to = from + (r.height() / _st.rowHeight) + 2; int32 from = floorclamp(r.y() - _st.verticalMargin, _st.rowHeight, 0, l);
if (to >= l) { int32 to = ceilclamp(r.y() + r.height() - _st.verticalMargin, _st.rowHeight, 0, l);
if (from >= l) return;
to = l;
}
p.setFont(_st.font->f); p.setFont(_st.font->f);
QRectF textRect(_st.margin + _st.borderMargin, _st.verticalMargin + from * _st.rowHeight, width() - 2 * _st.margin - 2 * _st.borderMargin, _st.rowHeight - _st.borderWidth); QRectF textRect(_st.margin + _st.borderMargin, _st.verticalMargin + from * _st.rowHeight, width() - 2 * _st.margin - 2 * _st.borderMargin, _st.rowHeight - _st.borderWidth);
for (int i = from; i < to; ++i) { for (int i = from; i < to; ++i) {

View File

@ -526,6 +526,15 @@ LocalImage::LocalImage(const QPixmap &pixmap, QByteArray format) : Image(format)
} }
} }
LocalImage::LocalImage(const QByteArray &filecontent, QByteArray fmt, const QPixmap &pixmap) {
data = pixmap;
format = fmt;
saved = filecontent;
if (!data.isNull()) {
globalAquiredSize += int64(data.width()) * data.height() * 4;
}
}
const QPixmap &LocalImage::pixData() const { const QPixmap &LocalImage::pixData() const {
return data; return data;
} }
@ -564,6 +573,10 @@ LocalImage *getImage(const QPixmap &pixmap, QByteArray format) {
return new LocalImage(pixmap, format); return new LocalImage(pixmap, format);
} }
LocalImage *getImage(const QByteArray &filecontent, QByteArray format, const QPixmap &pixmap) {
return new LocalImage(filecontent, format, pixmap);
}
void clearStorageImages() { void clearStorageImages() {
for (StorageImages::const_iterator i = storageImages.cbegin(), e = storageImages.cend(); i != e; ++i) { for (StorageImages::const_iterator i = storageImages.cbegin(), e = storageImages.cend(); i != e; ++i) {
delete i.value(); delete i.value();

View File

@ -117,7 +117,8 @@ public:
LocalImage(const QString &file, QByteArray format = QByteArray()); LocalImage(const QString &file, QByteArray format = QByteArray());
LocalImage(const QByteArray &filecontent, QByteArray format = QByteArray()); LocalImage(const QByteArray &filecontent, QByteArray format = QByteArray());
LocalImage(const QPixmap &pixmap, QByteArray format = QByteArray()); LocalImage(const QPixmap &pixmap, QByteArray format = QByteArray());
LocalImage(const QByteArray &filecontent, QByteArray format, const QPixmap &pixmap);
int32 width() const; int32 width() const;
int32 height() const; int32 height() const;
@ -143,6 +144,7 @@ private:
LocalImage *getImage(const QString &file, QByteArray format); LocalImage *getImage(const QString &file, QByteArray format);
LocalImage *getImage(const QByteArray &filecontent, QByteArray format); LocalImage *getImage(const QByteArray &filecontent, QByteArray format);
LocalImage *getImage(const QPixmap &pixmap, QByteArray format); LocalImage *getImage(const QPixmap &pixmap, QByteArray format);
LocalImage *getImage(const QByteArray &filecontent, QByteArray format, const QPixmap &pixmap);
typedef QPair<uint64, uint64> StorageKey; typedef QPair<uint64, uint64> StorageKey;
inline uint64 storageMix32To64(int32 a, int32 b) { inline uint64 storageMix32To64(int32 a, int32 b) {
@ -220,6 +222,8 @@ public:
} }
ImagePtr(const QByteArray &filecontent, QByteArray format = QByteArray()) : Parent(getImage(filecontent, format)) { ImagePtr(const QByteArray &filecontent, QByteArray format = QByteArray()) : Parent(getImage(filecontent, format)) {
} }
ImagePtr(const QByteArray &filecontent, QByteArray format, const QPixmap &pixmap) : Parent(getImage(filecontent, format, pixmap)) {
}
ImagePtr(const QPixmap &pixmap, QByteArray format) : Parent(getImage(pixmap, format)) { ImagePtr(const QPixmap &pixmap, QByteArray format) : Parent(getImage(pixmap, format)) {
} }
ImagePtr(const StorageImageLocation &location, int32 size = 0) : Parent(getImage(location, size)) { ImagePtr(const StorageImageLocation &location, int32 size = 0) : Parent(getImage(location, size)) {

View File

@ -598,7 +598,7 @@ void ScrollArea::touchScrollUpdated(const QPoint &screenPos) {
void ScrollArea::disableScroll(bool dis) { void ScrollArea::disableScroll(bool dis) {
_disabled = dis; _disabled = dis;
if (_disabled) { if (_disabled && _st.hiding) {
hor.hideTimeout(0); hor.hideTimeout(0);
vert.hideTimeout(0); vert.hideTimeout(0);
} }
@ -706,6 +706,7 @@ void ScrollArea::setWidget(QWidget *w) {
} else if (!_other && splitted) { } else if (!_other && splitted) {
_other = new SplittedWidgetOther(this); _other = new SplittedWidgetOther(this);
_other->setAttribute(Qt::WA_OpaquePaintEvent); _other->setAttribute(Qt::WA_OpaquePaintEvent);
_other->resize(vert.width(), _other->height());
connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(onVerticalScroll())); connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(onVerticalScroll()));
hor.raise(); hor.raise();
vert.raise(); vert.raise();
@ -720,7 +721,7 @@ void ScrollArea::setWidget(QWidget *w) {
} }
if (splitted) { if (splitted) {
splitted->setOtherWidth(vert.width()); splitted->setOtherWidth(vert.width());
w->resize(width() - splitted->otherWidth(), w->height()); w->setGeometry(rtl() ? splitted->otherWidth() : 0, 0, width() - splitted->otherWidth(), w->height());
connect(splitted, SIGNAL(resizeOther()), this, SLOT(onResizeOther())); connect(splitted, SIGNAL(resizeOther()), this, SLOT(onResizeOther()));
connect(splitted, SIGNAL(updateOther(const QRect&)), this, SLOT(onUpdateOther(const QRect&))); connect(splitted, SIGNAL(updateOther(const QRect&)), this, SLOT(onUpdateOther(const QRect&)));
connect(splitted, SIGNAL(updateOther(const QRegion&)), this, SLOT(onUpdateOther(const QRegion&))); connect(splitted, SIGNAL(updateOther(const QRegion&)), this, SLOT(onUpdateOther(const QRegion&)));

View File

@ -2114,7 +2114,7 @@ void History::updateShowFrom() {
--i; --i;
for (HistoryBlock::Items::const_iterator j = (*i)->items.cend(); j != (*i)->items.cbegin();) { for (HistoryBlock::Items::const_iterator j = (*i)->items.cend(); j != (*i)->items.cbegin();) {
--j; --j;
if ((*j)->type() == HistoryItemMsg && (*j)->id > 0) { if ((*j)->type() == HistoryItemMsg && (*j)->id > 0 && (!(*j)->out() || !showFrom)) {
if ((*j)->id >= inboxReadBefore) { if ((*j)->id >= inboxReadBefore) {
showFrom = *j; showFrom = *j;
} else { } else {
@ -2896,11 +2896,11 @@ int32 HistoryPhoto::resize(int32 width, const HistoryItem *parent) {
} }
const QString HistoryPhoto::inDialogsText() const { const QString HistoryPhoto::inDialogsText() const {
return lang(lng_in_dlg_photo); return _caption.isEmpty() ? lang(lng_in_dlg_photo) : _caption.original(0, 0xFFFF, false);
} }
const QString HistoryPhoto::inHistoryText() const { const QString HistoryPhoto::inHistoryText() const {
return qsl("[ ") + lang(lng_in_dlg_photo) + qsl(" ]"); return qsl("[ ") + lang(lng_in_dlg_photo) + (_caption.isEmpty() ? QString() : (qsl(", ") + _caption.original(0, 0xFFFF))) + qsl(" ]");
} }
const Text &HistoryPhoto::captionForClone() const { const Text &HistoryPhoto::captionForClone() const {
@ -3230,11 +3230,11 @@ void HistoryVideo::unregItem(HistoryItem *item) {
} }
const QString HistoryVideo::inDialogsText() const { const QString HistoryVideo::inDialogsText() const {
return lang(lng_in_dlg_video); return _caption.isEmpty() ? lang(lng_in_dlg_video) : _caption.original(0, 0xFFFF, false);
} }
const QString HistoryVideo::inHistoryText() const { const QString HistoryVideo::inHistoryText() const {
return qsl("[ ") + lang(lng_in_dlg_video) + qsl(" ]"); return qsl("[ ") + lang(lng_in_dlg_video) + (_caption.isEmpty() ? QString() : (qsl(", ") + _caption.original(0, 0xFFFF))) + qsl(" ]");
} }
bool HistoryVideo::hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width) const { bool HistoryVideo::hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width) const {

View File

@ -96,6 +96,8 @@ void HistoryInner::updateMsg(const HistoryItem *msg) {
} }
void HistoryInner::paintEvent(QPaintEvent *e) { void HistoryInner::paintEvent(QPaintEvent *e) {
if (App::wnd() && App::wnd()->contentOverlapped(this, e)) return;
if (!App::main()) return; if (!App::main()) return;
QRect r(e->rect()); QRect r(e->rect());
@ -107,7 +109,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
} }
if (!_firstLoading && botInfo && !botInfo->text.isEmpty() && botDescHeight > 0) { if (!_firstLoading && botInfo && !botInfo->text.isEmpty() && botDescHeight > 0) {
if (r.top() < botDescRect.y() + botDescRect.height() && r.bottom() > botDescRect.y()) { if (r.y() < botDescRect.y() + botDescRect.height() && r.y() + r.height() > botDescRect.y()) {
textstyleSet(&st::inTextStyle); textstyleSet(&st::inTextStyle);
App::roundRect(p, botDescRect, st::msgInBg, MessageInCorners, &st::msgInShadow); App::roundRect(p, botDescRect, st::msgInBg, MessageInCorners, &st::msgInShadow);
@ -131,7 +133,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
SelectedItems::const_iterator selEnd = _selected.cend(); SelectedItems::const_iterator selEnd = _selected.cend();
bool hasSel = !_selected.isEmpty(); bool hasSel = !_selected.isEmpty();
int32 drawToY = r.bottom() - ySkip; int32 drawToY = r.y() + r.height() - ySkip;
int32 selfromy = 0, seltoy = 0; int32 selfromy = 0, seltoy = 0;
if (_dragSelFrom && _dragSelTo) { if (_dragSelFrom && _dragSelTo) {
@ -1746,8 +1748,8 @@ void BotKeyboard::paintEvent(QPaintEvent *e) {
for (; j != s; ++j) { for (; j != s; ++j) {
const Button &btn(_btns.at(i).at(j)); const Button &btn(_btns.at(i).at(j));
QRect rect(btn.rect); QRect rect(btn.rect);
if (rect.top() >= r.bottom()) break; if (rect.y() >= r.y() + r.height()) break;
if (rect.bottom() < r.top()) continue; if (rect.y() + rect.height() < r.y()) continue;
if (rtl()) rect.moveLeft(width() - rect.left() - rect.width()); if (rtl()) rect.moveLeft(width() - rect.left() - rect.width());
@ -3077,6 +3079,14 @@ void HistoryWidget::updateNotifySettings() {
_muteUnmute.setText(lang(_history->mute ? lng_channel_unmute : lng_channel_mute)); _muteUnmute.setText(lang(_history->mute ? lng_channel_unmute : lng_channel_mute));
} }
bool HistoryWidget::contentOverlapped(const QRect &globalRect) {
return (_attachDragDocument.overlaps(globalRect) ||
_attachDragPhoto.overlaps(globalRect) ||
_attachType.overlaps(globalRect) ||
_attachMention.overlaps(globalRect) ||
_emojiPan.overlaps(globalRect));
}
void HistoryWidget::updateReportSpamStatus() { void HistoryWidget::updateReportSpamStatus() {
if (!_peer || (_peer->isUser() && (peerToUser(_peer->id) == MTP::authedId() || isNotificationsUser(_peer->id) || isServiceUser(_peer->id) || _peer->asUser()->botInfo))) { if (!_peer || (_peer->isUser() && (peerToUser(_peer->id) == MTP::authedId() || isNotificationsUser(_peer->id) || isServiceUser(_peer->id) || _peer->asUser()->botInfo))) {
_reportSpamStatus = dbiprsNoButton; _reportSpamStatus = dbiprsNoButton;
@ -6202,6 +6212,8 @@ void HistoryWidget::drawRecording(Painter &p) {
} }
void HistoryWidget::paintEvent(QPaintEvent *e) { void HistoryWidget::paintEvent(QPaintEvent *e) {
if (App::wnd() && App::wnd()->contentOverlapped(this, e)) return;
Painter p(this); Painter p(this);
QRect r(e->rect()); QRect r(e->rect());
if (r != rect()) { if (r != rect()) {

View File

@ -534,6 +534,8 @@ public:
void updateNotifySettings(); void updateNotifySettings();
bool contentOverlapped(const QRect &globalRect);
~HistoryWidget(); ~HistoryWidget();
signals: signals:

View File

@ -54,7 +54,7 @@ void BackgroundWidget::paintEvent(QPaintEvent *e) {
p.fillRect(rect(), st::layerBG->b); p.fillRect(rect(), st::layerBG->b);
p.setOpacity(aBackground.current()); p.setOpacity(aBackground.current());
shadow.paint(p, w->boxRect(), st::boxShadowShift); shadow.paint(p, w->geometry(), st::boxShadowShift);
} }
void BackgroundWidget::keyPressEvent(QKeyEvent *e) { void BackgroundWidget::keyPressEvent(QKeyEvent *e) {
@ -105,6 +105,11 @@ void BackgroundWidget::setInnerFocus() {
} }
} }
bool BackgroundWidget::contentOverlapped(const QRect &globalRect) {
if (isHidden()) return false;
return w && w->overlaps(globalRect);
}
void BackgroundWidget::resizeEvent(QResizeEvent *e) { void BackgroundWidget::resizeEvent(QResizeEvent *e) {
w->parentResized(); w->parentResized();
} }

View File

@ -38,16 +38,15 @@ public:
emit resized(); emit resized();
} }
virtual QRect boxRect() const {
QRect res(rect());
res.moveTopLeft(geometry().topLeft());
return res;
}
void mousePressEvent(QMouseEvent *e) { void mousePressEvent(QMouseEvent *e) {
e->accept(); e->accept();
} }
bool overlaps(const QRect &globalRect) {
if (isHidden() || !testAttribute(Qt::WA_OpaquePaintEvent)) return false;
return rect().contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
}
signals: signals:
void closed(); void closed();
@ -78,6 +77,8 @@ public:
bool canSetFocus() const; bool canSetFocus() const;
void setInnerFocus(); void setInnerFocus();
bool contentOverlapped(const QRect &globalRect);
~BackgroundWidget(); ~BackgroundWidget();
public slots: public slots:

View File

@ -2279,11 +2279,11 @@ namespace Local {
} }
} }
class ImageLoadTask : public Task { class AbstractCachedLoadTask : public Task {
public: public:
ImageLoadTask(const FileKey &key, const StorageKey &location, mtpFileLoader *loader) : AbstractCachedLoadTask(const FileKey &key, const StorageKey &location, bool readImageFlag, mtpFileLoader *loader) :
_key(key), _location(location), _loader(loader), _result(0) { _key(key), _location(location), _readImageFlag(readImageFlag), _loader(loader), _result(0) {
} }
void process() { void process() {
FileReadDescriptor image; FileReadDescriptor image;
@ -2294,43 +2294,44 @@ namespace Local {
QByteArray imageData; QByteArray imageData;
quint64 locFirst, locSecond; quint64 locFirst, locSecond;
quint32 imageType; quint32 imageType;
image.stream >> locFirst >> locSecond >> imageType >> imageData; readFromStream(image.stream, locFirst, locSecond, imageType, imageData);
if (locFirst != _location.first || locSecond != _location.second) { if (locFirst != _location.first || locSecond != _location.second) {
return; return;
} }
_result = new Result(StorageFileType(imageType), imageData); _result = new Result(StorageFileType(imageType), imageData, _readImageFlag);
} }
void finish() { void finish() {
if (_result) { if (_result) {
_loader->localLoaded(_result->image, _result->format, _result->pixmap); _loader->localLoaded(_result->image, _result->format, _result->pixmap);
} else { } else {
StorageMap::iterator j = _imagesMap.find(_location); clearInMap();
if (j != _imagesMap.cend() && j->first == _key) {
clearKey(_key, UserPath);
_storageImagesSize -= j->second;
_imagesMap.erase(j);
}
_loader->localLoaded(StorageImageSaved()); _loader->localLoaded(StorageImageSaved());
} }
} }
virtual void readFromStream(QDataStream &stream, quint64 &first, quint64 &second, quint32 &type, QByteArray &data) = 0;
virtual void clearInMap() = 0;
private: protected:
FileKey _key; FileKey _key;
StorageKey _location; StorageKey _location;
bool _readImageFlag;
struct Result { struct Result {
Result(StorageFileType type, const QByteArray &data) : image(type, data) { Result(StorageFileType type, const QByteArray &data, bool readImageFlag) : image(type, data) {
QByteArray guessFormat; if (readImageFlag) {
switch (type) { QByteArray guessFormat;
case mtpc_storage_fileGif: guessFormat = "GIF"; break; switch (type) {
case mtpc_storage_fileJpeg: guessFormat = "JPG"; break; case StorageFileGif: guessFormat = "GIF"; break;
case mtpc_storage_filePng: guessFormat = "PNG"; break; case StorageFileJpeg: guessFormat = "JPG"; break;
default: guessFormat = QByteArray(); break; case StorageFilePng: guessFormat = "PNG"; break;
} case StorageFileWebp: guessFormat = "WEBP"; break;
pixmap = QPixmap::fromImage(App::readImage(data, &guessFormat, false), Qt::ColorOnly); default: guessFormat = QByteArray(); break;
if (!pixmap.isNull()) { }
format = guessFormat; pixmap = QPixmap::fromImage(App::readImage(data, &guessFormat, false), Qt::ColorOnly);
if (!pixmap.isNull()) {
format = guessFormat;
}
} }
} }
StorageImageSaved image; StorageImageSaved image;
@ -2342,6 +2343,24 @@ namespace Local {
}; };
class ImageLoadTask : public AbstractCachedLoadTask {
public:
ImageLoadTask(const FileKey &key, const StorageKey &location, mtpFileLoader *loader) :
AbstractCachedLoadTask(key, location, true, loader) {
}
void readFromStream(QDataStream &stream, quint64 &first, quint64 &second, quint32 &type, QByteArray &data) {
stream >> first >> second >> type >> data;
}
void clearInMap() {
StorageMap::iterator j = _imagesMap.find(_location);
if (j != _imagesMap.cend() && j->first == _key) {
clearKey(_key, UserPath);
_storageImagesSize -= j->second;
_imagesMap.erase(j);
}
}
};
TaskId startImageLoad(const StorageKey &location, mtpFileLoader *loader) { TaskId startImageLoad(const StorageKey &location, mtpFileLoader *loader) {
StorageMap::iterator j = _imagesMap.find(location); StorageMap::iterator j = _imagesMap.find(location);
if (j == _imagesMap.cend() || !_localLoader) { if (j == _imagesMap.cend() || !_localLoader) {
@ -2350,27 +2369,6 @@ namespace Local {
return _localLoader->addTask(new ImageLoadTask(j->first, location, loader)); return _localLoader->addTask(new ImageLoadTask(j->first, location, loader));
} }
StorageImageSaved readImage(const StorageKey &location) {
StorageMap::iterator j = _imagesMap.find(location);
if (j == _imagesMap.cend()) {
return StorageImageSaved();
}
FileReadDescriptor image;
if (!readEncryptedFile(image, j.value().first, UserPath)) {
clearKey(j.value().first, UserPath);
_storageImagesSize -= j.value().second;
_imagesMap.erase(j);
return StorageImageSaved();
}
QByteArray imageData;
quint64 locFirst, locSecond;
quint32 imageType;
image.stream >> locFirst >> locSecond >> imageType >> imageData;
return (locFirst == location.first && locSecond == location.second) ? StorageImageSaved(StorageFileType(imageType), imageData) : StorageImageSaved();
}
int32 hasImages() { int32 hasImages() {
return _imagesMap.size(); return _imagesMap.size();
} }
@ -2403,32 +2401,31 @@ namespace Local {
} }
} }
class StickerImageLoadTask : public AbstractCachedLoadTask {
public:
StickerImageLoadTask(const FileKey &key, const StorageKey &location, mtpFileLoader *loader) :
AbstractCachedLoadTask(key, location, true, loader) {
}
void readFromStream(QDataStream &stream, quint64 &first, quint64 &second, quint32 &type, QByteArray &data) {
stream >> first >> second >> data;
type = StorageFilePartial;
}
void clearInMap() {
StorageMap::iterator j = _stickerImagesMap.find(_location);
if (j != _stickerImagesMap.cend() && j->first == _key) {
clearKey(j.value().first, UserPath);
_storageStickersSize -= j.value().second;
_stickerImagesMap.erase(j);
}
}
};
TaskId startStickerImageLoad(const StorageKey &location, mtpFileLoader *loader) { TaskId startStickerImageLoad(const StorageKey &location, mtpFileLoader *loader) {
StorageMap::iterator j = _stickerImagesMap.find(location); StorageMap::iterator j = _stickerImagesMap.find(location);
if (j == _stickerImagesMap.cend()) { if (j == _stickerImagesMap.cend()) {
return 0; return 0;
} }
return 0; return _localLoader->addTask(new StickerImageLoadTask(j->first, location, loader));
}
QByteArray readStickerImage(const StorageKey &location) {
StorageMap::iterator j = _stickerImagesMap.find(location);
if (j == _stickerImagesMap.cend()) {
return QByteArray();
}
FileReadDescriptor draft;
if (!readEncryptedFile(draft, j.value().first, UserPath)) {
clearKey(j.value().first, UserPath);
_storageStickersSize -= j.value().second;
_stickerImagesMap.erase(j);
return QByteArray();
}
QByteArray stickerData;
quint64 locFirst, locSecond;
draft.stream >> locFirst >> locSecond >> stickerData;
return (locFirst == location.first && locSecond == location.second) ? stickerData : QByteArray();
} }
int32 hasStickers() { int32 hasStickers() {
@ -2463,32 +2460,31 @@ namespace Local {
} }
} }
class AudioLoadTask : public AbstractCachedLoadTask {
public:
AudioLoadTask(const FileKey &key, const StorageKey &location, mtpFileLoader *loader) :
AbstractCachedLoadTask(key, location, false, loader) {
}
void readFromStream(QDataStream &stream, quint64 &first, quint64 &second, quint32 &type, QByteArray &data) {
stream >> first >> second >> data;
type = StorageFilePartial;
}
void clearInMap() {
StorageMap::iterator j = _audiosMap.find(_location);
if (j != _audiosMap.cend() && j->first == _key) {
clearKey(j.value().first, UserPath);
_storageAudiosSize -= j.value().second;
_audiosMap.erase(j);
}
}
};
TaskId startAudioLoad(const StorageKey &location, mtpFileLoader *loader) { TaskId startAudioLoad(const StorageKey &location, mtpFileLoader *loader) {
StorageMap::iterator j = _audiosMap.find(location); StorageMap::iterator j = _audiosMap.find(location);
if (j == _audiosMap.cend()) { if (j == _audiosMap.cend()) {
return 0; return 0;
} }
return 0; return _localLoader->addTask(new AudioLoadTask(j->first, location, loader));
}
QByteArray readAudio(const StorageKey &location) {
StorageMap::iterator j = _audiosMap.find(location);
if (j == _audiosMap.cend()) {
return QByteArray();
}
FileReadDescriptor draft;
if (!readEncryptedFile(draft, j.value().first, UserPath)) {
clearKey(j.value().first, UserPath);
_storageAudiosSize -= j.value().second;
_audiosMap.erase(j);
return QByteArray();
}
QByteArray audioData;
quint64 locFirst, locSecond;
draft.stream >> locFirst >> locSecond >> audioData;
return (locFirst == location.first && locSecond == location.second) ? audioData : QByteArray();
} }
int32 hasAudios() { int32 hasAudios() {

View File

@ -121,19 +121,16 @@ namespace Local {
void writeImage(const StorageKey &location, const ImagePtr &img); void writeImage(const StorageKey &location, const ImagePtr &img);
void writeImage(const StorageKey &location, const StorageImageSaved &jpeg, bool overwrite = true); void writeImage(const StorageKey &location, const StorageImageSaved &jpeg, bool overwrite = true);
TaskId startImageLoad(const StorageKey &location, mtpFileLoader *loader); TaskId startImageLoad(const StorageKey &location, mtpFileLoader *loader);
StorageImageSaved readImage(const StorageKey &location);
int32 hasImages(); int32 hasImages();
qint64 storageImagesSize(); qint64 storageImagesSize();
void writeStickerImage(const StorageKey &location, const QByteArray &data, bool overwrite = true); void writeStickerImage(const StorageKey &location, const QByteArray &data, bool overwrite = true);
TaskId startStickerImageLoad(const StorageKey &location, mtpFileLoader *loader); TaskId startStickerImageLoad(const StorageKey &location, mtpFileLoader *loader);
QByteArray readStickerImage(const StorageKey &location);
int32 hasStickers(); int32 hasStickers();
qint64 storageStickersSize(); qint64 storageStickersSize();
void writeAudio(const StorageKey &location, const QByteArray &data, bool overwrite = true); void writeAudio(const StorageKey &location, const QByteArray &data, bool overwrite = true);
TaskId startAudioLoad(const StorageKey &location, mtpFileLoader *loader); TaskId startAudioLoad(const StorageKey &location, mtpFileLoader *loader);
QByteArray readAudio(const StorageKey &location);
int32 hasAudios(); int32 hasAudios();
qint64 storageAudiosSize(); qint64 storageAudiosSize();

View File

@ -3568,6 +3568,11 @@ void MainWidget::onSelfParticipantUpdated(ChannelData *channel) {
} }
} }
bool MainWidget::contentOverlapped(const QRect &globalRect) {
return (history.contentOverlapped(globalRect) ||
_mediaType.overlaps(globalRect));
}
void MainWidget::usernameResolveDone(QPair<bool, QString> toProfileStartToken, const MTPcontacts_ResolvedPeer &result) { void MainWidget::usernameResolveDone(QPair<bool, QString> toProfileStartToken, const MTPcontacts_ResolvedPeer &result) {
App::wnd()->hideLayer(); App::wnd()->hideLayer();
if (result.type() != mtpc_contacts_resolvedPeer) return; if (result.type() != mtpc_contacts_resolvedPeer) return;

View File

@ -398,6 +398,8 @@ public:
void gotRangeDifference(ChannelData *channel, const MTPupdates_ChannelDifference &diff); void gotRangeDifference(ChannelData *channel, const MTPupdates_ChannelDifference &diff);
void onSelfParticipantUpdated(ChannelData *channel); void onSelfParticipantUpdated(ChannelData *channel);
bool contentOverlapped(const QRect &globalRect);
~MainWidget(); ~MainWidget();
signals: signals:

View File

@ -335,11 +335,9 @@ bool mtpFileLoader::tryLoadLocal() {
if (duplicateInData) { if (duplicateInData) {
MediaKey mkey = mediaKey(_locationType, dc, id); MediaKey mkey = mediaKey(_locationType, dc, id);
if (_locationType == DocumentFileLocation) { if (_locationType == DocumentFileLocation) {
data = Local::readStickerImage(mkey); _localTaskId = Local::startStickerImageLoad(mkey, this);
if (!data.isEmpty()) type = mtpc_storage_filePartial;
} else if (_locationType == AudioFileLocation) { } else if (_locationType == AudioFileLocation) {
data = Local::readAudio(mkey); _localTaskId = Local::startAudioLoad(mkey, this);
if (!data.isEmpty()) type = mtpc_storage_filePartial;
} }
} }
} }
@ -382,7 +380,7 @@ void mtpFileLoader::localLoaded(const StorageImageSaved &result, const QByteArra
} }
data = result.data; data = result.data;
type = mtpFromStorageType(result.type); type = mtpFromStorageType(result.type);
if (_locationType == UnknownFileLocation) { // photo if (!imagePixmap.isNull()) {
_imageFormat = imageFormat; _imageFormat = imageFormat;
_imagePixmap = imagePixmap; _imagePixmap = imagePixmap;
} }

View File

@ -988,6 +988,8 @@ QPixmap OverviewInner::genPix(PhotoData *photo, int32 size) {
} }
void OverviewInner::paintEvent(QPaintEvent *e) { void OverviewInner::paintEvent(QPaintEvent *e) {
if (App::wnd() && App::wnd()->contentOverlapped(this, e)) return;
Painter p(this); Painter p(this);
QRect r(e->rect()); QRect r(e->rect());
@ -1014,10 +1016,10 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
bool hasSel = !_selected.isEmpty(); bool hasSel = !_selected.isEmpty();
if (_type == OverviewPhotos) { if (_type == OverviewPhotos) {
int32 rowFrom = int32(r.top() - _addToY - st::overviewPhotoSkip) / int32(_vsize + st::overviewPhotoSkip);
int32 rowTo = int32(r.bottom() - _addToY - st::overviewPhotoSkip) / int32(_vsize + st::overviewPhotoSkip) + 1;
History::MediaOverview &overview(_hist->overview[_type]); History::MediaOverview &overview(_hist->overview[_type]);
int32 count = overview.size(); int32 count = overview.size();
int32 rowFrom = floorclamp(r.y() - _addToY - st::overviewPhotoSkip, _vsize + st::overviewPhotoSkip, 0, count);
int32 rowTo = ceilclamp(r.y() + r.height() - _addToY - st::overviewPhotoSkip, _vsize + st::overviewPhotoSkip, 0, count);
float64 w = float64(_width - st::overviewPhotoSkip) / _photosInRow; float64 w = float64(_width - st::overviewPhotoSkip) / _photosInRow;
for (int32 row = rowFrom; row < rowTo; ++row) { for (int32 row = rowFrom; row < rowTo; ++row) {
if (row * _photosInRow >= _photosToAdd + count) break; if (row * _photosInRow >= _photosToAdd + count) break;
@ -1097,10 +1099,10 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
} }
} }
} else if (_type == OverviewAudioDocuments) { } else if (_type == OverviewAudioDocuments) {
int32 from = int32(r.top() - _addToY) / int32(_audioHeight);
int32 to = int32(r.bottom() - _addToY) / int32(_audioHeight) + 1;
History::MediaOverview &overview(_hist->overview[_type]); History::MediaOverview &overview(_hist->overview[_type]);
int32 count = overview.size(); int32 count = overview.size();
int32 from = floorclamp(r.y() - _addToY, _audioHeight, 0, count);
int32 to = ceilclamp(r.y() + r.height() - _addToY, _audioHeight, 0, count);
p.translate(_audioLeft, _addToY + from * _audioHeight); p.translate(_audioLeft, _addToY + from * _audioHeight);
for (int32 index = from; index < to; ++index) { for (int32 index = from; index < to; ++index) {
if (index >= count) break; if (index >= count) break;
@ -1128,7 +1130,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
for (int32 i = 0, l = _items.size(); i < l; ++i) { for (int32 i = 0, l = _items.size(); i < l; ++i) {
if (i + 1 == l || _addToY + _items[i + 1].y > r.top()) { if (i + 1 == l || _addToY + _items[i + 1].y > r.top()) {
int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, top = st::linksMargin + st::linksBorder, curY = _items[i].y; int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, top = st::linksMargin + st::linksBorder, curY = _items[i].y;
if (_addToY + curY >= r.bottom()) break; if (_addToY + curY >= r.y() + r.height()) break;
p.translate(0, curY - y); p.translate(0, curY - y);
if (_items[i].msgid) { // draw item if (_items[i].msgid) { // draw item
@ -1220,7 +1222,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
--i; --i;
if (!i || (_addToY + _height - _items[i - 1].y > r.top())) { if (!i || (_addToY + _height - _items[i - 1].y > r.top())) {
int32 curY = _height - _items[i].y; int32 curY = _height - _items[i].y;
if (_addToY + curY >= r.bottom()) break; if (_addToY + curY >= r.y() + r.height()) break;
p.translate(0, curY - y); p.translate(0, curY - y);
if (_items[i].msgid) { // draw item if (_items[i].msgid) { // draw item
@ -2598,7 +2600,9 @@ void OverviewWidget::resizeEvent(QResizeEvent *e) {
} }
void OverviewWidget::paintEvent(QPaintEvent *e) { void OverviewWidget::paintEvent(QPaintEvent *e) {
QPainter p(this); if (App::wnd() && App::wnd()->contentOverlapped(this, e)) return;
Painter p(this);
if (animating() && _showing) { if (animating() && _showing) {
p.setOpacity(a_bgAlpha.current()); p.setOpacity(a_bgAlpha.current());
p.drawPixmap(a_bgCoord.current(), 0, _bgAnimCache); p.drawPixmap(a_bgCoord.current(), 0, _bgAnimCache);

View File

@ -651,6 +651,8 @@ bool ProfileInner::event(QEvent *e) {
} }
void ProfileInner::paintEvent(QPaintEvent *e) { void ProfileInner::paintEvent(QPaintEvent *e) {
if (App::wnd() && App::wnd()->contentOverlapped(this, e)) return;
Painter p(this); Painter p(this);
QRect r(e->rect()); QRect r(e->rect());
@ -810,7 +812,7 @@ void ProfileInner::paintEvent(QPaintEvent *e) {
for (Participants::const_iterator i = _participants.cbegin(), e = _participants.cend(); i != e; ++i, ++cnt) { for (Participants::const_iterator i = _participants.cbegin(), e = _participants.cend(); i != e; ++i, ++cnt) {
int32 top = partfrom + cnt * _pHeight; int32 top = partfrom + cnt * _pHeight;
if (top + _pHeight <= r.top()) continue; if (top + _pHeight <= r.top()) continue;
if (top > r.bottom()) break; if (top >= r.y() + r.height()) break;
if (_selectedRow == cnt) { if (_selectedRow == cnt) {
p.fillRect(_left - st::profileListPadding.width(), top, _width + 2 * st::profileListPadding.width(), _pHeight, st::profileHoverBG->b); p.fillRect(_left - st::profileListPadding.width(), top, _width + 2 * st::profileListPadding.width(), _pHeight, st::profileHoverBG->b);
@ -1553,7 +1555,9 @@ void ProfileWidget::mousePressEvent(QMouseEvent *e) {
} }
void ProfileWidget::paintEvent(QPaintEvent *e) { void ProfileWidget::paintEvent(QPaintEvent *e) {
QPainter p(this); if (App::wnd() && App::wnd()->contentOverlapped(this, e)) return;
Painter p(this);
if (animating() && _showing) { if (animating() && _showing) {
p.setOpacity(a_bgAlpha.current()); p.setOpacity(a_bgAlpha.current());
p.drawPixmap(a_bgCoord.current(), 0, _bgAnimCache); p.drawPixmap(a_bgCoord.current(), 0, _bgAnimCache);

View File

@ -208,7 +208,7 @@ void settingsParseArgs(int argc, char *argv[]) {
RecentEmojiPack &cGetRecentEmojis() { RecentEmojiPack &cGetRecentEmojis() {
if (cRecentEmojis().isEmpty()) { if (cRecentEmojis().isEmpty()) {
RecentEmojiPack r; RecentEmojiPack r;
if (!cRecentEmojisPreload().isEmpty()) { if (!cRecentEmojisPreload().isEmpty() && false) {
RecentEmojisPreload p(cRecentEmojisPreload()); RecentEmojisPreload p(cRecentEmojisPreload());
cSetRecentEmojisPreload(RecentEmojisPreload()); cSetRecentEmojisPreload(RecentEmojisPreload());
r.reserve(p.size()); r.reserve(p.size());

View File

@ -205,7 +205,8 @@ RecentStickerPack &cGetRecentStickers();
DeclareSetting(uint64, LastStickersUpdate); DeclareSetting(uint64, LastStickersUpdate);
static const uint64 DefaultStickerSetId = 0; // for backward compatibility static const uint64 DefaultStickerSetId = 0; // for backward compatibility
static const uint64 CustomStickerSetId = 0xFFFFFFFFFFFFFFFFLLU, RecentStickerSetId = 0xFFFFFFFFFFFFFFFELLU; static const uint64 CustomStickerSetId = 0xFFFFFFFFFFFFFFFFULL, RecentStickerSetId = 0xFFFFFFFFFFFFFFFEULL;
static const uint64 NoneStickerSetId = 0xFFFFFFFFFFFFFFFDULL; // for emoji/stickers panel
struct StickerSet { struct StickerSet {
StickerSet(uint64 id, uint64 access, const QString &title, const QString &shortName, int32 count, int32 hash, int32 flags) : id(id), access(access), title(title), shortName(shortName), count(count), hash(hash), flags(flags) { StickerSet(uint64 id, uint64 access, const QString &title, const QString &shortName, int32 count, int32 hash, int32 flags) : id(id), access(access), title(title), shortName(shortName), count(count), hash(hash), flags(flags) {
} }

View File

@ -936,6 +936,9 @@ struct DocumentData {
if (loader->done()) { if (loader->done()) {
location = FileLocation(mtpToStorageType(loader->fileType()), loader->fileName()); location = FileLocation(mtpToStorageType(loader->fileType()), loader->fileName());
data = loader->bytes(); data = loader->bytes();
if (sticker() && !loader->imagePixmap().isNull()) {
sticker()->img = ImagePtr(data, loader->imageFormat(), loader->imagePixmap());
}
} }
loader->deleteLater(); loader->deleteLater();
loader->rpcInvalidate(); loader->rpcInvalidate();

View File

@ -65,6 +65,7 @@ TitleWidget::TitleWidget(Window *window)
, lastMaximized(!(window->windowState() & Qt::WindowMaximized)) , lastMaximized(!(window->windowState() & Qt::WindowMaximized))
{ {
setGeometry(0, 0, wnd->width(), st::titleHeight); setGeometry(0, 0, wnd->width(), st::titleHeight);
setAttribute(Qt::WA_OpaquePaintEvent);
_lock.hide(); _lock.hide();
_update.hide(); _update.hide();
_cancel.hide(); _cancel.hide();
@ -363,7 +364,7 @@ void TitleWidget::maximizedChanged(bool maximized, bool force) {
HitTestType TitleWidget::hitTest(const QPoint &p) { HitTestType TitleWidget::hitTest(const QPoint &p) {
if (App::wnd() && App::wnd()->layerShown()) return HitTestNone; if (App::wnd() && App::wnd()->layerShown()) return HitTestNone;
int x(p.x()), y(p.y()), w(width()), h(height() - st::titleShadow); int x(p.x()), y(p.y()), w(width()), h(height());
if (cWideMode() && hider && x >= App::main()->dlgsWidth()) return HitTestNone; if (cWideMode() && hider && x >= App::main()->dlgsWidth()) return HitTestNone;
if (x >= st::titleIconPos.x() && y >= st::titleIconPos.y() && x < st::titleIconPos.x() + st::titleIconImg.pxWidth() && y < st::titleIconPos.y() + st::titleIconImg.pxHeight()) { if (x >= st::titleIconPos.x() && y >= st::titleIconPos.y() && x < st::titleIconPos.x() + st::titleIconImg.pxWidth() && y < st::titleIconPos.y() + st::titleIconImg.pxHeight()) {

View File

@ -417,3 +417,16 @@ private:
MimeType mimeTypeForName(const QString &mime); MimeType mimeTypeForName(const QString &mime);
MimeType mimeTypeForFile(const QFileInfo &file); MimeType mimeTypeForFile(const QFileInfo &file);
MimeType mimeTypeForData(const QByteArray &data); MimeType mimeTypeForData(const QByteArray &data);
inline int32 floorclamp(int32 value, int32 step, int32 lowest, int32 highest) {
return qMin(qMax(value / step, lowest), highest);
}
inline int32 floorclamp(float64 value, int32 step, int32 lowest, int32 highest) {
return qMin(qMax(qFloor(value / step), lowest), highest);
}
inline int32 ceilclamp(int32 value, int32 step, int32 lowest, int32 highest) {
return qMax(qMin((value / step) + ((value % step) ? 1 : 0), highest), lowest);
}
inline int32 ceilclamp(float64 value, int32 step, int32 lowest, int32 highest) {
return qMax(qMin(qCeil(value / step), highest), lowest);
}

View File

@ -865,6 +865,12 @@ void Window::hideMediaview() {
} }
} }
bool Window::contentOverlapped(const QRect &globalRect) {
if (main && main->contentOverlapped(globalRect)) return true;
if (layerBG && layerBG->contentOverlapped(globalRect)) return true;
return false;
}
void Window::setInnerFocus() { void Window::setInnerFocus() {
if (layerBG && layerBG->canSetFocus()) { if (layerBG && layerBG->canSetFocus()) {
layerBG->setInnerFocus(); layerBG->setInnerFocus();
@ -1177,7 +1183,7 @@ void Window::resizeEvent(QResizeEvent *e) {
cSetWideMode(wideMode); cSetWideMode(wideMode);
updateWideMode(); updateWideMode();
} }
title->setGeometry(QRect(0, 0, width(), st::titleHeight + st::titleShadow)); title->setGeometry(0, 0, width(), st::titleHeight);
if (layerBG) layerBG->resize(width(), height()); if (layerBG) layerBG->resize(width(), height());
if (_connecting) _connecting->setGeometry(0, height() - _connecting->height(), _connecting->width(), _connecting->height()); if (_connecting) _connecting->setGeometry(0, height() - _connecting->height(), _connecting->width(), _connecting->height());
emit resized(QSize(width(), height() - st::titleHeight)); emit resized(QSize(width(), height() - st::titleHeight));

View File

@ -233,6 +233,14 @@ public:
bool isActive(bool cached = true) const; bool isActive(bool cached = true) const;
void hideMediaview(); void hideMediaview();
bool contentOverlapped(const QRect &globalRect);
bool contentOverlapped(QWidget *w, QPaintEvent *e) {
return contentOverlapped(QRect(w->mapToGlobal(e->rect().topLeft()), e->rect().size()));
}
bool contentOverlapped(QWidget *w, const QRegion &r) {
return contentOverlapped(QRect(w->mapToGlobal(r.boundingRect().topLeft()), r.boundingRect().size()));
}
public slots: public slots:
void updateIsActive(int timeout = 0); void updateIsActive(int timeout = 0);