savedgifs -> contextitems in stickers panel, fixed atomic uint64, now with mutex :(

This commit is contained in:
John Preston 2015-12-30 14:47:39 +08:00
parent 96a698a4dc
commit cbb0219812
15 changed files with 661 additions and 448 deletions

View File

@ -578,7 +578,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
"lng_media_auto_settings" = "Automatic media download settings";
"lng_media_auto_photo" = "Automatic photo download";
"lng_media_auto_audio" = "Automatic audio download";
"lng_media_auto_audio" = "Automatic voice message download";
"lng_media_auto_gif" = "Automatic GIF download";
"lng_media_auto_private_chats" = "Private chats";
"lng_media_auto_groups" = "Groups and channels";

View File

@ -1213,7 +1213,8 @@ void EmojiPanInner::showEmojiPack(DBIEmojiTab packIndex) {
StickerPanInner::StickerPanInner() : TWidget()
, _a_selected(animation(this, &StickerPanInner::step_selected))
, _top(0)
, _showingGifs(cShowingSavedGifs())
, _showingSavedGifs(cShowingSavedGifs())
, _showingContextItems(_showingSavedGifs)
, _selected(-1)
, _pressedSel(-1)
, _settings(this, lang(lng_stickers_you_have))
@ -1246,8 +1247,11 @@ void StickerPanInner::setScrollTop(int top) {
int StickerPanInner::countHeight() {
int result = 0, minLastH = _maxHeight - st::rbEmoji.height - st::stickerPanPadding;
if (_showingGifs) {
result = st::emojiPanHeader + _gifRows.count() * (st::savedGifHeight + st::savedGifsSkip) - st::savedGifsSkip;
if (_showingContextItems) {
result = st::emojiPanHeader;
for (int i = 0, l = _contextRows.count(); i < l; ++i) {
result += _contextRows.at(i).height;
}
} else {
for (int i = 0; i < _sets.size(); ++i) {
int cnt = _sets.at(i).pack.size(), rows = (cnt / StickerPanPerRow) + ((cnt % StickerPanPerRow) ? 1 : 0);
@ -1284,33 +1288,36 @@ void StickerPanInner::paintEvent(QPaintEvent *e) {
}
p.fillRect(r, st::white);
if (_showingGifs) {
paintSavedGifs(p, r);
if (_showingContextItems) {
paintContextItems(p, r);
} else {
paintStickers(p, r);
}
}
void StickerPanInner::paintSavedGifs(Painter &p, const QRect &r) {
uint64 ms = getms();
void StickerPanInner::paintContextItems(Painter &p, const QRect &r) {
ContextPaintContext context(getms(), false, _previewShown);
int32 fromrow = floorclamp(r.y() - st::emojiPanHeader, st::savedGifHeight + st::savedGifsSkip, 0, _gifRows.size());
int32 torow = ceilclamp(r.y() + r.height() - st::emojiPanHeader - st::savedGifsSkip, st::savedGifHeight + st::savedGifsSkip, 0, _gifRows.size());
int32 top = st::emojiPanHeader;
int32 fromx = rtl() ? (width() - r.x() - r.width()) : r.x(), tox = rtl() ? (width() - r.x()) : (r.x() + r.width());
for (int32 row = fromrow; row < torow; ++row) {
const GifRow &gifRow(_gifRows.at(row));
int32 left = st::savedGifsLeft, top = st::emojiPanHeader + row * (st::savedGifHeight + st::savedGifsSkip);
for (int32 col = 0, cols = gifRow.size(); col < cols; ++col) {
if (left >= tox) break;
for (int32 row = 0, rows = _contextRows.size(); row < rows; ++row) {
const ContextRow &contextRow(_contextRows.at(row));
if (top >= r.top() + r.height()) break;
if (top + contextRow.height > r.top()) {
int32 left = st::savedGifsLeft;
for (int32 col = 0, cols = contextRow.items.size(); col < cols; ++col) {
if (left >= tox) break;
int32 w = gifRow.at(col)->width();
if (left + w > fromx) {
p.translate(left, top);
gifRow.at(col)->paint(p, _previewShown, ms);
p.translate(-left, -top);
int32 w = contextRow.items.at(col)->width();
if (left + w > fromx) {
p.translate(left, top);
contextRow.items.at(col)->paint(p, r.translated(-left, -top), 0, &context);
p.translate(-left, -top);
}
left += w + st::savedGifsSkip;
}
left += w + st::savedGifsSkip;
}
top += contextRow.height;
}
}
@ -1392,6 +1399,7 @@ void StickerPanInner::mousePressEvent(QMouseEvent *e) {
updateSelected();
_pressedSel = _selected;
textlnkDown(textlnkOver());
_previewTimer.start(QApplication::startDragTime());
}
@ -1399,7 +1407,9 @@ void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) {
_previewTimer.stop();
int32 pressed = _pressedSel;
TextLinkPtr down(textlnkDown());
_pressedSel = -1;
textlnkDown(TextLinkPtr());
_lastMousePos = e->globalPos();
updateSelected();
@ -1409,31 +1419,24 @@ void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) {
return;
}
if (_selected < 0 || _selected != pressed) return;
if (_showingGifs) {
if (_selected < 0 || _selected != pressed || textlnkOver() != down) return;
if (_showingContextItems) {
int32 row = _selected / MatrixRowShift, col = _selected % MatrixRowShift;
bool del = (col >= SavedGifsMaxPerRow);
if (del) col -= SavedGifsMaxPerRow;
if (row < _gifRows.size() && col < _gifRows.at(row).size()) {
DocumentData *doc = _gifRows.at(row).at(col)->document();
if (del) {
int32 index = cSavedGifs().indexOf(doc);
if (index >= 0) {
cRefSavedGifs().remove(index);
Local::writeSavedGifs();
if (App::main()) emit App::main()->savedGifsUpdated();
if (row < _contextRows.size() && col < _contextRows.at(row).items.size()) {
if (down) {
if (down->type() == qstr("SendContextItemLink") && e->button() == Qt::LeftButton) {
DocumentData *doc = _contextRows.at(row).items.at(col)->document();
if (!doc) return;
MTP::send(MTPmessages_SaveGif(MTP_inputDocument(MTP_long(doc->id), MTP_long(doc->access)), MTP_bool(true)));
if (doc->loaded()) {
emit selected(doc);
} else if (doc->loading()) {
doc->cancel();
} else {
DocumentOpenLink::doOpen(doc, ActionOnLoadNone);
}
} else {
refreshSavedGifs();
}
} else {
if (doc->loaded()) {
emit selected(doc);
} else if (doc->loading()) {
doc->cancel();
} else {
DocumentOpenLink::doOpen(doc, ActionOnLoadNone);
down->onClick(e->button());
}
}
}
@ -1505,14 +1508,13 @@ void StickerPanInner::enterFromChildEvent(QEvent *e) {
void StickerPanInner::clearSelection(bool fast) {
_lastMousePos = mapToGlobal(QPoint(-10, -10));
if (fast) {
if (_showingGifs) {
if (_showingContextItems) {
if (_selected >= 0) {
int32 srow = _selected / MatrixRowShift, scol = _selected % MatrixRowShift;
bool sdel = (scol >= SavedGifsMaxPerRow);
if (sdel) scol -= SavedGifsMaxPerRow;
if (srow < _gifRows.size() && scol < _gifRows.at(srow).size()) {
_gifRows.at(srow).at(scol)->notify_over(false);
if (sdel) _gifRows.at(srow).at(scol)->notify_deleteOver(false);
t_assert(srow >= 0 && srow < _contextRows.size() && scol >= 0 && scol < _contextRows.at(srow).items.size());
if (textlnkOver()) {
_contextRows.at(srow).items.at(scol)->linkOut(textlnkOver());
textlnkOver(TextLinkPtr());
}
setCursor(style::cur_default);
}
@ -1548,10 +1550,18 @@ void StickerPanInner::clearSelection(bool fast) {
}
void StickerPanInner::hideFinish() {
clearSavedGifs();
clearContextRows();
for (GifLayouts::const_iterator i = _gifLayouts.cbegin(), e = _gifLayouts.cend(); i != e; ++i) {
i.value()->document()->forget();
}
for (ContextLayouts::const_iterator i = _contextLayouts.cbegin(), e = _contextLayouts.cend(); i != e; ++i) {
if (i.value()->result()->doc) {
i.value()->result()->doc->forget();
}
if (i.value()->result()->photo) {
i.value()->result()->photo->forget();
}
}
}
void StickerPanInner::refreshStickers() {
@ -1565,13 +1575,13 @@ void StickerPanInner::refreshStickers() {
appendSet(*i);
}
if (!_showingGifs) {
if (_showingContextItems) {
_settings.hide();
} else {
int32 h = countHeight();
if (h != height()) resize(width(), h);
_settings.setVisible(_sets.isEmpty());
} else {
_settings.hide();
}
@ -1583,69 +1593,88 @@ void StickerPanInner::refreshStickers() {
void StickerPanInner::refreshSavedGifs() {
clearSelection(true);
clearSavedGifs();
if (_showingGifs) {
const SavedGifs &saved(cSavedGifs());
if (saved.isEmpty()) {
showStickerSet(RecentStickerSetId);
return;
} else {
_gifRows.reserve(saved.size());
GifRow row;
row.reserve(SavedGifsMaxPerRow);
int32 maxWidth = width() - st::savedGifsLeft, sumWidth = 0, widths[SavedGifsMaxPerRow] = { 0 };
for (SavedGifs::const_iterator i = saved.cbegin(), e = saved.cend(); i != e; ++i) {
DocumentData *doc = *i;
int32 w = doc->dimensions.width(), h = doc->dimensions.height();
if ((w <= 0 || h <= 0) && !doc->thumb->isNull()) {
w = doc->thumb->width();
h = doc->thumb->height();
if (_showingSavedGifs) {
clearContextRows();
if (_showingContextItems) {
const SavedGifs &saved(cSavedGifs());
if (saved.isEmpty()) {
showStickerSet(RecentStickerSetId);
return;
} else {
_contextRows.reserve(saved.size());
ContextRow row;
row.items.reserve(SavedGifsMaxPerRow);
int32 maxWidth = width() - st::savedGifsLeft, sumWidth = 0, widths[SavedGifsMaxPerRow] = { 0 };
for (SavedGifs::const_iterator i = saved.cbegin(), e = saved.cend(); i != e; ++i) {
DocumentData *doc = *i;
int32 w = doc->dimensions.width(), h = doc->dimensions.height();
if ((w <= 0 || h <= 0) && !doc->thumb->isNull()) {
w = doc->thumb->width();
h = doc->thumb->height();
}
if (w <= 0 || h <= 0) continue;
w = w * st::savedGifHeight / h;
widths[row.items.size()] = w;
w = qMax(w, int32(st::savedGifMinWidth));
sumWidth += w;
row.items.push_back(layoutPrepare(doc, (_contextRows.size() * MatrixRowShift) + row.items.size(), w));
if (row.items.size() >= SavedGifsMaxPerRow || sumWidth >= maxWidth - (row.items.size() - 1) * st::savedGifsSkip) {
_contextRows.push_back(layoutContextRow(row, widths, sumWidth));
row = ContextRow();
sumWidth = 0;
memset(widths, 0, sizeof(widths));
}
}
if (w <= 0 || h <= 0) continue;
w = w * st::savedGifHeight / h;
widths[row.size()] = w;
w = qMax(w, int32(st::savedGifMinWidth));
sumWidth += w;
row.push_back(layoutPrepare(doc, (_gifRows.size() * MatrixRowShift) + row.size(), w));
if (row.size() >= SavedGifsMaxPerRow || sumWidth >= maxWidth - (row.size() - 1) * st::savedGifsSkip) {
_gifRows.push_back(layoutGifRow(row, widths, sumWidth));
row.clear();
row.reserve(SavedGifsMaxPerRow);
sumWidth = 0;
memset(widths, 0, sizeof(widths));
if (!row.items.isEmpty()) {
_contextRows.push_back(layoutContextRow(row, 0, 0));
}
}
if (!row.isEmpty()) {
_gifRows.push_back(row);
}
deleteUnusedGifLayouts();
int32 h = countHeight();
if (h != height()) resize(width(), h);
update();
}
deleteUnusedLayouts();
int32 h = countHeight();
if (h != height()) resize(width(), h);
update();
}
emit refreshIcons();
updateSelected();
}
void StickerPanInner::clearSavedGifs() {
for (GifRows::const_iterator i = _gifRows.cbegin(), e = _gifRows.cend(); i != e; ++i) {
for (GifRow::const_iterator j = i->cbegin(), end = i->cend(); j != end; ++j) {
void StickerPanInner::refreshContextResults(const ContextResults &results) {
}
void StickerPanInner::contextBotChanged() {
refreshContextResults(ContextResults());
deleteUnusedContextLayouts();
}
void StickerPanInner::clearContextRows() {
for (ContextRows::const_iterator i = _contextRows.cbegin(), e = _contextRows.cend(); i != e; ++i) {
for (ContextItems::const_iterator j = i->items.cbegin(), end = i->items.cend(); j != end; ++j) {
(*j)->setPosition(-1, 0);
}
}
_gifRows.clear();
_contextRows.clear();
}
void StickerPanInner::deleteUnusedLayouts() {
if (_gifRows.isEmpty()) { // delete all
LayoutContextGif *StickerPanInner::layoutPrepare(DocumentData *doc, int32 position, int32 width) {
GifLayouts::const_iterator i = _gifLayouts.constFind(doc);
if (i == _gifLayouts.cend()) {
i = _gifLayouts.insert(doc, new LayoutContextGif(doc, true));
i.value()->initDimensions();
}
i.value()->setPosition(position, width);
return i.value();
}
void StickerPanInner::deleteUnusedGifLayouts() {
if (_contextRows.isEmpty()) { // delete all
for (GifLayouts::const_iterator i = _gifLayouts.cbegin(), e = _gifLayouts.cend(); i != e; ++i) {
delete i.value();
}
@ -1662,26 +1691,36 @@ void StickerPanInner::deleteUnusedLayouts() {
}
}
LayoutSavedGif *StickerPanInner::layoutPrepare(DocumentData *doc, int32 position, int32 width) {
GifLayouts::const_iterator i = _gifLayouts.constFind(doc);
if (i == _gifLayouts.cend()) {
i = _gifLayouts.insert(doc, new LayoutSavedGif(doc));
void StickerPanInner::deleteUnusedContextLayouts() {
if (_contextRows.isEmpty()) { // delete all
for (ContextLayouts::const_iterator i = _contextLayouts.cbegin(), e = _contextLayouts.cend(); i != e; ++i) {
delete i.value();
}
_contextLayouts.clear();
} else {
for (ContextLayouts::iterator i = _contextLayouts.begin(); i != _contextLayouts.cend();) {
if (i.value()->position() < 0) {
delete i.value();
i = _contextLayouts.erase(i);
} else {
++i;
}
}
}
i.value()->setPosition(position, width);
return i.value();
}
const StickerPanInner::GifRow &StickerPanInner::layoutGifRow(const GifRow &row, int32 *widths, int32 sumWidth) {
int32 count = row.size();
StickerPanInner::ContextRow &StickerPanInner::layoutContextRow(ContextRow &row, int32 *widths, int32 sumWidth) {
int32 count = row.items.size();
t_assert(count <= SavedGifsMaxPerRow);
row.height = 0;
int32 availw = width() - st::savedGifsLeft - st::savedGifsSkip * (count - 1);
if (sumWidth != availw) {
for (int32 i = 0; i < count; ++i) {
int32 w = widths[i] * availw / sumWidth;
int32 actualw = qMax(w, int32(st::savedGifMinWidth));
row.at(i)->setWidth(actualw);
for (int32 i = 0; i < count; ++i) {
int32 w = widths ? (widths[i] * availw / sumWidth) : row.items.at(i)->width();
int32 actualw = qMax(w, int32(st::savedGifMinWidth));
row.height = qMax(row.height, row.items.at(i)->resizeGetHeight(actualw));
if (widths) {
availw -= actualw;
sumWidth -= qMax(widths[i], int32(st::savedGifMinWidth));
}
@ -1690,14 +1729,15 @@ const StickerPanInner::GifRow &StickerPanInner::layoutGifRow(const GifRow &row,
}
void StickerPanInner::preloadImages() {
if (_showingGifs) {
for (int32 row = 0, rows = _gifRows.size(); row < rows; ++row) {
for (int32 col = 0, cols = _gifRows.at(row).size(); col < cols; ++col) {
_gifRows.at(row).at(col)->preload();
if (_showingContextItems) {
for (int32 row = 0, rows = _contextRows.size(); row < rows; ++row) {
for (int32 col = 0, cols = _contextRows.at(row).items.size(); col < cols; ++col) {
_contextRows.at(row).items.at(col)->preload();
}
}
return;
}
uint64 ms = getms();
for (int32 i = 0, l = _sets.size(), k = 0; i < l; ++i) {
for (int32 j = 0, n = _sets.at(i).pack.size(); j < n; ++j) {
if (++k > StickerPanPerRow * (StickerPanPerRow + 1)) break;
@ -1717,7 +1757,7 @@ void StickerPanInner::preloadImages() {
}
uint64 StickerPanInner::currentSet(int yOffset) const {
if (_showingGifs) return NoneStickerSetId;
if (_showingContextItems) return NoneStickerSetId;
int y, ytill = 0;
for (int i = 0, l = _sets.size(); i < l; ++i) {
@ -1731,31 +1771,45 @@ uint64 StickerPanInner::currentSet(int yOffset) const {
return _sets.isEmpty() ? RecentStickerSetId : _sets.back().id;
}
void StickerPanInner::ui_repaintSavedGif(const LayoutSavedGif *layout) {
if (!_showingGifs) return;
void StickerPanInner::refreshContextRows(const ContextResults &results) {
int32 position = layout->position();
int32 row = position / MatrixRowShift, col = position % MatrixRowShift;
t_assert((row < _gifRows.size()) && (col < _gifRows.at(row).size()));
const GifRow &gifRow(_gifRows.at(row));
int32 left = st::savedGifsLeft, top = st::emojiPanHeader + row * (st::savedGifHeight + st::savedGifsSkip);
for (int32 i = 0; i < col; ++i) left += gifRow.at(i)->width() + st::savedGifsSkip;
rtlupdate(left, top, gifRow.at(col)->width(), st::savedGifHeight);
}
bool StickerPanInner::ui_isSavedGifVisible(const LayoutSavedGif *layout) {
void StickerPanInner::ui_repaintContextItem(const LayoutContextItem *layout) {
int32 position = layout->position();
int32 row = position / MatrixRowShift, col = position % MatrixRowShift;
t_assert((row < _gifRows.size()) && (col < _gifRows.at(row).size()));
if (!_showingContextItems || position < 0) return;
int32 top = st::emojiPanHeader + row * (st::savedGifHeight + st::savedGifsSkip);
return (top < _top + _maxHeight) && (top + st::savedGifHeight > _top);
int32 row = position / MatrixRowShift, col = position % MatrixRowShift;
t_assert((row < _contextRows.size()) && (col < _contextRows.at(row).items.size()));
const ContextItems &contextItems(_contextRows.at(row).items);
int32 left = st::savedGifsLeft, top = st::emojiPanHeader;
for (int32 i = 0; i < row; ++i) {
top += _contextRows.at(i).height;
}
for (int32 i = 0; i < col; ++i) left += contextItems.at(i)->width() + st::savedGifsSkip;
rtlupdate(left, top, contextItems.at(col)->width(), contextItems.at(col)->height());
}
bool StickerPanInner::ui_isGifBeingChosen() {
return _showingGifs;
bool StickerPanInner::ui_isContextItemVisible(const LayoutContextItem *layout) {
int32 position = layout->position();
if (!_showingContextItems || position < 0) return false;
int32 row = position / MatrixRowShift, col = position % MatrixRowShift;
t_assert((row < _contextRows.size()) && (col < _contextRows.at(row).items.size()));
const ContextItems &contextItems(_contextRows.at(row).items);
int32 top = st::emojiPanHeader;
for (int32 i = 0; i < row; ++i) {
top += _contextRows.at(i).height;
}
return (top < _top + _maxHeight) && (top + _contextRows.at(row).items.at(col)->height() > _top);
}
bool StickerPanInner::ui_isContextItemBeingChosen() {
return _showingContextItems;
}
void StickerPanInner::appendSet(uint64 setId) {
@ -1772,8 +1826,10 @@ void StickerPanInner::appendSet(uint64 setId) {
}
void StickerPanInner::refreshRecent() {
if (_showingGifs) {
refreshSavedGifs();
if (_showingContextItems) {
if (_showingSavedGifs) {
refreshSavedGifs();
}
} else {
refreshRecentStickers();
}
@ -1816,7 +1872,7 @@ void StickerPanInner::refreshRecentStickers(bool performResize) {
}
}
if (performResize && !_showingGifs) {
if (performResize && !_showingContextItems) {
int32 h = countHeight();
if (h != height()) {
resize(width(), h);
@ -1860,7 +1916,7 @@ void StickerPanInner::fillPanels(QVector<EmojiPanel*> &panels) {
}
panels.clear();
if (_showingGifs) {
if (_showingContextItems) {
panels.push_back(new EmojiPanel(parentWidget(), lang(lng_saved_gifs), NoneStickerSetId, true, 0));
panels.back()->show();
return;
@ -1882,7 +1938,7 @@ void StickerPanInner::fillPanels(QVector<EmojiPanel*> &panels) {
}
void StickerPanInner::refreshPanels(QVector<EmojiPanel*> &panels) {
if (_showingGifs) return;
if (_showingContextItems) return;
if (panels.size() != _sets.size()) return fillPanels(panels);
@ -1901,58 +1957,55 @@ void StickerPanInner::updateSelected() {
int32 selIndex = -1;
QPoint p(mapFromGlobal(_lastMousePos));
if (_showingGifs) {
if (_showingContextItems) {
int sx = (rtl() ? width() - p.x() : p.x()) - st::savedGifsLeft, sy = p.y() - st::emojiPanHeader;
int32 row = sy / int32(st::savedGifHeight + st::savedGifsSkip), col = 0, sel = -1;
bool del = false;
if (sx >= 0 && row >= 0 && row < _gifRows.size() && sy < (row + 1) * st::savedGifHeight) {
const GifRow &gifRow(_gifRows.at(row));
for (int32 left = 0, cols = gifRow.size(); col < cols; ++col) {
int32 width = gifRow.at(col)->width();
if (sx >= left && sx < left + width) {
del = (sx >= left + width - st::stickerPanDelete.pxWidth()) && (sy < row * st::savedGifHeight + st::stickerPanDelete.pxHeight());
int32 row = -1, col = -1, sel = -1;
TextLinkPtr lnk;
HistoryCursorState cursor = HistoryDefaultCursorState;
if (sy >= 0) {
row = 0;
for (int32 rows = _contextRows.size(); row < rows; ++row) {
if (sy < _contextRows.at(row).height) {
break;
}
left += width + st::savedGifsSkip;
sy -= _contextRows.at(row).height;
}
if (col < gifRow.size()) {
sel = row * MatrixRowShift + col + (del ? SavedGifsMaxPerRow : 0);
} else {
row = col = -1;
}
} else {
row = col = -1;
}
if (_selected != sel) {
if (sx >= 0 && row >= 0 && row < _contextRows.size()) {
const ContextItems &contextItems(_contextRows.at(row).items);
col = 0;
for (int32 cols = contextItems.size(); col < cols; ++col) {
int32 width = contextItems.at(col)->width();
if (sx < width) {
break;
}
sx -= width + st::savedGifsSkip;
}
if (col < contextItems.size()) {
sel = row * MatrixRowShift + col;
contextItems.at(col)->getState(lnk, cursor, sx, sy);
}
}
if (_selected != sel || textlnkOver() != lnk) {
int32 srow = (_selected >= 0) ? (_selected / MatrixRowShift) : -1;
int32 scol = (_selected >= 0) ? (_selected % MatrixRowShift) : -1;
bool sdel = (scol >= SavedGifsMaxPerRow);
if (sdel) scol -= SavedGifsMaxPerRow;
if (srow != row || scol != col) {
if (srow >= 0 && srow < _gifRows.size()) {
if (scol >= 0 && scol < _gifRows.at(srow).size()) {
_gifRows.at(srow).at(scol)->notify_over(false);
if (sdel) _gifRows.at(srow).at(scol)->notify_deleteOver(false);
}
}
if (row >= 0 && row < _gifRows.size()) {
if (col >= 0 && col < _gifRows.at(row).size()) {
_gifRows.at(row).at(col)->notify_over(true);
if (del) _gifRows.at(row).at(col)->notify_deleteOver(true);
}
}
} else if (sdel != del) {
if (sdel) _gifRows.at(srow).at(scol)->notify_deleteOver(false);
if (del) _gifRows.at(row).at(col)->notify_deleteOver(true);
if (srow >= 0 && scol >= 0 && textlnkOver()) {
t_assert(srow >= 0 && srow < _contextRows.size() && scol >= 0 && scol < _contextRows.at(srow).items.size());
_contextRows.at(srow).items.at(scol)->linkOut(textlnkOver());
}
if ((_selected >= 0 && sel < 0) || (_selected < 0 && sel >= 0)) {
setCursor(sel >= 0 ? style::cur_pointer : style::cur_default);
if ((textlnkOver() && !lnk) || (!textlnkOver() && lnk)) {
setCursor(lnk ? style::cur_pointer : style::cur_default);
}
_selected = sel;
textlnkOver(lnk);
if (row >= 0 && col >= 0 && textlnkOver()) {
t_assert(row >= 0 && row < _contextRows.size() && col >= 0 && col < _contextRows.at(row).items.size());
_contextRows.at(row).items.at(col)->linkOver(textlnkOver());
}
if (_pressedSel >= 0 && _selected >= 0 && _pressedSel != _selected) {
_pressedSel = _selected;
if (row >= 0 && col >= 0) {
Ui::showStickerPreview(_gifRows.at(row).at(col)->document());
if (row >= 0 && col >= 0 && _contextRows.at(row).items.at(col)->document()) {
Ui::showStickerPreview(_contextRows.at(row).items.at(col)->document());
}
}
}
@ -2046,11 +2099,11 @@ void StickerPanInner::onSettings() {
void StickerPanInner::onPreview() {
if (_pressedSel < 0) return;
if (_showingGifs) {
if (_showingContextItems) {
int32 row = _pressedSel / MatrixRowShift, col = _pressedSel % MatrixRowShift;
if (col >= SavedGifsMaxPerRow) col -= SavedGifsMaxPerRow;
if (row < _gifRows.size() && col < _gifRows.at(row).size() && _gifRows.at(row).at(col)->document()->loaded()) {
Ui::showStickerPreview(_gifRows.at(row).at(col)->document());
if (row < _contextRows.size() && col < _contextRows.at(row).items.size() && _contextRows.at(row).items.at(col)->document() && _contextRows.at(row).items.at(col)->document()->loaded()) {
Ui::showStickerPreview(_contextRows.at(row).items.at(col)->document());
_previewShown = true;
}
} else if (_pressedSel < MatrixRowShift * _sets.size()) {
@ -2084,12 +2137,12 @@ void StickerPanInner::showStickerSet(uint64 setId) {
clearSelection(true);
if (setId == NoneStickerSetId) {
if (_gifRows.isEmpty() && !cSavedGifs().isEmpty()) {
if (_contextRows.isEmpty() && !cSavedGifs().isEmpty()) {
refreshSavedGifs();
}
bool wasNotShowingGifs = !_showingGifs;
bool wasNotShowingGifs = !_showingContextItems;
if (wasNotShowingGifs) {
_showingGifs = true;
_showingContextItems = true;
cSetShowingSavedGifs(true);
emit saveConfigDelayed(SaveRecentEmojisTimeout);
}
@ -2099,8 +2152,8 @@ void StickerPanInner::showStickerSet(uint64 setId) {
return;
}
if (_showingGifs) {
_showingGifs = false;
if (_showingContextItems) {
_showingContextItems = false;
cSetShowingSavedGifs(false);
emit saveConfigDelayed(SaveRecentEmojisTimeout);
@ -2931,22 +2984,22 @@ void EmojiPan::stickersInstalled(uint64 setId) {
showStart();
}
void EmojiPan::ui_repaintSavedGif(const LayoutSavedGif *layout) {
void EmojiPan::ui_repaintContextItem(const LayoutContextItem *layout) {
if (_stickersShown && !isHidden()) {
s_inner.ui_repaintSavedGif(layout);
s_inner.ui_repaintContextItem(layout);
}
}
bool EmojiPan::ui_isSavedGifVisible(const LayoutSavedGif *layout) {
bool EmojiPan::ui_isContextItemVisible(const LayoutContextItem *layout) {
if (_stickersShown && !isHidden()) {
return s_inner.ui_isSavedGifVisible(layout);
return s_inner.ui_isContextItemVisible(layout);
}
return false;
}
bool EmojiPan::ui_isGifBeingChosen() {
bool EmojiPan::ui_isContextItemBeingChosen() {
if (_stickersShown && !isHidden()) {
return s_inner.ui_isGifBeingChosen();
return s_inner.ui_isContextItemBeingChosen();
}
return false;
}
@ -3165,12 +3218,18 @@ void EmojiPan::onDelayedHide() {
_removingSetId = 0;
}
void EmojiPan::clearContextResults() {
void EmojiPan::contextBotChanged() {
if (!_contextBot) return;
if (_contextRequestId) MTP::cancel(_contextRequestId);
_contextRequestId = 0;
_contextQuery = _contextNextQuery = _contextNextOffset = QString();
_contextBot = 0;
for (ContextCache::const_iterator i = _contextCache.cbegin(), e = _contextCache.cend(); i != e; ++i) {
delete i.value();
}
_contextCache.clear();
s_inner.contextBotChanged();
}
void EmojiPan::contextResultsDone(const MTPmessages_BotResults &result) {
@ -3185,54 +3244,56 @@ void EmojiPan::contextResultsDone(const MTPmessages_BotResults &result) {
uint64 queryId(d.vquery_id.v);
if (!adding) {
it = _contextCache.insert(_contextQuery, ContextCacheEntry());
it = _contextCache.insert(_contextQuery, new ContextCacheEntry());
}
it->nextOffset = v.isEmpty() ? QString() : qs(d.vnext_offset);
it.value()->nextOffset = v.isEmpty() ? QString() : qs(d.vnext_offset);
int32 count = v.size();
if (count) {
it->results.reserve(it->results.size() + count);
it.value()->results.reserve(it.value()->results.size() + count);
}
for (int32 i = 0; i < count; ++i) {
ContextResult result(queryId);
ContextResult *result = new ContextResult(queryId);
const MTPBotContextMessage *message = 0;
switch (v.at(i).type()) {
case mtpc_botContextMediaResultPhoto: {
const MTPDbotContextMediaResultPhoto &r(v.at(i).c_botContextMediaResultPhoto());
result.id = qs(r.vid);
result.type = qs(r.vtype);
result.photo = App::feedPhoto(r.vphoto);
result->id = qs(r.vid);
result->type = qs(r.vtype);
result->photo = App::feedPhoto(r.vphoto);
message = &r.vsend_message;
} break;
case mtpc_botContextMediaResultDocument: {
const MTPDbotContextMediaResultDocument &r(v.at(i).c_botContextMediaResultDocument());
result.id = qs(r.vid);
result.type = qs(r.vtype);
result.doc = App::feedDocument(r.vdocument);
result->id = qs(r.vid);
result->type = qs(r.vtype);
result->doc = App::feedDocument(r.vdocument);
message = &r.vsend_message;
} break;
case mtpc_botContextResult: {
const MTPDbotContextResult &r(v.at(i).c_botContextResult());
result.id = qs(r.vid);
result.type = qs(r.vtype);
result.title = qs(r.vtitle);
result.description = qs(r.vdescription);
result.url = qs(r.vurl);
result.thumb_url = qs(r.vthumb_url);
result.content_type = qs(r.vcontent_type);
result.content_url = qs(r.vcontent_url);
result->id = qs(r.vid);
result->type = qs(r.vtype);
result->title = qs(r.vtitle);
result->description = qs(r.vdescription);
result->url = qs(r.vurl);
result->thumb_url = qs(r.vthumb_url);
result->content_type = qs(r.vcontent_type);
result->content_url = qs(r.vcontent_url);
message = &r.vsend_message;
} break;
}
bool badAttachment = (!result.photo || result.photo->access) && (!result.doc || result.doc->access);
bool canSend = (result.photo || result.doc || !result.message.isEmpty());
if (!result.type.isEmpty() && !badAttachment && !canSend) {
it->results.push_back(result);
bool badAttachment = (!result->photo || result->photo->access) && (!result->doc || result->doc->access);
bool canSend = (result->photo || result->doc || !result->message.isEmpty());
if (result->type.isEmpty() || badAttachment || !canSend) {
delete result;
} else {
it.value()->results.push_back(result);
}
}
} else if (adding) {
it->results.clear();
it->nextOffset = QString();
it.value()->clearResults();
it.value()->nextOffset = QString();
}
refreshContextRows(!adding);
}
@ -3248,7 +3309,7 @@ void EmojiPan::showContextResults(UserData *bot, QString query) {
if (bot != _contextBot) {
if (!isHidden()) hideStart();
clearContextResults();
contextBotChanged();
_contextBot = bot;
force = true;
}
@ -3273,19 +3334,22 @@ void EmojiPan::onContextRequest() {
QString nextOffset;
ContextCache::const_iterator i = _contextCache.constFind(_contextQuery);
if (i != _contextCache.cend()) {
nextOffset = i->nextOffset;
nextOffset = i.value()->nextOffset;
if (nextOffset.isEmpty()) return;
}
_contextRequestId = MTP::send(MTPmessages_GetContextBotResults(_contextBot->inputUser, MTP_string(_contextQuery), MTP_string(nextOffset)), rpcDone(&EmojiPan::contextResultsDone), rpcFail(&EmojiPan::contextResultsFail));
}
void EmojiPan::refreshContextRows(bool toDown) {
void EmojiPan::refreshContextRows(bool newResults) {
bool clear = true;
ContextCache::const_iterator i = _contextCache.constFind(_contextQuery);
if (i == _contextCache.cend()) {
clear = !i->results.isEmpty();
_contextNextOffset = i->nextOffset;
if (i != _contextCache.cend()) {
clear = !i.value()->results.isEmpty();
_contextNextOffset = i.value()->nextOffset;
}
s_inner.refreshContextRows(clear ? ContextResults() : i.value()->results);
if (newResults) s_scroll.scrollToY(0);
}
MentionsInner::MentionsInner(MentionsDropdown *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows)

View File

@ -314,6 +314,31 @@ struct StickerIcon {
int32 pixw, pixh;
};
struct ContextResult {
ContextResult(uint64 queryId)
: queryId(queryId)
, doc(0)
, photo(0)
, width(0)
, height(0)
, duration(0)
, noWebPage(false) {
}
uint64 queryId;
QString id, type;
DocumentData *doc;
PhotoData *photo;
QString title, description, url, thumb_url;
QString content_type, content_url;
int32 width, height, duration;
QString message; // botContextMessageText
bool noWebPage;
EntitiesInText entities;
QString caption; // if message.isEmpty() use botContextMessageMediaAuto
};
typedef QList<ContextResult*> ContextResults;
class StickerPanInner : public TWidget {
Q_OBJECT
@ -341,6 +366,7 @@ public:
void refreshStickers();
void refreshRecentStickers(bool resize = true);
void refreshSavedGifs();
void refreshContextRows(const ContextResults &results);
void refreshRecent();
void fillIcons(QList<StickerIcon> &icons);
@ -351,14 +377,17 @@ public:
void preloadImages();
uint64 currentSet(int yOffset) const;
void refreshContextResults(const ContextResults &results);
void contextBotChanged();
void ui_repaintSavedGif(const LayoutSavedGif *layout);
bool ui_isSavedGifVisible(const LayoutSavedGif *layout);
bool ui_isGifBeingChosen();
void ui_repaintContextItem(const LayoutContextItem *layout);
bool ui_isContextItemVisible(const LayoutContextItem *layout);
bool ui_isContextItemBeingChosen();
~StickerPanInner() {
clearSavedGifs();
deleteUnusedLayouts();
clearContextRows();
deleteUnusedGifLayouts();
deleteUnusedContextLayouts();
}
public slots:
@ -385,7 +414,7 @@ signals:
private:
void paintSavedGifs(Painter &p, const QRect &r);
void paintContextItems(Painter &p, const QRect &r);
void paintStickers(Painter &p, const QRect &r);
int32 _maxHeight;
@ -414,18 +443,30 @@ private:
QList<DisplayedSet> _sets;
QList<bool> _custom;
bool _showingGifs;
bool _showingSavedGifs, _showingContextItems;
typedef QList<LayoutSavedGif*> GifRow;
typedef QList<GifRow> GifRows;
GifRows _gifRows;
void clearSavedGifs();
void deleteUnusedLayouts();
typedef QList<LayoutContextItem*> ContextItems;
struct ContextRow {
ContextRow() : height(0) {
}
int32 height;
ContextItems items;
};
typedef QList<ContextRow> ContextRows;
ContextRows _contextRows;
void clearContextRows();
typedef QMap<DocumentData*, LayoutSavedGif*> GifLayouts;
typedef QMap<DocumentData*, LayoutContextGif*> GifLayouts;
GifLayouts _gifLayouts;
LayoutSavedGif *layoutPrepare(DocumentData *doc, int32 position, int32 width);
const GifRow &layoutGifRow(const GifRow &row, int32 *widths, int32 sumWidth);
LayoutContextGif *layoutPrepare(DocumentData *doc, int32 position, int32 width);
typedef QMap<ContextResult*, LayoutContextItem*> ContextLayouts;
ContextLayouts _contextLayouts;
ContextRow &layoutContextRow(ContextRow &row, int32 *widths, int32 sumWidth);
void deleteUnusedGifLayouts();
void deleteUnusedContextLayouts();
int32 _selected, _pressedSel;
QPoint _lastMousePos;
@ -525,7 +566,7 @@ public:
void stickersInstalled(uint64 setId);
void showContextResults(UserData *bot, QString query);
void clearContextResults();
void contextBotChanged();
bool overlaps(const QRect &globalRect) {
if (isHidden() || !_cache.isNull()) return false;
@ -537,9 +578,9 @@ public:
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
}
void ui_repaintSavedGif(const LayoutSavedGif *layout);
bool ui_isSavedGifVisible(const LayoutSavedGif *layout);
bool ui_isGifBeingChosen();
void ui_repaintContextItem(const LayoutContextItem *layout);
bool ui_isContextItemVisible(const LayoutContextItem *layout);
bool ui_isContextItemBeingChosen();
public slots:
@ -639,38 +680,24 @@ private:
QTimer _saveConfigTimer;
// context bots
struct ContextResult {
ContextResult(uint64 queryId)
: queryId(queryId)
, doc(0)
, photo(0)
, width(0)
, height(0)
, duration(0)
, noWebPage(false) {
}
uint64 queryId;
QString id, type;
DocumentData *doc;
PhotoData *photo;
QString title, description, url, thumb_url;
QString content_type, content_url;
int32 width, height, duration;
QString message; // botContextMessageText
bool noWebPage;
EntitiesInText entities;
QString caption; // if message.isEmpty() use botContextMessageMediaAuto
};
struct ContextCacheEntry {
~ContextCacheEntry() {
clearResults();
}
QString nextOffset;
QList<ContextResult> results;
ContextResults results;
void clearResults() {
for (int32 i = 0, l = results.size(); i < l; ++i) {
delete results.at(i);
}
results.clear();
}
};
typedef QMap<QString, ContextCacheEntry> ContextCache;
typedef QMap<QString, ContextCacheEntry*> ContextCache;
ContextCache _contextCache;
QTimer _contextRequestTimer;
void refreshContextRows(bool toDown);
void refreshContextRows(bool newResults);
UserData *_contextBot;
QString _contextQuery, _contextNextQuery, _contextNextOffset;
mtpRequestId _contextRequestId;

View File

@ -102,8 +102,8 @@ namespace Ui {
return false;
}
bool isGifBeingChosen() {
if (MainWidget *m = App::main()) return m->ui_isGifBeingChosen();
bool isContextItemBeingChosen() {
if (MainWidget *m = App::main()) return m->ui_isContextItemBeingChosen();
return false;
}
@ -112,13 +112,13 @@ namespace Ui {
if (MainWidget *m = App::main()) m->ui_repaintHistoryItem(item);
}
void repaintSavedGif(const LayoutSavedGif *layout) {
void repaintContextItem(const LayoutContextItem *layout) {
if (!layout) return;
if (MainWidget *m = App::main()) m->ui_repaintSavedGif(layout);
if (MainWidget *m = App::main()) m->ui_repaintContextItem(layout);
}
bool isSavedGifVisible(const LayoutSavedGif *layout) {
if (MainWidget *m = App::main()) return m->ui_isSavedGifVisible(layout);
bool isContextItemVisible(const LayoutContextItem *layout) {
if (MainWidget *m = App::main()) return m->ui_isContextItemVisible(layout);
return false;
}

View File

@ -46,11 +46,11 @@ namespace Ui { // openssl doesn't allow me to use UI :(
void hideLayer(bool fast = false);
bool isLayerShown();
bool isMediaViewShown();
bool isGifBeingChosen();
bool isContextItemBeingChosen();
void repaintHistoryItem(const HistoryItem *item);
void repaintSavedGif(const LayoutSavedGif *layout);
bool isSavedGifVisible(const LayoutSavedGif *reader);
void repaintContextItem(const LayoutContextItem *layout);
bool isContextItemVisible(const LayoutContextItem *reader);
void showPeerHistory(const PeerId &peer, MsgId msgId, bool back = false);
inline void showPeerHistory(const PeerData *peer, MsgId msgId, bool back = false) {

View File

@ -226,7 +226,8 @@ ClipReader::ClipReader(const FileLocation &location, const QByteArray &data, Cal
, _height(0)
, _currentDisplayed(1)
, _paused(0)
, _lastDisplayMs(getms())
, _lastDisplayMs(0)
, _startDisplayMs(getms())
, _autoplay(false)
, _private(0) {
if (_clipThreads.size() < ClipThreadsCount) {
@ -270,11 +271,11 @@ void ClipReader::start(int32 framew, int32 frameh, int32 outerw, int32 outerh, b
}
QPixmap ClipReader::current(int32 framew, int32 frameh, int32 outerw, int32 outerh, uint64 ms) {
_currentDisplayed.set(true);
_currentDisplayed.store(1);
if (ms) {
_lastDisplayMs.set(ms);
if (_paused.get()) {
_paused.set(false);
_lastDisplayMs.storeRelease(int32(ms - _startDisplayMs.get()));
if (_paused.loadAcquire()) {
_paused.storeRelease(0);
if (_clipManagers.size() <= _threadIndex) error();
if (_state != ClipError) {
_clipManagers.at(_threadIndex)->update(this);
@ -953,7 +954,7 @@ ClipReadManager::ClipReadManager(QThread *thread) : _processingInThread(0), _nee
void ClipReadManager::append(ClipReader *reader, const FileLocation &location, const QByteArray &data) {
reader->_private = new ClipReaderPrivate(reader, location, data);
_loadLevel.fetchAndAddRelease(AverageGifSize);
_loadLevel.fetchAndAddRelaxed(AverageGifSize);
update(reader);
}
@ -995,14 +996,18 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess
}
if (result == ClipProcessStarted) {
_loadLevel.fetchAndAddRelease(reader->_width * reader->_height - AverageGifSize);
_loadLevel.fetchAndAddRelaxed(reader->_width * reader->_height - AverageGifSize);
}
if (!reader->_paused && (result == ClipProcessRepaint || result == ClipProcessWait)) {
if (it.key()->_lastDisplayMs.get() + WaitBeforeGifPause < qMax(reader->_previousMs, ms)) {
int32 lastDisplay = it.key()->_lastDisplayMs.loadAcquire();
if (lastDisplay > 3000 || lastDisplay < 0) { // playing more then a day
it.key()->_startDisplayMs.set(ms);
it.key()->_lastDisplayMs.storeRelease(getms() - ms);
} else if (it.key()->_startDisplayMs.get() + lastDisplay + WaitBeforeGifPause < qMax(reader->_previousMs, ms)) {
reader->_paused = true;
it.key()->_paused.set(true);
if (it.key()->_lastDisplayMs.get() + WaitBeforeGifPause >= qMax(reader->_previousMs, ms)) {
it.key()->_paused.set(false);
it.key()->_paused.storeRelease(true);
if (it.key()->_startDisplayMs.get() + it.key()->_lastDisplayMs.loadAcquire() + WaitBeforeGifPause >= qMax(reader->_previousMs, ms)) {
it.key()->_paused.storeRelease(false);
reader->_paused = false;
} else {
result = ClipProcessReinit;
@ -1012,7 +1017,7 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess
if (result == ClipProcessReinit || result == ClipProcessRepaint || result == ClipProcessStarted) {
it.key()->_current = reader->_current;
it.key()->_currentOriginal = reader->_currentOriginal;
it.key()->_currentDisplayed.set(false);
it.key()->_currentDisplayed.store(false);
if (result == ClipProcessReinit) {
emit callback(it.key(), it.key()->threadIndex(), ClipReaderReinit);
} else if (result == ClipProcessRepaint) {
@ -1024,7 +1029,7 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess
ClipReadManager::ResultHandleState ClipReadManager::handleResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms) {
if (!handleProcessResult(reader, result, ms)) {
_loadLevel.fetchAndAddRelease(-1 * (reader->_currentOriginal.isNull() ? AverageGifSize : reader->_width * reader->_height));
_loadLevel.fetchAndAddRelaxed(-1 * (reader->_currentOriginal.isNull() ? AverageGifSize : reader->_width * reader->_height));
delete reader;
return ResultHandleRemove;
}
@ -1060,7 +1065,7 @@ void ClipReadManager::process() {
_readers.insert(i.value(), 0);
} else {
it.value() = ms;
if (it.key()->_paused && !i.key()->_paused.get()) {
if (it.key()->_paused && !i.key()->_paused.loadAcquire()) {
it.key()->_paused = false;
}
}

View File

@ -495,21 +495,23 @@ template <typename Type>
class Atomic {
public:
Atomic(const Type &value = Type()) : _v(1, value) {
Atomic(const Type &value = Type()) : _value(value) {
}
Type get() const {
QVector<Type> v(_v);
return v.at(0);
QReadLocker lock(&_lock);
Type result = _value;
return result;
}
void set(const Type &value) {
QVector<Type> v(1, value);
_v = v;
QWriteLocker lock(&_lock);
_value = value;
}
private:
QVector<Type> _v;
Type _value;
mutable QReadWriteLock _lock;
};
@ -540,10 +542,10 @@ public:
return _currentOriginal;
}
bool currentDisplayed() const {
return _currentDisplayed.get();
return _currentDisplayed.load();
}
bool paused() const {
return _paused.get();
return _paused.loadAcquire();
}
int32 threadIndex() const {
return _threadIndex;
@ -575,8 +577,8 @@ private:
QPixmap _current;
QImage _currentOriginal, _cacheForResize;
Atomic<bool> _currentDisplayed, _paused;
Atomic<uint64> _lastDisplayMs;
QAtomicInt _currentDisplayed, _paused, _lastDisplayMs;
Atomic<uint64> _startDisplayMs;
int32 _threadIndex;
bool _autoplay;
@ -604,7 +606,7 @@ public:
ClipReadManager(QThread *thread);
int32 loadLevel() const {
return _loadLevel.loadAcquire();
return _loadLevel.load();
}
void append(ClipReader *reader, const FileLocation &location, const QByteArray &data);
void start(ClipReader *reader);

View File

@ -38,7 +38,7 @@ namespace {
typedef QMap<StorageKey, StorageImage*> StorageImages;
StorageImages storageImages;
int64 globalAquiredSize = 0;
int64 globalAcquiredSize = 0;
static const uint64 BlurredCacheSkip = 0x1000000000000000LLU;
static const uint64 ColoredCacheSkip = 0x2000000000000000LLU;
@ -63,7 +63,7 @@ Image::Image(const QString &file, QByteArray fmt) : _forgot(false) {
_data = QPixmap::fromImage(App::readImage(file, &fmt, false, 0, &_saved), Qt::ColorOnly);
_format = fmt;
if (!_data.isNull()) {
globalAquiredSize += int64(_data.width()) * _data.height() * 4;
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
}
}
@ -72,13 +72,13 @@ Image::Image(const QByteArray &filecontent, QByteArray fmt) : _forgot(false) {
_format = fmt;
_saved = filecontent;
if (!_data.isNull()) {
globalAquiredSize += int64(_data.width()) * _data.height() * 4;
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
}
}
Image::Image(const QPixmap &pixmap, QByteArray format) : _format(format), _forgot(false), _data(pixmap) {
if (!_data.isNull()) {
globalAquiredSize += int64(_data.width()) * _data.height() * 4;
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
}
}
@ -87,7 +87,7 @@ Image::Image(const QByteArray &filecontent, QByteArray fmt, const QPixmap &pixma
_format = fmt;
_saved = filecontent;
if (!_data.isNull()) {
globalAquiredSize += int64(_data.width()) * _data.height() * 4;
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
}
}
@ -107,7 +107,7 @@ const QPixmap &Image::pix(int32 w, int32 h) const {
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
i = _sizesCache.insert(k, p);
if (!p.isNull()) {
globalAquiredSize += int64(p.width()) * p.height() * 4;
globalAcquiredSize += int64(p.width()) * p.height() * 4;
}
}
return i.value();
@ -129,7 +129,7 @@ const QPixmap &Image::pixRounded(int32 w, int32 h) const {
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
i = _sizesCache.insert(k, p);
if (!p.isNull()) {
globalAquiredSize += int64(p.width()) * p.height() * 4;
globalAcquiredSize += int64(p.width()) * p.height() * 4;
}
}
return i.value();
@ -151,7 +151,7 @@ const QPixmap &Image::pixBlurred(int32 w, int32 h) const {
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
i = _sizesCache.insert(k, p);
if (!p.isNull()) {
globalAquiredSize += int64(p.width()) * p.height() * 4;
globalAcquiredSize += int64(p.width()) * p.height() * 4;
}
}
return i.value();
@ -173,7 +173,7 @@ const QPixmap &Image::pixColored(const style::color &add, int32 w, int32 h) cons
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
i = _sizesCache.insert(k, p);
if (!p.isNull()) {
globalAquiredSize += int64(p.width()) * p.height() * 4;
globalAcquiredSize += int64(p.width()) * p.height() * 4;
}
}
return i.value();
@ -195,7 +195,7 @@ const QPixmap &Image::pixBlurredColored(const style::color &add, int32 w, int32
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
i = _sizesCache.insert(k, p);
if (!p.isNull()) {
globalAquiredSize += int64(p.width()) * p.height() * 4;
globalAcquiredSize += int64(p.width()) * p.height() * 4;
}
}
return i.value();
@ -214,13 +214,13 @@ const QPixmap &Image::pixSingle(int32 w, int32 h, int32 outerw, int32 outerh) co
Sizes::const_iterator i = _sizesCache.constFind(k);
if (i == _sizesCache.cend() || i->width() != (outerw * cIntRetinaFactor()) || i->height() != (outerh * cIntRetinaFactor())) {
if (i != _sizesCache.cend()) {
globalAquiredSize -= int64(i->width()) * i->height() * 4;
globalAcquiredSize -= int64(i->width()) * i->height() * 4;
}
QPixmap p(pixNoCache(w, h, true, false, true, outerw, outerh));
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
i = _sizesCache.insert(k, p);
if (!p.isNull()) {
globalAquiredSize += int64(p.width()) * p.height() * 4;
globalAcquiredSize += int64(p.width()) * p.height() * 4;
}
}
return i.value();
@ -239,13 +239,13 @@ const QPixmap &Image::pixBlurredSingle(int32 w, int32 h, int32 outerw, int32 out
Sizes::const_iterator i = _sizesCache.constFind(k);
if (i == _sizesCache.cend() || i->width() != (outerw * cIntRetinaFactor()) || i->height() != (outerh * cIntRetinaFactor())) {
if (i != _sizesCache.cend()) {
globalAquiredSize -= int64(i->width()) * i->height() * 4;
globalAcquiredSize -= int64(i->width()) * i->height() * 4;
}
QPixmap p(pixNoCache(w, h, true, true, true, outerw, outerh));
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
i = _sizesCache.insert(k, p);
if (!p.isNull()) {
globalAquiredSize += int64(p.width()) * p.height() * 4;
globalAcquiredSize += int64(p.width()) * p.height() * 4;
}
}
return i.value();
@ -519,7 +519,7 @@ void Image::forget() const {
}
}
}
globalAquiredSize -= int64(_data.width()) * _data.height() * 4;
globalAcquiredSize -= int64(_data.width()) * _data.height() * 4;
_data = QPixmap();
_forgot = true;
}
@ -535,7 +535,7 @@ void Image::restore() const {
_data = QPixmap::fromImageReader(&reader, Qt::ColorOnly);
if (!_data.isNull()) {
globalAquiredSize += int64(_data.width()) * _data.height() * 4;
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
}
_forgot = false;
}
@ -543,7 +543,7 @@ void Image::restore() const {
void Image::invalidateSizeCache() const {
for (Sizes::const_iterator i = _sizesCache.cbegin(), e = _sizesCache.cend(); i != e; ++i) {
if (!i->isNull()) {
globalAquiredSize -= int64(i->width()) * i->height() * 4;
globalAcquiredSize -= int64(i->width()) * i->height() * 4;
}
}
_sizesCache.clear();
@ -552,7 +552,7 @@ void Image::invalidateSizeCache() const {
Image::~Image() {
invalidateSizeCache();
if (!_data.isNull()) {
globalAquiredSize -= int64(_data.width()) * _data.height() * 4;
globalAcquiredSize -= int64(_data.width()) * _data.height() * 4;
}
}
@ -594,7 +594,7 @@ void clearAllImages() {
}
int64 imageCacheSize() {
return globalAquiredSize;
return globalAcquiredSize;
}
StorageImage::StorageImage(const StorageImageLocation &location, int32 size) : _location(location), _size(size), _loader(0) {
@ -627,7 +627,7 @@ void StorageImage::doCheckload() const {
}
if (!_data.isNull()) {
globalAquiredSize -= int64(_data.width()) * _data.height() * 4;
globalAcquiredSize -= int64(_data.width()) * _data.height() * 4;
}
_format = _loader->imageFormat();
@ -635,7 +635,7 @@ void StorageImage::doCheckload() const {
_saved = _loader->bytes();
const_cast<StorageImage*>(this)->_size = _saved.size();
const_cast<StorageImage*>(this)->_location.setSize(_data.width(), _data.height());
globalAquiredSize += int64(_data.width()) * _data.height() * 4;
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
invalidateSizeCache();
@ -650,12 +650,12 @@ void StorageImage::setData(QByteArray &bytes, const QByteArray &bytesFormat) {
QBuffer buffer(&bytes);
if (!_data.isNull()) {
globalAquiredSize -= int64(_data.width()) * _data.height() * 4;
globalAcquiredSize -= int64(_data.width()) * _data.height() * 4;
}
QByteArray fmt(bytesFormat);
_data = QPixmap::fromImage(App::readImage(bytes, &fmt, false), Qt::ColorOnly);
if (!_data.isNull()) {
globalAquiredSize += int64(_data.width()) * _data.height() * 4;
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
_location.setSize(_data.width(), _data.height());
}
@ -713,7 +713,7 @@ void StorageImage::loadEvenCancelled(bool loadFirst, bool prior) {
StorageImage::~StorageImage() {
if (!_data.isNull()) {
globalAquiredSize -= int64(_data.width()) * _data.height() * 4;
globalAcquiredSize -= int64(_data.width()) * _data.height() * 4;
}
if (amLoading()) {
_loader->deleteLater();

View File

@ -4583,7 +4583,7 @@ void HistoryGif::draw(Painter &p, const HistoryItem *parent, const QRect &r, boo
QRect rthumb(rtlrect(skipx, skipy, width, height, _width));
if (animating) {
p.drawPixmap(rthumb.topLeft(), _gif->current(_thumbw, _thumbh, width, height, (Ui::isLayerShown() || Ui::isMediaViewShown() || Ui::isGifBeingChosen()) ? 0 : ms));
p.drawPixmap(rthumb.topLeft(), _gif->current(_thumbw, _thumbh, width, height, (Ui::isLayerShown() || Ui::isMediaViewShown() || Ui::isContextItemBeingChosen()) ? 0 : ms));
} else {
p.drawPixmap(rthumb.topLeft(), _data->thumb->pixBlurredSingle(_thumbw, _thumbh, width, height));
}

View File

@ -5332,7 +5332,7 @@ void HistoryWidget::onCheckMentionDropdown() {
_attachMention.hideStart();
}
} else {
_emojiPan.clearContextResults();
_emojiPan.contextBotChanged();
if (!start.isEmpty()) {
if (start.at(0) == '#' && cRecentWriteHashtags().isEmpty() && cRecentSearchHashtags().isEmpty()) Local::readRecentHashtags();
if (start.at(0) == '@' && _peer->isUser()) return;
@ -5770,16 +5770,16 @@ void HistoryWidget::ui_repaintHistoryItem(const HistoryItem *item) {
}
}
void HistoryWidget::ui_repaintSavedGif(const LayoutSavedGif *layout) {
_emojiPan.ui_repaintSavedGif(layout);
void HistoryWidget::ui_repaintContextItem(const LayoutContextItem *layout) {
_emojiPan.ui_repaintContextItem(layout);
}
bool HistoryWidget::ui_isSavedGifVisible(const LayoutSavedGif *layout) {
return _emojiPan.ui_isSavedGifVisible(layout);
bool HistoryWidget::ui_isContextItemVisible(const LayoutContextItem *layout) {
return _emojiPan.ui_isContextItemVisible(layout);
}
bool HistoryWidget::ui_isGifBeingChosen() {
return _emojiPan.ui_isGifBeingChosen();
bool HistoryWidget::ui_isContextItemBeingChosen() {
return _emojiPan.ui_isContextItemBeingChosen();
}
void HistoryWidget::notify_historyItemLayoutChanged(const HistoryItem *item) {

View File

@ -559,9 +559,9 @@ public:
bool isItemVisible(HistoryItem *item);
void ui_repaintHistoryItem(const HistoryItem *item);
void ui_repaintSavedGif(const LayoutSavedGif *gif);
bool ui_isSavedGifVisible(const LayoutSavedGif *layout);
bool ui_isGifBeingChosen();
void ui_repaintContextItem(const LayoutContextItem *gif);
bool ui_isContextItemVisible(const LayoutContextItem *layout);
bool ui_isContextItemBeingChosen();
void notify_historyItemLayoutChanged(const HistoryItem *item);
void notify_botCommandsChanged(UserData *user);

View File

@ -1281,70 +1281,88 @@ LayoutOverviewLink::Link::Link(const QString &url, const QString &text)
, lnk(linkFromUrl(url)) {
}
LayoutSavedGif::LayoutSavedGif(DocumentData *data)
: _data(data)
, _position(0)
, _width(st::savedGifMinWidth)
LayoutContextItem::LayoutContextItem(ContextResult *result)
: _result(result)
, _doc(0)
, _position(0) {
}
LayoutContextItem::LayoutContextItem(DocumentData *doc)
: _result(0)
, _doc(doc)
, _position(0) {
}
void LayoutContextItem::setPosition(int32 position, int32 width) {
_position = position;
resizeGetHeight(width);
}
int32 LayoutContextItem::position() const {
return _position;
}
DocumentData *LayoutContextItem::document() const {
return _doc;
}
ContextResult *LayoutContextItem::result() const {
return _result;
}
void LayoutContextItem::preload() {
if (_result) {
if (_result->photo) {
_result->photo->thumb->load();
} else if (_result->doc) {
_result->doc->thumb->load();
}
} else if (_doc) {
_doc->thumb->load();
}
}
LayoutContextGif::LayoutContextGif(DocumentData *data, bool saved) : LayoutContextItem(data)
, _state(0)
, _gif(0)
, _send(new SendContextItemLink())
, _delete(saved ? new DeleteSavedGifLink(data) : 0)
, _animation(0) {
}
void LayoutSavedGif::setPosition(int32 position, int32 width) {
_position = position;
_width = width;
void LayoutContextGif::initDimensions() {
_maxw = st::emojiPanWidth - st::emojiScroll.width - st::savedGifsLeft;
_minh = st::savedGifHeight + st::savedGifsSkip;
}
void LayoutContextGif::setPosition(int32 position, int32 width) {
LayoutContextItem::setPosition(position, width);
if (_position < 0) {
if (gif()) delete _gif;
_gif = 0;
}
}
void LayoutSavedGif::setWidth(int32 width) {
_width = width;
}
void DeleteSavedGifLink::onClick(Qt::MouseButton button) const {
if (button != Qt::LeftButton) return;
int32 LayoutSavedGif::position() const {
return _position;
}
int32 index = cSavedGifs().indexOf(_data);
if (index >= 0) {
cRefSavedGifs().remove(index);
Local::writeSavedGifs();
int32 LayoutSavedGif::width() const {
return _width;
}
void LayoutSavedGif::notify_over(bool over) {
if (!_data->loaded()) {
ensureAnimation();
if (over == !(_state & StateOver)) {
EnsureAnimation(_animation->_a_over, (_state & StateOver) ? 1 : 0, func(this, &LayoutSavedGif::update));
_animation->_a_over.start(over ? 1 : 0, st::stickersRowDuration);
}
}
if (over) {
_state |= StateOver;
} else {
_state &= ~StateOver;
MTP::send(MTPmessages_SaveGif(MTP_inputDocument(MTP_long(_data->id), MTP_long(_data->access)), MTP_bool(true)));
}
if (App::main()) emit App::main()->savedGifsUpdated();
}
void LayoutSavedGif::notify_deleteOver(bool over) {
if (over == !(_state & StateDeleteOver)) {
EnsureAnimation(_a_deleteOver, (_state & StateDeleteOver) ? 1 : 0, func(this, &LayoutSavedGif::update));
if (over) {
_state |= StateDeleteOver;
} else {
_state &= ~StateDeleteOver;
}
_a_deleteOver.start((_state & StateDeleteOver) ? 1 : 0, st::stickersRowDuration);
}
}
void LayoutContextGif::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const {
_doc->automaticLoad(0);
void LayoutSavedGif::paint(Painter &p, bool paused, uint64 ms) const {
_data->automaticLoad(0);
bool loaded = _data->loaded(), displayLoading = _data->displayLoading();
bool loaded = _doc->loaded(), displayLoading = _doc->displayLoading();
if (loaded && !gif() && _gif != BadClipReader) {
LayoutSavedGif *that = const_cast<LayoutSavedGif*>(this);
that->_gif = new ClipReader(_data->location(), _data->data(), func(that, &LayoutSavedGif::clipCallback));
LayoutContextGif *that = const_cast<LayoutContextGif*>(this);
that->_gif = new ClipReader(_doc->location(), _doc->data(), func(that, &LayoutContextGif::clipCallback));
if (gif()) _gif->setAutoplay();
}
@ -1352,34 +1370,36 @@ void LayoutSavedGif::paint(Painter &p, bool paused, uint64 ms) const {
if (displayLoading) {
ensureAnimation();
if (!_animation->radial.animating()) {
_animation->radial.start(_data->progress());
_animation->radial.start(_doc->progress());
}
}
bool radial = isRadialAnimation(ms);
bool radial = isRadialAnimation(context->ms);
int32 height = st::savedGifHeight;
QSize frame = countFrameSize();
QRect r(0, 0, _width, height);
if (animating) {
if (!_thumb.isNull()) const_cast<LayoutSavedGif*>(this)->_thumb = QPixmap();
p.drawPixmap(r.topLeft(), _gif->current(frame.width(), frame.height(), _width, height, paused ? 0 : ms));
if (!_thumb.isNull()) const_cast<LayoutContextGif*>(this)->_thumb = QPixmap();
const ContextPaintContext *ctx = context->toContextPaintContext();
t_assert(ctx);
p.drawPixmap(r.topLeft(), _gif->current(frame.width(), frame.height(), _width, height, ctx->paused ? 0 : context->ms));
} else {
if (!_data->thumb->isNull()) {
if (_data->thumb->loaded()) {
if (!_doc->thumb->isNull()) {
if (_doc->thumb->loaded()) {
if (_thumb.width() != _width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
const_cast<LayoutSavedGif*>(this)->_thumb = _data->thumb->pixNoCache(frame.width(), frame.height(), true, false, false, _width, height);
const_cast<LayoutContextGif*>(this)->_thumb = _doc->thumb->pixNoCache(frame.width(), frame.height(), true, false, false, _width, height);
}
} else {
_data->thumb->load();
_doc->thumb->load();
}
}
p.drawPixmap(r.topLeft(), _thumb);
}
if (radial || (!_gif && !loaded && !_data->loading()) || (_gif == BadClipReader)) {
float64 radialOpacity = (radial && loaded && !_data->uploading()) ? _animation->radial.opacity() : 1;
if (_animation && _animation->_a_over.animating(ms)) {
if (radial || (!_gif && !loaded && !_doc->loading()) || (_gif == BadClipReader)) {
float64 radialOpacity = (radial && loaded && !_doc->uploading()) ? _animation->radial.opacity() : 1;
if (_animation && _animation->_a_over.animating(context->ms)) {
float64 over = _animation->_a_over.current();
p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over));
p.fillRect(r, st::black);
@ -1390,9 +1410,9 @@ void LayoutSavedGif::paint(Painter &p, bool paused, uint64 ms) const {
p.setOpacity(radialOpacity);
style::sprite icon;
if (_data->loaded() && !radial) {
if (_doc->loaded() && !radial) {
icon = st::msgFileInPlay;
} else if (radial || _data->loading()) {
} else if (radial || _doc->loading()) {
icon = st::msgFileInCancel;
} else {
icon = st::msgFileInDownload;
@ -1407,7 +1427,7 @@ void LayoutSavedGif::paint(Painter &p, bool paused, uint64 ms) const {
}
if (_state & StateOver) {
float64 deleteOver = _a_deleteOver.current(ms, (_state & StateDeleteOver) ? 1 : 0);
float64 deleteOver = _a_deleteOver.current(context->ms, (_state & StateDeleteOver) ? 1 : 0);
QPoint deletePos = QPoint(_width - st::stickerPanDelete.pxWidth(), 0);
p.setOpacity(deleteOver + (1 - deleteOver) * st::stickerPanDeleteOpacity);
p.drawSpriteLeft(deletePos, _width, st::stickerPanDelete);
@ -1415,9 +1435,57 @@ void LayoutSavedGif::paint(Painter &p, bool paused, uint64 ms) const {
}
}
QSize LayoutSavedGif::countFrameSize() const {
void LayoutContextGif::getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const {
if (x >= 0 && x < _width && y >= 0 && y < st::savedGifHeight) {
if ((rtl() ? _width - x : x) >= _width - st::stickerPanDelete.pxWidth() && y < st::stickerPanDelete.pxHeight()) {
link = _delete;
} else {
link = _send;
}
}
}
void LayoutContextGif::linkOver(const TextLinkPtr &link) {
if (link == _delete) {
if (!(_state & StateDeleteOver)) {
EnsureAnimation(_a_deleteOver, 0, func(this, &LayoutContextGif::update));
_state |= StateDeleteOver;
_a_deleteOver.start(1, st::stickersRowDuration);
}
} else if (link == _send) {
if (!_doc->loaded()) {
ensureAnimation();
if (!(_state & StateOver)) {
EnsureAnimation(_animation->_a_over, 0, func(this, &LayoutContextGif::update));
_animation->_a_over.start(1, st::stickersRowDuration);
}
}
_state |= StateOver;
}
}
void LayoutContextGif::linkOut(const TextLinkPtr &link) {
if (link == _delete) {
if (_state & StateDeleteOver) {
EnsureAnimation(_a_deleteOver, 1, func(this, &LayoutContextGif::update));
_state &= ~StateDeleteOver;
_a_deleteOver.start(0, st::stickersRowDuration);
}
} else if (link == _send) {
if (!_doc->loaded()) {
ensureAnimation();
if (_state & StateOver) {
EnsureAnimation(_animation->_a_over, 1, func(this, &LayoutContextGif::update));
_animation->_a_over.start(0, st::stickersRowDuration);
}
}
_state &= ~StateOver;
}
}
QSize LayoutContextGif::countFrameSize() const {
bool animating = (gif() && _gif->ready());
int32 framew = animating ? _gif->width() : _data->thumb->width(), frameh = animating ? _gif->height() : _data->thumb->height(), height = st::savedGifHeight;
int32 framew = animating ? _gif->width() : _doc->thumb->width(), frameh = animating ? _gif->height() : _doc->thumb->height(), height = st::savedGifHeight;
if (framew * height > frameh * _width) {
if (framew < st::maxStickerSize || frameh > height) {
if (frameh > height || (framew * height / frameh) <= st::maxStickerSize) {
@ -1442,55 +1510,51 @@ QSize LayoutSavedGif::countFrameSize() const {
return QSize(framew, frameh);
}
void LayoutSavedGif::preload() {
_data->thumb->load();
}
LayoutSavedGif::~LayoutSavedGif() {
LayoutContextGif::~LayoutContextGif() {
deleteAndMark(_animation);
}
void LayoutSavedGif::ensureAnimation() const {
void LayoutContextGif::ensureAnimation() const {
if (!_animation) {
_animation = new AnimationData(animation(const_cast<LayoutSavedGif*>(this), &LayoutSavedGif::step_radial));
_animation = new AnimationData(animation(const_cast<LayoutContextGif*>(this), &LayoutContextGif::step_radial));
}
}
bool LayoutSavedGif::isRadialAnimation(uint64 ms) const {
bool LayoutContextGif::isRadialAnimation(uint64 ms) const {
if (!_animation || !_animation->radial.animating()) return false;
_animation->radial.step(ms);
return _animation && _animation->radial.animating();
}
void LayoutSavedGif::step_radial(uint64 ms, bool timer) {
void LayoutContextGif::step_radial(uint64 ms, bool timer) {
if (timer) {
update();
} else {
_animation->radial.update(_data->progress(), !_data->loading() || _data->loaded(), ms);
if (!_animation->radial.animating() && _data->loaded()) {
_animation->radial.update(_doc->progress(), !_doc->loading() || _doc->loaded(), ms);
if (!_animation->radial.animating() && _doc->loaded()) {
delete _animation;
_animation = 0;
}
}
}
void LayoutSavedGif::clipCallback(ClipReaderNotification notification) {
void LayoutContextGif::clipCallback(ClipReaderNotification notification) {
switch (notification) {
case ClipReaderReinit: {
if (gif()) {
if (_gif->state() == ClipError) {
delete _gif;
_gif = BadClipReader;
_data->forget();
_doc->forget();
} else if (_gif->ready() && !_gif->started()) {
int32 height = st::savedGifHeight;
QSize frame = countFrameSize();
_gif->start(frame.width(), frame.height(), _width, height, false);
} else if (_gif->paused() && !Ui::isSavedGifVisible(this)) {
} else if (_gif->paused() && !Ui::isContextItemVisible(this)) {
delete _gif;
_gif = 0;
_data->forget();
_doc->forget();
}
}
@ -1505,8 +1569,8 @@ void LayoutSavedGif::clipCallback(ClipReaderNotification notification) {
}
}
void LayoutSavedGif::update() {
void LayoutContextGif::update() {
if (_position >= 0) {
Ui::repaintSavedGif(this);
Ui::repaintContextItem(this);
}
}

View File

@ -78,9 +78,7 @@ style::color documentColor(int32 colorIndex);
style::sprite documentCorner(int32 colorIndex);
RoundCorners documentCorners(int32 colorIndex);
class LayoutMediaItem;
class OverviewItemInfo;
class ContextPaintContext;
class PaintContext {
public:
@ -88,9 +86,15 @@ public:
}
uint64 ms;
bool selecting;
virtual const ContextPaintContext *toContextPaintContext() const {
return 0;
}
};
class LayoutMediaItem;
class OverviewItemInfo;
class LayoutItem {
public:
LayoutItem() : _maxw(0), _minh(0) {
@ -471,30 +475,76 @@ private:
};
class LayoutSavedGif {
class ContextPaintContext : public PaintContext {
public:
LayoutSavedGif(DocumentData *data);
ContextPaintContext(uint64 ms, bool selecting, bool paused) : PaintContext(ms, selecting), paused(paused) {
}
virtual const ContextPaintContext *toContextPaintContext() const {
return this;
}
bool paused;
};
void paint(Painter &p, bool paused, uint64 ms) const;
struct ContextResult;
class LayoutContextItem : public LayoutItem {
public:
LayoutContextItem(ContextResult *result);
LayoutContextItem(DocumentData *doc);
virtual void setPosition(int32 position, int32 width);
int32 position() const;
DocumentData *document() const;
ContextResult *result() const;
void preload();
DocumentData *document() const {
return _data;
protected:
ContextResult *_result;
DocumentData *_doc;
int32 _position; // < 0 means removed from layout
};
class SendContextItemLink : public ITextLink {
TEXT_LINK_CLASS(SendContextItemLink)
public:
virtual void onClick(Qt::MouseButton) const {
}
void setPosition(int32 position, int32 width);
void setWidth(int32 width);
int32 position() const;
int32 width() const;
};
void notify_over(bool over);
void notify_deleteOver(bool over);
class DeleteSavedGifLink : public ITextLink {
TEXT_LINK_CLASS(DeleteSavedGifLink)
~LayoutSavedGif();
public:
DeleteSavedGifLink(DocumentData *data) : _data(data) {
}
virtual void onClick(Qt::MouseButton) const;
private:
DocumentData *_data;
};
class LayoutContextGif : public LayoutContextItem {
public:
LayoutContextGif(DocumentData *data, bool saved);
virtual void setPosition(int32 position, int32 width);
virtual void initDimensions();
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const;
virtual void getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const;
virtual void linkOver(const TextLinkPtr &lnk);
virtual void linkOut(const TextLinkPtr &lnk);
~LayoutContextGif();
private:
DocumentData *_data;
int32 _position; // < 0 means removed from layout
int32 _width;
QSize countFrameSize() const;
enum StateFlags {
@ -504,6 +554,7 @@ private:
int32 _state;
ClipReader *_gif;
TextLinkPtr _send, _delete;
bool gif() const {
return (!_gif || _gif == BadClipReader) ? false : true;
}

View File

@ -798,16 +798,16 @@ void MainWidget::ui_repaintHistoryItem(const HistoryItem *item) {
if (overview) overview->ui_repaintHistoryItem(item);
}
void MainWidget::ui_repaintSavedGif(const LayoutSavedGif *layout) {
history.ui_repaintSavedGif(layout);
void MainWidget::ui_repaintContextItem(const LayoutContextItem *layout) {
history.ui_repaintContextItem(layout);
}
bool MainWidget::ui_isSavedGifVisible(const LayoutSavedGif *layout) {
return history.ui_isSavedGifVisible(layout);
bool MainWidget::ui_isContextItemVisible(const LayoutContextItem *layout) {
return history.ui_isContextItemVisible(layout);
}
bool MainWidget::ui_isGifBeingChosen() {
return history.ui_isGifBeingChosen();
bool MainWidget::ui_isContextItemBeingChosen() {
return history.ui_isContextItemBeingChosen();
}
void MainWidget::notify_historyItemLayoutChanged(const HistoryItem *item) {

View File

@ -410,9 +410,9 @@ public:
void ui_showStickerPreview(DocumentData *sticker);
void ui_hideStickerPreview();
void ui_repaintHistoryItem(const HistoryItem *item);
void ui_repaintSavedGif(const LayoutSavedGif *layout);
bool ui_isSavedGifVisible(const LayoutSavedGif *layout);
bool ui_isGifBeingChosen();
void ui_repaintContextItem(const LayoutContextItem *layout);
bool ui_isContextItemVisible(const LayoutContextItem *layout);
bool ui_isContextItemBeingChosen();
void ui_showPeerHistory(quint64 peer, qint32 msgId, bool back);
void notify_botCommandsChanged(UserData *bot);