mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +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->thumbnailWanted(paper.data.fileOrigin());
|
||||
}
|
||||
}
|
||||
if (!paper.dataMedia || !paper.dataMedia->thumbnail()) {
|
||||
if (!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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -419,12 +419,24 @@ BackgroundPreviewBox::BackgroundPreviewBox(
|
|||
if (_media) {
|
||||
_media->thumbnailWanted(_paper.fileOrigin());
|
||||
}
|
||||
generateBackground();
|
||||
_controller->session().downloaderTaskFinished(
|
||||
) | rpl::start_with_next([=] {
|
||||
update();
|
||||
}, 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() {
|
||||
return static_cast<HistoryView::ElementDelegate*>(this);
|
||||
}
|
||||
|
@ -525,21 +537,23 @@ void BackgroundPreviewBox::paintEvent(QPaintEvent *e) {
|
|||
Painter p(this);
|
||||
|
||||
const auto ms = crl::now();
|
||||
const auto color = _paper.backgroundColor();
|
||||
if (color) {
|
||||
p.fillRect(e->rect(), *color);
|
||||
if (_scaled.isNull()) {
|
||||
setScaledFromThumb();
|
||||
}
|
||||
if (!color || _paper.isPattern()) {
|
||||
if (!_scaled.isNull() || setScaledFromThumb()) {
|
||||
paintImage(p);
|
||||
paintRadial(p);
|
||||
} else if (!color) {
|
||||
p.fillRect(e->rect(), st::boxBg);
|
||||
return;
|
||||
} else {
|
||||
// Progress of pattern loading.
|
||||
paintRadial(p);
|
||||
}
|
||||
if (!_generated.isNull()
|
||||
&& (_scaled.isNull()
|
||||
|| (_fadeOutThumbnail.isNull() && _fadeIn.animating()))) {
|
||||
p.drawPixmap(0, 0, _generated);
|
||||
}
|
||||
if (!_scaled.isNull()) {
|
||||
paintImage(p);
|
||||
paintRadial(p);
|
||||
} else if (_generated.isNull()) {
|
||||
p.fillRect(e->rect(), st::boxBg);
|
||||
return;
|
||||
} else {
|
||||
// Progress of pattern loading.
|
||||
paintRadial(p);
|
||||
}
|
||||
paintTexts(p, ms);
|
||||
}
|
||||
|
@ -655,7 +669,10 @@ void BackgroundPreviewBox::radialAnimationCallback(crl::time now) {
|
|||
checkLoadedDocument();
|
||||
}
|
||||
|
||||
bool BackgroundPreviewBox::setScaledFromThumb() {
|
||||
void BackgroundPreviewBox::setScaledFromThumb() {
|
||||
if (!_scaled.isNull()) {
|
||||
return;
|
||||
}
|
||||
const auto localThumbnail = _paper.localThumbnail();
|
||||
const auto thumbnail = localThumbnail
|
||||
? localThumbnail
|
||||
|
@ -663,9 +680,9 @@ bool BackgroundPreviewBox::setScaledFromThumb() {
|
|||
? _media->thumbnail()
|
||||
: nullptr;
|
||||
if (!thumbnail) {
|
||||
return false;
|
||||
return;
|
||||
} else if (_paper.isPattern() && _paper.document() != nullptr) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
auto scaled = PrepareScaledFromFull(
|
||||
thumbnail->original(),
|
||||
|
@ -679,7 +696,6 @@ bool BackgroundPreviewBox::setScaledFromThumb() {
|
|||
Data::PrepareBlurredBackground(thumbnail->original()),
|
||||
Images::Option(0));
|
||||
setScaledFromImage(std::move(scaled), std::move(blurred));
|
||||
return true;
|
||||
}
|
||||
|
||||
void BackgroundPreviewBox::setScaledFromImage(
|
||||
|
|
|
@ -56,8 +56,9 @@ private:
|
|||
void radialAnimationCallback(crl::time now);
|
||||
QRect radialRect() const;
|
||||
|
||||
void generateBackground();
|
||||
void checkLoadedDocument();
|
||||
bool setScaledFromThumb();
|
||||
void setScaledFromThumb();
|
||||
void setScaledFromImage(QImage &&image, QImage &&blurred);
|
||||
void updateServiceBg(const std::vector<QColor> &bg);
|
||||
std::vector<QColor> patternBackgroundColors() const;
|
||||
|
@ -76,7 +77,7 @@ private:
|
|||
Data::WallPaper _paper;
|
||||
std::shared_ptr<Data::DocumentMedia> _media;
|
||||
QImage _full;
|
||||
QPixmap _scaled, _blurred, _fadeOutThumbnail;
|
||||
QPixmap _generated, _scaled, _blurred, _fadeOutThumbnail;
|
||||
Ui::Animations::Simple _fadeIn;
|
||||
Ui::RadialAnimation _radial;
|
||||
base::binary_guard _generating;
|
||||
|
|
|
@ -755,26 +755,31 @@ bool IsCloudWallPaper(const WallPaper &paper) {
|
|||
p.fillRect(0, 0, width, height, QBrush(std::move(gradient)));
|
||||
p.end();
|
||||
|
||||
return image;
|
||||
return Images::DitherImage(std::move(image));
|
||||
}
|
||||
|
||||
QImage PreparePatternImage(
|
||||
QImage GenerateWallPaper(
|
||||
QSize size,
|
||||
Fn<void(QPainter&)> drawPattern,
|
||||
const std::vector<QColor> &bg,
|
||||
int rotation,
|
||||
float64 opacity) {
|
||||
int gradientRotation,
|
||||
float64 patternOpacity,
|
||||
Fn<void(QPainter&)> drawPattern) {
|
||||
auto result = QImage(size, QImage::Format_ARGB32_Premultiplied);
|
||||
if (bg.size() < 2) {
|
||||
result.fill(bg.empty() ? DefaultBackgroundColor() : bg.front());
|
||||
} 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;
|
||||
}
|
||||
|
@ -782,11 +787,16 @@ QImage PreparePatternImage(
|
|||
QImage PreparePatternImage(
|
||||
QImage pattern,
|
||||
const std::vector<QColor> &bg,
|
||||
int rotation,
|
||||
float64 opacity) {
|
||||
auto result = PreparePatternImage(pattern.size(), [&](QPainter &p) {
|
||||
p.drawImage(QRect(QPoint(), pattern.size()), pattern);
|
||||
}, bg, rotation, opacity);
|
||||
int gradientRotation,
|
||||
float64 patternOpacity) {
|
||||
auto result = GenerateWallPaper(
|
||||
pattern.size(),
|
||||
bg,
|
||||
gradientRotation,
|
||||
patternOpacity,
|
||||
[&](QPainter &p) {
|
||||
p.drawImage(QRect(QPoint(), pattern.size()), pattern);
|
||||
});
|
||||
|
||||
pattern = QImage();
|
||||
return result;
|
||||
|
|
|
@ -122,17 +122,17 @@ private:
|
|||
[[nodiscard]] bool IsDefaultWallPaper(const WallPaper &paper);
|
||||
[[nodiscard]] bool IsCloudWallPaper(const WallPaper &paper);
|
||||
|
||||
[[nodiscard]] QImage PreparePatternImage(
|
||||
[[nodiscard]] QImage GenerateWallPaper(
|
||||
QSize size,
|
||||
Fn<void(QPainter&)> drawPattern,
|
||||
const std::vector<QColor> &bg,
|
||||
int rotation,
|
||||
float64 opacity);
|
||||
int gradientRotation,
|
||||
float64 patternOpacity = 1.,
|
||||
Fn<void(QPainter&)> drawPattern = nullptr);
|
||||
[[nodiscard]] QImage PreparePatternImage(
|
||||
QImage pattern,
|
||||
const std::vector<QColor> &bg,
|
||||
int rotation,
|
||||
float64 opacity);
|
||||
int gradientRotation,
|
||||
float64 patternOpacity);
|
||||
[[nodiscard]] QImage PrepareBlurredBackground(QImage image);
|
||||
[[nodiscard]] QImage GenerateDitheredGradient(
|
||||
const std::vector<QColor> &colors,
|
||||
|
|
|
@ -436,77 +436,6 @@ bool InitializeFromSaved(Saved &&saved) {
|
|||
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(
|
||||
QImage image,
|
||||
const Data::WallPaper &paper) {
|
||||
|
@ -517,7 +446,7 @@ bool InitializeFromSaved(Saved &&saved) {
|
|||
image.setDevicePixelRatio(cRetinaFactor());
|
||||
if (Data::IsDefaultWallPaper(paper)
|
||||
|| Data::details::IsTestingDefaultWallPaper(paper)) {
|
||||
return DitherImage(std::move(image));
|
||||
return Images::DitherImage(std::move(image));
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
|
|
@ -993,13 +993,13 @@ void MainMenu::refreshBackground() {
|
|||
QRect to, from;
|
||||
Window::Theme::ComputeBackgroundRects(fill, pixmap.size(), to, from);
|
||||
|
||||
auto backgroundImage = paper.isPattern()
|
||||
? Data::PreparePatternImage(
|
||||
auto backgroundImage = !paper.backgroundColors().empty()
|
||||
? Data::GenerateWallPaper(
|
||||
fill.size() * cIntRetinaFactor(),
|
||||
[&](QPainter &p) { p.drawPixmap(to, pixmap, from); },
|
||||
paper.backgroundColors(),
|
||||
paper.gradientRotation(),
|
||||
paper.patternOpacity())
|
||||
paper.patternOpacity(),
|
||||
[&](QPainter &p) { p.drawPixmap(to, pixmap, from); })
|
||||
: QImage(
|
||||
fill.size() * cIntRetinaFactor(),
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 40f0e3c6d43a02c20a5cb189ead8559c97bbbd9b
|
||||
Subproject commit 3d5fcdb7ddab336ee2fadc3ceeced420e2c1f504
|
Loading…
Add table
Reference in a new issue