photo and video overview rewritten on layouts

This commit is contained in:
John Preston 2015-12-22 15:49:42 +03:00
parent 62723f7576
commit d3896ff53b
8 changed files with 616 additions and 267 deletions

View file

@ -2011,6 +2011,11 @@ botKbScroll: flatScroll(solidScroll) {
width: 10px;
}
minPhotoSize: 104px;
maxMediaSize: 420px;
maxStickerSize: 256px;
maxGifSize: 320px;
mvBgColor: #222;
mvBgOpacity: 0.92;
mvThickFont: semiboldFont;
@ -2132,7 +2137,8 @@ medviewSaveMsg: #000000b2;
mvTransparentBrush: sprite(9px, 124px, 8px, 8px);
overviewPhotoSkip: 10px;
overviewPhotoMinSize: 100px;
overviewPhotoBg: #F1F1F1;
overviewPhotoMinSize: minPhotoSize;
overviewPhotoCheck: sprite(245px, 308px, 32px, 32px);
overviewPhotoChecked: sprite(278px, 308px, 32px, 32px);
overviewPhotoSelectOverlay: #0a7bb03f;
@ -2193,11 +2199,6 @@ mediaviewLoader: size(78px, 33px);
mediaviewLoaderPoint: size(9px, 9px);
mediaviewLoaderSkip: 9px;
minPhotoSize: 104px;
maxMediaSize: 420px;
maxStickerSize: 256px;
maxGifSize: 320px;
downloadPathSkip: 10px;
usernamePadding: margins(23px, 22px, 21px, 12px);

View file

@ -3026,8 +3026,8 @@ HistoryItem *regItem(HistoryItem *item, bool returnExisting) {
return item;
}
RadialAnimation::RadialAnimation(int32 thickness, AnimationCallbacks *callbacks) : _thickness(thickness)
, _firstStart(0)
RadialAnimation::RadialAnimation(AnimationCallbacks *callbacks)
: _firstStart(0)
, _lastStart(0)
, _lastTime(0)
, _opacity(0)
@ -3078,12 +3078,12 @@ void RadialAnimation::step(uint64 ms) {
_animation.step(ms);
}
void RadialAnimation::draw(Painter &p, const QRect &inner, const style::color &color) {
void RadialAnimation::draw(Painter &p, const QRect &inner, int32 thickness, const style::color &color) {
float64 o = p.opacity();
p.setOpacity(o * _opacity);
QPen pen(color->p), was(p.pen());
pen.setWidth(_thickness);
pen.setWidth(thickness);
p.setPen(pen);
int32 len = MinArcLength + a_arcEnd.current();
@ -3651,7 +3651,7 @@ void HistoryVideo::draw(Painter &p, const HistoryItem *parent, const QRect &r, b
p.drawSpriteCenter(inner, icon);
if (radial) {
QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine)));
_animation->radial.draw(p, rinner, selected ? st::msgInBgSelected : st::msgInBg);
_animation->radial.draw(p, rinner, st::msgFileRadialLine, selected ? st::msgInBgSelected : st::msgInBg);
}
int32 statusX = skipx + st::msgDateImgDelta + st::msgDateImgPadding.x(), statusY = skipy + st::msgDateImgDelta + st::msgDateImgPadding.y();
@ -3836,7 +3836,7 @@ void HistoryAudio::draw(Painter &p, const HistoryItem *parent, const QRect &r, b
if (radial) {
QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine)));
style::color bg(outbg ? (selected ? st::msgOutBgSelected : st::msgOutBg) : (selected ? st::msgInBgSelected : st::msgInBg));
_animation->radial.draw(p, rinner, bg);
_animation->radial.draw(p, rinner, st::msgFileRadialLine, bg);
}
style::sprite icon;
@ -4091,7 +4091,7 @@ void HistoryDocument::draw(Painter &p, const HistoryItem *parent, const QRect &r
p.setOpacity(1);
QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine)));
_animation->radial.draw(p, rinner, selected ? st::msgInBgSelected : st::msgInBg);
_animation->radial.draw(p, rinner, st::msgFileRadialLine, selected ? st::msgInBgSelected : st::msgInBg);
}
}
@ -4127,7 +4127,7 @@ void HistoryDocument::draw(Painter &p, const HistoryItem *parent, const QRect &r
if (radial) {
QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine)));
style::color bg(outbg ? (selected ? st::msgOutBgSelected : st::msgOutBg) : (selected ? st::msgInBgSelected : st::msgInBg));
_animation->radial.draw(p, rinner, bg);
_animation->radial.draw(p, rinner, st::msgFileRadialLine, bg);
}
style::sprite icon;
@ -4485,7 +4485,7 @@ void HistoryGif::draw(Painter &p, const HistoryItem *parent, const QRect &r, boo
p.drawSpriteCenter(inner, icon);
if (radial) {
QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine)));
_animation->radial.draw(p, rinner, selected ? st::msgInBgSelected : st::msgInBg);
_animation->radial.draw(p, rinner, st::msgFileRadialLine, selected ? st::msgInBgSelected : st::msgInBg);
}
if (!animating) {

View file

@ -1106,7 +1106,7 @@ HistoryItem *regItem(HistoryItem *item, bool returnExisting = false);
class RadialAnimation {
public:
RadialAnimation(int32 thickness, AnimationCallbacks *callbacks);
RadialAnimation(AnimationCallbacks *callbacks);
float64 opacity() const {
return _opacity;
@ -1124,11 +1124,10 @@ public:
step(getms());
}
void draw(Painter &p, const QRect &inner, const style::color &color);
void draw(Painter &p, const QRect &inner, int32 thickness, const style::color &color);
private:
int32 _thickness;
uint64 _firstStart, _lastStart, _lastTime;
float64 _opacity;
anim::ivalue a_arcEnd, a_arcStart;
@ -1341,7 +1340,7 @@ protected:
struct AnimationData {
AnimationData(AnimationCallbacks *thumbOverCallbacks, AnimationCallbacks *radialCallbacks) : a_thumbOver(0, 0)
, _a_thumbOver(thumbOverCallbacks)
, radial(st::msgFileRadialLine, radialCallbacks) {
, radial(radialCallbacks) {
}
anim::fvalue a_thumbOver;
Animation _a_thumbOver;

View file

@ -203,14 +203,14 @@ RoundCorners documentCorners(int32 colorIndex) {
}
void LayoutRadialProgressItem::linkOver(const TextLinkPtr &lnk) {
if (lnk == _savel || lnk == _cancell) {
if (lnk == _openl || lnk == _savel || lnk == _cancell) {
a_iconOver.start(1);
_a_iconOver.start();
}
}
void LayoutRadialProgressItem::linkOut(const TextLinkPtr &lnk) {
if (lnk == _savel || lnk == _cancell) {
if (lnk == _openl || lnk == _savel || lnk == _cancell) {
a_iconOver.start(0);
_a_iconOver.start();
}
@ -247,9 +247,7 @@ void LayoutRadialProgressItem::step_radial(uint64 ms, bool timer) {
void LayoutRadialProgressItem::ensureRadial() const {
if (!_radial) {
_radial = new RadialAnimation(
st::msgFileRadialLine,
animation(const_cast<LayoutRadialProgressItem*>(this), &LayoutRadialProgressItem::step_radial));
_radial = new RadialAnimation(animation(const_cast<LayoutRadialProgressItem*>(this), &LayoutRadialProgressItem::step_radial));
}
}
@ -293,7 +291,7 @@ void LayoutOverviewDate::initDimensions() {
_minh = st::linksDateMargin + st::normalFont->height + st::linksDateMargin + st::linksBorder;
}
void LayoutOverviewDate::paint(Painter &p, const QRect &clip, uint32 selection, uint64 ms) const {
void LayoutOverviewDate::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const {
if (clip.intersects(QRect(0, st::linksDateMargin, _width, st::normalFont->height))) {
p.setPen(st::linksDateColor);
p.setFont(st::normalFont);
@ -301,6 +299,215 @@ void LayoutOverviewDate::paint(Painter &p, const QRect &clip, uint32 selection,
}
}
LayoutOverviewPhoto::LayoutOverviewPhoto(PhotoData *photo, HistoryItem *parent) : LayoutMediaItem(parent)
, _data(photo)
, _link(new PhotoLink(photo))
, _goodLoaded(false) {
}
void LayoutOverviewPhoto::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const {
bool good = _data->full->loaded();
if (!good) {
_data->medium->load(false, false);
good = _data->medium->loaded();
}
if ((good && !_goodLoaded) || _pix.width() != _width * cIntRetinaFactor()) {
_goodLoaded = good;
int32 size = _width * cIntRetinaFactor();
if (_goodLoaded || _data->thumb->loaded()) {
QImage img = (_data->full->loaded() ? _data->full : (_data->medium->loaded() ? _data->medium : _data->thumb))->pix().toImage();
if (!_goodLoaded) {
img = imageBlur(img);
}
if (img.width() == img.height()) {
if (img.width() != _width) {
img = img.scaled(_width, _width, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
}
} else if (img.width() > img.height()) {
img = img.copy((img.width() - img.height()) / 2, 0, img.height(), img.height()).scaled(_width, _width, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
} else {
img = img.copy(0, (img.height() - img.width()) / 2, img.width(), img.width()).scaled(_width, _width, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
}
img.setDevicePixelRatio(cRetinaFactor());
_data->forget();
_pix = QPixmap::fromImage(img, Qt::ColorOnly);
} else if (!_pix.isNull()) {
_pix = QPixmap();
}
}
if (_pix.isNull()) {
p.fillRect(0, 0, _width, _height, st::overviewPhotoBg);
} else {
p.drawPixmap(0, 0, _pix);
}
if (selection == FullSelection) {
p.fillRect(QRect(0, 0, _width, _height), st::overviewPhotoSelectOverlay);
p.drawSprite(QPoint(rtl() ? 0 : (_width - st::overviewPhotoChecked.pxWidth()), _height - st::overviewPhotoChecked.pxHeight()), st::overviewPhotoChecked);
} else if (context->selecting) {
p.drawSprite(QPoint(rtl() ? 0 : (_width - st::overviewPhotoCheck.pxWidth()), _height - st::overviewPhotoCheck.pxHeight()), st::overviewPhotoCheck);
}
}
void LayoutOverviewPhoto::getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const {
if (hasPoint(x, y)) {
link = _link;
}
}
LayoutOverviewVideo::LayoutOverviewVideo(VideoData *video, HistoryItem *parent) : LayoutAbstractFileItem(parent)
, _data(video)
, _duration(formatDurationText(_data->duration))
, _thumbLoaded(false) {
setLinks(new VideoOpenLink(_data), new VideoSaveLink(_data), new VideoCancelLink(_data));
}
void LayoutOverviewVideo::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const {
bool selected = (selection == FullSelection), thumbLoaded = _data->thumb->loaded();
bool already = !_data->already().isEmpty();
if (_data->loader) {
ensureRadial();
if (!_radial->animating()) {
_radial->start(_data->progress());
}
}
updateStatusText();
bool radial = isRadialAnimation(context->ms);
if ((thumbLoaded && !_thumbLoaded) || (_pix.width() != _width * cIntRetinaFactor())) {
_thumbLoaded = thumbLoaded;
if (_thumbLoaded && !_data->thumb->isNull()) {
int32 size = _width * cIntRetinaFactor();
QImage img = _data->thumb->pix().toImage();
img = imageBlur(img);
if (img.width() == img.height()) {
if (img.width() != _width) {
img = img.scaled(_width, _width, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
}
} else if (img.width() > img.height()) {
img = img.copy((img.width() - img.height()) / 2, 0, img.height(), img.height()).scaled(_width, _width, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
} else {
img = img.copy(0, (img.height() - img.width()) / 2, img.width(), img.width()).scaled(_width, _width, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
}
img.setDevicePixelRatio(cRetinaFactor());
_data->forget();
_pix = QPixmap::fromImage(img, Qt::ColorOnly);
} else if (!_pix.isNull()) {
_pix = QPixmap();
}
}
if (_pix.isNull()) {
p.fillRect(0, 0, _width, _height, st::overviewPhotoBg);
} else {
p.drawPixmap(0, 0, _pix);
}
if (selected) {
p.fillRect(QRect(0, 0, _width, _height), st::overviewPhotoSelectOverlay);
}
if (clip.intersects(QRect(0, _height - st::normalFont->height, _width, st::normalFont->height))) {
int32 statusX = st::msgDateImgPadding.x(), statusY = _height - st::normalFont->height - st::msgDateImgPadding.y();
int32 statusW = st::normalFont->width(_statusText) + 2 * st::msgDateImgPadding.x();
int32 statusH = st::normalFont->height + 2 * st::msgDateImgPadding.y();
statusX = _width - statusW + statusX;
p.fillRect(rtlrect(statusX - st::msgDateImgPadding.x(), statusY - st::msgDateImgPadding.y(), statusW, statusH, _width), selected ? st::msgDateImgBgSelected : st::msgDateImgBg);
p.setFont(st::normalFont);
p.setPen(st::white);
p.drawTextLeft(statusX, statusY, _width, _statusText, statusW - 2 * st::msgDateImgPadding.x());
}
if (clip.intersects(QRect(0, 0, _width, st::normalFont->height))) {
int32 statusX = st::msgDateImgPadding.x(), statusY = st::msgDateImgPadding.y();
int32 statusW = st::normalFont->width(_duration) + 2 * st::msgDateImgPadding.x();
int32 statusH = st::normalFont->height + 2 * st::msgDateImgPadding.y();
p.fillRect(rtlrect(statusX - st::msgDateImgPadding.x(), statusY - st::msgDateImgPadding.y(), statusW, statusH, _width), selected ? st::msgDateImgBgSelected : st::msgDateImgBg);
p.setFont(st::normalFont);
p.setPen(st::white);
p.drawTextLeft(statusX, statusY, _width, _duration, statusW - 2 * st::msgDateImgPadding.x());
}
QRect inner((_width - st::msgFileSize) / 2, (_height - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
if (clip.intersects(inner)) {
p.setPen(Qt::NoPen);
if (selected) {
p.setBrush(st::msgDateImgBgSelected);
} else if (_a_iconOver.animating()) {
_a_iconOver.step(context->ms);
float64 over = a_iconOver.current();
p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over));
p.setBrush(st::black);
} else {
bool over = textlnkDrawOver(already ? _openl : (_data->loader ? _cancell : _savel));
p.setBrush(over ? st::msgDateImgBgOver : st::msgDateImgBg);
}
p.setRenderHint(QPainter::HighQualityAntialiasing);
p.drawEllipse(inner);
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
style::sprite icon;
if (radial) {
icon = (selected ? st::msgFileInCancelSelected : st::msgFileInCancel);
} else if (already) {
icon = (selected ? st::msgFileInPlaySelected : st::msgFileInPlay);
} else {
icon = (selected ? st::msgFileInDownloadSelected : st::msgFileInDownload);
}
p.setOpacity(radial ? _radial->opacity() : 1);
p.drawSpriteCenter(inner, icon);
if (radial) {
p.setOpacity(1);
QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine)));
_radial->draw(p, rinner, st::msgFileRadialLine, selected ? st::msgInBgSelected : st::msgInBg);
}
}
if (selected) {
p.drawSprite(QPoint(rtl() ? 0 : (_width - st::overviewPhotoChecked.pxWidth()), _height - st::overviewPhotoChecked.pxHeight()), st::overviewPhotoChecked);
} else if (context->selecting) {
p.drawSprite(QPoint(rtl() ? 0 : (_width - st::overviewPhotoCheck.pxWidth()), _height - st::overviewPhotoCheck.pxHeight()), st::overviewPhotoCheck);
}
}
void LayoutOverviewVideo::getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const {
if (hasPoint(x, y)) {
link = _data->already().isEmpty() ? (_data->loader ? _cancell : _savel) : _openl;
}
}
void LayoutOverviewVideo::updateStatusText() const {
bool showPause = false;
int32 statusSize = 0;
if (_data->status == FileDownloadFailed || _data->status == FileUploadFailed) {
statusSize = FileStatusSizeFailed;
} else if (_data->status == FileUploading) {
statusSize = _data->uploadOffset;
} else if (_data->loader) {
statusSize = _data->loader->currentOffset();
} else if (!_data->already().isEmpty()) {
statusSize = FileStatusSizeLoaded;
} else {
statusSize = FileStatusSizeReady;
}
if (statusSize != _statusSize) {
int32 status = statusSize, size = _data->size;
if (statusSize >= 0 && statusSize < 0x7F000000) {
size = status;
status = FileStatusSizeReady;
}
setStatusSize(status, size, -1, 0);
_statusSize = statusSize;
}
}
LayoutOverviewDocument::LayoutOverviewDocument(DocumentData *document, HistoryItem *parent, int32 top) : LayoutAbstractFileItem(parent)
, _info(top)
, _data(document)
@ -338,7 +545,7 @@ void LayoutOverviewDocument::initDimensions() {
_minh = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom() + st::lineWidth;
}
void LayoutOverviewDocument::paint(Painter &p, const QRect &clip, uint32 selection, uint64 ms) const {
void LayoutOverviewDocument::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const {
bool selected = (selection == FullSelection);
bool already = !_data->already().isEmpty(), hasdata = !_data->data.isEmpty();
if (_data->loader) {
@ -348,7 +555,7 @@ void LayoutOverviewDocument::paint(Painter &p, const QRect &clip, uint32 selecti
}
}
updateStatusText();
bool radial = isRadialAnimation(ms);
bool radial = isRadialAnimation(context->ms);
int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0;
bool wthumb = withThumb();
@ -386,7 +593,6 @@ void LayoutOverviewDocument::paint(Painter &p, const QRect &clip, uint32 selecti
}
if (selected) {
App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, SelectedOverlayCorners);
p.drawSprite(rthumb.topLeft() + QPoint(rtl() ? 0 : (rthumb.width() - st::linksPhotoCheck.pxWidth()), rthumb.height() - st::linksPhotoCheck.pxHeight()), st::linksPhotoChecked);
}
if (!radial && (already || hasdata)) {
@ -400,7 +606,7 @@ void LayoutOverviewDocument::paint(Painter &p, const QRect &clip, uint32 selecti
p.setOpacity(st::msgDateImgBg->c.alphaF() * _radial->opacity());
p.setBrush(st::black);
} else if (_a_iconOver.animating()) {
_a_iconOver.step(ms);
_a_iconOver.step(context->ms);
float64 over = a_iconOver.current();
p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over));
p.setBrush(st::black);
@ -425,10 +631,15 @@ void LayoutOverviewDocument::paint(Painter &p, const QRect &clip, uint32 selecti
p.setOpacity(1);
QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine)));
_radial->draw(p, rinner, selected ? st::msgInBgSelected : st::msgInBg);
_radial->draw(p, rinner, st::msgFileRadialLine, selected ? st::msgInBgSelected : st::msgInBg);
}
}
}
if (selected) {
p.drawSprite(rthumb.topLeft() + QPoint(rtl() ? 0 : (rthumb.width() - st::linksPhotoChecked.pxWidth()), rthumb.height() - st::linksPhotoChecked.pxHeight()), st::linksPhotoChecked);
} else if (context->selecting) {
p.drawSprite(rthumb.topLeft() + QPoint(rtl() ? 0 : (rthumb.width() - st::linksPhotoCheck.pxWidth()), rthumb.height() - st::linksPhotoCheck.pxHeight()), st::linksPhotoCheck);
}
}
int32 namewidth = _width - nameleft - nameright;

View file

@ -81,6 +81,16 @@ RoundCorners documentCorners(int32 colorIndex);
class LayoutMediaItem;
class OverviewItemInfo;
class PaintContext {
public:
PaintContext(uint64 ms, bool selecting) : ms(ms), selecting(selecting) {
}
uint64 ms;
bool selecting;
};
class LayoutItem {
public:
LayoutItem() : _maxw(0), _minh(0) {
@ -99,7 +109,7 @@ public:
return _height;
}
virtual void paint(Painter &p, const QRect &clip, uint32 selection, uint64 ms) const = 0;
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const = 0;
virtual void getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const {
link = TextLinkPtr();
cursor = HistoryDefaultCursorState;
@ -264,7 +274,7 @@ public:
LayoutOverviewDate(const QDate &date, int32 top);
virtual void initDimensions();
virtual void paint(Painter &p, const QRect &clip, uint32 selection, uint64 ms) const;
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const;
virtual OverviewItemInfo *getOverviewItemInfo() {
return &_info;
@ -281,12 +291,120 @@ private:
};
class LayoutOverviewPhoto : public LayoutMediaItem {
public:
LayoutOverviewPhoto(PhotoData *photo, HistoryItem *parent);
virtual void initDimensions() {
_maxw = 2 * st::overviewPhotoMinSize;
_minh = _maxw;
}
virtual int32 resizeGetHeight(int32 width) {
width = qMin(width, _maxw);
if (width != _width || width != _height) {
_width = qMin(width, _maxw);
_height = _width;
}
return _height;
}
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;
private:
PhotoData *_data;
TextLinkPtr _link;
mutable QPixmap _pix;
mutable bool _goodLoaded;
};
class LayoutOverviewVideo : public LayoutAbstractFileItem {
public:
LayoutOverviewVideo(VideoData *photo, HistoryItem *parent);
virtual void initDimensions() {
_maxw = 2 * st::minPhotoSize;
_minh = _maxw;
}
virtual int32 resizeGetHeight(int32 width) {
_width = qMin(width, _maxw);
_height = _width;
return _height;
}
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;
protected:
virtual float64 dataProgress() const {
return _data->progress();
}
virtual bool dataFinished() const {
return !_data->loader;
}
virtual bool dataLoaded() const {
return !_data->already().isEmpty();
}
virtual bool iconAnimated() const {
return true;
}
private:
VideoData *_data;
QString _duration;
mutable QPixmap _pix;
mutable bool _thumbLoaded;
void updateStatusText() const;
};
class LayoutOverviewAudio : public LayoutAbstractFileItem {
public:
LayoutOverviewAudio(AudioData *audio, HistoryItem *parent, int32 top);
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 OverviewItemInfo *getOverviewItemInfo() {
return &_info;
}
virtual const OverviewItemInfo *getOverviewItemInfo() const {
return &_info;
}
protected:
virtual float64 dataProgress() const {
return _data->progress();
}
virtual bool dataFinished() const {
return !_data->loader;
}
virtual bool dataLoaded() const {
return !_data->already().isEmpty() || !_data->data.isEmpty();
}
virtual bool iconAnimated() const {
return !dataLoaded() || (_radial && _radial->animating());
}
private:
OverviewItemInfo _info;
AudioData *_data;
Text _name, _details;
void updateStatusText() const;
};
class LayoutOverviewDocument : public LayoutAbstractFileItem {
public:
LayoutOverviewDocument(DocumentData *document, HistoryItem *parent, int32 top);
virtual void initDimensions();
virtual void paint(Painter &p, const QRect &clip, uint32 selection, uint64 ms) const;
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 DocumentData *getDocument() const {
@ -328,3 +446,44 @@ private:
void updateStatusText() const;
};
class LayoutOverviewLink : public LayoutMediaItem {
public:
LayoutOverviewLink(HistoryItem *parent, int32 top);
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 OverviewItemInfo *getOverviewItemInfo() {
return &_info;
}
virtual const OverviewItemInfo *getOverviewItemInfo() const {
return &_info;
}
private:
OverviewItemInfo _info;
TextLinkPtr _msgl;
QString title, letter;
int32 titleWidth;
WebPageData *page;
int32 pixw, pixh;
Text text;
struct Link {
Link() : width(0) {
}
Link(const QString &url, const QString &text)
: text(text)
, width(st::normalFont->width(text))
, lnk(new TextLink(url)) {
}
QString text;
int32 width;
TextLinkPtr lnk;
};
QVector<Link> urls;
};

View file

@ -788,6 +788,7 @@ void MainWidget::ui_redrawHistoryItem(const HistoryItem *item) {
void MainWidget::notify_historyItemLayoutChanged(const HistoryItem *item) {
history.notify_historyItemLayoutChanged(item);
if (overview) overview->notify_historyItemLayoutChanged(item);
}
void MainWidget::notify_historyItemResized(const HistoryItem *item, bool scrollToIt) {

View file

@ -143,15 +143,16 @@ OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, PeerD
, _resizeSkip(0)
, _peer(peer->migrateTo() ? peer->migrateTo() : peer)
, _type(type)
, _reversed(_type != OverviewDocuments && _type != OverviewLinks)
, _migrated(_peer->migrateFrom() ? App::history(_peer->migrateFrom()->id) : 0)
, _history(App::history(_peer->id))
, _channel(peerToChannel(_peer->id))
, _selMode(false)
, _rowsLeft(0)
, _rowWidth(st::msgMinWidth)
, _rowHeight(0)
, _photosInRow(1)
, _photosToAdd(0)
, _selMode(false)
, _search(this, st::dlgFilter, lang(lng_dlg_filter))
, _cancelSearch(this, st::btnCancelSearch)
, _cachedItemsToBeLoaded(LinksOverviewPerPage * 2)
@ -292,7 +293,7 @@ int32 OverviewInner::migratedIndexSkip() const {
void OverviewInner::fixItemIndex(int32 &current, MsgId msgId) const {
if (!msgId) {
current = -1;
} else if (_type == OverviewPhotos || _type == OverviewVideos || _type == OverviewAudioDocuments) {
} else if (_type == OverviewAudioDocuments) {
History *history = itemMigrated(msgId) ? _migrated : _history;
int32 l = history->overview[_type].size(), indexskip = migratedIndexSkip();
int32 index = (current >= 0 && history == _history) ? (current - indexskip) : current;
@ -306,7 +307,7 @@ void OverviewInner::fixItemIndex(int32 &current, MsgId msgId) const {
}
}
}
} else if (_type == OverviewDocuments) {
} else if (_type == OverviewPhotos || _type == OverviewVideos || _type == OverviewDocuments) {
int32 l = _items.size();
if (current < 0 || current >= l || complexMsgId(_items.at(current)->getItem()) != msgId) {
current = -1;
@ -501,7 +502,7 @@ void OverviewInner::moveToNextItem(MsgId &msgId, int32 &index, MsgId upTo, int32
}
index += delta;
if (_type == OverviewPhotos || _type == OverviewVideos || _type == OverviewAudioDocuments) {
if (_type == OverviewAudioDocuments) {
int32 indexskip = migratedIndexSkip();
if (index < 0 || index >= indexskip + _history->overview[_type].size()) {
msgId = 0;
@ -509,7 +510,7 @@ void OverviewInner::moveToNextItem(MsgId &msgId, int32 &index, MsgId upTo, int32
} else {
msgId = (index >= indexskip) ? _history->overview[_type][index - indexskip] : (-_migrated->overview[_type][index]);
}
} else if (_type == OverviewDocuments) {
} else if (_type == OverviewPhotos || _type == OverviewVideos || _type == OverviewDocuments) {
while (index >= 0 && index < _items.size() && !_items.at(index)->toLayoutMediaItem()) {
index += (delta > 0) ? 1 : -1;
}
@ -536,9 +537,10 @@ void OverviewInner::redrawItem(MsgId itemId, int32 itemIndex) {
fixItemIndex(itemIndex, itemId);
if (itemIndex >= 0) {
if (_type == OverviewPhotos || _type == OverviewVideos) {
int32 shownAtIndex = _items.size() - itemIndex - 1;
float64 w = (float64(_width - st::overviewPhotoSkip) / _photosInRow);
int32 vsize = (_vsize + st::overviewPhotoSkip);
int32 row = (_photosToAdd + itemIndex) / _photosInRow, col = (_photosToAdd + itemIndex) % _photosInRow;
int32 row = (_photosToAdd + shownAtIndex) / _photosInRow, col = (_photosToAdd + shownAtIndex) % _photosInRow;
update(int32(col * w), _addToY + int32(row * vsize), qCeil(w), vsize);
} else if (_type == OverviewAudioDocuments) {
update(_rowsLeft, _addToY + int32(itemIndex * _rowHeight), _rowWidth, _rowHeight);
@ -916,9 +918,9 @@ void OverviewInner::addSelectionRange(int32 selFrom, int32 selTo, History *histo
if (selFrom < 0 || selTo < 0) return;
for (int32 i = selFrom; i <= selTo; ++i) {
MsgId msgid = 0;
if (_type == OverviewPhotos || _type == OverviewVideos || _type == OverviewAudioDocuments) {
if (_type == OverviewAudioDocuments) {
msgid = ((history == _history) ? 1 : -1) * history->overview[_type][i];
} else if (_type == OverviewDocuments) {
} else if (_type == OverviewPhotos || _type == OverviewVideos || _type == OverviewDocuments) {
msgid = complexMsgId(_items.at(i)->getItem());
} else if (_type == OverviewLinks) {
msgid = _cachedItems[i].msgid;
@ -948,7 +950,7 @@ void OverviewInner::applyDragSelection() {
_selected.clear();
}
int32 selfrom = _dragSelToIndex, selto = _dragSelFromIndex;
if (_migrated && (_type == OverviewPhotos || _type == OverviewVideos || _type == OverviewAudioDocuments)) {
if (_migrated && (_type == OverviewAudioDocuments)) {
int32 indexskip = migratedIndexSkip();
if (selfrom < indexskip) {
if (selto < indexskip) {
@ -978,7 +980,8 @@ QPoint OverviewInner::mapMouseToItem(QPoint p, MsgId itemId, int32 itemIndex) {
if (itemIndex < 0) return QPoint(0, 0);
if (_type == OverviewPhotos || _type == OverviewVideos) {
int32 row = (_photosToAdd + itemIndex) / _photosInRow, col = (_photosToAdd + itemIndex) % _photosInRow;
int32 shownAtIndex = _items.size() - itemIndex - 1;
int32 row = (_photosToAdd + shownAtIndex) / _photosInRow, col = (_photosToAdd + shownAtIndex) % _photosInRow;
float64 w = (_width - st::overviewPhotoSkip) / float64(_photosInRow);
p.setX(p.x() - int32(col * w) - st::overviewPhotoSkip);
p.setY(p.y() - _addToY - row * (_vsize + st::overviewPhotoSkip) - st::overviewPhotoSkip);
@ -1003,7 +1006,15 @@ void OverviewInner::activate() {
}
void OverviewInner::clear() {
_cached.clear();
_selected.clear();
_dragItemIndex = _mousedItemIndex = _dragSelFromIndex = _dragSelToIndex = -1;
_dragItem = _mousedItem = _dragSelFrom = _dragSelTo = 0;
_lnkOverIndex = _lnkDownIndex = 0;
for (int32 i = 0, l = _items.size(); i != l; ++i) {
delete _items.at(i);
}
_items.clear();
_cachedItems.clear();
}
int32 OverviewInner::itemTop(const FullMsgId &msgId) const {
@ -1046,7 +1057,7 @@ void OverviewInner::preloadMore() {
}
bool OverviewInner::preloadLocal() {
if (_type != OverviewLinks && _type != OverviewDocuments) return false;
if (_type != OverviewLinks && _type != OverviewDocuments && _type != OverviewPhotos && _type != OverviewVideos) return false;
if (_cachedItemsToBeLoaded >= migratedIndexSkip() + _history->overview[_type].size()) return false;
_cachedItemsToBeLoaded += LinksOverviewPerPage;
mediaOverviewUpdated();
@ -1087,6 +1098,25 @@ QPixmap OverviewInner::genPix(VideoData *video, int32 size) {
return result;
}
uint32 OverviewInner::itemSelectedValue(int32 index) const {
int32 selfrom = -1, selto = -1;
if (_dragSelFromIndex >= 0 && _dragSelToIndex >= 0) {
selfrom = _dragSelToIndex;
selto = _dragSelFromIndex;
}
if (_items.at(index)->toLayoutMediaItem()) { // draw item
if (index >= _dragSelToIndex && index <= _dragSelFromIndex && _dragSelToIndex >= 0) {
return (_dragSelecting && _items.at(index)->msgId() > 0) ? FullSelection : 0;
} else if (!_selected.isEmpty()) {
SelectedItems::const_iterator j = _selected.constFind(complexMsgId(_items.at(index)->getItem()));
if (j != _selected.cend()) {
return j.value();
}
}
}
return 0;
}
void OverviewInner::paintEvent(QPaintEvent *e) {
if (App::wnd() && App::wnd()->contentOverlapped(this, e)) return;
@ -1098,6 +1128,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
p.setClipRect(r);
}
uint64 ms = getms();
PaintContext context(ms, _selMode);
if (_history->overview[_type].isEmpty() && (!_migrated || !_history->overviewLoaded(_type) || _migrated->overview[_type].isEmpty())) {
QPoint dogPos((_width - st::msgDogImg.pxWidth()) / 2, ((height() - st::msgDogImg.pxHeight()) * 4) / 9);
@ -1120,111 +1151,21 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
bool hasSel = !_selected.isEmpty();
if (_type == OverviewPhotos || _type == OverviewVideos) {
History::MediaOverview &overview(_history->overview[_type]), *migratedOverview = _migrated ? &_migrated->overview[_type] : 0;
int32 migratedCount = migratedIndexSkip();
int32 count = migratedCount + 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);
int32 count = _items.size(), rowsCount = (_photosToAdd + count) / _photosInRow + (((_photosToAdd + count) % _photosInRow) ? 1 : 0);
int32 rowFrom = floorclamp(r.y() - _addToY - st::overviewPhotoSkip, _vsize + st::overviewPhotoSkip, 0, rowsCount);
int32 rowTo = ceilclamp(r.y() + r.height() - _addToY - st::overviewPhotoSkip, _vsize + st::overviewPhotoSkip, 0, rowsCount);
float64 w = float64(_width - st::overviewPhotoSkip) / _photosInRow;
for (int32 row = rowFrom; row < rowTo; ++row) {
if (row * _photosInRow >= _photosToAdd + count) break;
for (int32 i = 0; i < _photosInRow; ++i) {
int32 index = row * _photosInRow + i - _photosToAdd;
if (index < 0) continue;
if (index >= count) break;
for (int32 col = 0; col < _photosInRow; ++col) {
int32 i = count - (row * _photosInRow + col - _photosToAdd) - 1;
if (i < 0) continue;
if (i >= count) break;
bool migratedindex = (index < migratedCount);
int32 bareindex = migratedindex ? index : (index - migratedCount);
HistoryItem *item = App::histItemById(migratedindex ? _migrated->channelId() : _channel, (migratedindex ? *migratedOverview : overview)[bareindex]);
HistoryMedia *m = item ? item->getMedia(true) : 0;
QPoint pos(int32(i * w + st::overviewPhotoSkip), _addToY + row * (_vsize + st::overviewPhotoSkip) + st::overviewPhotoSkip);
if (m) switch (m->type()) {
case MediaTypePhoto: {
PhotoData *photo = static_cast<HistoryPhoto*>(m)->photo();
bool quality = photo->full->loaded();
if (!quality) {
if (photo->thumb->loaded()) {
photo->medium->load(false, false);
quality = photo->medium->loaded();
} else {
photo->thumb->load();
}
}
CachedSizes::iterator it = _cached.find(photo);
if (it == _cached.cend()) {
CachedSize size;
size.medium = quality;
size.vsize = _vsize;
size.pix = genPix(photo, _vsize);
it = _cached.insert(photo, size);
} else if (it->medium != quality || it->vsize != _vsize) {
it->medium = quality;
it->vsize = _vsize;
it->pix = genPix(photo, _vsize);
}
p.drawPixmap(pos, it->pix);
if (!quality) {
uint64 dt = itemAnimations().animate(item, ms);
int32 cnt = int32(st::photoLoaderCnt), period = int32(st::photoLoaderPeriod), t = dt % period, delta = int32(st::photoLoaderDelta);
int32 x = pos.x() + (_vsize - st::overviewLoader.width()) / 2, y = pos.y() + (_vsize - st::overviewLoader.height()) / 2;
p.fillRect(x, y, st::overviewLoader.width(), st::overviewLoader.height(), st::photoLoaderBg->b);
x += (st::overviewLoader.width() - cnt * st::overviewLoaderPoint.width() - (cnt - 1) * st::overviewLoaderSkip) / 2;
y += (st::overviewLoader.height() - st::overviewLoaderPoint.height()) / 2;
QColor c(st::white->c);
QBrush b(c);
for (int32 i = 0; i < cnt; ++i) {
t -= delta;
while (t < 0) t += period;
float64 alpha = (t >= st::photoLoaderDuration1 + st::photoLoaderDuration2) ? 0 : ((t > st::photoLoaderDuration1 ? ((st::photoLoaderDuration1 + st::photoLoaderDuration2 - t) / st::photoLoaderDuration2) : (t / st::photoLoaderDuration1)));
c.setAlphaF(st::photoLoaderAlphaMin + alpha * (1 - st::photoLoaderAlphaMin));
b.setColor(c);
p.fillRect(x + i * (st::overviewLoaderPoint.width() + st::overviewLoaderSkip), y, st::overviewLoaderPoint.width(), st::overviewLoaderPoint.height(), b);
}
}
} break;
case MediaTypeVideo: {
VideoData *video = static_cast<HistoryVideo*>(m)->video();
CachedSizes::iterator it = _cached.find(video);
if (it == _cached.cend()) {
CachedSize size;
size.medium = 0;
size.vsize = _vsize;
size.pix = genPix(video, _vsize);
it = _cached.insert(video, size);
} else if (it->vsize != _vsize) {
it->vsize = _vsize;
it->pix = genPix(video, _vsize);
}
p.drawPixmap(pos, it->pix);
} break;
}
uint32 sel = 0;
if (index >= selfrom && index <= selto) {
sel = (_dragSelecting && item->id > 0) ? FullSelection : 0;
} else if (hasSel) {
SelectedItems::const_iterator i = _selected.constFind(migratedindex ? -item->id : item->id);
if (i != selEnd) {
sel = i.value();
}
}
if (sel == FullSelection) {
p.fillRect(QRect(pos.x(), pos.y(), _vsize, _vsize), st::overviewPhotoSelectOverlay);
p.drawSprite(QPoint(pos.x() + _vsize - st::overviewPhotoCheck.pxWidth(), pos.y() + _vsize - st::overviewPhotoCheck.pxHeight()), st::overviewPhotoChecked);
} else if (_selMode/* || (selfrom < count && selfrom <= selto && 0 <= selto)*/) {
p.drawSprite(QPoint(pos.x() + _vsize - st::overviewPhotoCheck.pxWidth(), pos.y() + _vsize - st::overviewPhotoCheck.pxHeight()), st::overviewPhotoCheck);
}
if (m) {
p.translate(pos.x(), pos.y());
// m->drawOverview(p, _vsize, item, r.translated(-pos.x(), -pos.y()), sel == FullSelection, ms);
p.translate(-pos.x(), -pos.y());
}
QPoint pos(int32(col * w + st::overviewPhotoSkip), _addToY + row * (_vsize + st::overviewPhotoSkip) + st::overviewPhotoSkip);
p.translate(pos.x(), pos.y());
_items.at(i)->paint(p, r.translated(-pos.x(), -pos.y()), itemSelectedValue(i), &context);
p.translate(-pos.x(), -pos.y());
}
}
} else if (_type == OverviewAudioDocuments) {
@ -1358,18 +1299,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
if (_addToY + curY >= r.y() + r.height()) break;
p.translate(0, curY - y);
uint32 sel = 0;
if (_items.at(i)->toLayoutMediaItem()) { // draw item
if (i >= selfrom && i <= selto) {
sel = (_dragSelecting && _items.at(i)->msgId() > 0) ? FullSelection : 0;
} else if (hasSel) {
SelectedItems::const_iterator j = _selected.constFind(complexMsgId(_items.at(i)->getItem()));
if (j != selEnd) {
sel = j.value();
}
}
}
_items.at(i)->paint(p, r.translated(-_rowsLeft, -_addToY - curY), sel, ms);
_items.at(i)->paint(p, r.translated(-_rowsLeft, -_addToY - curY), itemSelectedValue(i), &context);
y = curY;
}
}
@ -1433,15 +1363,13 @@ void OverviewInner::onUpdateSelected() {
HistoryCursorState cursorState = HistoryDefaultCursorState;
if (_type == OverviewPhotos || _type == OverviewVideos) {
float64 w = (float64(_width - st::overviewPhotoSkip) / _photosInRow);
int32 inRow = int32((m.x() - (st::overviewPhotoSkip / 2)) / w), vsize = (_vsize + st::overviewPhotoSkip);
int32 col = int32((m.x() - (st::overviewPhotoSkip / 2)) / w), vsize = (_vsize + st::overviewPhotoSkip);
int32 row = int32((m.y() - _addToY - (st::overviewPhotoSkip / 2)) / vsize);
if (inRow < 0) inRow = 0;
if (col < 0) col = 0;
if (row < 0) row = 0;
bool upon = true;
History::MediaOverview &overview(_history->overview[_type]), *migratedOverview = _migrated ? &_migrated->overview[_type] : 0;
int32 migratedCount = migratedIndexSkip();
int32 i = row * _photosInRow + inRow - _photosToAdd, count = migratedCount + overview.size();
int32 count = _items.size(), i = count - (row * _photosInRow + col - _photosToAdd) - 1;
if (i < 0) {
i = 0;
upon = false;
@ -1451,18 +1379,11 @@ void OverviewInner::onUpdateSelected() {
upon = false;
}
if (i >= 0) {
MsgId msgid = (i >= migratedCount) ? overview[i - migratedCount] : (*migratedOverview)[i];
HistoryItem *histItem = App::histItemById((i >= migratedCount) ? _channel : _migrated->channelId(), msgid);
if (histItem) {
item = histItem;
if (LayoutMediaItem *media = _items.at(i)->toLayoutMediaItem()) {
item = media->getItem();
index = i;
if (upon && m.x() >= inRow * w + st::overviewPhotoSkip && m.x() < inRow * w + st::overviewPhotoSkip + _vsize) {
if (m.y() >= _addToY + row * vsize + st::overviewPhotoSkip && m.y() < _addToY + (row + 1) * vsize + st::overviewPhotoSkip) {
HistoryMedia *media = item->getMedia(true);
if (media) {
// media->getStateOverview(lnk, m.x() - inRow * w - st::overviewPhotoSkip, m.y() - _addToY - row * vsize - st::overviewPhotoSkip, item, _vsize);
}
}
if (upon) {
media->getState(lnk, cursorState, m.x() - col * w - st::overviewPhotoSkip, m.y() - _addToY - row * vsize - st::overviewPhotoSkip);
}
}
}
@ -1618,11 +1539,32 @@ void OverviewInner::onUpdateSelected() {
bool lnkChanged = false;
if (lnk != textlnkOver()) {
lnkChanged = true;
redrawItem(App::hoveredLinkItem());
if (textlnkOver()) {
if (HistoryItem *item = App::hoveredLinkItem()) {
if (_type == OverviewPhotos || _type == OverviewVideos || _type == OverviewDocuments) {
MsgId itemId = complexMsgId(item);
int32 itemIndex = oldMousedItemIndex;
fixItemIndex(itemIndex, itemId);
if (itemIndex >= 0) {
_items.at(itemIndex)->linkOut(textlnkOver());
redrawItem(itemId, itemIndex);
}
} else {
redrawItem(item);
}
}
}
textlnkOver(lnk);
App::hoveredLinkItem(lnk ? item : 0);
redrawItem(App::hoveredLinkItem());
QToolTip::hideText();
App::hoveredLinkItem(lnk ? item : 0);
if (textlnkOver()) {
if (item && index >= 0) {
if (_type == OverviewPhotos || _type == OverviewVideos || _type == OverviewDocuments) {
_items.at(index)->linkOver(textlnkOver());
}
redrawItem(complexMsgId(item), index);
}
}
} else {
App::mousedItem(item);
}
@ -1671,44 +1613,28 @@ void OverviewInner::onUpdateSelected() {
_selected[_dragItem] = 0;
updateDragSelection(0, -1, 0, -1, false);
} else if (canSelectMany) {
bool selectingDown = ((_type == OverviewPhotos || _type == OverviewVideos || _type == OverviewAudioDocuments || _type == OverviewLinks || _type == OverviewDocuments) ? (_mousedItemIndex > _dragItemIndex) : (_mousedItemIndex < _dragItemIndex)) || (_mousedItemIndex == _dragItemIndex && ((_type == OverviewPhotos || _type == OverviewVideos) ? (_dragStartPos.x() < m.x()) : (_dragStartPos.y() < m.y())));
bool selectingDown = (_reversed ? (_mousedItemIndex < _dragItemIndex) : (_mousedItemIndex > _dragItemIndex)) || (_mousedItemIndex == _dragItemIndex && ((_type == OverviewPhotos || _type == OverviewVideos) ? (_dragStartPos.x() < m.x()) : (_dragStartPos.y() < m.y())));
MsgId dragSelFrom = _dragItem, dragSelTo = _mousedItem;
int32 dragSelFromIndex = _dragItemIndex, dragSelToIndex = _mousedItemIndex;
if (!itemHasPoint(dragSelFrom, dragSelFromIndex, _dragStartPos.x(), _dragStartPos.y())) { // maybe exclude dragSelFrom
if (selectingDown) {
if (_type == OverviewPhotos || _type == OverviewVideos) {
if (_dragStartPos.x() >= _vsize || ((_mousedItem == dragSelFrom) && (m.x() < _dragStartPos.x() + QApplication::startDragDistance()))) {
moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, 1);
}
} else if (_type == OverviewAudioDocuments) {
if (_dragStartPos.y() >= itemHeight(dragSelFrom, dragSelFromIndex) || ((_mousedItem == dragSelFrom) && (m.y() < _dragStartPos.y() + QApplication::startDragDistance()))) {
moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, -1);
}
} else if (_type == OverviewLinks || _type == OverviewDocuments) {
} else {
if (_dragStartPos.y() >= itemHeight(dragSelFrom, dragSelFromIndex) || ((_mousedItem == dragSelFrom) && (m.y() < _dragStartPos.y() + QApplication::startDragDistance()))) {
moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, 1);
}
} else if (_type == OverviewAudios) {
if (_dragStartPos.y() >= itemHeight(dragSelFrom, dragSelFromIndex) || ((_mousedItem == dragSelFrom) && (m.y() < _dragStartPos.y() + QApplication::startDragDistance()))) {
moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, -1);
moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, _reversed ? -1 : 1);
}
}
} else {
if (_type == OverviewPhotos || _type == OverviewVideos) {
if (_dragStartPos.x() < 0 || ((_mousedItem == dragSelFrom) && (m.x() >= _dragStartPos.x() - QApplication::startDragDistance()))) {
moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, -1);
}
} else if (_type == OverviewAudioDocuments) {
if (_dragStartPos.y() < 0 || ((_mousedItem == dragSelFrom) && (m.y() >= _dragStartPos.y() - QApplication::startDragDistance()))) {
moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, 1);
}
} else if (_type == OverviewLinks || _type == OverviewDocuments) {
} else {
if (_dragStartPos.y() < 0 || ((_mousedItem == dragSelFrom) && (m.y() >= _dragStartPos.y() - QApplication::startDragDistance()))) {
moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, -1);
}
} else if (_type == OverviewAudios) {
if (_dragStartPos.y() < 0 || ((_mousedItem == dragSelFrom) && (m.y() >= _dragStartPos.y() - QApplication::startDragDistance()))) {
moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, 1);
moveToNextItem(dragSelFrom, dragSelFromIndex, dragSelTo, _reversed ? 1 : -1);
}
}
}
@ -1717,37 +1643,21 @@ void OverviewInner::onUpdateSelected() {
if (selectingDown) {
if (_type == OverviewPhotos || _type == OverviewVideos) {
if (m.x() < 0) {
moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, -1);
}
} else if (_type == OverviewAudioDocuments) {
if (m.y() < 0) {
moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, 1);
}
} else if (_type == OverviewLinks || _type == OverviewDocuments) {
} else {
if (m.y() < 0) {
moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, -1);
}
} else if (_type == OverviewAudios) {
if (m.y() < 0) {
moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, 1);
moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, _reversed ? 1 : -1);
}
}
} else {
if (_type == OverviewPhotos || _type == OverviewVideos) {
if (m.x() >= _vsize) {
moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, 1);
}
} else if (_type == OverviewAudioDocuments) {
if (m.y() >= itemHeight(dragSelTo, dragSelToIndex)) {
moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, -1);
}
} else if (_type == OverviewLinks || _type == OverviewDocuments) {
} else {
if (m.y() >= itemHeight(dragSelTo, dragSelToIndex)) {
moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, 1);
}
} else if (_type == OverviewAudios) {
if (m.y() >= itemHeight(dragSelTo, dragSelToIndex)) {
moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, -1);
moveToNextItem(dragSelTo, dragSelToIndex, dragSelFrom, _reversed ? -1 : 1);
}
}
}
@ -1756,7 +1666,7 @@ void OverviewInner::onUpdateSelected() {
MsgId dragFirstAffected = dragSelFrom;
int32 dragFirstAffectedIndex = dragSelFromIndex;
while (dragFirstAffectedIndex >= 0 && itemMsgId(dragFirstAffected) <= 0) {
moveToNextItem(dragFirstAffected, dragFirstAffectedIndex, dragSelTo, ((selectingDown && (_type == OverviewPhotos || _type == OverviewVideos || _type == OverviewAudioDocuments)) || (!selectingDown && (_type != OverviewPhotos && _type != OverviewVideos && _type != OverviewAudioDocuments))) ? -1 : 1);
moveToNextItem(dragFirstAffected, dragFirstAffectedIndex, dragSelTo, selectingDown ? (_reversed ? -1 : 1) : (_reversed ? 1 : -1));
}
if (dragFirstAffectedIndex >= 0) {
SelectedItems::const_iterator i = _selected.constFind(dragFirstAffected);
@ -2029,8 +1939,10 @@ int32 OverviewInner::resizeToWidth(int32 nwidth, int32 scrollTop, int32 minHeigh
_addToY = (_height < _minHeight) ? (_minHeight - _height) : 0;
}
if ((_type == OverviewPhotos || _type == OverviewVideos) && _resizeIndex < 0) {
_resizeIndex = _photosInRow * ((scrollTop + minHeight) / int32(_vsize + st::overviewPhotoSkip)) + _photosInRow - 1;
_resizeSkip = (scrollTop + minHeight) - ((scrollTop + minHeight) / int32(_vsize + st::overviewPhotoSkip)) * int32(_vsize + st::overviewPhotoSkip);
if (_resizeIndex < 0) {
_resizeIndex = _photosInRow * ((scrollTop + minHeight) / int32(_vsize + st::overviewPhotoSkip)) + _photosInRow - 1;
_resizeSkip = (scrollTop + minHeight) - ((scrollTop + minHeight) / int32(_vsize + st::overviewPhotoSkip)) * int32(_vsize + st::overviewPhotoSkip);
}
}
resize(nwidth, height() > _minHeight ? height() : _minHeight);
showAll();
@ -2059,17 +1971,9 @@ MediaOverviewType OverviewInner::type() const {
void OverviewInner::switchType(MediaOverviewType type) {
if (_type != type) {
_selected.clear();
_dragItemIndex = _mousedItemIndex = _dragSelFromIndex = _dragSelToIndex = -1;
_dragItem = _mousedItem = _dragSelFrom = _dragSelTo = 0;
_lnkOverIndex = _lnkDownIndex = 0;
for (int32 i = 0, l = _items.size(); i != l; ++i) {
delete _items.at(i);
}
_items.clear();
_cachedItems.clear();
_cached.clear();
clear();
_type = type;
_reversed = (_type != OverviewLinks && _type != OverviewDocuments);
if (_type == OverviewLinks || _type == OverviewDocuments) {
_search.show();
} else {
@ -2348,17 +2252,71 @@ void OverviewInner::mediaOverviewUpdated(bool fromResize) {
}
int32 oldHeight = _height;
if (_type == OverviewDocuments) {
if (_type == OverviewPhotos || _type == OverviewVideos) {
History::MediaOverview &o(_history->overview[_type]), *migratedOverview = _migrated ? &_migrated->overview[_type] : 0;
int32 migrateCount = migratedIndexSkip();
int32 wasCount = _items.size(), fullCount = (migrateCount + o.size());
int32 tocheck = qMin(fullCount, _cachedItemsToBeLoaded);
_items.reserve(tocheck);
int32 index = 0;
bool allGood = true;
for (int32 i = fullCount, l = fullCount - tocheck; i > l;) {
--i;
MsgId msgid = ((i < migrateCount) ? -migratedOverview->at(i) : o.at(i - migrateCount));
if (allGood) {
if (_items.size() > index && complexMsgId(_items.at(index)->getItem()) == msgid) {
++index;
continue;
}
allGood = false;
}
HistoryItem *item = App::histItemById(itemChannel(msgid), itemMsgId(msgid));
HistoryMedia *media = item ? item->getMedia(true) : 0;
LayoutItem *layout = 0;
if (_type == OverviewPhotos) {
PhotoData *photo = (media && media->type() == MediaTypePhoto) ? static_cast<HistoryPhoto*>(media)->photo() : 0;
if (photo) layout = new LayoutOverviewPhoto(photo, item);
} else if (_type == OverviewVideos) {
VideoData *video = (media && media->type() == MediaTypeVideo) ? static_cast<HistoryVideo*>(media)->video() : 0;
if (video) layout = new LayoutOverviewVideo(video, item);
}
if (!layout) continue;
QDate date = item->date.date();
if (_items.size() > index) {
delete _items.at(index);
_items[index] = layout;
} else {
_items.push_back(layout);
}
layout->initDimensions();
layout->resizeGetHeight(_vsize);
++index;
}
for (int32 l = _items.size(); l > index;) {
delete _items.at(--l);
}
_items.resize(index);
if (!fromResize && _items.size() != wasCount) {
_height = qMax(recountHeight(), _minHeight);
if (height() != _height) {
resize(width(), _height);
}
}
dragActionUpdate(QCursor::pos());
update();
} else if (_type == OverviewDocuments) {
History::MediaOverview &o(_history->overview[_type]), *migratedOverview = _migrated ? &_migrated->overview[_type] : 0;
int32 migrateCount = migratedIndexSkip();
int32 l = _inSearch ? _searchResults.size() : (migrateCount + o.size()), tocheck = qMin(l, _cachedItemsToBeLoaded);
_items.reserve(2 * l); // day items
_items.reserve(2 * tocheck); // day items
int32 top = 0, in = 0, addtoheight = _addToY + st::linksSearchMargin.top();
bool allGood = true;
QDate prevDate;
for (int32 i = 0; i < tocheck; ++i) {
MsgId msgid = _inSearch ? _searchResults.at(l - i - 1) : ((l - i - 1 < migrateCount) ? -(*migratedOverview)[l - i - 1] : o.at(l - i - 1 - migrateCount));
MsgId msgid = _inSearch ? _searchResults.at(l - i - 1) : ((l - i - 1 < migrateCount) ? -migratedOverview->at(l - i - 1) : o.at(l - i - 1 - migrateCount));
if (allGood) {
if (_items.size() > in && complexMsgId(_items.at(in)->getItem()) == msgid) {
prevDate = _items.at(in)->getItem()->date.date();
@ -2391,7 +2349,8 @@ void OverviewInner::mediaOverviewUpdated(bool fromResize) {
}
HistoryItem *item = App::histItemById(itemChannel(msgid), itemMsgId(msgid));
HistoryMedia *media = item ? item->getMedia(true) : 0;
if (!media) continue;
DocumentData *document = media ? media->getDocument() : 0;
if (!document) continue;
QDate date = item->date.date();
if (!in || (in > 0 && date != prevDate)) {
@ -2409,9 +2368,9 @@ void OverviewInner::mediaOverviewUpdated(bool fromResize) {
if (_items.size() > in) {
delete _items.at(in);
_items[in] = new LayoutOverviewDocument(media->getDocument(), item, top);
_items[in] = new LayoutOverviewDocument(document, item, top);
} else {
_items.push_back(new LayoutOverviewDocument(media->getDocument(), item, top));
_items.push_back(new LayoutOverviewDocument(document, item, top));
}
_items.at(in)->initDimensions();
top += _items.at(in)->resizeGetHeight(_rowWidth);
@ -2435,13 +2394,13 @@ void OverviewInner::mediaOverviewUpdated(bool fromResize) {
History::MediaOverview &o(_history->overview[_type]), *migratedOverview = _migrated ? &_migrated->overview[_type] : 0;
int32 migrateCount = migratedIndexSkip();
int32 l = _inSearch ? _searchResults.size() : (migrateCount + o.size()), tocheck = qMin(l, _cachedItemsToBeLoaded);
_cachedItems.reserve(2 * l); // day items
_cachedItems.reserve(2 * tocheck); // day items
int32 y = 0, in = 0, addtoheight = _addToY + st::linksSearchMargin.top();
bool allGood = true;
QDate prevDate;
for (int32 i = 0; i < tocheck; ++i) {
MsgId msgid = _inSearch ? _searchResults.at(l - i - 1) : ((l - i - 1 < migrateCount) ? -(*migratedOverview)[l - i - 1] : o.at(l - i - 1 - migrateCount));
MsgId msgid = _inSearch ? _searchResults.at(l - i - 1) : ((l - i - 1 < migrateCount) ? -migratedOverview->at(l - i - 1) : o.at(l - i - 1 - migrateCount));
if (allGood) {
if (_cachedItems.size() > in && _cachedItems.at(in).msgid == msgid) {
prevDate = _cachedItems.at(in).date;
@ -2684,13 +2643,16 @@ void OverviewInner::redrawItem(const HistoryItem *msg) {
MsgId msgid = msg->id;
if (history->overviewHasMsgId(_type, msgid) && (history == _history || migrateindex > 0)) {
if (_type == OverviewPhotos || _type == OverviewVideos) {
int32 index = history->overview[_type].indexOf(msgid);
if (index >= 0) {
if (history == _history) index += migrateindex;
float64 w = (float64(width() - st::overviewPhotoSkip) / _photosInRow);
int32 vsize = (_vsize + st::overviewPhotoSkip);
int32 row = (_photosToAdd + index) / _photosInRow, col = (_photosToAdd + index) % _photosInRow;
update(int32(col * w), _addToY + int32(row * vsize), qCeil(w), vsize);
if (history == _migrated) msgid = -msgid;
for (int32 i = 0, l = _items.size(); i != l; ++i) {
if (complexMsgId(_items.at(i)->getItem()) == msgid) {
int32 shownAtIndex = _items.size() - i - 1;
float64 w = (float64(width() - st::overviewPhotoSkip) / _photosInRow);
int32 vsize = (_vsize + st::overviewPhotoSkip);
int32 row = (_photosToAdd + shownAtIndex) / _photosInRow, col = (_photosToAdd + shownAtIndex) % _photosInRow;
update(int32(col * w), _addToY + int32(row * vsize), qCeil(w), vsize);
break;
}
}
} else if (_type == OverviewAudioDocuments) {
int32 index = history->overview[_type].indexOf(msgid);
@ -2726,12 +2688,10 @@ void OverviewInner::redrawItem(const HistoryItem *msg) {
}
}
void OverviewInner::showAll(bool recountHeights) {
int32 newHeight = height();
int32 OverviewInner::recountHeight() {
int32 result = _height;
if (_type == OverviewPhotos || _type == OverviewVideos) {
_photosInRow = int32(width() - st::overviewPhotoSkip) / int32(st::overviewPhotoMinSize + st::overviewPhotoSkip);
_vsize = (int32(width() - st::overviewPhotoSkip) / _photosInRow) - st::overviewPhotoSkip;
int32 migratedCount = migratedIndexSkip(), count = migratedCount + _history->overview[_type].size();
int32 count = _items.size();
int32 migratedFullCount = _migrated ? _migrated->overviewCount(_type) : 0;
int32 fullCount = migratedFullCount + _history->overviewCount(_type);
if (fullCount > 0 && migratedFullCount >= 0) {
@ -2742,8 +2702,21 @@ void OverviewInner::showAll(bool recountHeights) {
_photosToAdd = 0;
}
int32 rows = ((_photosToAdd + count) / _photosInRow) + (((_photosToAdd + count) % _photosInRow) ? 1 : 0);
newHeight = _height = (_vsize + st::overviewPhotoSkip) * rows + st::overviewPhotoSkip;
_addToY = (_height < _minHeight) ? (_minHeight - _height) : 0;
result = (_vsize + st::overviewPhotoSkip) * rows + st::overviewPhotoSkip;
_addToY = (result < _minHeight) ? (_minHeight - result) : 0;
}
return result;
}
void OverviewInner::showAll(bool recountHeights) {
int32 newHeight = height();
if (_type == OverviewPhotos || _type == OverviewVideos) {
_photosInRow = int32(width() - st::overviewPhotoSkip) / int32(st::overviewPhotoMinSize + st::overviewPhotoSkip);
_vsize = (int32(width() - st::overviewPhotoSkip) / _photosInRow) - st::overviewPhotoSkip;
for (int32 i = 0, l = _items.size(); i < l; ++i) {
_items.at(i)->resizeGetHeight(_vsize);
}
newHeight = _height = recountHeight();
} else if (_type == OverviewAudioDocuments) {
int32 migratedCount = migratedIndexSkip(), count = migratedCount + _history->overview[_type].size();
newHeight = _height = count * _rowHeight + 2 * st::playlistPadding;
@ -2834,6 +2807,7 @@ void OverviewWidget::onScroll() {
}
void OverviewWidget::resizeEvent(QResizeEvent *e) {
_noDropResizeIndex = true;
int32 st = _scroll.scrollTop();
_scroll.resize(size());
int32 newScrollTop = _inner.resizeToWidth(width(), st, height());
@ -2841,10 +2815,9 @@ void OverviewWidget::resizeEvent(QResizeEvent *e) {
newScrollTop += addToY;
}
if (newScrollTop != _scroll.scrollTop()) {
_noDropResizeIndex = true;
_scroll.scrollToY(newScrollTop);
_noDropResizeIndex = false;
}
_noDropResizeIndex = false;
_topShadow.resize(width() - ((cWideMode() && !_inGrab) ? st::lineWidth : 0), st::lineWidth);
_topShadow.moveToLeft((cWideMode() && !_inGrab) ? st::lineWidth : 0, 0);
@ -3079,9 +3052,15 @@ void OverviewWidget::changingMsgId(HistoryItem *row, MsgId newId) {
}
}
void OverviewWidget::ui_redrawHistoryItem(const HistoryItem *msg) {
if (peer() == msg->history()->peer || migratePeer() == msg->history()->peer) {
_inner.redrawItem(msg);
void OverviewWidget::ui_redrawHistoryItem(const HistoryItem *item) {
if (peer() == item->history()->peer || migratePeer() == item->history()->peer) {
_inner.redrawItem(item);
}
}
void OverviewWidget::notify_historyItemLayoutChanged(const HistoryItem *item) {
if (peer() == item->history()->peer || migratePeer() == item->history()->peer) {
_inner.onUpdateSelected();
}
}

View file

@ -136,6 +136,7 @@ private:
QPixmap genPix(PhotoData *photo, int32 size);
QPixmap genPix(VideoData *video, int32 size);
void showAll(bool recountHeights = false);
int32 recountHeight();
OverviewWidget *_overview;
ScrollArea *_scroll;
@ -143,22 +144,18 @@ private:
PeerData *_peer;
MediaOverviewType _type;
bool _reversed;
History *_migrated, *_history;
ChannelId _channel;
bool _selMode;
uint32 itemSelectedValue(int32 index) const;
// for audio files, files, voice messages and links
int32 _rowsLeft, _rowWidth, _rowHeight;
// photos
int32 _photosInRow, _photosToAdd, _vsize;
struct CachedSize {
int32 vsize;
bool medium;
QPixmap pix;
};
typedef QMap<void*, CachedSize> CachedSizes;
CachedSizes _cached;
bool _selMode;
// shared links
struct Link {
@ -343,7 +340,9 @@ public:
resizeEvent(0);
}
void ui_redrawHistoryItem(const HistoryItem *msg);
void ui_redrawHistoryItem(const HistoryItem *item);
void notify_historyItemLayoutChanged(const HistoryItem *item);
~OverviewWidget();