mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Start support of linear gradient wallpapers.
This commit is contained in:
parent
1fd28d5cfb
commit
c2b1187948
14 changed files with 379 additions and 227 deletions
|
@ -336,13 +336,11 @@ void BackgroundBox::Inner::validatePaperThumbnail(
|
||||||
: paper.dataMedia->thumbnail();
|
: paper.dataMedia->thumbnail();
|
||||||
auto original = thumbnail->original();
|
auto original = thumbnail->original();
|
||||||
if (paper.data.isPattern()) {
|
if (paper.data.isPattern()) {
|
||||||
// #TODO themes gradients
|
|
||||||
const auto color = *paper.data.backgroundColor();
|
|
||||||
original = Data::PreparePatternImage(
|
original = Data::PreparePatternImage(
|
||||||
std::move(original),
|
std::move(original),
|
||||||
color,
|
paper.data.backgroundColors(),
|
||||||
Data::PatternColor(color),
|
paper.data.gradientRotation(),
|
||||||
paper.data.patternIntensity());
|
paper.data.patternOpacity());
|
||||||
}
|
}
|
||||||
paper.thumbnail = Ui::PixmapFromImage(TakeMiddleSample(
|
paper.thumbnail = Ui::PixmapFromImage(TakeMiddleSample(
|
||||||
original,
|
original,
|
||||||
|
|
|
@ -379,13 +379,17 @@ QImage ColorizePattern(QImage image, QColor color) {
|
||||||
|
|
||||||
QImage PrepareScaledFromFull(
|
QImage PrepareScaledFromFull(
|
||||||
const QImage &image,
|
const QImage &image,
|
||||||
std::optional<QColor> patternBackground,
|
const std::vector<QColor> &patternBackground,
|
||||||
|
int gradientRotation,
|
||||||
|
float64 patternOpacity,
|
||||||
Images::Option blur = Images::Option(0)) {
|
Images::Option blur = Images::Option(0)) {
|
||||||
auto result = PrepareScaledNonPattern(image, blur);
|
auto result = PrepareScaledNonPattern(image, blur);
|
||||||
if (patternBackground) {
|
if (!patternBackground.empty()) {
|
||||||
result = ColorizePattern(
|
result = Data::PreparePatternImage(
|
||||||
std::move(result),
|
std::move(result),
|
||||||
Data::PatternColor(*patternBackground));
|
patternBackground,
|
||||||
|
gradientRotation,
|
||||||
|
patternOpacity);
|
||||||
}
|
}
|
||||||
return std::move(result).convertToFormat(
|
return std::move(result).convertToFormat(
|
||||||
QImage::Format_ARGB32_Premultiplied);
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
|
@ -433,7 +437,7 @@ void BackgroundPreviewBox::prepare() {
|
||||||
if (_paper.hasShareUrl()) {
|
if (_paper.hasShareUrl()) {
|
||||||
addLeftButton(tr::lng_background_share(), [=] { share(); });
|
addLeftButton(tr::lng_background_share(), [=] { share(); });
|
||||||
}
|
}
|
||||||
updateServiceBg(_paper.backgroundColor());
|
updateServiceBg(_paper.backgroundColors());
|
||||||
|
|
||||||
_paper.loadDocument();
|
_paper.loadDocument();
|
||||||
const auto document = _paper.document();
|
const auto document = _paper.document();
|
||||||
|
@ -669,7 +673,9 @@ bool BackgroundPreviewBox::setScaledFromThumb() {
|
||||||
}
|
}
|
||||||
auto scaled = PrepareScaledFromFull(
|
auto scaled = PrepareScaledFromFull(
|
||||||
thumbnail->original(),
|
thumbnail->original(),
|
||||||
patternBackgroundColor(),
|
patternBackgroundColors(),
|
||||||
|
_paper.gradientRotation(),
|
||||||
|
_paper.patternOpacity(),
|
||||||
_paper.document() ? Images::Option::Blurred : Images::Option(0));
|
_paper.document() ? Images::Option::Blurred : Images::Option(0));
|
||||||
auto blurred = (_paper.document() || _paper.isPattern())
|
auto blurred = (_paper.document() || _paper.isPattern())
|
||||||
? QImage()
|
? QImage()
|
||||||
|
@ -683,7 +689,7 @@ bool BackgroundPreviewBox::setScaledFromThumb() {
|
||||||
void BackgroundPreviewBox::setScaledFromImage(
|
void BackgroundPreviewBox::setScaledFromImage(
|
||||||
QImage &&image,
|
QImage &&image,
|
||||||
QImage &&blurred) {
|
QImage &&blurred) {
|
||||||
updateServiceBg(Window::Theme::CountAverageColor(image));
|
updateServiceBg({ Window::Theme::CountAverageColor(image) });
|
||||||
if (!_full.isNull()) {
|
if (!_full.isNull()) {
|
||||||
startFadeInFrom(std::move(_scaled));
|
startFadeInFrom(std::move(_scaled));
|
||||||
}
|
}
|
||||||
|
@ -710,16 +716,26 @@ void BackgroundPreviewBox::checkBlurAnimationStart() {
|
||||||
startFadeInFrom(_paper.isBlurred() ? _scaled : _blurred);
|
startFadeInFrom(_paper.isBlurred() ? _scaled : _blurred);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundPreviewBox::updateServiceBg(std::optional<QColor> background) {
|
void BackgroundPreviewBox::updateServiceBg(const std::vector<QColor> &bg) {
|
||||||
if (background) {
|
const auto count = int(bg.size());
|
||||||
_serviceBg = Window::Theme::AdjustedColor(
|
if (!count) {
|
||||||
st::msgServiceBg->c,
|
return;
|
||||||
*background);
|
|
||||||
}
|
}
|
||||||
|
auto red = 0, green = 0, blue = 0;
|
||||||
|
for (const auto &color : bg) {
|
||||||
|
red += color.red();
|
||||||
|
green += color.green();
|
||||||
|
blue += color.blue();
|
||||||
|
}
|
||||||
|
_serviceBg = Window::Theme::AdjustedColor(
|
||||||
|
st::msgServiceBg->c,
|
||||||
|
QColor(red / count, green / count, blue / count));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<QColor> BackgroundPreviewBox::patternBackgroundColor() const {
|
std::vector<QColor> BackgroundPreviewBox::patternBackgroundColors() const {
|
||||||
return _paper.isPattern() ? _paper.backgroundColor() : std::nullopt;
|
return _paper.isPattern()
|
||||||
|
? _paper.backgroundColors()
|
||||||
|
: std::vector<QColor>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundPreviewBox::checkLoadedDocument() {
|
void BackgroundPreviewBox::checkLoadedDocument() {
|
||||||
|
@ -737,15 +753,21 @@ void BackgroundPreviewBox::checkLoadedDocument() {
|
||||||
crl::async([
|
crl::async([
|
||||||
this,
|
this,
|
||||||
image = std::move(image),
|
image = std::move(image),
|
||||||
patternBackground = patternBackgroundColor(),
|
patternBackground = patternBackgroundColors(),
|
||||||
|
gradientRotation = _paper.gradientRotation(),
|
||||||
|
patternOpacity = _paper.patternOpacity(),
|
||||||
guard = _generating.make_guard()
|
guard = _generating.make_guard()
|
||||||
]() mutable {
|
]() mutable {
|
||||||
auto scaled = PrepareScaledFromFull(image, patternBackground);
|
auto scaled = PrepareScaledFromFull(
|
||||||
auto blurred = patternBackground
|
image,
|
||||||
? QImage()
|
patternBackground,
|
||||||
: PrepareScaledNonPattern(
|
gradientRotation,
|
||||||
|
patternOpacity);
|
||||||
|
auto blurred = patternBackground.empty()
|
||||||
|
? PrepareScaledNonPattern(
|
||||||
Data::PrepareBlurredBackground(image),
|
Data::PrepareBlurredBackground(image),
|
||||||
Images::Option(0));
|
Images::Option(0))
|
||||||
|
: QImage();
|
||||||
crl::on_main(std::move(guard), [
|
crl::on_main(std::move(guard), [
|
||||||
this,
|
this,
|
||||||
image = std::move(image),
|
image = std::move(image),
|
||||||
|
|
|
@ -59,8 +59,8 @@ private:
|
||||||
void checkLoadedDocument();
|
void checkLoadedDocument();
|
||||||
bool setScaledFromThumb();
|
bool setScaledFromThumb();
|
||||||
void setScaledFromImage(QImage &&image, QImage &&blurred);
|
void setScaledFromImage(QImage &&image, QImage &&blurred);
|
||||||
void updateServiceBg(std::optional<QColor> background);
|
void updateServiceBg(const std::vector<QColor> &bg);
|
||||||
std::optional<QColor> patternBackgroundColor() const;
|
std::vector<QColor> patternBackgroundColors() const;
|
||||||
void paintImage(Painter &p);
|
void paintImage(Painter &p);
|
||||||
void paintRadial(Painter &p);
|
void paintRadial(Painter &p);
|
||||||
void paintTexts(Painter &p, crl::time ms);
|
void paintTexts(Painter &p, crl::time ms);
|
||||||
|
|
|
@ -232,17 +232,20 @@ bool ShowWallPaper(
|
||||||
match->captured(1),
|
match->captured(1),
|
||||||
qthelp::UrlParamNameTransform::ToLower);
|
qthelp::UrlParamNameTransform::ToLower);
|
||||||
const auto bg = params.value("bg_color");
|
const auto bg = params.value("bg_color");
|
||||||
if (!params.value("gradient").isEmpty()
|
const auto color = params.value("color");
|
||||||
|| bg.contains('~')
|
const auto gradient = params.value("gradient");
|
||||||
|| bg.contains('-')) {
|
if (gradient.contains('~') || bg.contains('~')) {
|
||||||
Ui::show(Box<InformBox>(
|
Ui::show(Box<InformBox>(
|
||||||
tr::lng_background_gradient_unsupported(tr::now)));
|
tr::lng_background_gradient_unsupported(tr::now)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto color = params.value("color");
|
|
||||||
return BackgroundPreviewBox::Start(
|
return BackgroundPreviewBox::Start(
|
||||||
controller,
|
controller,
|
||||||
(color.isEmpty() ? params.value(qsl("slug")) : color),
|
(!color.isEmpty()
|
||||||
|
? color
|
||||||
|
: !gradient.isEmpty()
|
||||||
|
? gradient
|
||||||
|
: params.value(qsl("slug"))),
|
||||||
params);
|
params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,7 @@ constexpr auto kVersion = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::vector<QColor> ColorsFromString(const QString &string) {
|
[[nodiscard]] std::vector<QColor> ColorsFromString(const QString &string) {
|
||||||
constexpr auto kMaxColors = 1; // #TODO themes gradients replace to 4
|
constexpr auto kMaxColors = 2; // #TODO themes gradients replace to 4
|
||||||
const auto view = QStringView(string);
|
const auto view = QStringView(string);
|
||||||
const auto count = int(view.size() / 6);
|
const auto count = int(view.size() / 6);
|
||||||
if (!count || count > kMaxColors || view.size() != count * 7 - 1) {
|
if (!count || count > kMaxColors || view.size() != count * 7 - 1) {
|
||||||
|
@ -237,6 +237,14 @@ int WallPaper::patternIntensity() const {
|
||||||
return _intensity;
|
return _intensity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float64 WallPaper::patternOpacity() const {
|
||||||
|
return _intensity / 100.;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WallPaper::gradientRotation() const {
|
||||||
|
return _rotation;
|
||||||
|
}
|
||||||
|
|
||||||
bool WallPaper::hasShareUrl() const {
|
bool WallPaper::hasShareUrl() const {
|
||||||
return !_slug.isEmpty();
|
return !_slug.isEmpty();
|
||||||
}
|
}
|
||||||
|
@ -350,6 +358,8 @@ WallPaper WallPaper::withUrlParams(
|
||||||
result._intensity = intensity;
|
result._intensity = intensity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
result._rotation = params.value("rotation").toInt();
|
||||||
|
result._rotation = (std::clamp(result._rotation, 0, 315) / 45) * 45;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -420,8 +430,7 @@ std::optional<WallPaper> WallPaper::Create(
|
||||||
}
|
}
|
||||||
const auto unsupported = data.vsettings()
|
const auto unsupported = data.vsettings()
|
||||||
&& data.vsettings()->match([&](const MTPDwallPaperSettings &data) {
|
&& data.vsettings()->match([&](const MTPDwallPaperSettings &data) {
|
||||||
return data.vsecond_background_color()
|
return data.vthird_background_color()
|
||||||
|| data.vthird_background_color()
|
|
||||||
|| data.vfourth_background_color(); // #TODO themes gradients
|
|| data.vfourth_background_color(); // #TODO themes gradients
|
||||||
});
|
});
|
||||||
if (unsupported) {
|
if (unsupported) {
|
||||||
|
@ -450,14 +459,16 @@ std::optional<WallPaper> WallPaper::Create(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (result.isPattern() && result.backgroundColors().empty()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<WallPaper> WallPaper::Create(const MTPDwallPaperNoFile &data) {
|
std::optional<WallPaper> WallPaper::Create(const MTPDwallPaperNoFile &data) {
|
||||||
const auto unsupported = data.vsettings()
|
const auto unsupported = data.vsettings()
|
||||||
&& data.vsettings()->match([&](const MTPDwallPaperSettings &data) {
|
&& data.vsettings()->match([&](const MTPDwallPaperSettings &data) {
|
||||||
return data.vsecond_background_color()
|
return data.vthird_background_color()
|
||||||
|| data.vthird_background_color()
|
|
||||||
|| data.vfourth_background_color(); // #TODO themes gradients
|
|| data.vfourth_background_color(); // #TODO themes gradients
|
||||||
});
|
});
|
||||||
if (unsupported) {
|
if (unsupported) {
|
||||||
|
@ -477,6 +488,9 @@ std::optional<WallPaper> WallPaper::Create(const MTPDwallPaperNoFile &data) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (result.backgroundColors().empty()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,7 +568,7 @@ std::optional<WallPaper> WallPaper::FromSerialized(
|
||||||
>> blurred
|
>> blurred
|
||||||
>> backgroundColorsCount;
|
>> backgroundColorsCount;
|
||||||
// #TODO themes gradients replace with 4
|
// #TODO themes gradients replace with 4
|
||||||
if (backgroundColorsCount < 0 || backgroundColorsCount > 1) {
|
if (backgroundColorsCount < 0 || backgroundColorsCount > 2) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
backgroundColors.reserve(backgroundColorsCount);
|
backgroundColors.reserve(backgroundColorsCount);
|
||||||
|
@ -610,6 +624,9 @@ std::optional<WallPaper> WallPaper::FromSerialized(
|
||||||
result._backgroundColors = std::move(backgroundColors);
|
result._backgroundColors = std::move(backgroundColors);
|
||||||
result._intensity = intensity;
|
result._intensity = intensity;
|
||||||
result._rotation = rotation;
|
result._rotation = rotation;
|
||||||
|
if (result.isPattern() && result.backgroundColors().empty()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -625,6 +642,9 @@ std::optional<WallPaper> WallPaper::FromLegacySerialized(
|
||||||
if (const auto color = ColorFromString(slug)) {
|
if (const auto color = ColorFromString(slug)) {
|
||||||
result._backgroundColors.push_back(*color);
|
result._backgroundColors.push_back(*color);
|
||||||
}
|
}
|
||||||
|
if (result.isPattern() && result.backgroundColors().empty()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -695,78 +715,69 @@ bool IsCloudWallPaper(const WallPaper &paper) {
|
||||||
&& !details::IsTestingEditorWallPaper(paper);
|
&& !details::IsTestingEditorWallPaper(paper);
|
||||||
}
|
}
|
||||||
|
|
||||||
QColor PatternColor(QColor background) {
|
[[nodiscard]] QImage FillDitheredGradient(
|
||||||
const auto hue = background.hueF();
|
QImage image,
|
||||||
const auto saturation = background.saturationF();
|
const std::vector<QColor> &colors,
|
||||||
const auto value = background.valueF();
|
int rotation) {
|
||||||
return QColor::fromHsvF(
|
Expects(colors.size() > 1);
|
||||||
hue,
|
|
||||||
std::min(1.0, saturation + 0.05 + 0.1 * (1. - saturation)),
|
image.setDevicePixelRatio(1.);
|
||||||
(value > 0.5
|
const auto width = image.width();
|
||||||
? std::max(0., value * 0.65)
|
const auto height = image.height();
|
||||||
: std::max(0., std::min(1., 1. - value * 0.65))),
|
if (!width || !height) {
|
||||||
0.4
|
return image;
|
||||||
).toRgb();
|
}
|
||||||
|
|
||||||
|
auto p = QPainter(&image);
|
||||||
|
const auto [start, finalStop] = [&]() -> std::pair<QPoint, QPoint> {
|
||||||
|
const auto type = std::clamp(rotation, 0, 315) / 45;
|
||||||
|
switch (type) {
|
||||||
|
case 0: return { { 0, 0 }, { 0, height } };
|
||||||
|
case 1: return { { width, 0 }, { 0, height } };
|
||||||
|
case 2: return { { width, 0 }, { 0, 0 } };
|
||||||
|
case 3: return { { width, height }, { 0, 0 } };
|
||||||
|
case 4: return { { 0, height }, { 0, 0 } };
|
||||||
|
case 5: return { { 0, height }, { width, 0 } };
|
||||||
|
case 6: return { { 0, 0 }, { width, 0 } };
|
||||||
|
case 7: return { { 0, 0 }, { width, height } };
|
||||||
|
}
|
||||||
|
Unexpected("Rotation value in GenerateDitheredGradient.");
|
||||||
|
}();
|
||||||
|
auto gradient = QLinearGradient(start, finalStop);
|
||||||
|
gradient.setStops(QGradientStops{
|
||||||
|
{ 0.0, colors[0] },
|
||||||
|
{ 1.0, colors[1] }
|
||||||
|
});
|
||||||
|
p.fillRect(0, 0, width, height, QBrush(std::move(gradient)));
|
||||||
|
p.end();
|
||||||
|
|
||||||
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage PreparePatternImage(
|
QImage PreparePatternImage(
|
||||||
QImage image,
|
QImage image,
|
||||||
QColor bg,
|
const std::vector<QColor> &bg,
|
||||||
QColor fg,
|
int rotation,
|
||||||
int intensity) {
|
float64 opacity) {
|
||||||
if (image.format() != QImage::Format_ARGB32_Premultiplied) {
|
if (image.format() != QImage::Format_ARGB32_Premultiplied) {
|
||||||
image = std::move(image).convertToFormat(
|
image = std::move(image).convertToFormat(
|
||||||
QImage::Format_ARGB32_Premultiplied);
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
}
|
}
|
||||||
// Similar to ColorizePattern.
|
|
||||||
// But here we set bg to all 'alpha=0' pixels and fg to opaque ones.
|
|
||||||
|
|
||||||
const auto width = image.width();
|
auto result = QImage(image.size(), QImage::Format_ARGB32_Premultiplied);
|
||||||
const auto height = image.height();
|
if (bg.size() < 2) {
|
||||||
const auto alpha = anim::interpolate(
|
result.fill(bg.empty() ? QColor(213, 223, 233) : bg.front());
|
||||||
0,
|
} else {
|
||||||
255,
|
result = FillDitheredGradient(std::move(result), bg, rotation);
|
||||||
fg.alphaF() * std::clamp(intensity / 100., 0., 1.));
|
|
||||||
if (!alpha) {
|
|
||||||
image.fill(bg);
|
|
||||||
return image;
|
|
||||||
}
|
}
|
||||||
fg.setAlpha(255);
|
auto p = QPainter(&result);
|
||||||
const auto patternBg = anim::shifted(bg);
|
p.setCompositionMode(QPainter::CompositionMode_SoftLight);
|
||||||
const auto patternFg = anim::shifted(fg);
|
p.setOpacity(opacity);
|
||||||
|
p.drawImage(QRect(QPoint(), image.size()), image);
|
||||||
|
p.end();
|
||||||
|
|
||||||
constexpr auto resultIntsPerPixel = 1;
|
image = QImage();
|
||||||
const auto resultIntsPerLine = (image.bytesPerLine() >> 2);
|
return result;
|
||||||
const auto resultIntsAdded = resultIntsPerLine - width * resultIntsPerPixel;
|
|
||||||
auto resultInts = reinterpret_cast<uint32*>(image.bits());
|
|
||||||
Assert(resultIntsAdded >= 0);
|
|
||||||
Assert(image.depth() == static_cast<int>((resultIntsPerPixel * sizeof(uint32)) << 3));
|
|
||||||
Assert(image.bytesPerLine() == (resultIntsPerLine << 2));
|
|
||||||
|
|
||||||
const auto maskBytesPerPixel = (image.depth() >> 3);
|
|
||||||
const auto maskBytesPerLine = image.bytesPerLine();
|
|
||||||
const auto maskBytesAdded = maskBytesPerLine - width * maskBytesPerPixel;
|
|
||||||
|
|
||||||
// We want to read the last byte of four available.
|
|
||||||
// This is the difference with style::colorizeImage.
|
|
||||||
auto maskBytes = image.constBits() + (maskBytesPerPixel - 1);
|
|
||||||
Assert(maskBytesAdded >= 0);
|
|
||||||
Assert(image.depth() == (maskBytesPerPixel << 3));
|
|
||||||
for (auto y = 0; y != height; ++y) {
|
|
||||||
for (auto x = 0; x != width; ++x) {
|
|
||||||
const auto maskOpacity = static_cast<anim::ShiftedMultiplier>(
|
|
||||||
*maskBytes) + 1;
|
|
||||||
const auto fgOpacity = (maskOpacity * alpha) >> 8;
|
|
||||||
const auto bgOpacity = 256 - fgOpacity;
|
|
||||||
*resultInts = anim::unshifted(
|
|
||||||
patternBg * bgOpacity + patternFg * fgOpacity);
|
|
||||||
maskBytes += maskBytesPerPixel;
|
|
||||||
resultInts += resultIntsPerPixel;
|
|
||||||
}
|
|
||||||
maskBytes += maskBytesAdded;
|
|
||||||
resultInts += resultIntsAdded;
|
|
||||||
}
|
|
||||||
return image;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage PrepareBlurredBackground(QImage image) {
|
QImage PrepareBlurredBackground(QImage image) {
|
||||||
|
@ -782,6 +793,22 @@ QImage PrepareBlurredBackground(QImage image) {
|
||||||
return Images::BlurLargeImage(image, kRadius);
|
return Images::BlurLargeImage(image, kRadius);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QImage GenerateDitheredGradient(
|
||||||
|
const std::vector<QColor> &colors,
|
||||||
|
int rotation) {
|
||||||
|
constexpr auto kSize = 512;
|
||||||
|
return FillDitheredGradient(
|
||||||
|
QImage(kSize, kSize, QImage::Format_ARGB32_Premultiplied),
|
||||||
|
colors,
|
||||||
|
rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage GenerateDitheredGradient(const Data::WallPaper &paper) {
|
||||||
|
return GenerateDitheredGradient(
|
||||||
|
paper.backgroundColors(),
|
||||||
|
paper.gradientRotation());
|
||||||
|
}
|
||||||
|
|
||||||
namespace details {
|
namespace details {
|
||||||
|
|
||||||
WallPaper UninitializedWallPaper() {
|
WallPaper UninitializedWallPaper() {
|
||||||
|
|
|
@ -46,6 +46,8 @@ public:
|
||||||
[[nodiscard]] bool isLocal() const;
|
[[nodiscard]] bool isLocal() const;
|
||||||
[[nodiscard]] bool isBlurred() const;
|
[[nodiscard]] bool isBlurred() const;
|
||||||
[[nodiscard]] int patternIntensity() const;
|
[[nodiscard]] int patternIntensity() const;
|
||||||
|
[[nodiscard]] float64 patternOpacity() const;
|
||||||
|
[[nodiscard]] int gradientRotation() const;
|
||||||
[[nodiscard]] bool hasShareUrl() const;
|
[[nodiscard]] bool hasShareUrl() const;
|
||||||
[[nodiscard]] QString shareUrl(not_null<Main::Session*> session) const;
|
[[nodiscard]] QString shareUrl(not_null<Main::Session*> session) const;
|
||||||
|
|
||||||
|
@ -120,13 +122,16 @@ 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);
|
||||||
|
|
||||||
QColor PatternColor(QColor background);
|
[[nodiscard]] QImage PreparePatternImage(
|
||||||
QImage PreparePatternImage(
|
|
||||||
QImage image,
|
QImage image,
|
||||||
QColor bg,
|
const std::vector<QColor> &bg,
|
||||||
QColor fg,
|
int rotation,
|
||||||
int intensity);
|
float64 opacity);
|
||||||
QImage PrepareBlurredBackground(QImage image);
|
[[nodiscard]] QImage PrepareBlurredBackground(QImage image);
|
||||||
|
[[nodiscard]] QImage GenerateDitheredGradient(
|
||||||
|
const std::vector<QColor> &colors,
|
||||||
|
int rotation);
|
||||||
|
[[nodiscard]] QImage GenerateDitheredGradient(const WallPaper &paper);
|
||||||
|
|
||||||
namespace details {
|
namespace details {
|
||||||
|
|
||||||
|
|
|
@ -59,10 +59,10 @@ void ThemeDocument::fillPatternFieldsFrom(const QString &url) {
|
||||||
const auto params = qthelp::url_parse_params(
|
const auto params = qthelp::url_parse_params(
|
||||||
paramsString,
|
paramsString,
|
||||||
qthelp::UrlParamNameTransform::ToLower);
|
qthelp::UrlParamNameTransform::ToLower);
|
||||||
const auto kDefaultBackground = QColor(213, 223, 233);
|
|
||||||
const auto paper = Data::DefaultWallPaper().withUrlParams(params);
|
const auto paper = Data::DefaultWallPaper().withUrlParams(params);
|
||||||
_intensity = paper.patternIntensity();
|
_background = paper.backgroundColors();
|
||||||
_background = paper.backgroundColor().value_or(kDefaultBackground);
|
_patternOpacity = paper.patternOpacity();
|
||||||
|
_gradientRotation = paper.gradientRotation();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize ThemeDocument::countOptimalSize() {
|
QSize ThemeDocument::countOptimalSize() {
|
||||||
|
@ -262,8 +262,8 @@ void ThemeDocument::prepareThumbnailFrom(
|
||||||
original = Data::PreparePatternImage(
|
original = Data::PreparePatternImage(
|
||||||
std::move(original),
|
std::move(original),
|
||||||
_background,
|
_background,
|
||||||
Data::PatternColor(_background),
|
_gradientRotation,
|
||||||
_intensity);
|
_patternOpacity);
|
||||||
}
|
}
|
||||||
_thumbnail = Ui::PixmapFromImage(std::move(original));
|
_thumbnail = Ui::PixmapFromImage(std::move(original));
|
||||||
_thumbnailGood = good;
|
_thumbnailGood = good;
|
||||||
|
|
|
@ -74,8 +74,9 @@ private:
|
||||||
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
|
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
|
||||||
|
|
||||||
// For wallpaper documents.
|
// For wallpaper documents.
|
||||||
QColor _background;
|
std::vector<QColor> _background;
|
||||||
int _intensity = 0;
|
float64 _patternOpacity = 0.;
|
||||||
|
int _gradientRotation = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -781,24 +781,39 @@ bool MainWidget::selectingPeer() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::cacheBackground() {
|
void MainWidget::cacheBackground() {
|
||||||
if (Window::Theme::Background()->colorForFill()) {
|
const auto background = Window::Theme::Background();
|
||||||
|
if (background->colorForFill()) {
|
||||||
return;
|
return;
|
||||||
} else if (Window::Theme::Background()->tile()) {
|
}
|
||||||
auto &bg = Window::Theme::Background()->pixmapForTiled();
|
const auto gradient = background->gradientForFill();
|
||||||
|
const auto patternOpacity = background->paper().patternOpacity();
|
||||||
auto result = QImage(_willCacheFor.width() * cIntRetinaFactor(), _willCacheFor.height() * cIntRetinaFactor(), QImage::Format_RGB32);
|
const auto &bg = background->pixmap();
|
||||||
|
if (background->tile() || bg.isNull()) {
|
||||||
|
auto result = gradient.isNull()
|
||||||
|
? QImage(
|
||||||
|
_willCacheFor.size() * cIntRetinaFactor(),
|
||||||
|
QImage::Format_ARGB32_Premultiplied)
|
||||||
|
: gradient.scaled(
|
||||||
|
_willCacheFor.size() * cIntRetinaFactor(),
|
||||||
|
Qt::IgnoreAspectRatio,
|
||||||
|
Qt::SmoothTransformation);
|
||||||
result.setDevicePixelRatio(cRetinaFactor());
|
result.setDevicePixelRatio(cRetinaFactor());
|
||||||
{
|
if (!bg.isNull()) {
|
||||||
QPainter p(&result);
|
QPainter p(&result);
|
||||||
auto w = bg.width() / cRetinaFactor();
|
if (!gradient.isNull()) {
|
||||||
auto h = bg.height() / cRetinaFactor();
|
p.setCompositionMode(QPainter::CompositionMode_SoftLight);
|
||||||
|
p.setOpacity(patternOpacity);
|
||||||
|
}
|
||||||
|
const auto &tiled = background->pixmapForTiled();
|
||||||
|
auto w = tiled.width() / cRetinaFactor();
|
||||||
|
auto h = tiled.height() / cRetinaFactor();
|
||||||
auto sx = 0;
|
auto sx = 0;
|
||||||
auto sy = 0;
|
auto sy = 0;
|
||||||
auto cx = qCeil(_willCacheFor.width() / w);
|
auto cx = qCeil(_willCacheFor.width() / w);
|
||||||
auto cy = qCeil(_willCacheFor.height() / h);
|
auto cy = qCeil(_willCacheFor.height() / h);
|
||||||
for (int i = sx; i < cx; ++i) {
|
for (int i = sx; i < cx; ++i) {
|
||||||
for (int j = sy; j < cy; ++j) {
|
for (int j = sy; j < cy; ++j) {
|
||||||
p.drawPixmap(QPointF(i * w, j * h), bg);
|
p.drawPixmap(QPointF(i * w, j * h), tiled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -806,18 +821,30 @@ void MainWidget::cacheBackground() {
|
||||||
_cachedY = 0;
|
_cachedY = 0;
|
||||||
_cachedBackground = Ui::PixmapFromImage(std::move(result));
|
_cachedBackground = Ui::PixmapFromImage(std::move(result));
|
||||||
} else {
|
} else {
|
||||||
auto &bg = Window::Theme::Background()->pixmap();
|
|
||||||
|
|
||||||
QRect to, from;
|
QRect to, from;
|
||||||
Window::Theme::ComputeBackgroundRects(_willCacheFor, bg.size(), to, from);
|
Window::Theme::ComputeBackgroundRects(_willCacheFor, bg.size(), to, from);
|
||||||
|
auto image = bg.toImage().copy(from).scaled(
|
||||||
|
to.width() * cIntRetinaFactor(),
|
||||||
|
to.height() * cIntRetinaFactor(),
|
||||||
|
Qt::IgnoreAspectRatio,
|
||||||
|
Qt::SmoothTransformation);
|
||||||
|
auto result = gradient.isNull()
|
||||||
|
? std::move(image)
|
||||||
|
: gradient.scaled(
|
||||||
|
image.size(),
|
||||||
|
Qt::IgnoreAspectRatio,
|
||||||
|
Qt::SmoothTransformation);
|
||||||
|
result.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
if (!gradient.isNull()) {
|
||||||
|
QPainter p(&result);
|
||||||
|
p.setCompositionMode(QPainter::CompositionMode_SoftLight);
|
||||||
|
p.setOpacity(patternOpacity);
|
||||||
|
p.drawImage(QRect(QPoint(), to.size()), image);
|
||||||
|
}
|
||||||
|
image = QImage();
|
||||||
_cachedX = to.x();
|
_cachedX = to.x();
|
||||||
_cachedY = to.y();
|
_cachedY = to.y();
|
||||||
_cachedBackground = Ui::PixmapFromImage(
|
_cachedBackground = Ui::PixmapFromImage(std::move(result));
|
||||||
bg.toImage().copy(from).scaled(
|
|
||||||
to.width() * cIntRetinaFactor(),
|
|
||||||
to.height() * cIntRetinaFactor(),
|
|
||||||
Qt::IgnoreAspectRatio,
|
|
||||||
Qt::SmoothTransformation));
|
|
||||||
_cachedBackground.setDevicePixelRatio(cRetinaFactor());
|
_cachedBackground.setDevicePixelRatio(cRetinaFactor());
|
||||||
}
|
}
|
||||||
_cachedFor = _willCacheFor;
|
_cachedFor = _willCacheFor;
|
||||||
|
|
|
@ -551,41 +551,39 @@ void BackgroundRow::radialAnimationCallback(crl::time now) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundRow::updateImage() {
|
void BackgroundRow::updateImage() {
|
||||||
int32 size = st::settingsBackgroundThumb * cIntRetinaFactor();
|
const auto size = st::settingsBackgroundThumb;
|
||||||
QImage back(size, size, QImage::Format_ARGB32_Premultiplied);
|
const auto fullsize = size * cIntRetinaFactor();
|
||||||
|
QImage back(fullsize, fullsize, QImage::Format_ARGB32_Premultiplied);
|
||||||
back.setDevicePixelRatio(cRetinaFactor());
|
back.setDevicePixelRatio(cRetinaFactor());
|
||||||
{
|
{
|
||||||
Painter p(&back);
|
Painter p(&back);
|
||||||
PainterHighQualityEnabler hq(p);
|
PainterHighQualityEnabler hq(p);
|
||||||
|
|
||||||
if (const auto color = Window::Theme::Background()->colorForFill()) {
|
const auto background = Window::Theme::Background();
|
||||||
p.fillRect(
|
if (const auto color = background->colorForFill()) {
|
||||||
0,
|
p.fillRect(0, 0, size, size, *color);
|
||||||
0,
|
|
||||||
st::settingsBackgroundThumb,
|
|
||||||
st::settingsBackgroundThumb,
|
|
||||||
*color);
|
|
||||||
} else {
|
} else {
|
||||||
const auto &pix = Window::Theme::Background()->pixmap();
|
const auto gradient = background->gradientForFill();
|
||||||
const auto sx = (pix.width() > pix.height())
|
const auto patternOpacity = background->paper().patternOpacity();
|
||||||
? ((pix.width() - pix.height()) / 2)
|
if (!gradient.isNull()) {
|
||||||
: 0;
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
const auto sy = (pix.height() > pix.width())
|
p.drawImage(QRect(0, 0, size, size), gradient);
|
||||||
? ((pix.height() - pix.width()) / 2)
|
p.setCompositionMode(QPainter::CompositionMode_SoftLight);
|
||||||
: 0;
|
p.setOpacity(patternOpacity);
|
||||||
const auto s = (pix.width() > pix.height())
|
}
|
||||||
? pix.height()
|
const auto &pix = background->pixmap();
|
||||||
: pix.width();
|
if (!pix.isNull()) {
|
||||||
p.drawPixmap(
|
const auto sx = (pix.width() > pix.height())
|
||||||
0,
|
? ((pix.width() - pix.height()) / 2)
|
||||||
0,
|
: 0;
|
||||||
st::settingsBackgroundThumb,
|
const auto sy = (pix.height() > pix.width())
|
||||||
st::settingsBackgroundThumb,
|
? ((pix.height() - pix.width()) / 2)
|
||||||
pix,
|
: 0;
|
||||||
sx,
|
const auto s = (pix.width() > pix.height())
|
||||||
sy,
|
? pix.height()
|
||||||
s,
|
: pix.width();
|
||||||
s);
|
p.drawPixmap(0, 0, size, size, pix, sx, sy, s, s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Images::prepareRound(back, ImageRoundRadius::Small);
|
Images::prepareRound(back, ImageRoundRadius::Small);
|
||||||
|
|
|
@ -90,8 +90,9 @@ void SectionWidget::PaintBackground(
|
||||||
QRect clip) {
|
QRect clip) {
|
||||||
Painter p(widget);
|
Painter p(widget);
|
||||||
|
|
||||||
|
const auto background = Window::Theme::Background();
|
||||||
auto fill = QRect(0, 0, widget->width(), controller->content()->height());
|
auto fill = QRect(0, 0, widget->width(), controller->content()->height());
|
||||||
if (const auto color = Window::Theme::Background()->colorForFill()) {
|
if (const auto color = background->colorForFill()) {
|
||||||
p.fillRect(fill, *color);
|
p.fillRect(fill, *color);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -99,31 +100,45 @@ void SectionWidget::PaintBackground(
|
||||||
auto x = 0, y = 0;
|
auto x = 0, y = 0;
|
||||||
auto cached = controller->content()->cachedBackground(fill, x, y);
|
auto cached = controller->content()->cachedBackground(fill, x, y);
|
||||||
if (cached.isNull()) {
|
if (cached.isNull()) {
|
||||||
if (Window::Theme::Background()->tile()) {
|
const auto gradient = background->gradientForFill();
|
||||||
auto &pix = Window::Theme::Background()->pixmapForTiled();
|
const auto patternOpacity = background->paper().patternOpacity();
|
||||||
auto left = clip.left();
|
const auto &bg = background->pixmap();
|
||||||
auto top = clip.top();
|
if (background->tile() || bg.isNull()) {
|
||||||
auto right = clip.left() + clip.width();
|
if (!gradient.isNull()) {
|
||||||
auto bottom = clip.top() + clip.height();
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
auto w = pix.width() / cRetinaFactor();
|
p.drawImage(fill, gradient);
|
||||||
auto h = pix.height() / cRetinaFactor();
|
p.setCompositionMode(QPainter::CompositionMode_SoftLight);
|
||||||
auto sx = qFloor(left / w);
|
p.setOpacity(patternOpacity);
|
||||||
auto sy = qFloor((top - fromy) / h);
|
}
|
||||||
auto cx = qCeil(right / w);
|
if (!bg.isNull()) {
|
||||||
auto cy = qCeil((bottom - fromy) / h);
|
auto &tiled = background->pixmapForTiled();
|
||||||
for (auto i = sx; i < cx; ++i) {
|
auto left = clip.left();
|
||||||
for (auto j = sy; j < cy; ++j) {
|
auto top = clip.top();
|
||||||
p.drawPixmap(QPointF(i * w, fromy + j * h), pix);
|
auto right = clip.left() + clip.width();
|
||||||
|
auto bottom = clip.top() + clip.height();
|
||||||
|
auto w = tiled.width() / cRetinaFactor();
|
||||||
|
auto h = tiled.height() / cRetinaFactor();
|
||||||
|
auto sx = qFloor(left / w);
|
||||||
|
auto sy = qFloor((top - fromy) / h);
|
||||||
|
auto cx = qCeil(right / w);
|
||||||
|
auto cy = qCeil((bottom - fromy) / h);
|
||||||
|
for (auto i = sx; i < cx; ++i) {
|
||||||
|
for (auto j = sy; j < cy; ++j) {
|
||||||
|
p.drawPixmap(QPointF(i * w, fromy + j * h), tiled);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PainterHighQualityEnabler hq(p);
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
|
|
||||||
auto &pix = Window::Theme::Background()->pixmap();
|
|
||||||
QRect to, from;
|
QRect to, from;
|
||||||
Window::Theme::ComputeBackgroundRects(fill, pix.size(), to, from);
|
Window::Theme::ComputeBackgroundRects(fill, bg.size(), to, from);
|
||||||
|
if (!gradient.isNull()) {
|
||||||
|
p.drawImage(to, gradient);
|
||||||
|
p.setCompositionMode(QPainter::CompositionMode_SoftLight);
|
||||||
|
p.setOpacity(patternOpacity);
|
||||||
|
}
|
||||||
to.moveTop(to.top() + fromy);
|
to.moveTop(to.top() + fromy);
|
||||||
p.drawPixmap(to, pix, from);
|
p.drawPixmap(to, bg, from);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
p.drawPixmap(x, fromy + y, cached);
|
p.drawPixmap(x, fromy + y, cached);
|
||||||
|
|
|
@ -58,18 +58,23 @@ inline bool AreTestingTheme() {
|
||||||
return !GlobalApplying.paletteForRevert.isEmpty();
|
return !GlobalApplying.paletteForRevert.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CalculateIsMonoColorImage(const QImage &image) {
|
std::optional<QColor> CalculateImageMonoColor(const QImage &image) {
|
||||||
if (!image.isNull()) {
|
if (image.isNull()) {
|
||||||
const auto bits = reinterpret_cast<const uint32*>(image.constBits());
|
return std::nullopt;
|
||||||
const auto first = bits[0];
|
|
||||||
for (auto i = 0; i < image.width() * image.height(); i++) {
|
|
||||||
if (first != bits[i]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
const auto bits = reinterpret_cast<const uint32*>(image.constBits());
|
||||||
|
const auto first = bits[0];
|
||||||
|
for (auto i = 0; i < image.width() * image.height(); i++) {
|
||||||
|
if (first != bits[i]) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return image.pixelColor(QPoint());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool GoodImageFormatAndSize(const QImage &image) {
|
||||||
|
return (image.format() == QImage::Format_ARGB32_Premultiplied)
|
||||||
|
&& !image.size().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray readThemeContent(const QString &path) {
|
QByteArray readThemeContent(const QString &path) {
|
||||||
|
@ -731,7 +736,7 @@ void ChatBackground::set(const Data::WallPaper &paper, QImage image) {
|
||||||
}
|
}
|
||||||
if (Data::IsThemeWallPaper(_paper)) {
|
if (Data::IsThemeWallPaper(_paper)) {
|
||||||
(nightMode() ? _tileNightValue : _tileDayValue) = _themeTile;
|
(nightMode() ? _tileNightValue : _tileDayValue) = _themeTile;
|
||||||
setPreparedImage(_themeImage, _themeImage);
|
setPrepared(_themeImage, _themeImage, QImage());
|
||||||
} else if (Data::details::IsTestingThemeWallPaper(_paper)
|
} else if (Data::details::IsTestingThemeWallPaper(_paper)
|
||||||
|| Data::details::IsTestingDefaultWallPaper(_paper)
|
|| Data::details::IsTestingDefaultWallPaper(_paper)
|
||||||
|| Data::details::IsTestingEditorWallPaper(_paper)) {
|
|| Data::details::IsTestingEditorWallPaper(_paper)) {
|
||||||
|
@ -741,8 +746,9 @@ void ChatBackground::set(const Data::WallPaper &paper, QImage image) {
|
||||||
setPaper(Data::details::TestingDefaultWallPaper());
|
setPaper(Data::details::TestingDefaultWallPaper());
|
||||||
}
|
}
|
||||||
image = postprocessBackgroundImage(std::move(image));
|
image = postprocessBackgroundImage(std::move(image));
|
||||||
setPreparedImage(image, image);
|
setPrepared(image, image, QImage());
|
||||||
} else {
|
} else {
|
||||||
|
const auto &bgColors = _paper.backgroundColors();
|
||||||
if (Data::IsLegacy1DefaultWallPaper(_paper)) {
|
if (Data::IsLegacy1DefaultWallPaper(_paper)) {
|
||||||
image.load(qsl(":/gui/art/bg_initial.jpg"));
|
image.load(qsl(":/gui/art/bg_initial.jpg"));
|
||||||
const auto scale = cScale() * cIntRetinaFactor();
|
const auto scale = cScale() * cIntRetinaFactor();
|
||||||
|
@ -752,7 +758,7 @@ void ChatBackground::set(const Data::WallPaper &paper, QImage image) {
|
||||||
Qt::SmoothTransformation);
|
Qt::SmoothTransformation);
|
||||||
}
|
}
|
||||||
} else if (Data::IsDefaultWallPaper(_paper)
|
} else if (Data::IsDefaultWallPaper(_paper)
|
||||||
|| (_paper.backgroundColors().empty() && image.isNull())) {
|
|| (bgColors.empty() && image.isNull())) {
|
||||||
setPaper(Data::DefaultWallPaper().withParamsFrom(_paper));
|
setPaper(Data::DefaultWallPaper().withParamsFrom(_paper));
|
||||||
image.load(qsl(":/gui/art/background.jpg"));
|
image.load(qsl(":/gui/art/background.jpg"));
|
||||||
}
|
}
|
||||||
|
@ -762,29 +768,38 @@ void ChatBackground::set(const Data::WallPaper &paper, QImage image) {
|
||||||
|| Data::IsLegacy1DefaultWallPaper(_paper))
|
|| Data::IsLegacy1DefaultWallPaper(_paper))
|
||||||
? QImage()
|
? QImage()
|
||||||
: image));
|
: image));
|
||||||
if (const auto fill = _paper.backgroundColor()) {
|
if (_paper.isPattern() && !image.isNull()) {
|
||||||
if (_paper.isPattern() && !image.isNull()) {
|
if (bgColors.size() < 2) {
|
||||||
auto prepared = postprocessBackgroundImage(
|
auto prepared = postprocessBackgroundImage(
|
||||||
Data::PreparePatternImage(
|
Data::PreparePatternImage(
|
||||||
image,
|
image,
|
||||||
*fill,
|
bgColors,
|
||||||
Data::PatternColor(*fill),
|
_paper.gradientRotation(),
|
||||||
_paper.patternIntensity()));
|
_paper.patternOpacity()));
|
||||||
setPreparedImage(std::move(image), std::move(prepared));
|
setPrepared(
|
||||||
|
std::move(image),
|
||||||
|
std::move(prepared),
|
||||||
|
QImage());
|
||||||
} else {
|
} else {
|
||||||
_original = QImage();
|
setPrepared(
|
||||||
_pixmap = QPixmap();
|
image,
|
||||||
_pixmapForTiled = QPixmap();
|
image,
|
||||||
if (adjustPaletteRequired()) {
|
Data::GenerateDitheredGradient(_paper));
|
||||||
adjustPaletteUsingColor(*fill);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else if (bgColors.size() == 1) {
|
||||||
|
setPrepared(QImage(), QImage(), QImage());
|
||||||
|
} else if (!bgColors.empty()) {
|
||||||
|
setPrepared(
|
||||||
|
QImage(),
|
||||||
|
QImage(),
|
||||||
|
Data::GenerateDitheredGradient(_paper));
|
||||||
} else {
|
} else {
|
||||||
image = postprocessBackgroundImage(std::move(image));
|
image = postprocessBackgroundImage(std::move(image));
|
||||||
setPreparedImage(image, image);
|
setPrepared(image, image, QImage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Assert(colorForFill()
|
Assert(colorForFill()
|
||||||
|
|| !_gradient.isNull()
|
||||||
|| (!_original.isNull()
|
|| (!_original.isNull()
|
||||||
&& !_pixmap.isNull()
|
&& !_pixmap.isNull()
|
||||||
&& !_pixmapForTiled.isNull()));
|
&& !_pixmapForTiled.isNull()));
|
||||||
|
@ -797,27 +812,37 @@ void ChatBackground::set(const Data::WallPaper &paper, QImage image) {
|
||||||
checkUploadWallPaper();
|
checkUploadWallPaper();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatBackground::setPreparedImage(QImage original, QImage prepared) {
|
void ChatBackground::setPrepared(
|
||||||
Expects(original.format() == QImage::Format_ARGB32_Premultiplied);
|
QImage original,
|
||||||
Expects(original.width() > 0 && original.height() > 0);
|
QImage prepared,
|
||||||
Expects(prepared.format() == QImage::Format_ARGB32_Premultiplied);
|
QImage gradient) {
|
||||||
Expects(prepared.width() > 0 && prepared.height() > 0);
|
Expects(original.isNull() || GoodImageFormatAndSize(original));
|
||||||
|
Expects(prepared.isNull() || GoodImageFormatAndSize(prepared));
|
||||||
|
Expects(gradient.isNull() || GoodImageFormatAndSize(gradient));
|
||||||
|
|
||||||
_original = std::move(original);
|
if (!prepared.isNull() && !_paper.isPattern() && _paper.isBlurred()) {
|
||||||
if (!_paper.isPattern() && _paper.isBlurred()) {
|
|
||||||
prepared = Data::PrepareBlurredBackground(std::move(prepared));
|
prepared = Data::PrepareBlurredBackground(std::move(prepared));
|
||||||
}
|
}
|
||||||
if (adjustPaletteRequired()) {
|
if (adjustPaletteRequired()) {
|
||||||
adjustPaletteUsingBackground(prepared);
|
if (!gradient.isNull()) {
|
||||||
|
adjustPaletteUsingBackground(gradient);
|
||||||
|
} else if (!prepared.isNull()) {
|
||||||
|
adjustPaletteUsingBackground(prepared);
|
||||||
|
} else if (!_paper.backgroundColors().empty()) {
|
||||||
|
adjustPaletteUsingColor(_paper.backgroundColors().front());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_original = std::move(original);
|
||||||
|
_gradient = std::move(gradient);
|
||||||
preparePixmaps(std::move(prepared));
|
preparePixmaps(std::move(prepared));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatBackground::preparePixmaps(QImage image) {
|
void ChatBackground::preparePixmaps(QImage image) {
|
||||||
const auto width = image.width();
|
const auto width = image.width();
|
||||||
const auto height = image.height();
|
const auto height = image.height();
|
||||||
const auto isSmallForTiled = (width < kMinimumTiledSize)
|
const auto isSmallForTiled = (width > 0 && height > 0)
|
||||||
|| (height < kMinimumTiledSize);
|
&& (width < kMinimumTiledSize || height < kMinimumTiledSize);
|
||||||
if (isSmallForTiled) {
|
if (isSmallForTiled) {
|
||||||
const auto repeatTimesX = qCeil(kMinimumTiledSize / (1. * width));
|
const auto repeatTimesX = qCeil(kMinimumTiledSize / (1. * width));
|
||||||
const auto repeatTimesY = qCeil(kMinimumTiledSize / (1. * height));
|
const auto repeatTimesY = qCeil(kMinimumTiledSize / (1. * height));
|
||||||
|
@ -841,8 +866,12 @@ void ChatBackground::preparePixmaps(QImage image) {
|
||||||
}
|
}
|
||||||
_pixmapForTiled = Ui::PixmapFromImage(std::move(imageForTiled));
|
_pixmapForTiled = Ui::PixmapFromImage(std::move(imageForTiled));
|
||||||
}
|
}
|
||||||
_isMonoColorImage = CalculateIsMonoColorImage(image);
|
_imageMonoColor = _gradient.isNull()
|
||||||
_pixmap = Ui::PixmapFromImage(std::move(image));
|
? CalculateImageMonoColor(image)
|
||||||
|
: std::nullopt;
|
||||||
|
_pixmap = image.isNull()
|
||||||
|
? QPixmap()
|
||||||
|
: Ui::PixmapFromImage(std::move(image));
|
||||||
if (!isSmallForTiled) {
|
if (!isSmallForTiled) {
|
||||||
_pixmapForTiled = _pixmap;
|
_pixmapForTiled = _pixmap;
|
||||||
}
|
}
|
||||||
|
@ -910,7 +939,15 @@ void ChatBackground::adjustPaletteUsingColor(QColor color) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<QColor> ChatBackground::colorForFill() const {
|
std::optional<QColor> ChatBackground::colorForFill() const {
|
||||||
return _pixmap.isNull() ? _paper.backgroundColor() : std::nullopt;
|
return !_pixmap.isNull()
|
||||||
|
? imageMonoColor()
|
||||||
|
: !_gradient.isNull()
|
||||||
|
? std::nullopt
|
||||||
|
: _paper.backgroundColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage ChatBackground::gradientForFill() const {
|
||||||
|
return _gradient;
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage ChatBackground::createCurrentImage() const {
|
QImage ChatBackground::createCurrentImage() const {
|
||||||
|
@ -921,8 +958,24 @@ QImage ChatBackground::createCurrentImage() const {
|
||||||
QImage::Format_ARGB32_Premultiplied);
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
result.fill(*fill);
|
result.fill(*fill);
|
||||||
return result;
|
return result;
|
||||||
|
} else if (_gradient.isNull()) {
|
||||||
|
return pixmap().toImage();
|
||||||
|
} else if (pixmap().isNull()) {
|
||||||
|
return _gradient;
|
||||||
}
|
}
|
||||||
return pixmap().toImage();
|
const auto &pattern = pixmap();
|
||||||
|
auto result = _gradient.scaled(
|
||||||
|
pattern.size(),
|
||||||
|
Qt::IgnoreAspectRatio,
|
||||||
|
Qt::SmoothTransformation);
|
||||||
|
result.setDevicePixelRatio(1.);
|
||||||
|
{
|
||||||
|
auto p = QPainter(&result);
|
||||||
|
p.setCompositionMode(QPainter::CompositionMode_SoftLight);
|
||||||
|
p.setOpacity(paper().patternOpacity());
|
||||||
|
p.drawPixmap(QRect(QPoint(), pattern.size()), pattern);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChatBackground::tile() const {
|
bool ChatBackground::tile() const {
|
||||||
|
@ -949,8 +1002,8 @@ bool ChatBackground::tileNight() const {
|
||||||
return _tileNightValue;
|
return _tileNightValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChatBackground::isMonoColorImage() const {
|
std::optional<QColor> ChatBackground::imageMonoColor() const {
|
||||||
return _isMonoColorImage;
|
return _imageMonoColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatBackground::setTile(bool tile) {
|
void ChatBackground::setTile(bool tile) {
|
||||||
|
|
|
@ -164,7 +164,7 @@ public:
|
||||||
void appliedEditedPalette();
|
void appliedEditedPalette();
|
||||||
void downloadingStarted(bool tile);
|
void downloadingStarted(bool tile);
|
||||||
|
|
||||||
[[nodiscard]] Data::WallPaper paper() const {
|
[[nodiscard]] const Data::WallPaper &paper() const {
|
||||||
return _paper;
|
return _paper;
|
||||||
}
|
}
|
||||||
[[nodiscard]] WallPaperId id() const {
|
[[nodiscard]] WallPaperId id() const {
|
||||||
|
@ -177,11 +177,12 @@ public:
|
||||||
return _pixmapForTiled;
|
return _pixmapForTiled;
|
||||||
}
|
}
|
||||||
[[nodiscard]] std::optional<QColor> colorForFill() const;
|
[[nodiscard]] std::optional<QColor> colorForFill() const;
|
||||||
|
[[nodiscard]] QImage gradientForFill() const;
|
||||||
[[nodiscard]] QImage createCurrentImage() const;
|
[[nodiscard]] QImage createCurrentImage() const;
|
||||||
[[nodiscard]] bool tile() const;
|
[[nodiscard]] bool tile() const;
|
||||||
[[nodiscard]] bool tileDay() const;
|
[[nodiscard]] bool tileDay() const;
|
||||||
[[nodiscard]] bool tileNight() const;
|
[[nodiscard]] bool tileNight() const;
|
||||||
[[nodiscard]] bool isMonoColorImage() const;
|
[[nodiscard]] std::optional<QColor> imageMonoColor() const;
|
||||||
[[nodiscard]] bool nightModeChangeAllowed() const;
|
[[nodiscard]] bool nightModeChangeAllowed() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -195,7 +196,7 @@ private:
|
||||||
[[nodiscard]] bool started() const;
|
[[nodiscard]] bool started() const;
|
||||||
void initialRead();
|
void initialRead();
|
||||||
void saveForRevert();
|
void saveForRevert();
|
||||||
void setPreparedImage(QImage original, QImage prepared);
|
void setPrepared(QImage original, QImage prepared, QImage gradient);
|
||||||
void preparePixmaps(QImage image);
|
void preparePixmaps(QImage image);
|
||||||
void writeNewBackgroundSettings();
|
void writeNewBackgroundSettings();
|
||||||
void setPaper(const Data::WallPaper &paper);
|
void setPaper(const Data::WallPaper &paper);
|
||||||
|
@ -236,6 +237,7 @@ private:
|
||||||
rpl::event_stream<BackgroundUpdate> _updates;
|
rpl::event_stream<BackgroundUpdate> _updates;
|
||||||
Data::WallPaper _paper = Data::details::UninitializedWallPaper();
|
Data::WallPaper _paper = Data::details::UninitializedWallPaper();
|
||||||
std::optional<QColor> _paperColor;
|
std::optional<QColor> _paperColor;
|
||||||
|
QImage _gradient;
|
||||||
QImage _original;
|
QImage _original;
|
||||||
QPixmap _pixmap;
|
QPixmap _pixmap;
|
||||||
QPixmap _pixmapForTiled;
|
QPixmap _pixmapForTiled;
|
||||||
|
@ -245,7 +247,7 @@ private:
|
||||||
std::optional<bool> _localStoredTileDayValue;
|
std::optional<bool> _localStoredTileDayValue;
|
||||||
std::optional<bool> _localStoredTileNightValue;
|
std::optional<bool> _localStoredTileNightValue;
|
||||||
|
|
||||||
bool _isMonoColorImage = false;
|
std::optional<QColor> _imageMonoColor;
|
||||||
|
|
||||||
Object _themeObject;
|
Object _themeObject;
|
||||||
QImage _themeImage;
|
QImage _themeImage;
|
||||||
|
|
|
@ -87,9 +87,10 @@ constexpr auto kMinDiffIntensity = 0.25;
|
||||||
|
|
||||||
[[nodiscard]] bool IsFilledCover() {
|
[[nodiscard]] bool IsFilledCover() {
|
||||||
const auto background = Window::Theme::Background();
|
const auto background = Window::Theme::Background();
|
||||||
|
return false; AssertIsDebug();
|
||||||
return background->tile()
|
return background->tile()
|
||||||
|| background->colorForFill().has_value()
|
|| background->colorForFill().has_value()
|
||||||
|| background->isMonoColorImage()
|
|| !background->gradientForFill().isNull()
|
||||||
|| background->paper().isPattern()
|
|| background->paper().isPattern()
|
||||||
|| Data::IsLegacy1DefaultWallPaper(background->paper());
|
|| Data::IsLegacy1DefaultWallPaper(background->paper());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue