Photo and video overview and background gallery checkboxes improved.
This commit is contained in:
		
							parent
							
								
									e880c4876e
								
							
						
					
					
						commit
						9fa284a6d1
					
				
					 13 changed files with 491 additions and 246 deletions
				
			
		
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 313 B After Width: | Height: | Size: 309 B  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 632 B After Width: | Height: | Size: 623 B  | 
| 
						 | 
					@ -27,6 +27,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 | 
				
			||||||
#include "window/window_theme.h"
 | 
					#include "window/window_theme.h"
 | 
				
			||||||
#include "styles/style_overview.h"
 | 
					#include "styles/style_overview.h"
 | 
				
			||||||
#include "styles/style_boxes.h"
 | 
					#include "styles/style_boxes.h"
 | 
				
			||||||
 | 
					#include "ui/effects/round_image_checkbox.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BackgroundBox::BackgroundBox() : ItemListBox(st::backgroundScroll)
 | 
					BackgroundBox::BackgroundBox() : ItemListBox(st::backgroundScroll)
 | 
				
			||||||
, _inner(this) {
 | 
					, _inner(this) {
 | 
				
			||||||
| 
						 | 
					@ -50,10 +51,8 @@ void BackgroundBox::onBackgroundChosen(int index) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BackgroundBox::Inner::Inner(QWidget *parent) : TWidget(parent)
 | 
					BackgroundBox::Inner::Inner(QWidget *parent) : TWidget(parent)
 | 
				
			||||||
, _bgCount(0)
 | 
					, _check(std_::make_unique<Ui::RoundCheckbox>(st::overviewCheck, [this] { update(); })) {
 | 
				
			||||||
, _rows(0)
 | 
						_check->setChecked(true, Ui::RoundCheckbox::SetStyle::Fast);
 | 
				
			||||||
, _over(-1)
 | 
					 | 
				
			||||||
, _overDown(-1) {
 | 
					 | 
				
			||||||
	if (App::cServerBackgrounds().isEmpty()) {
 | 
						if (App::cServerBackgrounds().isEmpty()) {
 | 
				
			||||||
		resize(BackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
 | 
							resize(BackgroundsInRow * (st::backgroundSize.width() + st::backgroundPadding) + st::backgroundPadding, 2 * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
 | 
				
			||||||
		MTP::send(MTPaccount_GetWallPapers(), rpcDone(&Inner::gotWallpapers));
 | 
							MTP::send(MTPaccount_GetWallPapers(), rpcDone(&Inner::gotWallpapers));
 | 
				
			||||||
| 
						 | 
					@ -157,9 +156,9 @@ void BackgroundBox::Inner::paintEvent(QPaintEvent *e) {
 | 
				
			||||||
				p.drawPixmap(x, y, pix);
 | 
									p.drawPixmap(x, y, pix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (paper.id == Window::Theme::Background()->id()) {
 | 
									if (paper.id == Window::Theme::Background()->id()) {
 | 
				
			||||||
					int checkPosX = x + st::backgroundSize.width() - st::overviewPhotoChecked.width();
 | 
										auto checkLeft = x + st::backgroundSize.width() - st::overviewCheckSkip - st::overviewCheck.size;
 | 
				
			||||||
					int checkPosY = y + st::backgroundSize.height() - st::overviewPhotoChecked.height();
 | 
										auto checkTop = y + st::backgroundSize.height() - st::overviewCheckSkip - st::overviewCheck.size;
 | 
				
			||||||
					st::overviewPhotoChecked.paint(p, QPoint(checkPosX, checkPosY), width());
 | 
										_check->paint(p, getms(), checkLeft, checkTop, width());
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -198,5 +197,4 @@ void BackgroundBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void BackgroundBox::Inner::resizeEvent(QResizeEvent *e) {
 | 
					BackgroundBox::Inner::~Inner() = default;
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "boxes/abstractbox.h"
 | 
					#include "boxes/abstractbox.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ui {
 | 
				
			||||||
 | 
					class RoundCheckbox;
 | 
				
			||||||
 | 
					} // namespace Ui
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class BackgroundBox : public ItemListBox {
 | 
					class BackgroundBox : public ItemListBox {
 | 
				
			||||||
	Q_OBJECT
 | 
						Q_OBJECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,6 +47,7 @@ class BackgroundBox::Inner : public TWidget, public RPCSender, private base::Sub
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	Inner(QWidget *parent);
 | 
						Inner(QWidget *parent);
 | 
				
			||||||
 | 
						~Inner();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
signals:
 | 
					signals:
 | 
				
			||||||
	void backgroundChosen(int index);
 | 
						void backgroundChosen(int index);
 | 
				
			||||||
| 
						 | 
					@ -52,13 +57,15 @@ protected:
 | 
				
			||||||
	void mouseMoveEvent(QMouseEvent *e) override;
 | 
						void mouseMoveEvent(QMouseEvent *e) override;
 | 
				
			||||||
	void mousePressEvent(QMouseEvent *e) override;
 | 
						void mousePressEvent(QMouseEvent *e) override;
 | 
				
			||||||
	void mouseReleaseEvent(QMouseEvent *e) override;
 | 
						void mouseReleaseEvent(QMouseEvent *e) override;
 | 
				
			||||||
	void resizeEvent(QResizeEvent *e) override;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	void gotWallpapers(const MTPVector<MTPWallPaper> &result);
 | 
						void gotWallpapers(const MTPVector<MTPWallPaper> &result);
 | 
				
			||||||
	void updateWallpapers();
 | 
						void updateWallpapers();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int32 _bgCount, _rows;
 | 
						int _bgCount = 0;
 | 
				
			||||||
	int32 _over, _overDown;
 | 
						int _rows = 0;
 | 
				
			||||||
 | 
						int _over = -1;
 | 
				
			||||||
 | 
						int _overDown = -1;
 | 
				
			||||||
 | 
						std_::unique_ptr<Ui::RoundCheckbox> _check;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -304,11 +304,11 @@ contactsPhotoCheckbox: RoundImageCheckbox {
 | 
				
			||||||
	selectWidth: 2px;
 | 
						selectWidth: 2px;
 | 
				
			||||||
	selectFg: windowBgActive;
 | 
						selectFg: windowBgActive;
 | 
				
			||||||
	selectDuration: 150;
 | 
						selectDuration: 150;
 | 
				
			||||||
	checkBorder: windowBg;
 | 
						check: RoundCheckbox(defaultRoundCheckbox) {
 | 
				
			||||||
	checkBg: windowBgActive;
 | 
							size: 20px;
 | 
				
			||||||
	checkRadius: 10px;
 | 
							sizeSmall: 0.3;
 | 
				
			||||||
	checkSmallRadius: 3px;
 | 
							check: icon {{ "default_checkbox_check", windowFgActive, point(3px, 6px) }};
 | 
				
			||||||
	checkIcon: icon {{ "default_checkbox_check", windowFgActive, point(3px, 6px) }};
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
contactsPhotoDisabledCheckFg: #bbbbbb;
 | 
					contactsPhotoDisabledCheckFg: #bbbbbb;
 | 
				
			||||||
contactsNameCheckedFg: #2b88b8;
 | 
					contactsNameCheckedFg: #2b88b8;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1002,11 +1002,11 @@ void ContactsBox::Inner::paintDisabledCheckUserpic(Painter &p, PeerData *peer, i
 | 
				
			||||||
	auto userpicBorderPen = st::contactsPhotoDisabledCheckFg->p;
 | 
						auto userpicBorderPen = st::contactsPhotoDisabledCheckFg->p;
 | 
				
			||||||
	userpicBorderPen.setWidth(st::contactsPhotoCheckbox.selectWidth);
 | 
						userpicBorderPen.setWidth(st::contactsPhotoCheckbox.selectWidth);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto iconDiameter = 2 * st::contactsPhotoCheckbox.checkRadius;
 | 
						auto iconDiameter = st::contactsPhotoCheckbox.check.size;
 | 
				
			||||||
	auto iconLeft = x + userpicDiameter + st::contactsPhotoCheckbox.selectWidth - iconDiameter;
 | 
						auto iconLeft = x + userpicDiameter + st::contactsPhotoCheckbox.selectWidth - iconDiameter;
 | 
				
			||||||
	auto iconTop = y + userpicDiameter + st::contactsPhotoCheckbox.selectWidth - iconDiameter;
 | 
						auto iconTop = y + userpicDiameter + st::contactsPhotoCheckbox.selectWidth - iconDiameter;
 | 
				
			||||||
	auto iconEllipse = rtlrect(iconLeft, iconTop, iconDiameter, iconDiameter, outerWidth);
 | 
						auto iconEllipse = rtlrect(iconLeft, iconTop, iconDiameter, iconDiameter, outerWidth);
 | 
				
			||||||
	auto iconBorderPen = st::contactsPhotoCheckbox.checkBorder->p;
 | 
						auto iconBorderPen = st::contactsPhotoCheckbox.check.border->p;
 | 
				
			||||||
	iconBorderPen.setWidth(st::contactsPhotoCheckbox.selectWidth);
 | 
						iconBorderPen.setWidth(st::contactsPhotoCheckbox.selectWidth);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	peer->paintUserpicLeft(p, userpicRadius * 2, userpicLeft, userpicTop, width());
 | 
						peer->paintUserpicLeft(p, userpicRadius * 2, userpicLeft, userpicTop, width());
 | 
				
			||||||
| 
						 | 
					@ -1023,7 +1023,7 @@ void ContactsBox::Inner::paintDisabledCheckUserpic(Painter &p, PeerData *peer, i
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p.setRenderHint(QPainter::HighQualityAntialiasing, false);
 | 
						p.setRenderHint(QPainter::HighQualityAntialiasing, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	st::contactsPhotoCheckbox.checkIcon.paint(p, iconEllipse.topLeft(), outerWidth);
 | 
						st::contactsPhotoCheckbox.check.check.paint(p, iconEllipse.topLeft(), outerWidth);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ContactsBox::Inner::paintEvent(QPaintEvent *e) {
 | 
					void ContactsBox::Inner::paintEvent(QPaintEvent *e) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2082,8 +2082,8 @@ void MainWidget::fillPeerMenu(PeerData *peer, base::lambda<QAction*(const QStrin
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if (peer->isChat()) {
 | 
						} else if (peer->isChat()) {
 | 
				
			||||||
		callback(lang(lng_profile_clear_history), std_::move(clearHistoryHandler));
 | 
					 | 
				
			||||||
		callback(lang(lng_profile_clear_and_exit), std_::move(deleteAndLeaveHandler));
 | 
							callback(lang(lng_profile_clear_and_exit), std_::move(deleteAndLeaveHandler));
 | 
				
			||||||
 | 
							callback(lang(lng_profile_clear_history), std_::move(clearHistoryHandler));
 | 
				
			||||||
	} else if (peer->isChannel() && peer->asChannel()->amIn() && !peer->asChannel()->amCreator()) {
 | 
						} else if (peer->isChannel() && peer->asChannel()->amIn() && !peer->asChannel()->amCreator()) {
 | 
				
			||||||
		callback(lang(peer->isMegagroup() ? lng_profile_leave_group : lng_profile_leave_channel), std_::move(deleteAndLeaveHandler));
 | 
							callback(lang(peer->isMegagroup() ? lng_profile_leave_group : lng_profile_leave_channel), std_::move(deleteAndLeaveHandler));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,21 +43,22 @@ OverviewFileLayout {
 | 
				
			||||||
	fileDateTop: pixels;
 | 
						fileDateTop: pixels;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
overviewCheckBg: #00000042;
 | 
					overviewCheckBg: #00000040;
 | 
				
			||||||
overviewCheckedBg: #2fa9e2;
 | 
					overviewCheckFg: windowBg;
 | 
				
			||||||
 | 
					overviewCheckFgActive: windowBg;
 | 
				
			||||||
 | 
					overviewCheckPressedSize: 0.8;
 | 
				
			||||||
 | 
					overviewCheck: RoundCheckbox(defaultRoundCheckbox) {
 | 
				
			||||||
 | 
						bgInactive: overviewCheckBg;
 | 
				
			||||||
 | 
						size: 29px;
 | 
				
			||||||
 | 
						sizeSmall: 0.3;
 | 
				
			||||||
 | 
						check: icon {{ "overview_photo_check", overviewCheckFgActive, point(4px, 8px) }};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					overviewCheckSkip: 5px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
overviewPhotoSkip: 10px;
 | 
					overviewPhotoSkip: 10px;
 | 
				
			||||||
overviewPhotoBg: #F1F1F1;
 | 
					overviewPhotoBg: #F1F1F1;
 | 
				
			||||||
overviewPhotoMinSize: minPhotoSize;
 | 
					overviewPhotoMinSize: minPhotoSize;
 | 
				
			||||||
overviewPhotoCheck: icon {
 | 
					overviewPhotoSelectOverlay: #40ace333;
 | 
				
			||||||
	{ size(31px, 31px), overviewCheckBg },
 | 
					 | 
				
			||||||
	{ "overview_photo_check", #ffffff, point(4px, 8px) },
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
overviewPhotoChecked: icon {
 | 
					 | 
				
			||||||
	{ size(31px, 31px), overviewCheckedBg },
 | 
					 | 
				
			||||||
	{ "overview_photo_check", #ffffff, point(4px, 8px) },
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
overviewPhotoSelectOverlay: #0a7bb03f;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
overviewVideoBg: #000000;
 | 
					overviewVideoBg: #000000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -111,11 +112,11 @@ linksPhotoSize: 46px;
 | 
				
			||||||
linksPhotoPadding: 12px;
 | 
					linksPhotoPadding: 12px;
 | 
				
			||||||
overviewLinksCheck: icon {
 | 
					overviewLinksCheck: icon {
 | 
				
			||||||
	{ "overview_links_check_bg", overviewCheckBg },
 | 
						{ "overview_links_check_bg", overviewCheckBg },
 | 
				
			||||||
	{ "overview_links_check", #ffffff, point(4px, 5px) },
 | 
						{ "overview_links_check", overviewCheckFg, point(4px, 5px) },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
overviewLinksChecked: icon {
 | 
					overviewLinksChecked: icon {
 | 
				
			||||||
	{ "overview_links_check_bg", overviewCheckedBg },
 | 
						{ "overview_links_check_bg", windowBgActive },
 | 
				
			||||||
	{ "overview_links_check", #ffffff, point(4px, 5px) },
 | 
						{ "overview_links_check", overviewCheckFgActive, point(4px, 5px) },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
overviewFilter: FlatInput(defaultFlatInput) {
 | 
					overviewFilter: FlatInput(defaultFlatInput) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,6 +35,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 | 
				
			||||||
#include "media/player/media_player_instance.h"
 | 
					#include "media/player/media_player_instance.h"
 | 
				
			||||||
#include "localstorage.h"
 | 
					#include "localstorage.h"
 | 
				
			||||||
#include "history/history_media_types.h"
 | 
					#include "history/history_media_types.h"
 | 
				
			||||||
 | 
					#include "ui/effects/round_image_checkbox.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Overview {
 | 
					namespace Overview {
 | 
				
			||||||
namespace Layout {
 | 
					namespace Layout {
 | 
				
			||||||
| 
						 | 
					@ -101,7 +102,7 @@ void RadialProgressItem::step_radial(uint64 ms, bool timer) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void RadialProgressItem::ensureRadial() const {
 | 
					void RadialProgressItem::ensureRadial() {
 | 
				
			||||||
	if (!_radial) {
 | 
						if (!_radial) {
 | 
				
			||||||
		_radial = new Ui::RadialAnimation(animation(const_cast<RadialProgressItem*>(this), &RadialProgressItem::step_radial));
 | 
							_radial = new Ui::RadialAnimation(animation(const_cast<RadialProgressItem*>(this), &RadialProgressItem::step_radial));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -118,21 +119,25 @@ RadialProgressItem::~RadialProgressItem() {
 | 
				
			||||||
	delete base::take(_radial);
 | 
						delete base::take(_radial);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FileBase::setStatusSize(int32 newSize, int32 fullSize, int32 duration, qint64 realDuration) const {
 | 
					void StatusText::update(int newSize, int fullSize, int duration, int64 realDuration) {
 | 
				
			||||||
	_statusSize = newSize;
 | 
						setSize(newSize);
 | 
				
			||||||
	if (_statusSize == FileStatusSizeReady) {
 | 
						if (_size == FileStatusSizeReady) {
 | 
				
			||||||
		_statusText = (duration >= 0) ? formatDurationAndSizeText(duration, fullSize) : (duration < -1 ? formatGifAndSizeText(fullSize) : formatSizeText(fullSize));
 | 
							_text = (duration >= 0) ? formatDurationAndSizeText(duration, fullSize) : (duration < -1 ? formatGifAndSizeText(fullSize) : formatSizeText(fullSize));
 | 
				
			||||||
	} else if (_statusSize == FileStatusSizeLoaded) {
 | 
						} else if (_size == FileStatusSizeLoaded) {
 | 
				
			||||||
		_statusText = (duration >= 0) ? formatDurationText(duration) : (duration < -1 ? qsl("GIF") : formatSizeText(fullSize));
 | 
							_text = (duration >= 0) ? formatDurationText(duration) : (duration < -1 ? qsl("GIF") : formatSizeText(fullSize));
 | 
				
			||||||
	} else if (_statusSize == FileStatusSizeFailed) {
 | 
						} else if (_size == FileStatusSizeFailed) {
 | 
				
			||||||
		_statusText = lang(lng_attach_failed);
 | 
							_text = lang(lng_attach_failed);
 | 
				
			||||||
	} else if (_statusSize >= 0) {
 | 
						} else if (_size >= 0) {
 | 
				
			||||||
		_statusText = formatDownloadText(_statusSize, fullSize);
 | 
							_text = formatDownloadText(_size, fullSize);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		_statusText = formatPlayedText(-_statusSize - 1, realDuration);
 | 
							_text = formatPlayedText(-_size - 1, realDuration);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void StatusText::setSize(int newSize) {
 | 
				
			||||||
 | 
						_size = newSize;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Date::Date(const QDate &date, bool month)
 | 
					Date::Date(const QDate &date, bool month)
 | 
				
			||||||
: _date(date)
 | 
					: _date(date)
 | 
				
			||||||
, _text(month ? langMonthFull(date) : langDayOfMonthFull(date)) {
 | 
					, _text(month ? langMonthFull(date) : langDayOfMonthFull(date)) {
 | 
				
			||||||
| 
						 | 
					@ -144,7 +149,7 @@ void Date::initDimensions() {
 | 
				
			||||||
	_minh = st::linksDateMargin.top() + st::normalFont->height + st::linksDateMargin.bottom() + st::linksBorder;
 | 
						_minh = st::linksDateMargin.top() + st::normalFont->height + st::linksDateMargin.bottom() + st::linksBorder;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Date::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const {
 | 
					void Date::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) {
 | 
				
			||||||
	if (clip.intersects(QRect(0, st::linksDateMargin.top(), _width, st::normalFont->height))) {
 | 
						if (clip.intersects(QRect(0, st::linksDateMargin.top(), _width, st::normalFont->height))) {
 | 
				
			||||||
		p.setPen(st::linksDateColor);
 | 
							p.setPen(st::linksDateColor);
 | 
				
			||||||
		p.setFont(st::semiboldFont);
 | 
							p.setFont(st::semiboldFont);
 | 
				
			||||||
| 
						 | 
					@ -152,25 +157,62 @@ void Date::paint(Painter &p, const QRect &clip, TextSelection selection, const P
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					class PhotoVideoCheckbox {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						template <typename UpdateCallback>
 | 
				
			||||||
 | 
						PhotoVideoCheckbox(UpdateCallback callback) : _updateCallback(callback), _check(st::overviewCheck, _updateCallback) {
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void paintPhotoVideoCheck(Painter &p, int width, int height, bool selected) {
 | 
						void paint(Painter &p, uint64 ms, int width, int height, bool selected, bool selecting);
 | 
				
			||||||
	int checkPosX = width - st::overviewPhotoCheck.width();
 | 
					
 | 
				
			||||||
	int checkPosY = height - st::overviewPhotoCheck.height();
 | 
						void setActive(bool active);
 | 
				
			||||||
 | 
						void setPressed(bool pressed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						void startAnimation();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						base::lambda_copy<void()> _updateCallback;
 | 
				
			||||||
 | 
						Ui::RoundCheckbox _check;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FloatAnimation _pression;
 | 
				
			||||||
 | 
						bool _active = false;
 | 
				
			||||||
 | 
						bool _pressed = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void PhotoVideoCheckbox::paint(Painter &p, uint64 ms, int width, int height, bool selected, bool selecting) {
 | 
				
			||||||
	if (selected) {
 | 
						if (selected) {
 | 
				
			||||||
		p.fillRect(QRect(0, 0, width, height), st::overviewPhotoSelectOverlay);
 | 
							p.fillRect(0, 0, width, height, st::overviewPhotoSelectOverlay);
 | 
				
			||||||
		st::overviewPhotoChecked.paint(p, QPoint(checkPosX, checkPosY), width);
 | 
						}
 | 
				
			||||||
	} else {
 | 
						_check.setDisplayInactive(selecting);
 | 
				
			||||||
		st::overviewPhotoCheck.paint(p, QPoint(checkPosX, checkPosY), width);
 | 
						_check.setChecked(selected);
 | 
				
			||||||
 | 
						auto pression = _pression.current(ms, (_active && _pressed) ? 1. : 0.);
 | 
				
			||||||
 | 
						auto masterScale = 1. - (1. - st::overviewCheckPressedSize) * pression;
 | 
				
			||||||
 | 
						_check.paint(p, ms, width - st::overviewCheckSkip - st::overviewCheck.size, height - st::overviewCheckSkip - st::overviewCheck.size, width, masterScale);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void PhotoVideoCheckbox::setActive(bool active) {
 | 
				
			||||||
 | 
						_active = active;
 | 
				
			||||||
 | 
						if (_pressed) {
 | 
				
			||||||
 | 
							startAnimation();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace
 | 
					void PhotoVideoCheckbox::setPressed(bool pressed) {
 | 
				
			||||||
 | 
						_pressed = pressed;
 | 
				
			||||||
 | 
						if (_active) {
 | 
				
			||||||
 | 
							startAnimation();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void PhotoVideoCheckbox::startAnimation() {
 | 
				
			||||||
 | 
						auto showPressed = (_pressed && _active);
 | 
				
			||||||
 | 
						_pression.start(_updateCallback, showPressed ? 0. : 1., showPressed ? 1. : 0., st::overviewCheck.duration);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Photo::Photo(PhotoData *photo, HistoryItem *parent) : ItemBase(parent)
 | 
					Photo::Photo(PhotoData *photo, HistoryItem *parent) : ItemBase(parent)
 | 
				
			||||||
, _data(photo)
 | 
					, _data(photo)
 | 
				
			||||||
, _link(new PhotoOpenClickHandler(photo))
 | 
					, _link(new PhotoOpenClickHandler(photo)) {
 | 
				
			||||||
, _goodLoaded(false) {
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Photo::initDimensions() {
 | 
					void Photo::initDimensions() {
 | 
				
			||||||
| 
						 | 
					@ -187,7 +229,7 @@ int32 Photo::resizeGetHeight(int32 width) {
 | 
				
			||||||
	return _height;
 | 
						return _height;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Photo::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const {
 | 
					void Photo::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) {
 | 
				
			||||||
	bool good = _data->loaded(), selected = (selection == FullSelection);
 | 
						bool good = _data->loaded(), selected = (selection == FullSelection);
 | 
				
			||||||
	if (!good) {
 | 
						if (!good) {
 | 
				
			||||||
		_data->medium->automaticLoad(_parent);
 | 
							_data->medium->automaticLoad(_parent);
 | 
				
			||||||
| 
						 | 
					@ -225,9 +267,19 @@ void Photo::paint(Painter &p, const QRect &clip, TextSelection selection, const
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		p.drawPixmap(0, 0, _pix);
 | 
							p.drawPixmap(0, 0, _pix);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (selected || context->selecting) {
 | 
						if (selected || context->selecting) {
 | 
				
			||||||
		paintPhotoVideoCheck(p, _width, _height, selected);
 | 
							ensureCheckboxCreated();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (_check) {
 | 
				
			||||||
 | 
							_check->paint(p, context->ms, _width, _height, selected, context->selecting);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Photo::ensureCheckboxCreated() {
 | 
				
			||||||
 | 
						if (!_check) _check = std_::make_unique<PhotoVideoCheckbox>([this] {
 | 
				
			||||||
 | 
							Ui::repaintHistoryItem(_parent);
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Photo::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const {
 | 
					void Photo::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const {
 | 
				
			||||||
| 
						 | 
					@ -236,7 +288,19 @@ void Photo::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, i
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Video::Video(DocumentData *video, HistoryItem *parent) : FileBase(parent)
 | 
					void Photo::clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) {
 | 
				
			||||||
 | 
						if (_check) {
 | 
				
			||||||
 | 
							_check->setActive(active);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Photo::clickHandlerPressedChanged(const ClickHandlerPtr &action, bool pressed) {
 | 
				
			||||||
 | 
						if (_check) {
 | 
				
			||||||
 | 
							_check->setPressed(pressed);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Video::Video(DocumentData *video, HistoryItem *parent) : RadialProgressItem(parent)
 | 
				
			||||||
, _data(video)
 | 
					, _data(video)
 | 
				
			||||||
, _duration(formatDurationText(_data->duration()))
 | 
					, _duration(formatDurationText(_data->duration()))
 | 
				
			||||||
, _thumbLoaded(false) {
 | 
					, _thumbLoaded(false) {
 | 
				
			||||||
| 
						 | 
					@ -254,7 +318,7 @@ int32 Video::resizeGetHeight(int32 width) {
 | 
				
			||||||
	return _height;
 | 
						return _height;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const {
 | 
					void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) {
 | 
				
			||||||
	bool selected = (selection == FullSelection), thumbLoaded = _data->thumb->loaded();
 | 
						bool selected = (selection == FullSelection), thumbLoaded = _data->thumb->loaded();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_data->automaticLoad(_parent);
 | 
						_data->automaticLoad(_parent);
 | 
				
			||||||
| 
						 | 
					@ -305,13 +369,13 @@ void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const
 | 
				
			||||||
	if (!selected && !context->selecting && !loaded) {
 | 
						if (!selected && !context->selecting && !loaded) {
 | 
				
			||||||
		if (clip.intersects(QRect(0, _height - st::normalFont->height, _width, st::normalFont->height))) {
 | 
							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 statusX = st::msgDateImgPadding.x(), statusY = _height - st::normalFont->height - st::msgDateImgPadding.y();
 | 
				
			||||||
			int32 statusW = st::normalFont->width(_statusText) + 2 * st::msgDateImgPadding.x();
 | 
								int32 statusW = st::normalFont->width(_status.text()) + 2 * st::msgDateImgPadding.x();
 | 
				
			||||||
			int32 statusH = st::normalFont->height + 2 * st::msgDateImgPadding.y();
 | 
								int32 statusH = st::normalFont->height + 2 * st::msgDateImgPadding.y();
 | 
				
			||||||
			statusX = _width - statusW + statusX;
 | 
								statusX = _width - statusW + statusX;
 | 
				
			||||||
			p.fillRect(rtlrect(statusX - st::msgDateImgPadding.x(), statusY - st::msgDateImgPadding.y(), statusW, statusH, _width), selected ? st::msgDateImgBgSelected : st::msgDateImgBg);
 | 
								p.fillRect(rtlrect(statusX - st::msgDateImgPadding.x(), statusY - st::msgDateImgPadding.y(), statusW, statusH, _width), selected ? st::msgDateImgBgSelected : st::msgDateImgBg);
 | 
				
			||||||
			p.setFont(st::normalFont);
 | 
								p.setFont(st::normalFont);
 | 
				
			||||||
			p.setPen(st::msgDateImgColor);
 | 
								p.setPen(st::msgDateImgColor);
 | 
				
			||||||
			p.drawTextLeft(statusX, statusY, _width, _statusText, statusW - 2 * st::msgDateImgPadding.x());
 | 
								p.drawTextLeft(statusX, statusY, _width, _status.text(), statusW - 2 * st::msgDateImgPadding.x());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (clip.intersects(QRect(0, 0, _width, st::normalFont->height))) {
 | 
						if (clip.intersects(QRect(0, 0, _width, st::normalFont->height))) {
 | 
				
			||||||
| 
						 | 
					@ -358,8 +422,32 @@ void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const
 | 
				
			||||||
			_radial->draw(p, rinner, st::msgFileRadialLine, selected ? st::msgInBgSelected : st::msgInBg);
 | 
								_radial->draw(p, rinner, st::msgFileRadialLine, selected ? st::msgInBgSelected : st::msgInBg);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (selected || context->selecting) {
 | 
						if (selected || context->selecting) {
 | 
				
			||||||
		paintPhotoVideoCheck(p, _width, _height, selected);
 | 
							ensureCheckboxCreated();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (_check) {
 | 
				
			||||||
 | 
							_check->paint(p, context->ms, _width, _height, selected, context->selecting);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Video::ensureCheckboxCreated() {
 | 
				
			||||||
 | 
						if (!_check) _check = std_::make_unique<PhotoVideoCheckbox>([this] {
 | 
				
			||||||
 | 
							Ui::repaintHistoryItem(_parent);
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Video::clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) {
 | 
				
			||||||
 | 
						RadialProgressItem::clickHandlerActiveChanged(action, active);
 | 
				
			||||||
 | 
						if (_check) {
 | 
				
			||||||
 | 
							_check->setActive(active);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Video::clickHandlerPressedChanged(const ClickHandlerPtr &action, bool pressed) {
 | 
				
			||||||
 | 
						RadialProgressItem::clickHandlerPressedChanged(action, pressed);
 | 
				
			||||||
 | 
						if (_check) {
 | 
				
			||||||
 | 
							_check->setPressed(pressed);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -371,9 +459,9 @@ void Video::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, i
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Video::updateStatusText() const {
 | 
					void Video::updateStatusText() {
 | 
				
			||||||
	bool showPause = false;
 | 
						bool showPause = false;
 | 
				
			||||||
	int32 statusSize = 0;
 | 
						int statusSize = 0;
 | 
				
			||||||
	if (_data->status == FileDownloadFailed || _data->status == FileUploadFailed) {
 | 
						if (_data->status == FileDownloadFailed || _data->status == FileUploadFailed) {
 | 
				
			||||||
		statusSize = FileStatusSizeFailed;
 | 
							statusSize = FileStatusSizeFailed;
 | 
				
			||||||
	} else if (_data->status == FileUploading) {
 | 
						} else if (_data->status == FileUploading) {
 | 
				
			||||||
| 
						 | 
					@ -385,18 +473,18 @@ void Video::updateStatusText() const {
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		statusSize = FileStatusSizeReady;
 | 
							statusSize = FileStatusSizeReady;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (statusSize != _statusSize) {
 | 
						if (statusSize != _status.size()) {
 | 
				
			||||||
		int32 status = statusSize, size = _data->size;
 | 
							int status = statusSize, size = _data->size;
 | 
				
			||||||
		if (statusSize >= 0 && statusSize < 0x7F000000) {
 | 
							if (statusSize >= 0 && statusSize < 0x7F000000) {
 | 
				
			||||||
			size = status;
 | 
								size = status;
 | 
				
			||||||
			status = FileStatusSizeReady;
 | 
								status = FileStatusSizeReady;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		setStatusSize(status, size, -1, 0);
 | 
							_status.update(status, size, -1, 0);
 | 
				
			||||||
		_statusSize = statusSize;
 | 
							_status.setSize(statusSize);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Voice::Voice(DocumentData *voice, HistoryItem *parent) : FileBase(parent)
 | 
					Voice::Voice(DocumentData *voice, HistoryItem *parent) : RadialProgressItem(parent)
 | 
				
			||||||
, _data(voice)
 | 
					, _data(voice)
 | 
				
			||||||
, _namel(new DocumentOpenClickHandler(_data)) {
 | 
					, _namel(new DocumentOpenClickHandler(_data)) {
 | 
				
			||||||
	AddComponents(Info::Bit());
 | 
						AddComponents(Info::Bit());
 | 
				
			||||||
| 
						 | 
					@ -417,7 +505,7 @@ void Voice::initDimensions() {
 | 
				
			||||||
	_minh = st::overviewFileLayout.songPadding.top() + st::overviewFileLayout.songThumbSize + st::overviewFileLayout.songPadding.bottom() + st::lineWidth;
 | 
						_minh = st::overviewFileLayout.songPadding.top() + st::overviewFileLayout.songThumbSize + st::overviewFileLayout.songPadding.bottom() + st::lineWidth;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const {
 | 
					void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) {
 | 
				
			||||||
	bool selected = (selection == FullSelection);
 | 
						bool selected = (selection == FullSelection);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_data->automaticLoad(_parent);
 | 
						_data->automaticLoad(_parent);
 | 
				
			||||||
| 
						 | 
					@ -474,7 +562,7 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const
 | 
				
			||||||
		auto icon = ([showPause, this, selected] {
 | 
							auto icon = ([showPause, this, selected] {
 | 
				
			||||||
			if (showPause) {
 | 
								if (showPause) {
 | 
				
			||||||
				return &(selected ? st::historyFileInPauseSelected : st::historyFileInPause);
 | 
									return &(selected ? st::historyFileInPauseSelected : st::historyFileInPause);
 | 
				
			||||||
			} else if (_statusSize < 0 || _statusSize == FileStatusSizeLoaded) {
 | 
								} else if (_status.size() < 0 || _status.size() == FileStatusSizeLoaded) {
 | 
				
			||||||
				return &(selected ? st::historyFileInPlaySelected : st::historyFileInPlay);
 | 
									return &(selected ? st::historyFileInPlaySelected : st::historyFileInPlay);
 | 
				
			||||||
			} else if (_data->loading()) {
 | 
								} else if (_data->loading()) {
 | 
				
			||||||
				return &(selected ? st::historyFileInCancelSelected : st::historyFileInCancel);
 | 
									return &(selected ? st::historyFileInCancelSelected : st::historyFileInCancel);
 | 
				
			||||||
| 
						 | 
					@ -495,14 +583,14 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const
 | 
				
			||||||
		p.setFont(st::normalFont);
 | 
							p.setFont(st::normalFont);
 | 
				
			||||||
		p.setPen(selected ? st::mediaInFgSelected : st::mediaInFg);
 | 
							p.setPen(selected ? st::mediaInFgSelected : st::mediaInFg);
 | 
				
			||||||
		int32 unreadx = nameleft;
 | 
							int32 unreadx = nameleft;
 | 
				
			||||||
		if (_statusSize == FileStatusSizeLoaded || _statusSize == FileStatusSizeReady) {
 | 
							if (_status.size() == FileStatusSizeLoaded || _status.size() == FileStatusSizeReady) {
 | 
				
			||||||
			textstyleSet(&(selected ? st::mediaInStyleSelected : st::mediaInStyle));
 | 
								textstyleSet(&(selected ? st::mediaInStyleSelected : st::mediaInStyle));
 | 
				
			||||||
			_details.drawLeftElided(p, nameleft, statustop, namewidth, _width);
 | 
								_details.drawLeftElided(p, nameleft, statustop, namewidth, _width);
 | 
				
			||||||
			textstyleRestore();
 | 
								textstyleRestore();
 | 
				
			||||||
			unreadx += _details.maxWidth();
 | 
								unreadx += _details.maxWidth();
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			int32 statusw = st::normalFont->width(_statusText);
 | 
								int32 statusw = st::normalFont->width(_status.text());
 | 
				
			||||||
			p.drawTextLeft(nameleft, statustop, _width, _statusText, statusw);
 | 
								p.drawTextLeft(nameleft, statustop, _width, _status.text(), statusw);
 | 
				
			||||||
			unreadx += statusw;
 | 
								unreadx += statusw;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (_parent->isMediaUnread() && unreadx + st::mediaUnreadSkip + st::mediaUnreadSize <= _width) {
 | 
							if (_parent->isMediaUnread() && unreadx + st::mediaUnreadSkip + st::mediaUnreadSize <= _width) {
 | 
				
			||||||
| 
						 | 
					@ -519,8 +607,6 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const
 | 
				
			||||||
void Voice::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const {
 | 
					void Voice::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const {
 | 
				
			||||||
	bool loaded = _data->loaded();
 | 
						bool loaded = _data->loaded();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool showPause = updateStatusText();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = 0;
 | 
						int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	nameleft = st::overviewFileLayout.songPadding.left() + st::overviewFileLayout.songThumbSize + st::overviewFileLayout.songPadding.right();
 | 
						nameleft = st::overviewFileLayout.songPadding.left() + st::overviewFileLayout.songThumbSize + st::overviewFileLayout.songPadding.right();
 | 
				
			||||||
| 
						 | 
					@ -534,7 +620,7 @@ void Voice::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, i
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (rtlrect(nameleft, statustop, _width - nameleft - nameright, st::normalFont->height, _width).contains(x, y)) {
 | 
						if (rtlrect(nameleft, statustop, _width - nameleft - nameright, st::normalFont->height, _width).contains(x, y)) {
 | 
				
			||||||
		if (_statusSize == FileStatusSizeLoaded || _statusSize == FileStatusSizeReady) {
 | 
							if (_status.size() == FileStatusSizeLoaded || _status.size() == FileStatusSizeReady) {
 | 
				
			||||||
			auto textState = _details.getStateLeft(x - nameleft, y - statustop, _width, _width);
 | 
								auto textState = _details.getStateLeft(x - nameleft, y - statustop, _width, _width);
 | 
				
			||||||
			link = textState.link;
 | 
								link = textState.link;
 | 
				
			||||||
			cursor = textState.uponSymbol ? HistoryInTextCursorState : HistoryDefaultCursorState;
 | 
								cursor = textState.uponSymbol ? HistoryInTextCursorState : HistoryDefaultCursorState;
 | 
				
			||||||
| 
						 | 
					@ -546,7 +632,7 @@ void Voice::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, i
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Voice::updateName() const {
 | 
					void Voice::updateName() {
 | 
				
			||||||
	int32 version = 0;
 | 
						int32 version = 0;
 | 
				
			||||||
	if (const HistoryMessageForwarded *fwd = _parent->Get<HistoryMessageForwarded>()) {
 | 
						if (const HistoryMessageForwarded *fwd = _parent->Get<HistoryMessageForwarded>()) {
 | 
				
			||||||
		if (_parent->fromOriginal()->isChannel()) {
 | 
							if (_parent->fromOriginal()->isChannel()) {
 | 
				
			||||||
| 
						 | 
					@ -561,7 +647,7 @@ void Voice::updateName() const {
 | 
				
			||||||
	_nameVersion = version;
 | 
						_nameVersion = version;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool Voice::updateStatusText() const {
 | 
					bool Voice::updateStatusText() {
 | 
				
			||||||
	bool showPause = false;
 | 
						bool showPause = false;
 | 
				
			||||||
	int32 statusSize = 0, realDuration = 0;
 | 
						int32 statusSize = 0, realDuration = 0;
 | 
				
			||||||
	if (_data->status == FileDownloadFailed || _data->status == FileUploadFailed) {
 | 
						if (_data->status == FileDownloadFailed || _data->status == FileUploadFailed) {
 | 
				
			||||||
| 
						 | 
					@ -580,13 +666,13 @@ bool Voice::updateStatusText() const {
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		statusSize = FileStatusSizeReady;
 | 
							statusSize = FileStatusSizeReady;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (statusSize != _statusSize) {
 | 
						if (statusSize != _status.size()) {
 | 
				
			||||||
		setStatusSize(statusSize, _data->size, _data->voice()->duration, realDuration);
 | 
							_status.update(statusSize, _data->size, _data->voice()->duration, realDuration);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return showPause;
 | 
						return showPause;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Document::Document(DocumentData *document, HistoryItem *parent, const style::OverviewFileLayout &st) : FileBase(parent)
 | 
					Document::Document(DocumentData *document, HistoryItem *parent, const style::OverviewFileLayout &st) : RadialProgressItem(parent)
 | 
				
			||||||
, _data(document)
 | 
					, _data(document)
 | 
				
			||||||
, _msgl(goToMessageClickHandler(parent))
 | 
					, _msgl(goToMessageClickHandler(parent))
 | 
				
			||||||
, _namel(new DocumentOpenClickHandler(_data))
 | 
					, _namel(new DocumentOpenClickHandler(_data))
 | 
				
			||||||
| 
						 | 
					@ -600,7 +686,7 @@ Document::Document(DocumentData *document, HistoryItem *parent, const style::Ove
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setDocumentLinks(_data);
 | 
						setDocumentLinks(_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setStatusSize(FileStatusSizeReady, _data->size, _data->song() ? _data->song()->duration : -1, 0);
 | 
						_status.update(FileStatusSizeReady, _data->size, _data->song() ? _data->song()->duration : -1, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (withThumb()) {
 | 
						if (withThumb()) {
 | 
				
			||||||
		_data->thumb->load();
 | 
							_data->thumb->load();
 | 
				
			||||||
| 
						 | 
					@ -630,7 +716,7 @@ void Document::initDimensions() {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Document::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const {
 | 
					void Document::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) {
 | 
				
			||||||
	bool selected = (selection == FullSelection);
 | 
						bool selected = (selection == FullSelection);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_data->automaticLoad(_parent);
 | 
						_data->automaticLoad(_parent);
 | 
				
			||||||
| 
						 | 
					@ -786,7 +872,7 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con
 | 
				
			||||||
	if (clip.intersects(rtlrect(nameleft, statustop, availwidth, st::normalFont->height, _width))) {
 | 
						if (clip.intersects(rtlrect(nameleft, statustop, availwidth, st::normalFont->height, _width))) {
 | 
				
			||||||
		p.setFont(st::normalFont);
 | 
							p.setFont(st::normalFont);
 | 
				
			||||||
		p.setPen(st::mediaInFg);
 | 
							p.setPen(st::mediaInFg);
 | 
				
			||||||
		p.drawTextLeft(nameleft, statustop, _width, _statusText);
 | 
							p.drawTextLeft(nameleft, statustop, _width, _status.text());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (datetop >= 0 && clip.intersects(rtlrect(nameleft, datetop, _datew, st::normalFont->height, _width))) {
 | 
						if (datetop >= 0 && clip.intersects(rtlrect(nameleft, datetop, _datew, st::normalFont->height, _width))) {
 | 
				
			||||||
		p.setFont(ClickHandler::showAsActive(_msgl) ? st::normalFont->underline() : st::normalFont);
 | 
							p.setFont(ClickHandler::showAsActive(_msgl) ? st::normalFont->underline() : st::normalFont);
 | 
				
			||||||
| 
						 | 
					@ -798,8 +884,6 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con
 | 
				
			||||||
void Document::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const {
 | 
					void Document::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const {
 | 
				
			||||||
	bool loaded = _data->loaded() || Local::willStickerImageLoad(_data->mediaKey());
 | 
						bool loaded = _data->loaded() || Local::willStickerImageLoad(_data->mediaKey());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool showPause = updateStatusText();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = 0;
 | 
						int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = 0;
 | 
				
			||||||
	bool wthumb = withThumb();
 | 
						bool wthumb = withThumb();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -850,7 +934,7 @@ void Document::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool Document::updateStatusText() const {
 | 
					bool Document::updateStatusText() {
 | 
				
			||||||
	bool showPause = false;
 | 
						bool showPause = false;
 | 
				
			||||||
	int32 statusSize = 0, realDuration = 0;
 | 
						int32 statusSize = 0, realDuration = 0;
 | 
				
			||||||
	if (_data->status == FileDownloadFailed || _data->status == FileUploadFailed) {
 | 
						if (_data->status == FileDownloadFailed || _data->status == FileUploadFailed) {
 | 
				
			||||||
| 
						 | 
					@ -880,8 +964,8 @@ bool Document::updateStatusText() const {
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		statusSize = FileStatusSizeReady;
 | 
							statusSize = FileStatusSizeReady;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (statusSize != _statusSize) {
 | 
						if (statusSize != _status.size()) {
 | 
				
			||||||
		setStatusSize(statusSize, _data->size, _data->song() ? _data->song()->duration : -1, realDuration);
 | 
							_status.update(statusSize, _data->size, _data->song() ? _data->song()->duration : -1, realDuration);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return showPause;
 | 
						return showPause;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1041,7 +1125,7 @@ int32 Link::resizeGetHeight(int32 width) {
 | 
				
			||||||
	return _height;
 | 
						return _height;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Link::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const {
 | 
					void Link::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) {
 | 
				
			||||||
	int32 left = st::linksPhotoSize + st::linksPhotoPadding, top = st::linksMargin.top() + st::linksBorder, w = _width - left;
 | 
						int32 left = st::linksPhotoSize + st::linksPhotoPadding, top = st::linksMargin.top() + st::linksBorder, w = _width - left;
 | 
				
			||||||
	if (clip.intersects(rtlrect(0, top, st::linksPhotoSize, st::linksPhotoSize, _width))) {
 | 
						if (clip.intersects(rtlrect(0, top, st::linksPhotoSize, st::linksPhotoSize, _width))) {
 | 
				
			||||||
		if (_page && _page->photo) {
 | 
							if (_page && _page->photo) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,8 +39,7 @@ public:
 | 
				
			||||||
class ItemBase;
 | 
					class ItemBase;
 | 
				
			||||||
class AbstractItem : public LayoutItemBase {
 | 
					class AbstractItem : public LayoutItemBase {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
						virtual void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) = 0;
 | 
				
			||||||
	virtual void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual ItemBase *toMediaItem() {
 | 
						virtual ItemBase *toMediaItem() {
 | 
				
			||||||
		return nullptr;
 | 
							return nullptr;
 | 
				
			||||||
| 
						 | 
					@ -115,7 +114,7 @@ protected:
 | 
				
			||||||
	void step_iconOver(float64 ms, bool timer);
 | 
						void step_iconOver(float64 ms, bool timer);
 | 
				
			||||||
	void step_radial(uint64 ms, bool timer);
 | 
						void step_radial(uint64 ms, bool timer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void ensureRadial() const;
 | 
						void ensureRadial();
 | 
				
			||||||
	void checkRadialFinished();
 | 
						void checkRadialFinished();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool isRadialAnimation(uint64 ms) const {
 | 
						bool isRadialAnimation(uint64 ms) const {
 | 
				
			||||||
| 
						 | 
					@ -132,28 +131,33 @@ protected:
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutable Ui::RadialAnimation *_radial;
 | 
						Ui::RadialAnimation *_radial;
 | 
				
			||||||
	anim::fvalue a_iconOver;
 | 
						anim::fvalue a_iconOver;
 | 
				
			||||||
	mutable Animation _a_iconOver;
 | 
						Animation _a_iconOver;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FileBase : public RadialProgressItem {
 | 
					class StatusText {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	FileBase(HistoryItem *parent) : RadialProgressItem(parent) {
 | 
						// duration = -1 - no duration, duration = -2 - "GIF" duration
 | 
				
			||||||
 | 
						void update(int newSize, int fullSize, int duration, int64 realDuration);
 | 
				
			||||||
 | 
						void setSize(int newSize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int size() const {
 | 
				
			||||||
 | 
							return _size;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						QString text() const {
 | 
				
			||||||
 | 
							return _text;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					private:
 | 
				
			||||||
	// >= 0 will contain download / upload string, _statusSize = loaded bytes
 | 
						// >= 0 will contain download / upload string, _size = loaded bytes
 | 
				
			||||||
	// < 0 will contain played string, _statusSize = -(seconds + 1) played
 | 
						// < 0 will contain played string, _size = -(seconds + 1) played
 | 
				
			||||||
	// 0x7FFFFFF0 will contain status for not yet downloaded file
 | 
						// 0x7FFFFFF0 will contain status for not yet downloaded file
 | 
				
			||||||
	// 0x7FFFFFF1 will contain status for already downloaded file
 | 
						// 0x7FFFFFF1 will contain status for already downloaded file
 | 
				
			||||||
	// 0x7FFFFFF2 will contain status for failed to download / upload file
 | 
						// 0x7FFFFFF2 will contain status for failed to download / upload file
 | 
				
			||||||
	mutable int32 _statusSize;
 | 
						int _size = 0;
 | 
				
			||||||
	mutable QString _statusText;
 | 
						QString _text;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	// duration = -1 - no duration, duration = -2 - "GIF" duration
 | 
					 | 
				
			||||||
	void setStatusSize(int32 newSize, int32 fullSize, int32 duration, qint64 realDuration) const;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -166,7 +170,7 @@ public:
 | 
				
			||||||
	Date(const QDate &date, bool month);
 | 
						Date(const QDate &date, bool month);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void initDimensions() override;
 | 
						void initDimensions() override;
 | 
				
			||||||
	void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const override;
 | 
						void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	QDate _date;
 | 
						QDate _date;
 | 
				
			||||||
| 
						 | 
					@ -174,33 +178,45 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PhotoVideoCheckbox;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Photo : public ItemBase {
 | 
					class Photo : public ItemBase {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	Photo(PhotoData *photo, HistoryItem *parent);
 | 
						Photo(PhotoData *photo, HistoryItem *parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void initDimensions() override;
 | 
						void initDimensions() override;
 | 
				
			||||||
	int32 resizeGetHeight(int32 width) override;
 | 
						int32 resizeGetHeight(int32 width) override;
 | 
				
			||||||
	void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const override;
 | 
						void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override;
 | 
				
			||||||
	void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
 | 
						void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) override;
 | 
				
			||||||
 | 
						void clickHandlerPressedChanged(const ClickHandlerPtr &action, bool pressed) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
 | 
						void ensureCheckboxCreated();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std_::unique_ptr<PhotoVideoCheckbox> _check;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	PhotoData *_data;
 | 
						PhotoData *_data;
 | 
				
			||||||
	ClickHandlerPtr _link;
 | 
						ClickHandlerPtr _link;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutable QPixmap _pix;
 | 
						QPixmap _pix;
 | 
				
			||||||
	mutable bool _goodLoaded;
 | 
						bool _goodLoaded = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Video : public FileBase {
 | 
					class Video : public RadialProgressItem {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	Video(DocumentData *video, HistoryItem *parent);
 | 
						Video(DocumentData *video, HistoryItem *parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void initDimensions() override;
 | 
						void initDimensions() override;
 | 
				
			||||||
	int32 resizeGetHeight(int32 width) override;
 | 
						int32 resizeGetHeight(int32 width) override;
 | 
				
			||||||
	void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const override;
 | 
						void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override;
 | 
				
			||||||
	void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
 | 
						void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) override;
 | 
				
			||||||
 | 
						void clickHandlerPressedChanged(const ClickHandlerPtr &action, bool pressed) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	float64 dataProgress() const override {
 | 
						float64 dataProgress() const override {
 | 
				
			||||||
		return _data->progress();
 | 
							return _data->progress();
 | 
				
			||||||
| 
						 | 
					@ -216,22 +232,27 @@ protected:
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
 | 
						void ensureCheckboxCreated();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std_::unique_ptr<PhotoVideoCheckbox> _check;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	DocumentData *_data;
 | 
						DocumentData *_data;
 | 
				
			||||||
 | 
						StatusText _status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	QString _duration;
 | 
						QString _duration;
 | 
				
			||||||
	mutable QPixmap _pix;
 | 
						QPixmap _pix;
 | 
				
			||||||
	mutable bool _thumbLoaded;
 | 
						bool _thumbLoaded = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void updateStatusText() const;
 | 
						void updateStatusText();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Voice : public FileBase {
 | 
					class Voice : public RadialProgressItem {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	Voice(DocumentData *voice, HistoryItem *parent);
 | 
						Voice(DocumentData *voice, HistoryItem *parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void initDimensions() override;
 | 
						void initDimensions() override;
 | 
				
			||||||
	void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const override;
 | 
						void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override;
 | 
				
			||||||
	void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
 | 
						void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
| 
						 | 
					@ -250,22 +271,23 @@ protected:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	DocumentData *_data;
 | 
						DocumentData *_data;
 | 
				
			||||||
 | 
						StatusText _status;
 | 
				
			||||||
	ClickHandlerPtr _namel;
 | 
						ClickHandlerPtr _namel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutable Text _name, _details;
 | 
						Text _name, _details;
 | 
				
			||||||
	mutable int32 _nameVersion;
 | 
						int _nameVersion;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void updateName() const;
 | 
						void updateName();
 | 
				
			||||||
	bool updateStatusText() const;
 | 
						bool updateStatusText();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Document : public FileBase {
 | 
					class Document : public RadialProgressItem {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	Document(DocumentData *document, HistoryItem *parent, const style::OverviewFileLayout &st);
 | 
						Document(DocumentData *document, HistoryItem *parent, const style::OverviewFileLayout &st);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void initDimensions() override;
 | 
						void initDimensions() override;
 | 
				
			||||||
	void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const override;
 | 
						void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override;
 | 
				
			||||||
	void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
 | 
						void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual DocumentData *getDocument() const override {
 | 
						virtual DocumentData *getDocument() const override {
 | 
				
			||||||
| 
						 | 
					@ -288,12 +310,13 @@ protected:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	DocumentData *_data;
 | 
						DocumentData *_data;
 | 
				
			||||||
 | 
						StatusText _status;
 | 
				
			||||||
	ClickHandlerPtr _msgl, _namel;
 | 
						ClickHandlerPtr _msgl, _namel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const style::OverviewFileLayout &_st;
 | 
						const style::OverviewFileLayout &_st;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutable bool _thumbForLoaded = false;
 | 
						bool _thumbForLoaded = false;
 | 
				
			||||||
	mutable QPixmap _thumb;
 | 
						QPixmap _thumb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Text _name;
 | 
						Text _name;
 | 
				
			||||||
	QString _date, _ext;
 | 
						QString _date, _ext;
 | 
				
			||||||
| 
						 | 
					@ -303,7 +326,7 @@ private:
 | 
				
			||||||
	bool withThumb() const {
 | 
						bool withThumb() const {
 | 
				
			||||||
		return !_data->thumb->isNull() && _data->thumb->width() && _data->thumb->height();
 | 
							return !_data->thumb->isNull() && _data->thumb->width() && _data->thumb->height();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	bool updateStatusText() const;
 | 
						bool updateStatusText();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -313,7 +336,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void initDimensions() override;
 | 
						void initDimensions() override;
 | 
				
			||||||
	int32 resizeGetHeight(int32 width) override;
 | 
						int32 resizeGetHeight(int32 width) override;
 | 
				
			||||||
	void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const override;
 | 
						void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) override;
 | 
				
			||||||
	void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
 | 
						void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,23 +24,25 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 | 
				
			||||||
namespace Ui {
 | 
					namespace Ui {
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static constexpr int kWideScale = 4;
 | 
					static constexpr int kWideScale = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void prepareCheckCaches(const style::RoundImageCheckbox *st, QPixmap &checkBgCache, QPixmap &checkFullCache) {
 | 
					void prepareCheckCaches(const style::RoundCheckbox *st, bool displayInactive, QPixmap &checkBgCache, QPixmap &checkFullCache) {
 | 
				
			||||||
	auto size = st->checkRadius * 2;
 | 
						auto size = st->size;
 | 
				
			||||||
	auto wideSize = size * kWideScale;
 | 
						auto wideSize = size * kWideScale;
 | 
				
			||||||
	auto cache = QImage(wideSize * cIntRetinaFactor(), wideSize * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
 | 
						auto cache = QImage(wideSize * cIntRetinaFactor(), wideSize * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
 | 
				
			||||||
	cache.setDevicePixelRatio(cRetinaFactor());
 | 
						cache.setDevicePixelRatio(cRetinaFactor());
 | 
				
			||||||
 | 
						cache.fill(Qt::transparent);
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Painter p(&cache);
 | 
							Painter p(&cache);
 | 
				
			||||||
		p.setCompositionMode(QPainter::CompositionMode_Source);
 | 
					 | 
				
			||||||
		p.fillRect(0, 0, wideSize, wideSize, Qt::transparent);
 | 
					 | 
				
			||||||
		p.setCompositionMode(QPainter::CompositionMode_SourceOver);
 | 
					 | 
				
			||||||
		p.setRenderHint(QPainter::HighQualityAntialiasing, true);
 | 
							p.setRenderHint(QPainter::HighQualityAntialiasing, true);
 | 
				
			||||||
		auto pen = st->checkBorder->p;
 | 
							if (displayInactive) {
 | 
				
			||||||
		pen.setWidth(st->selectWidth);
 | 
								p.setPen(Qt::NoPen);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								auto pen = st->border->p;
 | 
				
			||||||
 | 
								pen.setWidth(st->width);
 | 
				
			||||||
			p.setPen(pen);
 | 
								p.setPen(pen);
 | 
				
			||||||
		p.setBrush(st->checkBg);
 | 
							}
 | 
				
			||||||
 | 
							p.setBrush(st->bgActive);
 | 
				
			||||||
		auto ellipse = QRect((wideSize - size) / 2, (wideSize - size) / 2, size, size);
 | 
							auto ellipse = QRect((wideSize - size) / 2, (wideSize - size) / 2, size, size);
 | 
				
			||||||
		p.drawEllipse(ellipse);
 | 
							p.drawEllipse(ellipse);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -48,32 +50,183 @@ void prepareCheckCaches(const style::RoundImageCheckbox *st, QPixmap &checkBgCac
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Painter p(&cacheIcon);
 | 
							Painter p(&cacheIcon);
 | 
				
			||||||
		auto ellipse = QRect((wideSize - size) / 2, (wideSize - size) / 2, size, size);
 | 
							auto ellipse = QRect((wideSize - size) / 2, (wideSize - size) / 2, size, size);
 | 
				
			||||||
		st->checkIcon.paint(p, ellipse.topLeft(), wideSize);
 | 
							st->check.paint(p, ellipse.topLeft(), wideSize);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	checkBgCache = App::pixmapFromImageInPlace(std_::move(cache));
 | 
						checkBgCache = App::pixmapFromImageInPlace(std_::move(cache));
 | 
				
			||||||
	checkBgCache.setDevicePixelRatio(cRetinaFactor());
 | 
					 | 
				
			||||||
	checkFullCache = App::pixmapFromImageInPlace(std_::move(cacheIcon));
 | 
						checkFullCache = App::pixmapFromImageInPlace(std_::move(cacheIcon));
 | 
				
			||||||
	checkFullCache.setDevicePixelRatio(cRetinaFactor());
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace
 | 
					} // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RoundImageCheckbox::RoundImageCheckbox(const style::RoundImageCheckbox &st, const base::lambda_copy<void()> &updateCallback, PaintRoundImage &&paintRoundImage)
 | 
					RoundCheckbox::RoundCheckbox(const style::RoundCheckbox &st, const base::lambda_copy<void()> &updateCallback)
 | 
				
			||||||
: _st(st)
 | 
					: _st(st)
 | 
				
			||||||
, _updateCallback(updateCallback)
 | 
					, _updateCallback(updateCallback) {
 | 
				
			||||||
, _paintRoundImage(std_::move(paintRoundImage)) {
 | 
					 | 
				
			||||||
	prepareCheckCaches(&_st, _wideCheckBgCache, _wideCheckFullCache);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void RoundImageCheckbox::paint(Painter &p, uint64 ms, int x, int y, int outerWidth) {
 | 
					QRect RoundCheckbox::cacheDestRect(int x, int y, float64 scale) const {
 | 
				
			||||||
	_selection.step(ms);
 | 
						auto iconSizeFull = kWideScale * _st.size;
 | 
				
			||||||
 | 
						auto iconSize = qRound(iconSizeFull * scale);
 | 
				
			||||||
 | 
						if (iconSize % 2 != iconSizeFull % 2) {
 | 
				
			||||||
 | 
							++iconSize;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						auto iconShift = (iconSizeFull - iconSize) / 2;
 | 
				
			||||||
 | 
						auto iconLeft = x - (kWideScale - 1) * _st.size / 2 + iconShift;
 | 
				
			||||||
 | 
						auto iconTop = y - (kWideScale - 1) * _st.size / 2 + iconShift;
 | 
				
			||||||
 | 
						return QRect(iconLeft, iconTop, iconSize, iconSize);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RoundCheckbox::paint(Painter &p, uint64 ms, int x, int y, int outerWidth, float64 masterScale) {
 | 
				
			||||||
	for (auto &icon : _icons) {
 | 
						for (auto &icon : _icons) {
 | 
				
			||||||
		icon.fadeIn.step(ms);
 | 
							icon.fadeIn.step(ms);
 | 
				
			||||||
		icon.fadeOut.step(ms);
 | 
							icon.fadeOut.step(ms);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	removeFadeOutedIcons();
 | 
						removeFadeOutedIcons();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto selectionLevel = _selection.current(_checked ? 1. : 0.);
 | 
						auto cacheSize = kWideScale * _st.size * cIntRetinaFactor();
 | 
				
			||||||
 | 
						auto cacheFrom = QRect(0, 0, cacheSize, cacheSize);
 | 
				
			||||||
 | 
						auto displayInactive = !_inactiveCacheBg.isNull();
 | 
				
			||||||
 | 
						auto inactiveTo = cacheDestRect(x, y, masterScale);
 | 
				
			||||||
 | 
						p.setRenderHint(QPainter::SmoothPixmapTransform, true);
 | 
				
			||||||
 | 
						if (!_inactiveCacheBg.isNull()) {
 | 
				
			||||||
 | 
							p.drawPixmap(inactiveTo, _inactiveCacheBg, cacheFrom);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for (auto &icon : _icons) {
 | 
				
			||||||
 | 
							auto fadeIn = icon.fadeIn.current(1.);
 | 
				
			||||||
 | 
							auto fadeOut = icon.fadeOut.current(1.);
 | 
				
			||||||
 | 
							auto to = cacheDestRect(x, y, (1. - (1. - _st.sizeSmall) * (1. - fadeOut)) * masterScale);
 | 
				
			||||||
 | 
							p.setOpacity(fadeIn * fadeOut);
 | 
				
			||||||
 | 
							if (fadeOut < 1.) {
 | 
				
			||||||
 | 
								p.drawPixmapLeft(to, outerWidth, icon.wideCheckCache, cacheFrom);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								auto realDivider = ((kWideScale - 1) * _st.size / 2 + qMax(fadeIn - 0.5, 0.) * 2. * _st.size);
 | 
				
			||||||
 | 
								auto divider = qRound(realDivider * masterScale);
 | 
				
			||||||
 | 
								auto cacheDivider = qRound(realDivider) * cIntRetinaFactor();
 | 
				
			||||||
 | 
								p.drawPixmapLeft(QRect(to.x(), to.y(), divider, to.height()), outerWidth, _wideCheckFullCache, QRect(0, 0, cacheDivider, cacheFrom.height()));
 | 
				
			||||||
 | 
								p.drawPixmapLeft(QRect(to.x() + divider, to.y(), to.width() - divider, to.height()), outerWidth, _wideCheckBgCache, QRect(cacheDivider, 0, cacheFrom.width() - cacheDivider, _wideCheckBgCache.height()));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						p.setOpacity(1.);
 | 
				
			||||||
 | 
						if (!_inactiveCacheFg.isNull()) {
 | 
				
			||||||
 | 
							p.drawPixmap(inactiveTo, _inactiveCacheFg, cacheFrom);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						p.setRenderHint(QPainter::SmoothPixmapTransform, false);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RoundCheckbox::setChecked(bool newChecked, SetStyle speed) {
 | 
				
			||||||
 | 
						if (_checked == newChecked) {
 | 
				
			||||||
 | 
							if (speed != SetStyle::Animated && !_icons.isEmpty()) {
 | 
				
			||||||
 | 
								_icons.back().fadeIn.finish();
 | 
				
			||||||
 | 
								_icons.back().fadeOut.finish();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						_checked = newChecked;
 | 
				
			||||||
 | 
						if (_checked) {
 | 
				
			||||||
 | 
							if (_wideCheckBgCache.isNull()) {
 | 
				
			||||||
 | 
								prepareCheckCaches(&_st, _displayInactive, _wideCheckBgCache, _wideCheckFullCache);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							_icons.push_back(Icon());
 | 
				
			||||||
 | 
							_icons.back().fadeIn.start(_updateCallback, 0, 1, _st.duration);
 | 
				
			||||||
 | 
							if (speed != SetStyle::Animated) {
 | 
				
			||||||
 | 
								_icons.back().fadeIn.finish();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if (speed == SetStyle::Animated) {
 | 
				
			||||||
 | 
								prepareWideCheckIconCache(&_icons.back());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							_icons.back().fadeOut.start(_updateCallback, 1, 0, _st.duration);
 | 
				
			||||||
 | 
							if (speed != SetStyle::Animated) {
 | 
				
			||||||
 | 
								_icons.back().fadeOut.finish();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RoundCheckbox::setDisplayInactive(bool displayInactive) {
 | 
				
			||||||
 | 
						if (_displayInactive != displayInactive) {
 | 
				
			||||||
 | 
							_displayInactive = displayInactive;
 | 
				
			||||||
 | 
							if (_displayInactive) {
 | 
				
			||||||
 | 
								prepareInactiveCache();
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								_inactiveCacheBg = _inactiveCacheFg = QPixmap();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (!_wideCheckBgCache.isNull()) {
 | 
				
			||||||
 | 
								prepareCheckCaches(&_st, _displayInactive, _wideCheckBgCache, _wideCheckFullCache);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for (auto &icon : _icons) {
 | 
				
			||||||
 | 
								if (!icon.wideCheckCache.isNull()) {
 | 
				
			||||||
 | 
									prepareWideCheckIconCache(&icon);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RoundCheckbox::removeFadeOutedIcons() {
 | 
				
			||||||
 | 
						while (!_icons.empty() && !_icons.front().fadeIn.animating() && !_icons.front().fadeOut.animating()) {
 | 
				
			||||||
 | 
							if (_icons.size() > 1 || !_checked) {
 | 
				
			||||||
 | 
								_icons.erase(_icons.begin());
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RoundCheckbox::prepareWideCheckIconCache(Icon *icon) {
 | 
				
			||||||
 | 
						auto cacheWidth = _wideCheckBgCache.width() / _wideCheckBgCache.devicePixelRatio();
 | 
				
			||||||
 | 
						auto cacheHeight = _wideCheckBgCache.height() / _wideCheckBgCache.devicePixelRatio();
 | 
				
			||||||
 | 
						auto wideCache = QImage(cacheWidth * cIntRetinaFactor(), cacheHeight * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
 | 
				
			||||||
 | 
						wideCache.setDevicePixelRatio(cRetinaFactor());
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Painter p(&wideCache);
 | 
				
			||||||
 | 
							p.setCompositionMode(QPainter::CompositionMode_Source);
 | 
				
			||||||
 | 
							auto iconSize = kWideScale * _st.size;
 | 
				
			||||||
 | 
							auto divider = qRound((kWideScale - 1) * _st.size / 2 + qMax(icon->fadeIn.current(1.) - 0.5, 0.) * 2. * _st.size);
 | 
				
			||||||
 | 
							p.drawPixmapLeft(QRect(0, 0, divider, iconSize), cacheWidth, _wideCheckFullCache, QRect(0, 0, divider * cIntRetinaFactor(), _wideCheckFullCache.height()));
 | 
				
			||||||
 | 
							p.drawPixmapLeft(QRect(divider, 0, iconSize - divider, iconSize), cacheWidth, _wideCheckBgCache, QRect(divider * cIntRetinaFactor(), 0, _wideCheckBgCache.width() - divider * cIntRetinaFactor(), _wideCheckBgCache.height()));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						icon->wideCheckCache = App::pixmapFromImageInPlace(std_::move(wideCache));
 | 
				
			||||||
 | 
						icon->wideCheckCache.setDevicePixelRatio(cRetinaFactor());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RoundCheckbox::prepareInactiveCache() {
 | 
				
			||||||
 | 
						auto wideSize = _st.size * kWideScale;
 | 
				
			||||||
 | 
						auto ellipse = QRect((wideSize - _st.size) / 2, (wideSize - _st.size) / 2, _st.size, _st.size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto cacheBg = QImage(wideSize * cIntRetinaFactor(), wideSize * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
 | 
				
			||||||
 | 
						cacheBg.setDevicePixelRatio(cRetinaFactor());
 | 
				
			||||||
 | 
						cacheBg.fill(Qt::transparent);
 | 
				
			||||||
 | 
						auto cacheFg = cacheBg;
 | 
				
			||||||
 | 
						if (_st.bgInactive) {
 | 
				
			||||||
 | 
							Painter p(&cacheBg);
 | 
				
			||||||
 | 
							p.setRenderHint(QPainter::HighQualityAntialiasing, true);
 | 
				
			||||||
 | 
							p.setPen(Qt::NoPen);
 | 
				
			||||||
 | 
							p.setBrush(_st.bgInactive);
 | 
				
			||||||
 | 
							p.drawEllipse(ellipse);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						_inactiveCacheBg = App::pixmapFromImageInPlace(std_::move(cacheBg));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Painter p(&cacheFg);
 | 
				
			||||||
 | 
							p.setRenderHint(QPainter::HighQualityAntialiasing, true);
 | 
				
			||||||
 | 
							auto pen = _st.border->p;
 | 
				
			||||||
 | 
							pen.setWidth(_st.width);
 | 
				
			||||||
 | 
							p.setPen(pen);
 | 
				
			||||||
 | 
							p.setBrush(Qt::NoBrush);
 | 
				
			||||||
 | 
							p.drawEllipse(ellipse);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						_inactiveCacheFg = App::pixmapFromImageInPlace(std_::move(cacheFg));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RoundImageCheckbox::RoundImageCheckbox(const style::RoundImageCheckbox &st, const base::lambda_copy<void()> &updateCallback, PaintRoundImage &&paintRoundImage)
 | 
				
			||||||
 | 
					: _st(st)
 | 
				
			||||||
 | 
					, _updateCallback(updateCallback)
 | 
				
			||||||
 | 
					, _paintRoundImage(std_::move(paintRoundImage))
 | 
				
			||||||
 | 
					, _check(_st.check, _updateCallback) {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RoundImageCheckbox::paint(Painter &p, uint64 ms, int x, int y, int outerWidth) {
 | 
				
			||||||
 | 
						_selection.step(ms);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto selectionLevel = _selection.current(checked() ? 1. : 0.);
 | 
				
			||||||
	if (_selection.animating()) {
 | 
						if (_selection.animating()) {
 | 
				
			||||||
		auto userpicRadius = qRound(kWideScale * (_st.imageRadius + (_st.imageSmallRadius - _st.imageRadius) * selectionLevel));
 | 
							auto userpicRadius = qRound(kWideScale * (_st.imageRadius + (_st.imageSmallRadius - _st.imageRadius) * selectionLevel));
 | 
				
			||||||
		auto userpicShift = kWideScale * _st.imageRadius - userpicRadius;
 | 
							auto userpicShift = kWideScale * _st.imageRadius - userpicRadius;
 | 
				
			||||||
| 
						 | 
					@ -89,7 +242,7 @@ void RoundImageCheckbox::paint(Painter &p, uint64 ms, int x, int y, int outerWid
 | 
				
			||||||
		if (!_wideCache.isNull()) {
 | 
							if (!_wideCache.isNull()) {
 | 
				
			||||||
			_wideCache = QPixmap();
 | 
								_wideCache = QPixmap();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		auto userpicRadius = _checked ? _st.imageSmallRadius : _st.imageRadius;
 | 
							auto userpicRadius = checked() ? _st.imageSmallRadius : _st.imageRadius;
 | 
				
			||||||
		auto userpicShift = _st.imageRadius - userpicRadius;
 | 
							auto userpicShift = _st.imageRadius - userpicRadius;
 | 
				
			||||||
		auto userpicLeft = x + userpicShift;
 | 
							auto userpicLeft = x + userpicShift;
 | 
				
			||||||
		auto userpicTop = y + userpicShift;
 | 
							auto userpicTop = y + userpicShift;
 | 
				
			||||||
| 
						 | 
					@ -108,78 +261,32 @@ void RoundImageCheckbox::paint(Painter &p, uint64 ms, int x, int y, int outerWid
 | 
				
			||||||
		p.setRenderHint(QPainter::HighQualityAntialiasing, false);
 | 
							p.setRenderHint(QPainter::HighQualityAntialiasing, false);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p.setRenderHint(QPainter::SmoothPixmapTransform, true);
 | 
						auto iconLeft = x + 2 * _st.imageRadius + _st.selectWidth - _st.check.size;
 | 
				
			||||||
	for (auto &icon : _icons) {
 | 
						auto iconTop = y + 2 * _st.imageRadius + _st.selectWidth - _st.check.size;
 | 
				
			||||||
		auto fadeIn = icon.fadeIn.current(1.);
 | 
						_check.paint(p, ms, iconLeft, iconTop, outerWidth);
 | 
				
			||||||
		auto fadeOut = icon.fadeOut.current(1.);
 | 
					 | 
				
			||||||
		auto iconRadius = qRound(kWideScale * (_st.checkSmallRadius + fadeOut * (_st.checkRadius - _st.checkSmallRadius)));
 | 
					 | 
				
			||||||
		auto iconShift = kWideScale * _st.checkRadius - iconRadius;
 | 
					 | 
				
			||||||
		auto iconLeft = x + 2 * _st.imageRadius + _st.selectWidth - 2 * _st.checkRadius - (kWideScale - 1) * _st.checkRadius + iconShift;
 | 
					 | 
				
			||||||
		auto iconTop = y + 2 * _st.imageRadius + _st.selectWidth - 2 * _st.checkRadius - (kWideScale - 1) * _st.checkRadius + iconShift;
 | 
					 | 
				
			||||||
		auto to = QRect(iconLeft, iconTop, iconRadius * 2, iconRadius * 2);
 | 
					 | 
				
			||||||
		auto from = QRect(QPoint(0, 0), _wideCheckFullCache.size());
 | 
					 | 
				
			||||||
		auto opacity = fadeIn * fadeOut;
 | 
					 | 
				
			||||||
		p.setOpacity(opacity);
 | 
					 | 
				
			||||||
		if (fadeOut < 1.) {
 | 
					 | 
				
			||||||
			p.drawPixmapLeft(to, outerWidth, icon.wideCheckCache, from);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			auto divider = qRound((kWideScale - 2) * _st.checkRadius + fadeIn * 3 * _st.checkRadius);
 | 
					 | 
				
			||||||
			p.drawPixmapLeft(QRect(iconLeft, iconTop, divider, iconRadius * 2), outerWidth, _wideCheckFullCache, QRect(0, 0, divider * cIntRetinaFactor(), _wideCheckFullCache.height()));
 | 
					 | 
				
			||||||
			p.drawPixmapLeft(QRect(iconLeft + divider, iconTop, iconRadius * 2 - divider, iconRadius * 2), outerWidth, _wideCheckBgCache, QRect(divider * cIntRetinaFactor(), 0, _wideCheckBgCache.width() - divider * cIntRetinaFactor(), _wideCheckBgCache.height()));
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	p.setRenderHint(QPainter::SmoothPixmapTransform, false);
 | 
					 | 
				
			||||||
	p.setOpacity(1.);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
float64 RoundImageCheckbox::checkedAnimationRatio() const {
 | 
					float64 RoundImageCheckbox::checkedAnimationRatio() const {
 | 
				
			||||||
	return snap(_selection.current(_checked ? 1. : 0.), 0., 1.);
 | 
						return snap(_selection.current(checked() ? 1. : 0.), 0., 1.);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void RoundImageCheckbox::setChecked(bool checked, SetStyle speed) {
 | 
					void RoundImageCheckbox::setChecked(bool newChecked, SetStyle speed) {
 | 
				
			||||||
	if (_checked == checked) {
 | 
						auto changed = (checked() != newChecked);
 | 
				
			||||||
 | 
						_check.setChecked(newChecked, speed);
 | 
				
			||||||
 | 
						if (!changed) {
 | 
				
			||||||
		if (speed != SetStyle::Animated) {
 | 
							if (speed != SetStyle::Animated) {
 | 
				
			||||||
			if (!_icons.isEmpty()) {
 | 
					 | 
				
			||||||
				_icons.back().fadeIn.finish();
 | 
					 | 
				
			||||||
				_icons.back().fadeOut.finish();
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			_selection.finish();
 | 
								_selection.finish();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	_checked = checked;
 | 
					 | 
				
			||||||
	if (_checked) {
 | 
					 | 
				
			||||||
		_icons.push_back(Icon());
 | 
					 | 
				
			||||||
		_icons.back().fadeIn.start(_updateCallback, 0, 1, _st.selectDuration);
 | 
					 | 
				
			||||||
		if (speed != SetStyle::Animated) {
 | 
					 | 
				
			||||||
			_icons.back().fadeIn.finish();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		_icons.back().fadeOut.start(_updateCallback, 1, 0, _st.selectDuration);
 | 
					 | 
				
			||||||
		if (speed == SetStyle::Animated) {
 | 
					 | 
				
			||||||
			prepareWideCheckIconCache(&_icons.back());
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			_icons.back().fadeOut.finish();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (speed == SetStyle::Animated) {
 | 
						if (speed == SetStyle::Animated) {
 | 
				
			||||||
		prepareWideCache();
 | 
							prepareWideCache();
 | 
				
			||||||
		_selection.start(_updateCallback, _checked ? 0 : 1, _checked ? 1 : 0, _st.selectDuration, anim::bumpy(1.25));
 | 
							_selection.start(_updateCallback, checked() ? 0 : 1, checked() ? 1 : 0, _st.selectDuration, anim::bumpy(1.25));
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		_selection.finish();
 | 
							_selection.finish();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void RoundImageCheckbox::removeFadeOutedIcons() {
 | 
					 | 
				
			||||||
	while (!_icons.empty() && !_icons.front().fadeIn.animating() && !_icons.front().fadeOut.animating()) {
 | 
					 | 
				
			||||||
		if (_icons.size() > 1 || !_checked) {
 | 
					 | 
				
			||||||
			_icons.erase(_icons.begin());
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void RoundImageCheckbox::prepareWideCache() {
 | 
					void RoundImageCheckbox::prepareWideCache() {
 | 
				
			||||||
	if (_wideCache.isNull()) {
 | 
						if (_wideCache.isNull()) {
 | 
				
			||||||
		auto size = _st.imageRadius * 2;
 | 
							auto size = _st.imageRadius * 2;
 | 
				
			||||||
| 
						 | 
					@ -197,21 +304,4 @@ void RoundImageCheckbox::prepareWideCache() {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void RoundImageCheckbox::prepareWideCheckIconCache(Icon *icon) {
 | 
					 | 
				
			||||||
	auto cacheWidth = _wideCheckBgCache.width() / _wideCheckBgCache.devicePixelRatio();
 | 
					 | 
				
			||||||
	auto cacheHeight = _wideCheckBgCache.height() / _wideCheckBgCache.devicePixelRatio();
 | 
					 | 
				
			||||||
	auto wideCache = QImage(cacheWidth * cIntRetinaFactor(), cacheHeight * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
 | 
					 | 
				
			||||||
	wideCache.setDevicePixelRatio(cRetinaFactor());
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		Painter p(&wideCache);
 | 
					 | 
				
			||||||
		p.setCompositionMode(QPainter::CompositionMode_Source);
 | 
					 | 
				
			||||||
		auto iconRadius = kWideScale * _st.checkRadius;
 | 
					 | 
				
			||||||
		auto divider = qRound((kWideScale - 2) * _st.checkRadius + icon->fadeIn.current(1.) * (kWideScale - 1) * _st.checkRadius);
 | 
					 | 
				
			||||||
		p.drawPixmapLeft(QRect(0, 0, divider, iconRadius * 2), cacheWidth, _wideCheckFullCache, QRect(0, 0, divider * cIntRetinaFactor(), _wideCheckFullCache.height()));
 | 
					 | 
				
			||||||
		p.drawPixmapLeft(QRect(divider, 0, iconRadius * 2 - divider, iconRadius * 2), cacheWidth, _wideCheckBgCache, QRect(divider * cIntRetinaFactor(), 0, _wideCheckBgCache.width() - divider * cIntRetinaFactor(), _wideCheckBgCache.height()));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	icon->wideCheckCache = App::pixmapFromImageInPlace(std_::move(wideCache));
 | 
					 | 
				
			||||||
	icon->wideCheckCache.setDevicePixelRatio(cRetinaFactor());
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace Ui
 | 
					} // namespace Ui
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,47 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Ui {
 | 
					namespace Ui {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RoundCheckbox {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						RoundCheckbox(const style::RoundCheckbox &st, const base::lambda_copy<void()> &updateCallback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void paint(Painter &p, uint64 ms, int x, int y, int outerWidth, float64 masterScale = 1.);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void setDisplayInactive(bool displayInactive);
 | 
				
			||||||
 | 
						bool checked() const {
 | 
				
			||||||
 | 
							return _checked;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						enum class SetStyle {
 | 
				
			||||||
 | 
							Animated,
 | 
				
			||||||
 | 
							Fast,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						void setChecked(bool newChecked, SetStyle speed = SetStyle::Animated);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						struct Icon {
 | 
				
			||||||
 | 
							FloatAnimation fadeIn;
 | 
				
			||||||
 | 
							FloatAnimation fadeOut;
 | 
				
			||||||
 | 
							QPixmap wideCheckCache;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						void removeFadeOutedIcons();
 | 
				
			||||||
 | 
						void prepareWideCheckIconCache(Icon *icon);
 | 
				
			||||||
 | 
						void prepareInactiveCache();
 | 
				
			||||||
 | 
						QRect cacheDestRect(int x, int y, float64 scale) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const style::RoundCheckbox &_st;
 | 
				
			||||||
 | 
						base::lambda_copy<void()> _updateCallback;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool _checked = false;
 | 
				
			||||||
 | 
						std_::vector_of_moveable<Icon> _icons;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool _displayInactive = false;
 | 
				
			||||||
 | 
						QPixmap _inactiveCacheBg, _inactiveCacheFg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Those pixmaps are shared among all checkboxes that have the same style.
 | 
				
			||||||
 | 
						QPixmap _wideCheckBgCache, _wideCheckFullCache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RoundImageCheckbox {
 | 
					class RoundImageCheckbox {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	using PaintRoundImage = base::lambda<void(Painter &p, int x, int y, int outerWidth, int size)>;
 | 
						using PaintRoundImage = base::lambda<void(Painter &p, int x, int y, int outerWidth, int size)>;
 | 
				
			||||||
| 
						 | 
					@ -33,35 +74,22 @@ public:
 | 
				
			||||||
	float64 checkedAnimationRatio() const;
 | 
						float64 checkedAnimationRatio() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool checked() const {
 | 
						bool checked() const {
 | 
				
			||||||
		return _checked;
 | 
							return _check.checked();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	enum class SetStyle {
 | 
						using SetStyle = RoundCheckbox::SetStyle;
 | 
				
			||||||
		Animated,
 | 
						void setChecked(bool newChecked, SetStyle speed = SetStyle::Animated);
 | 
				
			||||||
		Fast,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	void setChecked(bool checked, SetStyle speed = SetStyle::Animated);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	struct Icon {
 | 
					 | 
				
			||||||
		FloatAnimation fadeIn;
 | 
					 | 
				
			||||||
		FloatAnimation fadeOut;
 | 
					 | 
				
			||||||
		QPixmap wideCheckCache;
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	void removeFadeOutedIcons();
 | 
					 | 
				
			||||||
	void prepareWideCache();
 | 
						void prepareWideCache();
 | 
				
			||||||
	void prepareWideCheckIconCache(Icon *icon);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const style::RoundImageCheckbox &_st;
 | 
						const style::RoundImageCheckbox &_st;
 | 
				
			||||||
	base::lambda_copy<void()> _updateCallback;
 | 
						base::lambda_copy<void()> _updateCallback;
 | 
				
			||||||
	PaintRoundImage _paintRoundImage;
 | 
						PaintRoundImage _paintRoundImage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool _checked = false;
 | 
					 | 
				
			||||||
	QPixmap _wideCache;
 | 
						QPixmap _wideCache;
 | 
				
			||||||
	FloatAnimation _selection;
 | 
						FloatAnimation _selection;
 | 
				
			||||||
	std_::vector_of_moveable<Icon> _icons;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Those pixmaps are shared among all checkboxes that have the same style.
 | 
						RoundCheckbox _check;
 | 
				
			||||||
	QPixmap _wideCheckBgCache, _wideCheckFullCache;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -319,17 +319,24 @@ FilledSlider {
 | 
				
			||||||
	duration: int;
 | 
						duration: int;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RoundCheckbox {
 | 
				
			||||||
 | 
						border: color;
 | 
				
			||||||
 | 
						bgInactive: color;
 | 
				
			||||||
 | 
						bgActive: color;
 | 
				
			||||||
 | 
						width: pixels;
 | 
				
			||||||
 | 
						size: pixels;
 | 
				
			||||||
 | 
						sizeSmall: double;
 | 
				
			||||||
 | 
						duration: int;
 | 
				
			||||||
 | 
						check: icon;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RoundImageCheckbox {
 | 
					RoundImageCheckbox {
 | 
				
			||||||
	imageRadius: pixels;
 | 
						imageRadius: pixels;
 | 
				
			||||||
	imageSmallRadius: pixels;
 | 
						imageSmallRadius: pixels;
 | 
				
			||||||
	selectWidth: pixels;
 | 
						selectWidth: pixels;
 | 
				
			||||||
	selectFg: color;
 | 
						selectFg: color;
 | 
				
			||||||
	selectDuration: int;
 | 
						selectDuration: int;
 | 
				
			||||||
	checkBorder: color;
 | 
						check: RoundCheckbox;
 | 
				
			||||||
	checkBg: color;
 | 
					 | 
				
			||||||
	checkRadius: pixels;
 | 
					 | 
				
			||||||
	checkSmallRadius: pixels;
 | 
					 | 
				
			||||||
	checkIcon: icon;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MultiSelectItem {
 | 
					MultiSelectItem {
 | 
				
			||||||
| 
						 | 
					@ -738,6 +745,13 @@ defaultPanelAnimation: PanelAnimation {
 | 
				
			||||||
	shadow: defaultRoundShadow;
 | 
						shadow: defaultRoundShadow;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defaultRoundCheckbox: RoundCheckbox {
 | 
				
			||||||
 | 
						border: windowBg;
 | 
				
			||||||
 | 
						bgActive: windowBgActive;
 | 
				
			||||||
 | 
						width: 2px;
 | 
				
			||||||
 | 
						duration: 150;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
defaultMenuArrow: icon {{ "dropdown_submenu_arrow", #373737 }};
 | 
					defaultMenuArrow: icon {{ "dropdown_submenu_arrow", #373737 }};
 | 
				
			||||||
defaultMenu: Menu {
 | 
					defaultMenu: Menu {
 | 
				
			||||||
	skip: 0px;
 | 
						skip: 0px;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue