2016-08-19 17:26:31 +00:00
|
|
|
/*
|
|
|
|
This file is part of Telegram Desktop,
|
|
|
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
|
|
|
|
|
|
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
It is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
In addition, as a special exception, the copyright holders give permission
|
|
|
|
to link the code of portions of this program with the OpenSSL library.
|
|
|
|
|
|
|
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
|
|
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "settings/settings_background_widget.h"
|
|
|
|
|
|
|
|
#include "styles/style_settings.h"
|
|
|
|
#include "lang.h"
|
2016-08-27 04:49:18 +00:00
|
|
|
#include "mainwidget.h"
|
|
|
|
#include "boxes/backgroundbox.h"
|
2016-10-26 10:06:00 +00:00
|
|
|
#include "ui/effects/widget_slide_wrap.h"
|
2016-11-11 13:46:04 +00:00
|
|
|
#include "ui/widgets/checkbox.h"
|
|
|
|
#include "ui/widgets/buttons.h"
|
2016-08-27 04:49:18 +00:00
|
|
|
#include "localstorage.h"
|
|
|
|
#include "mainwindow.h"
|
2016-10-28 12:44:28 +00:00
|
|
|
#include "window/window_theme.h"
|
2016-08-19 17:26:31 +00:00
|
|
|
|
|
|
|
namespace Settings {
|
|
|
|
|
2016-08-27 04:49:18 +00:00
|
|
|
BackgroundRow::BackgroundRow(QWidget *parent) : TWidget(parent)
|
2016-11-11 13:46:04 +00:00
|
|
|
, _chooseFromGallery(this, lang(lng_settings_bg_from_gallery), st::boxLinkButton)
|
|
|
|
, _chooseFromFile(this, lang(lng_settings_bg_from_file), st::boxLinkButton)
|
2016-08-27 04:49:18 +00:00
|
|
|
, _radial(animation(this, &BackgroundRow::step_radial)) {
|
|
|
|
updateImage();
|
|
|
|
|
|
|
|
connect(_chooseFromGallery, SIGNAL(clicked()), this, SIGNAL(chooseFromGallery()));
|
|
|
|
connect(_chooseFromFile, SIGNAL(clicked()), this, SIGNAL(chooseFromFile()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void BackgroundRow::paintEvent(QPaintEvent *e) {
|
|
|
|
Painter p(this);
|
|
|
|
|
|
|
|
bool radial = false;
|
|
|
|
float64 radialOpacity = 0;
|
|
|
|
if (_radial.animating()) {
|
|
|
|
_radial.step(getms());
|
|
|
|
radial = _radial.animating();
|
|
|
|
radialOpacity = _radial.opacity();
|
|
|
|
}
|
|
|
|
if (radial) {
|
|
|
|
auto backThumb = App::main() ? App::main()->newBackgroundThumb() : ImagePtr();
|
|
|
|
if (backThumb->isNull()) {
|
|
|
|
p.drawPixmap(0, 0, _background);
|
|
|
|
} else {
|
2016-09-29 11:37:16 +00:00
|
|
|
const QPixmap &pix = App::main()->newBackgroundThumb()->pixBlurred(st::settingsBackgroundSize);
|
|
|
|
p.drawPixmap(0, 0, st::settingsBackgroundSize, st::settingsBackgroundSize, pix, 0, (pix.height() - st::settingsBackgroundSize) / 2, st::settingsBackgroundSize, st::settingsBackgroundSize);
|
2016-08-27 04:49:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto outer = radialRect();
|
|
|
|
QRect inner(QPoint(outer.x() + (outer.width() - st::radialSize.width()) / 2, outer.y() + (outer.height() - st::radialSize.height()) / 2), st::radialSize);
|
|
|
|
p.setPen(Qt::NoPen);
|
2016-10-31 12:29:26 +00:00
|
|
|
p.setOpacity(radialOpacity);
|
|
|
|
p.setBrush(st::radialBg);
|
2016-08-27 04:49:18 +00:00
|
|
|
|
|
|
|
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
|
|
|
p.drawEllipse(inner);
|
|
|
|
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
|
|
|
|
|
|
|
|
p.setOpacity(1);
|
|
|
|
QRect arc(inner.marginsRemoved(QMargins(st::radialLine, st::radialLine, st::radialLine, st::radialLine)));
|
2016-10-31 12:29:26 +00:00
|
|
|
_radial.draw(p, arc, st::radialLine, st::radialFg);
|
2016-08-27 04:49:18 +00:00
|
|
|
} else {
|
|
|
|
p.drawPixmap(0, 0, _background);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int BackgroundRow::resizeGetHeight(int newWidth) {
|
|
|
|
int linkLeft = st::settingsBackgroundSize + st::settingsSmallSkip;
|
|
|
|
int linkWidth = newWidth - linkLeft;
|
|
|
|
_chooseFromGallery->resizeToWidth(qMin(linkWidth, _chooseFromGallery->naturalWidth()));
|
|
|
|
_chooseFromFile->resizeToWidth(qMin(linkWidth, _chooseFromFile->naturalWidth()));
|
|
|
|
|
2016-08-28 19:16:23 +00:00
|
|
|
_chooseFromGallery->moveToLeft(linkLeft, 0, newWidth);
|
|
|
|
_chooseFromFile->moveToLeft(linkLeft, _chooseFromGallery->height() + st::settingsSmallSkip, newWidth);
|
2016-08-27 04:49:18 +00:00
|
|
|
|
|
|
|
return st::settingsBackgroundSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
float64 BackgroundRow::radialProgress() const {
|
|
|
|
if (auto m = App::main()) {
|
|
|
|
return m->chatBackgroundProgress();
|
|
|
|
}
|
|
|
|
return 1.;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BackgroundRow::radialLoading() const {
|
|
|
|
if (auto m = App::main()) {
|
|
|
|
if (m->chatBackgroundLoading()) {
|
|
|
|
m->checkChatBackground();
|
|
|
|
if (m->chatBackgroundLoading()) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
const_cast<BackgroundRow*>(this)->updateImage();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
QRect BackgroundRow::radialRect() const {
|
2016-09-29 11:37:16 +00:00
|
|
|
return QRect(0, 0, st::settingsBackgroundSize, st::settingsBackgroundSize);
|
2016-08-27 04:49:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void BackgroundRow::radialStart() {
|
|
|
|
if (radialLoading() && !_radial.animating()) {
|
|
|
|
_radial.start(radialProgress());
|
|
|
|
if (auto shift = radialTimeShift()) {
|
|
|
|
_radial.update(radialProgress(), !radialLoading(), getms() + shift);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-01 19:20:33 +00:00
|
|
|
TimeMs BackgroundRow::radialTimeShift() const {
|
2016-08-27 04:49:18 +00:00
|
|
|
return st::radialDuration;
|
|
|
|
}
|
|
|
|
|
2016-12-01 19:20:33 +00:00
|
|
|
void BackgroundRow::step_radial(TimeMs ms, bool timer) {
|
2016-08-27 04:49:18 +00:00
|
|
|
_radial.update(radialProgress(), !radialLoading(), ms + radialTimeShift());
|
|
|
|
if (timer && _radial.animating()) {
|
|
|
|
rtlupdate(radialRect());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BackgroundRow::updateImage() {
|
2016-09-29 11:37:16 +00:00
|
|
|
int32 size = st::settingsBackgroundSize * cIntRetinaFactor();
|
2016-08-27 04:49:18 +00:00
|
|
|
QImage back(size, size, QImage::Format_ARGB32_Premultiplied);
|
|
|
|
back.setDevicePixelRatio(cRetinaFactor());
|
|
|
|
{
|
|
|
|
QPainter p(&back);
|
2016-10-28 12:44:28 +00:00
|
|
|
auto &pix = Window::Theme::Background()->image();
|
2016-08-27 04:49:18 +00:00
|
|
|
int sx = (pix.width() > pix.height()) ? ((pix.width() - pix.height()) / 2) : 0;
|
|
|
|
int sy = (pix.height() > pix.width()) ? ((pix.height() - pix.width()) / 2) : 0;
|
|
|
|
int s = (pix.width() > pix.height()) ? pix.height() : pix.width();
|
|
|
|
p.setRenderHint(QPainter::SmoothPixmapTransform);
|
2016-09-29 11:37:16 +00:00
|
|
|
p.drawPixmap(0, 0, st::settingsBackgroundSize, st::settingsBackgroundSize, pix, sx, sy, s, s);
|
2016-08-27 04:49:18 +00:00
|
|
|
}
|
2016-11-28 15:45:07 +00:00
|
|
|
Images::prepareRound(back, ImageRoundRadius::Small);
|
2016-08-27 04:49:18 +00:00
|
|
|
_background = App::pixmapFromImageInPlace(std_::move(back));
|
|
|
|
_background.setDevicePixelRatio(cRetinaFactor());
|
|
|
|
|
|
|
|
rtlupdate(radialRect());
|
|
|
|
|
|
|
|
if (radialLoading()) {
|
|
|
|
radialStart();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-19 17:26:31 +00:00
|
|
|
BackgroundWidget::BackgroundWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_background)) {
|
2016-08-27 04:49:18 +00:00
|
|
|
createControls();
|
|
|
|
|
2016-09-26 13:57:08 +00:00
|
|
|
subscribe(FileDialog::QueryDone(), [this](const FileDialog::QueryUpdate &update) {
|
|
|
|
notifyFileQueryUpdated(update);
|
|
|
|
});
|
2016-10-28 12:44:28 +00:00
|
|
|
using Update = Window::Theme::BackgroundUpdate;
|
|
|
|
subscribe(Window::Theme::Background(), [this](const Update &update) {
|
2016-08-27 04:49:18 +00:00
|
|
|
if (update.type == Update::Type::New) {
|
|
|
|
_background->updateImage();
|
|
|
|
} else if (update.type == Update::Type::Start) {
|
|
|
|
needBackgroundUpdate(update.tiled);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
subscribe(Adaptive::Changed(), [this]() {
|
|
|
|
if (Global::AdaptiveLayout() == Adaptive::WideLayout) {
|
|
|
|
_adaptive->slideDown();
|
|
|
|
} else {
|
|
|
|
_adaptive->slideUp();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void BackgroundWidget::createControls() {
|
|
|
|
style::margins margin(0, 0, 0, st::settingsSmallSkip);
|
|
|
|
style::margins slidedPadding(0, margin.bottom() / 2, 0, margin.bottom() - (margin.bottom() / 2));
|
|
|
|
|
|
|
|
addChildRow(_background, margin);
|
|
|
|
connect(_background, SIGNAL(chooseFromGallery()), this, SLOT(onChooseFromGallery()));
|
|
|
|
connect(_background, SIGNAL(chooseFromFile()), this, SLOT(onChooseFromFile()));
|
|
|
|
|
2016-10-28 12:44:28 +00:00
|
|
|
addChildRow(_tile, margin, lang(lng_settings_bg_tile), SLOT(onTile()), Window::Theme::Background()->tile());
|
2016-08-27 04:49:18 +00:00
|
|
|
addChildRow(_adaptive, margin, slidedPadding, lang(lng_settings_adaptive_wide), SLOT(onAdaptive()), Global::AdaptiveForWide());
|
|
|
|
if (Global::AdaptiveLayout() != Adaptive::WideLayout) {
|
|
|
|
_adaptive->hideFast();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BackgroundWidget::onChooseFromGallery() {
|
|
|
|
Ui::showLayer(new BackgroundBox());
|
|
|
|
}
|
|
|
|
|
|
|
|
void BackgroundWidget::needBackgroundUpdate(bool tile) {
|
|
|
|
_tile->setChecked(tile);
|
|
|
|
_background->updateImage();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BackgroundWidget::onChooseFromFile() {
|
2016-10-28 12:44:28 +00:00
|
|
|
auto imgExtensions = cImgExtensions();
|
|
|
|
auto filters = QStringList(qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(")"));
|
|
|
|
filters.push_back(qsl("Theme files (*.tdesktop-theme)"));
|
|
|
|
filters.push_back(filedialogAllFilesFilter());
|
2016-08-27 04:49:18 +00:00
|
|
|
|
2016-11-28 15:45:07 +00:00
|
|
|
_chooseFromFileQueryId = FileDialog::queryReadFile(lang(lng_choose_image), filters.join(qsl(";;")));
|
2016-08-19 17:26:31 +00:00
|
|
|
}
|
|
|
|
|
2016-08-27 04:49:18 +00:00
|
|
|
void BackgroundWidget::notifyFileQueryUpdated(const FileDialog::QueryUpdate &update) {
|
|
|
|
if (_chooseFromFileQueryId != update.queryId) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_chooseFromFileQueryId = 0;
|
|
|
|
|
|
|
|
if (update.filePaths.isEmpty() && update.remoteContent.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-10-28 12:44:28 +00:00
|
|
|
auto filePath = update.filePaths.front();
|
|
|
|
if (filePath.endsWith(qstr(".tdesktop-theme"), Qt::CaseInsensitive)) {
|
2016-11-02 14:44:33 +00:00
|
|
|
Window::Theme::Apply(filePath);
|
2016-10-28 12:44:28 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-08-27 04:49:18 +00:00
|
|
|
QImage img;
|
|
|
|
if (!update.remoteContent.isEmpty()) {
|
|
|
|
img = App::readImage(update.remoteContent);
|
|
|
|
} else {
|
2016-10-28 12:44:28 +00:00
|
|
|
img = App::readImage(filePath);
|
2016-08-27 04:49:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (img.isNull() || img.width() <= 0 || img.height() <= 0) return;
|
|
|
|
|
|
|
|
if (img.width() > 4096 * img.height()) {
|
|
|
|
img = img.copy((img.width() - 4096 * img.height()) / 2, 0, 4096 * img.height(), img.height());
|
|
|
|
} else if (img.height() > 4096 * img.width()) {
|
|
|
|
img = img.copy(0, (img.height() - 4096 * img.width()) / 2, img.width(), 4096 * img.width());
|
|
|
|
}
|
|
|
|
|
2016-10-28 12:44:28 +00:00
|
|
|
Window::Theme::Background()->setImage(Window::Theme::kCustomBackground, std_::move(img));
|
2016-08-27 04:49:18 +00:00
|
|
|
_tile->setChecked(false);
|
|
|
|
_background->updateImage();
|
2016-08-19 17:26:31 +00:00
|
|
|
}
|
|
|
|
|
2016-08-27 04:49:18 +00:00
|
|
|
void BackgroundWidget::onTile() {
|
2016-10-28 12:44:28 +00:00
|
|
|
Window::Theme::Background()->setTile(_tile->checked());
|
2016-08-27 04:49:18 +00:00
|
|
|
}
|
2016-08-19 17:26:31 +00:00
|
|
|
|
2016-08-27 04:49:18 +00:00
|
|
|
void BackgroundWidget::onAdaptive() {
|
|
|
|
if (Global::AdaptiveForWide() != _adaptive->entity()->checked()) {
|
|
|
|
Global::SetAdaptiveForWide(_adaptive->entity()->checked());
|
|
|
|
Adaptive::Changed().notify();
|
|
|
|
Local::writeUserSettings();
|
|
|
|
}
|
2016-08-19 17:26:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Settings
|