mirror of
https://github.com/Qz3rK/tdesktop.git
synced 2026-07-03 14:15:08 +02:00
Start support of linear gradient wallpapers.
This commit is contained in:
@@ -90,8 +90,9 @@ void SectionWidget::PaintBackground(
|
||||
QRect clip) {
|
||||
Painter p(widget);
|
||||
|
||||
const auto background = Window::Theme::Background();
|
||||
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);
|
||||
return;
|
||||
}
|
||||
@@ -99,31 +100,45 @@ void SectionWidget::PaintBackground(
|
||||
auto x = 0, y = 0;
|
||||
auto cached = controller->content()->cachedBackground(fill, x, y);
|
||||
if (cached.isNull()) {
|
||||
if (Window::Theme::Background()->tile()) {
|
||||
auto &pix = Window::Theme::Background()->pixmapForTiled();
|
||||
auto left = clip.left();
|
||||
auto top = clip.top();
|
||||
auto right = clip.left() + clip.width();
|
||||
auto bottom = clip.top() + clip.height();
|
||||
auto w = pix.width() / cRetinaFactor();
|
||||
auto h = pix.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), pix);
|
||||
const auto gradient = background->gradientForFill();
|
||||
const auto patternOpacity = background->paper().patternOpacity();
|
||||
const auto &bg = background->pixmap();
|
||||
if (background->tile() || bg.isNull()) {
|
||||
if (!gradient.isNull()) {
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
p.drawImage(fill, gradient);
|
||||
p.setCompositionMode(QPainter::CompositionMode_SoftLight);
|
||||
p.setOpacity(patternOpacity);
|
||||
}
|
||||
if (!bg.isNull()) {
|
||||
auto &tiled = background->pixmapForTiled();
|
||||
auto left = clip.left();
|
||||
auto top = clip.top();
|
||||
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 {
|
||||
PainterHighQualityEnabler hq(p);
|
||||
|
||||
auto &pix = Window::Theme::Background()->pixmap();
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
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);
|
||||
p.drawPixmap(to, pix, from);
|
||||
p.drawPixmap(to, bg, from);
|
||||
}
|
||||
} else {
|
||||
p.drawPixmap(x, fromy + y, cached);
|
||||
|
||||
@@ -58,18 +58,23 @@ inline bool AreTestingTheme() {
|
||||
return !GlobalApplying.paletteForRevert.isEmpty();
|
||||
}
|
||||
|
||||
bool CalculateIsMonoColorImage(const QImage &image) {
|
||||
if (!image.isNull()) {
|
||||
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 false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
std::optional<QColor> CalculateImageMonoColor(const QImage &image) {
|
||||
if (image.isNull()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
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) {
|
||||
@@ -731,7 +736,7 @@ void ChatBackground::set(const Data::WallPaper &paper, QImage image) {
|
||||
}
|
||||
if (Data::IsThemeWallPaper(_paper)) {
|
||||
(nightMode() ? _tileNightValue : _tileDayValue) = _themeTile;
|
||||
setPreparedImage(_themeImage, _themeImage);
|
||||
setPrepared(_themeImage, _themeImage, QImage());
|
||||
} else if (Data::details::IsTestingThemeWallPaper(_paper)
|
||||
|| Data::details::IsTestingDefaultWallPaper(_paper)
|
||||
|| Data::details::IsTestingEditorWallPaper(_paper)) {
|
||||
@@ -741,8 +746,9 @@ void ChatBackground::set(const Data::WallPaper &paper, QImage image) {
|
||||
setPaper(Data::details::TestingDefaultWallPaper());
|
||||
}
|
||||
image = postprocessBackgroundImage(std::move(image));
|
||||
setPreparedImage(image, image);
|
||||
setPrepared(image, image, QImage());
|
||||
} else {
|
||||
const auto &bgColors = _paper.backgroundColors();
|
||||
if (Data::IsLegacy1DefaultWallPaper(_paper)) {
|
||||
image.load(qsl(":/gui/art/bg_initial.jpg"));
|
||||
const auto scale = cScale() * cIntRetinaFactor();
|
||||
@@ -752,7 +758,7 @@ void ChatBackground::set(const Data::WallPaper &paper, QImage image) {
|
||||
Qt::SmoothTransformation);
|
||||
}
|
||||
} else if (Data::IsDefaultWallPaper(_paper)
|
||||
|| (_paper.backgroundColors().empty() && image.isNull())) {
|
||||
|| (bgColors.empty() && image.isNull())) {
|
||||
setPaper(Data::DefaultWallPaper().withParamsFrom(_paper));
|
||||
image.load(qsl(":/gui/art/background.jpg"));
|
||||
}
|
||||
@@ -762,29 +768,38 @@ void ChatBackground::set(const Data::WallPaper &paper, QImage image) {
|
||||
|| Data::IsLegacy1DefaultWallPaper(_paper))
|
||||
? QImage()
|
||||
: image));
|
||||
if (const auto fill = _paper.backgroundColor()) {
|
||||
if (_paper.isPattern() && !image.isNull()) {
|
||||
if (_paper.isPattern() && !image.isNull()) {
|
||||
if (bgColors.size() < 2) {
|
||||
auto prepared = postprocessBackgroundImage(
|
||||
Data::PreparePatternImage(
|
||||
image,
|
||||
*fill,
|
||||
Data::PatternColor(*fill),
|
||||
_paper.patternIntensity()));
|
||||
setPreparedImage(std::move(image), std::move(prepared));
|
||||
bgColors,
|
||||
_paper.gradientRotation(),
|
||||
_paper.patternOpacity()));
|
||||
setPrepared(
|
||||
std::move(image),
|
||||
std::move(prepared),
|
||||
QImage());
|
||||
} else {
|
||||
_original = QImage();
|
||||
_pixmap = QPixmap();
|
||||
_pixmapForTiled = QPixmap();
|
||||
if (adjustPaletteRequired()) {
|
||||
adjustPaletteUsingColor(*fill);
|
||||
}
|
||||
setPrepared(
|
||||
image,
|
||||
image,
|
||||
Data::GenerateDitheredGradient(_paper));
|
||||
}
|
||||
} else if (bgColors.size() == 1) {
|
||||
setPrepared(QImage(), QImage(), QImage());
|
||||
} else if (!bgColors.empty()) {
|
||||
setPrepared(
|
||||
QImage(),
|
||||
QImage(),
|
||||
Data::GenerateDitheredGradient(_paper));
|
||||
} else {
|
||||
image = postprocessBackgroundImage(std::move(image));
|
||||
setPreparedImage(image, image);
|
||||
setPrepared(image, image, QImage());
|
||||
}
|
||||
}
|
||||
Assert(colorForFill()
|
||||
|| !_gradient.isNull()
|
||||
|| (!_original.isNull()
|
||||
&& !_pixmap.isNull()
|
||||
&& !_pixmapForTiled.isNull()));
|
||||
@@ -797,27 +812,37 @@ void ChatBackground::set(const Data::WallPaper &paper, QImage image) {
|
||||
checkUploadWallPaper();
|
||||
}
|
||||
|
||||
void ChatBackground::setPreparedImage(QImage original, QImage prepared) {
|
||||
Expects(original.format() == QImage::Format_ARGB32_Premultiplied);
|
||||
Expects(original.width() > 0 && original.height() > 0);
|
||||
Expects(prepared.format() == QImage::Format_ARGB32_Premultiplied);
|
||||
Expects(prepared.width() > 0 && prepared.height() > 0);
|
||||
void ChatBackground::setPrepared(
|
||||
QImage original,
|
||||
QImage prepared,
|
||||
QImage gradient) {
|
||||
Expects(original.isNull() || GoodImageFormatAndSize(original));
|
||||
Expects(prepared.isNull() || GoodImageFormatAndSize(prepared));
|
||||
Expects(gradient.isNull() || GoodImageFormatAndSize(gradient));
|
||||
|
||||
_original = std::move(original);
|
||||
if (!_paper.isPattern() && _paper.isBlurred()) {
|
||||
if (!prepared.isNull() && !_paper.isPattern() && _paper.isBlurred()) {
|
||||
prepared = Data::PrepareBlurredBackground(std::move(prepared));
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
void ChatBackground::preparePixmaps(QImage image) {
|
||||
const auto width = image.width();
|
||||
const auto height = image.height();
|
||||
const auto isSmallForTiled = (width < kMinimumTiledSize)
|
||||
|| (height < kMinimumTiledSize);
|
||||
const auto isSmallForTiled = (width > 0 && height > 0)
|
||||
&& (width < kMinimumTiledSize || height < kMinimumTiledSize);
|
||||
if (isSmallForTiled) {
|
||||
const auto repeatTimesX = qCeil(kMinimumTiledSize / (1. * width));
|
||||
const auto repeatTimesY = qCeil(kMinimumTiledSize / (1. * height));
|
||||
@@ -841,8 +866,12 @@ void ChatBackground::preparePixmaps(QImage image) {
|
||||
}
|
||||
_pixmapForTiled = Ui::PixmapFromImage(std::move(imageForTiled));
|
||||
}
|
||||
_isMonoColorImage = CalculateIsMonoColorImage(image);
|
||||
_pixmap = Ui::PixmapFromImage(std::move(image));
|
||||
_imageMonoColor = _gradient.isNull()
|
||||
? CalculateImageMonoColor(image)
|
||||
: std::nullopt;
|
||||
_pixmap = image.isNull()
|
||||
? QPixmap()
|
||||
: Ui::PixmapFromImage(std::move(image));
|
||||
if (!isSmallForTiled) {
|
||||
_pixmapForTiled = _pixmap;
|
||||
}
|
||||
@@ -910,7 +939,15 @@ void ChatBackground::adjustPaletteUsingColor(QColor color) {
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -921,8 +958,24 @@ QImage ChatBackground::createCurrentImage() const {
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
result.fill(*fill);
|
||||
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 {
|
||||
@@ -949,8 +1002,8 @@ bool ChatBackground::tileNight() const {
|
||||
return _tileNightValue;
|
||||
}
|
||||
|
||||
bool ChatBackground::isMonoColorImage() const {
|
||||
return _isMonoColorImage;
|
||||
std::optional<QColor> ChatBackground::imageMonoColor() const {
|
||||
return _imageMonoColor;
|
||||
}
|
||||
|
||||
void ChatBackground::setTile(bool tile) {
|
||||
|
||||
@@ -164,7 +164,7 @@ public:
|
||||
void appliedEditedPalette();
|
||||
void downloadingStarted(bool tile);
|
||||
|
||||
[[nodiscard]] Data::WallPaper paper() const {
|
||||
[[nodiscard]] const Data::WallPaper &paper() const {
|
||||
return _paper;
|
||||
}
|
||||
[[nodiscard]] WallPaperId id() const {
|
||||
@@ -177,11 +177,12 @@ public:
|
||||
return _pixmapForTiled;
|
||||
}
|
||||
[[nodiscard]] std::optional<QColor> colorForFill() const;
|
||||
[[nodiscard]] QImage gradientForFill() const;
|
||||
[[nodiscard]] QImage createCurrentImage() const;
|
||||
[[nodiscard]] bool tile() const;
|
||||
[[nodiscard]] bool tileDay() const;
|
||||
[[nodiscard]] bool tileNight() const;
|
||||
[[nodiscard]] bool isMonoColorImage() const;
|
||||
[[nodiscard]] std::optional<QColor> imageMonoColor() const;
|
||||
[[nodiscard]] bool nightModeChangeAllowed() const;
|
||||
|
||||
private:
|
||||
@@ -195,7 +196,7 @@ private:
|
||||
[[nodiscard]] bool started() const;
|
||||
void initialRead();
|
||||
void saveForRevert();
|
||||
void setPreparedImage(QImage original, QImage prepared);
|
||||
void setPrepared(QImage original, QImage prepared, QImage gradient);
|
||||
void preparePixmaps(QImage image);
|
||||
void writeNewBackgroundSettings();
|
||||
void setPaper(const Data::WallPaper &paper);
|
||||
@@ -236,6 +237,7 @@ private:
|
||||
rpl::event_stream<BackgroundUpdate> _updates;
|
||||
Data::WallPaper _paper = Data::details::UninitializedWallPaper();
|
||||
std::optional<QColor> _paperColor;
|
||||
QImage _gradient;
|
||||
QImage _original;
|
||||
QPixmap _pixmap;
|
||||
QPixmap _pixmapForTiled;
|
||||
@@ -245,7 +247,7 @@ private:
|
||||
std::optional<bool> _localStoredTileDayValue;
|
||||
std::optional<bool> _localStoredTileNightValue;
|
||||
|
||||
bool _isMonoColorImage = false;
|
||||
std::optional<QColor> _imageMonoColor;
|
||||
|
||||
Object _themeObject;
|
||||
QImage _themeImage;
|
||||
|
||||
@@ -87,9 +87,10 @@ constexpr auto kMinDiffIntensity = 0.25;
|
||||
|
||||
[[nodiscard]] bool IsFilledCover() {
|
||||
const auto background = Window::Theme::Background();
|
||||
return false; AssertIsDebug();
|
||||
return background->tile()
|
||||
|| background->colorForFill().has_value()
|
||||
|| background->isMonoColorImage()
|
||||
|| !background->gradientForFill().isNull()
|
||||
|| background->paper().isPattern()
|
||||
|| Data::IsLegacy1DefaultWallPaper(background->paper());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user