mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Add support for linear gradients without patterns.
This commit is contained in:
parent
ba7e976fe2
commit
436d7b9d82
8 changed files with 87 additions and 121 deletions
|
@ -326,8 +326,18 @@ void BackgroundBox::Inner::validatePaperThumbnail(
|
||||||
paper.dataMedia = document->createMediaView();
|
paper.dataMedia = document->createMediaView();
|
||||||
paper.dataMedia->thumbnailWanted(paper.data.fileOrigin());
|
paper.dataMedia->thumbnailWanted(paper.data.fileOrigin());
|
||||||
}
|
}
|
||||||
}
|
if (!paper.dataMedia->thumbnail()) {
|
||||||
if (!paper.dataMedia || !paper.dataMedia->thumbnail()) {
|
return;
|
||||||
|
}
|
||||||
|
} else if (!paper.data.backgroundColors().empty()) {
|
||||||
|
paper.thumbnail = Ui::PixmapFromImage(
|
||||||
|
Data::GenerateWallPaper(
|
||||||
|
st::backgroundSize * cIntRetinaFactor(),
|
||||||
|
paper.data.backgroundColors(),
|
||||||
|
paper.data.gradientRotation()));
|
||||||
|
paper.thumbnail.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -419,12 +419,24 @@ BackgroundPreviewBox::BackgroundPreviewBox(
|
||||||
if (_media) {
|
if (_media) {
|
||||||
_media->thumbnailWanted(_paper.fileOrigin());
|
_media->thumbnailWanted(_paper.fileOrigin());
|
||||||
}
|
}
|
||||||
|
generateBackground();
|
||||||
_controller->session().downloaderTaskFinished(
|
_controller->session().downloaderTaskFinished(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
update();
|
update();
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BackgroundPreviewBox::generateBackground() {
|
||||||
|
if (_paper.backgroundColors().empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_generated = Ui::PixmapFromImage(Data::GenerateWallPaper(
|
||||||
|
QSize(st::boxWideWidth, st::boxWideWidth) * cIntRetinaFactor(),
|
||||||
|
_paper.backgroundColors(),
|
||||||
|
_paper.gradientRotation()));
|
||||||
|
_generated.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
}
|
||||||
|
|
||||||
not_null<HistoryView::ElementDelegate*> BackgroundPreviewBox::delegate() {
|
not_null<HistoryView::ElementDelegate*> BackgroundPreviewBox::delegate() {
|
||||||
return static_cast<HistoryView::ElementDelegate*>(this);
|
return static_cast<HistoryView::ElementDelegate*>(this);
|
||||||
}
|
}
|
||||||
|
@ -525,21 +537,23 @@ void BackgroundPreviewBox::paintEvent(QPaintEvent *e) {
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
|
|
||||||
const auto ms = crl::now();
|
const auto ms = crl::now();
|
||||||
const auto color = _paper.backgroundColor();
|
if (_scaled.isNull()) {
|
||||||
if (color) {
|
setScaledFromThumb();
|
||||||
p.fillRect(e->rect(), *color);
|
|
||||||
}
|
}
|
||||||
if (!color || _paper.isPattern()) {
|
if (!_generated.isNull()
|
||||||
if (!_scaled.isNull() || setScaledFromThumb()) {
|
&& (_scaled.isNull()
|
||||||
paintImage(p);
|
|| (_fadeOutThumbnail.isNull() && _fadeIn.animating()))) {
|
||||||
paintRadial(p);
|
p.drawPixmap(0, 0, _generated);
|
||||||
} else if (!color) {
|
}
|
||||||
p.fillRect(e->rect(), st::boxBg);
|
if (!_scaled.isNull()) {
|
||||||
return;
|
paintImage(p);
|
||||||
} else {
|
paintRadial(p);
|
||||||
// Progress of pattern loading.
|
} else if (_generated.isNull()) {
|
||||||
paintRadial(p);
|
p.fillRect(e->rect(), st::boxBg);
|
||||||
}
|
return;
|
||||||
|
} else {
|
||||||
|
// Progress of pattern loading.
|
||||||
|
paintRadial(p);
|
||||||
}
|
}
|
||||||
paintTexts(p, ms);
|
paintTexts(p, ms);
|
||||||
}
|
}
|
||||||
|
@ -655,7 +669,10 @@ void BackgroundPreviewBox::radialAnimationCallback(crl::time now) {
|
||||||
checkLoadedDocument();
|
checkLoadedDocument();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BackgroundPreviewBox::setScaledFromThumb() {
|
void BackgroundPreviewBox::setScaledFromThumb() {
|
||||||
|
if (!_scaled.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const auto localThumbnail = _paper.localThumbnail();
|
const auto localThumbnail = _paper.localThumbnail();
|
||||||
const auto thumbnail = localThumbnail
|
const auto thumbnail = localThumbnail
|
||||||
? localThumbnail
|
? localThumbnail
|
||||||
|
@ -663,9 +680,9 @@ bool BackgroundPreviewBox::setScaledFromThumb() {
|
||||||
? _media->thumbnail()
|
? _media->thumbnail()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
if (!thumbnail) {
|
if (!thumbnail) {
|
||||||
return false;
|
return;
|
||||||
} else if (_paper.isPattern() && _paper.document() != nullptr) {
|
} else if (_paper.isPattern() && _paper.document() != nullptr) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
auto scaled = PrepareScaledFromFull(
|
auto scaled = PrepareScaledFromFull(
|
||||||
thumbnail->original(),
|
thumbnail->original(),
|
||||||
|
@ -679,7 +696,6 @@ bool BackgroundPreviewBox::setScaledFromThumb() {
|
||||||
Data::PrepareBlurredBackground(thumbnail->original()),
|
Data::PrepareBlurredBackground(thumbnail->original()),
|
||||||
Images::Option(0));
|
Images::Option(0));
|
||||||
setScaledFromImage(std::move(scaled), std::move(blurred));
|
setScaledFromImage(std::move(scaled), std::move(blurred));
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundPreviewBox::setScaledFromImage(
|
void BackgroundPreviewBox::setScaledFromImage(
|
||||||
|
|
|
@ -56,8 +56,9 @@ private:
|
||||||
void radialAnimationCallback(crl::time now);
|
void radialAnimationCallback(crl::time now);
|
||||||
QRect radialRect() const;
|
QRect radialRect() const;
|
||||||
|
|
||||||
|
void generateBackground();
|
||||||
void checkLoadedDocument();
|
void checkLoadedDocument();
|
||||||
bool setScaledFromThumb();
|
void setScaledFromThumb();
|
||||||
void setScaledFromImage(QImage &&image, QImage &&blurred);
|
void setScaledFromImage(QImage &&image, QImage &&blurred);
|
||||||
void updateServiceBg(const std::vector<QColor> &bg);
|
void updateServiceBg(const std::vector<QColor> &bg);
|
||||||
std::vector<QColor> patternBackgroundColors() const;
|
std::vector<QColor> patternBackgroundColors() const;
|
||||||
|
@ -76,7 +77,7 @@ private:
|
||||||
Data::WallPaper _paper;
|
Data::WallPaper _paper;
|
||||||
std::shared_ptr<Data::DocumentMedia> _media;
|
std::shared_ptr<Data::DocumentMedia> _media;
|
||||||
QImage _full;
|
QImage _full;
|
||||||
QPixmap _scaled, _blurred, _fadeOutThumbnail;
|
QPixmap _generated, _scaled, _blurred, _fadeOutThumbnail;
|
||||||
Ui::Animations::Simple _fadeIn;
|
Ui::Animations::Simple _fadeIn;
|
||||||
Ui::RadialAnimation _radial;
|
Ui::RadialAnimation _radial;
|
||||||
base::binary_guard _generating;
|
base::binary_guard _generating;
|
||||||
|
|
|
@ -755,26 +755,31 @@ bool IsCloudWallPaper(const WallPaper &paper) {
|
||||||
p.fillRect(0, 0, width, height, QBrush(std::move(gradient)));
|
p.fillRect(0, 0, width, height, QBrush(std::move(gradient)));
|
||||||
p.end();
|
p.end();
|
||||||
|
|
||||||
return image;
|
return Images::DitherImage(std::move(image));
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage PreparePatternImage(
|
QImage GenerateWallPaper(
|
||||||
QSize size,
|
QSize size,
|
||||||
Fn<void(QPainter&)> drawPattern,
|
|
||||||
const std::vector<QColor> &bg,
|
const std::vector<QColor> &bg,
|
||||||
int rotation,
|
int gradientRotation,
|
||||||
float64 opacity) {
|
float64 patternOpacity,
|
||||||
|
Fn<void(QPainter&)> drawPattern) {
|
||||||
auto result = QImage(size, QImage::Format_ARGB32_Premultiplied);
|
auto result = QImage(size, QImage::Format_ARGB32_Premultiplied);
|
||||||
if (bg.size() < 2) {
|
if (bg.size() < 2) {
|
||||||
result.fill(bg.empty() ? DefaultBackgroundColor() : bg.front());
|
result.fill(bg.empty() ? DefaultBackgroundColor() : bg.front());
|
||||||
} else {
|
} else {
|
||||||
result = FillDitheredGradient(std::move(result), bg, rotation);
|
result = FillDitheredGradient(
|
||||||
|
std::move(result),
|
||||||
|
bg,
|
||||||
|
gradientRotation);
|
||||||
|
}
|
||||||
|
if (drawPattern) {
|
||||||
|
auto p = QPainter(&result);
|
||||||
|
p.setCompositionMode(QPainter::CompositionMode_SoftLight);
|
||||||
|
p.setOpacity(patternOpacity);
|
||||||
|
drawPattern(p);
|
||||||
|
p.end();
|
||||||
}
|
}
|
||||||
auto p = QPainter(&result);
|
|
||||||
p.setCompositionMode(QPainter::CompositionMode_SoftLight);
|
|
||||||
p.setOpacity(opacity);
|
|
||||||
drawPattern(p);
|
|
||||||
p.end();
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -782,11 +787,16 @@ QImage PreparePatternImage(
|
||||||
QImage PreparePatternImage(
|
QImage PreparePatternImage(
|
||||||
QImage pattern,
|
QImage pattern,
|
||||||
const std::vector<QColor> &bg,
|
const std::vector<QColor> &bg,
|
||||||
int rotation,
|
int gradientRotation,
|
||||||
float64 opacity) {
|
float64 patternOpacity) {
|
||||||
auto result = PreparePatternImage(pattern.size(), [&](QPainter &p) {
|
auto result = GenerateWallPaper(
|
||||||
p.drawImage(QRect(QPoint(), pattern.size()), pattern);
|
pattern.size(),
|
||||||
}, bg, rotation, opacity);
|
bg,
|
||||||
|
gradientRotation,
|
||||||
|
patternOpacity,
|
||||||
|
[&](QPainter &p) {
|
||||||
|
p.drawImage(QRect(QPoint(), pattern.size()), pattern);
|
||||||
|
});
|
||||||
|
|
||||||
pattern = QImage();
|
pattern = QImage();
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -122,17 +122,17 @@ private:
|
||||||
[[nodiscard]] bool IsDefaultWallPaper(const WallPaper &paper);
|
[[nodiscard]] bool IsDefaultWallPaper(const WallPaper &paper);
|
||||||
[[nodiscard]] bool IsCloudWallPaper(const WallPaper &paper);
|
[[nodiscard]] bool IsCloudWallPaper(const WallPaper &paper);
|
||||||
|
|
||||||
[[nodiscard]] QImage PreparePatternImage(
|
[[nodiscard]] QImage GenerateWallPaper(
|
||||||
QSize size,
|
QSize size,
|
||||||
Fn<void(QPainter&)> drawPattern,
|
|
||||||
const std::vector<QColor> &bg,
|
const std::vector<QColor> &bg,
|
||||||
int rotation,
|
int gradientRotation,
|
||||||
float64 opacity);
|
float64 patternOpacity = 1.,
|
||||||
|
Fn<void(QPainter&)> drawPattern = nullptr);
|
||||||
[[nodiscard]] QImage PreparePatternImage(
|
[[nodiscard]] QImage PreparePatternImage(
|
||||||
QImage pattern,
|
QImage pattern,
|
||||||
const std::vector<QColor> &bg,
|
const std::vector<QColor> &bg,
|
||||||
int rotation,
|
int gradientRotation,
|
||||||
float64 opacity);
|
float64 patternOpacity);
|
||||||
[[nodiscard]] QImage PrepareBlurredBackground(QImage image);
|
[[nodiscard]] QImage PrepareBlurredBackground(QImage image);
|
||||||
[[nodiscard]] QImage GenerateDitheredGradient(
|
[[nodiscard]] QImage GenerateDitheredGradient(
|
||||||
const std::vector<QColor> &colors,
|
const std::vector<QColor> &colors,
|
||||||
|
|
|
@ -436,77 +436,6 @@ bool InitializeFromSaved(Saved &&saved) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] QImage DitherImage(QImage image) {
|
|
||||||
Expects(image.bytesPerLine() == image.width() * 4);
|
|
||||||
|
|
||||||
const auto width = image.width();
|
|
||||||
const auto height = image.height();
|
|
||||||
|
|
||||||
if (width < 16 || height < 16) {
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto area = width * height;
|
|
||||||
const auto shifts = std::make_unique<uchar[]>(area);
|
|
||||||
memset_rand(shifts.get(), area);
|
|
||||||
|
|
||||||
// shiftx = int(shift & 0x0F) - 8; shifty = int(shift >> 4) - 8;
|
|
||||||
// Clamp shifts close to edges.
|
|
||||||
for (auto y = 0; y != 8; ++y) {
|
|
||||||
const auto min = 8 - y;
|
|
||||||
const auto shifted = (min << 4);
|
|
||||||
auto shift = shifts.get() + y * width;
|
|
||||||
for (const auto till = shift + width; shift != till; ++shift) {
|
|
||||||
if ((*shift >> 4) < min) {
|
|
||||||
*shift = shifted | (*shift & 0x0F);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (auto y = height - 7; y != height; ++y) {
|
|
||||||
const auto max = 8 + (height - y - 1);
|
|
||||||
const auto shifted = (max << 4);
|
|
||||||
auto shift = shifts.get() + y * width;
|
|
||||||
for (const auto till = shift + width; shift != till; ++shift) {
|
|
||||||
if ((*shift >> 4) > max) {
|
|
||||||
*shift = shifted | (*shift & 0x0F);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (auto shift = shifts.get(), ytill = shift + area
|
|
||||||
; shift != ytill
|
|
||||||
; shift += width - 8) {
|
|
||||||
for (const auto till = shift + 8; shift != till; ++shift) {
|
|
||||||
const auto min = (till - shift);
|
|
||||||
if ((*shift & 0x0F) < min) {
|
|
||||||
*shift = (*shift & 0xF0) | min;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (auto shift = shifts.get(), ytill = shift + area; shift != ytill;) {
|
|
||||||
shift += width - 7;
|
|
||||||
for (const auto till = shift + 7; shift != till; ++shift) {
|
|
||||||
const auto max = 8 + (till - shift - 1);
|
|
||||||
if ((*shift & 0x0F) > max) {
|
|
||||||
*shift = (*shift & 0xF0) | max;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto result = image;
|
|
||||||
result.detach();
|
|
||||||
|
|
||||||
const auto src = reinterpret_cast<const uint32*>(image.constBits());
|
|
||||||
const auto dst = reinterpret_cast<uint32*>(result.bits());
|
|
||||||
for (auto index = 0; index != area; ++index) {
|
|
||||||
const auto shift = shifts[index];
|
|
||||||
const auto shiftx = int(shift & 0x0F) - 8;
|
|
||||||
const auto shifty = int(shift >> 4) - 8;
|
|
||||||
dst[index] = src[index + (shifty * width) + shiftx];
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] QImage PostprocessBackgroundImage(
|
[[nodiscard]] QImage PostprocessBackgroundImage(
|
||||||
QImage image,
|
QImage image,
|
||||||
const Data::WallPaper &paper) {
|
const Data::WallPaper &paper) {
|
||||||
|
@ -517,7 +446,7 @@ bool InitializeFromSaved(Saved &&saved) {
|
||||||
image.setDevicePixelRatio(cRetinaFactor());
|
image.setDevicePixelRatio(cRetinaFactor());
|
||||||
if (Data::IsDefaultWallPaper(paper)
|
if (Data::IsDefaultWallPaper(paper)
|
||||||
|| Data::details::IsTestingDefaultWallPaper(paper)) {
|
|| Data::details::IsTestingDefaultWallPaper(paper)) {
|
||||||
return DitherImage(std::move(image));
|
return Images::DitherImage(std::move(image));
|
||||||
}
|
}
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
|
@ -993,13 +993,13 @@ void MainMenu::refreshBackground() {
|
||||||
QRect to, from;
|
QRect to, from;
|
||||||
Window::Theme::ComputeBackgroundRects(fill, pixmap.size(), to, from);
|
Window::Theme::ComputeBackgroundRects(fill, pixmap.size(), to, from);
|
||||||
|
|
||||||
auto backgroundImage = paper.isPattern()
|
auto backgroundImage = !paper.backgroundColors().empty()
|
||||||
? Data::PreparePatternImage(
|
? Data::GenerateWallPaper(
|
||||||
fill.size() * cIntRetinaFactor(),
|
fill.size() * cIntRetinaFactor(),
|
||||||
[&](QPainter &p) { p.drawPixmap(to, pixmap, from); },
|
|
||||||
paper.backgroundColors(),
|
paper.backgroundColors(),
|
||||||
paper.gradientRotation(),
|
paper.gradientRotation(),
|
||||||
paper.patternOpacity())
|
paper.patternOpacity(),
|
||||||
|
[&](QPainter &p) { p.drawPixmap(to, pixmap, from); })
|
||||||
: QImage(
|
: QImage(
|
||||||
fill.size() * cIntRetinaFactor(),
|
fill.size() * cIntRetinaFactor(),
|
||||||
QImage::Format_ARGB32_Premultiplied);
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 40f0e3c6d43a02c20a5cb189ead8559c97bbbd9b
|
Subproject commit 3d5fcdb7ddab336ee2fadc3ceeced420e2c1f504
|
Loading…
Add table
Reference in a new issue