Support new rounding for albums.

This commit is contained in:
John Preston 2022-10-03 12:41:51 +04:00
parent 8268e9f872
commit 9cab06e17d
10 changed files with 80 additions and 93 deletions

View File

@ -421,13 +421,7 @@ QSize Document::countCurrentSize(int newWidth) {
}
void Document::draw(Painter &p, const PaintContext &context) const {
const auto corners = (isBubbleTop()
? (RectPart::TopLeft | RectPart::TopRight)
: RectParts())
| ((isRoundedInBubbleBottom() && !Has<HistoryDocumentCaptioned>())
? (RectPart::BottomLeft | RectPart::BottomRight)
: RectParts());
draw(p, context, width(), LayoutMode::Full, corners);
draw(p, context, width(), LayoutMode::Full, adjustedBubbleRounding());
}
void Document::draw(
@ -435,7 +429,7 @@ void Document::draw(
const PaintContext &context,
int width,
LayoutMode mode,
RectParts corners) const {
Ui::BubbleRounding outsideRounding) const {
if (width < st::msgPadding.left() + st::msgPadding.right() + 1) return;
ensureDataMediaCreated();
@ -476,7 +470,7 @@ void Document::draw(
const auto inner = QRect(rthumb.x() + (rthumb.width() - innerSize) / 2, rthumb.y() + (rthumb.height() - innerSize) / 2, innerSize, innerSize);
const auto radialOpacity = radial ? _animation->radial.opacity() : 1.;
if (thumbed) {
const auto rounding = thumbRounding(mode, corners);
const auto rounding = thumbRounding(mode, outsideRounding);
validateThumbnail(thumbed, st.thumbSize, rounding);
p.drawImage(rthumb, thumbed->thumbnail);
if (context.selected()) {
@ -703,19 +697,20 @@ void Document::draw(
Ui::BubbleRounding Document::thumbRounding(
LayoutMode mode,
RectParts corners) const {
auto result = bubbleRounding();
Ui::BubbleRounding outsideRounding) const {
using Corner = Ui::BubbleCornerRounding;
if (mode != LayoutMode::Grouped && _parent->media() != this) {
return {}; // In a WebPage preview.
}
const auto adjust = [&](RectPart corner, Corner already) {
return (already == Corner::Large && (corners & corner))
const auto hasCaption = Has<HistoryDocumentCaptioned>();
const auto adjust = [&](Corner already, bool skip = false) {
return (already == Corner::Large && !skip)
? Corner::Large
: Corner::Small;
};
result.topLeft = adjust(RectPart::TopLeft, result.topLeft);
result.bottomLeft = adjust(RectPart::BottomLeft, result.bottomLeft);
auto result = Ui::BubbleRounding();
result.topLeft = adjust(outsideRounding.topLeft);
result.bottomLeft = adjust(outsideRounding.bottomLeft, hasCaption);
result.topRight = result.bottomRight = Corner::Small;
return result;
}
@ -1280,7 +1275,7 @@ void Document::drawGrouped(
const PaintContext &context,
const QRect &geometry,
RectParts sides,
RectParts corners,
Ui::BubbleRounding rounding,
float64 highlightOpacity,
not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const {
@ -1290,7 +1285,7 @@ void Document::drawGrouped(
context.translated(-geometry.topLeft()),
geometry.width(),
LayoutMode::Grouped,
corners);
rounding);
p.translate(-geometry.topLeft());
}

View File

@ -69,7 +69,7 @@ public:
const PaintContext &context,
const QRect &geometry,
RectParts sides,
RectParts corners,
Ui::BubbleRounding rounding,
float64 highlightOpacity,
not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const override;
@ -110,7 +110,7 @@ private:
const PaintContext &context,
int width,
LayoutMode mode,
RectParts corners) const;
Ui::BubbleRounding outsideRounding) const;
[[nodiscard]] TextState textState(
QPoint point,
QSize layout,
@ -128,7 +128,7 @@ private:
[[nodiscard]] Ui::BubbleRounding thumbRounding(
LayoutMode mode,
RectParts corners) const;
Ui::BubbleRounding outsideRounding) const;
void validateThumbnail(
not_null<const HistoryDocumentThumbed*> thumbed,
int size,

View File

@ -281,25 +281,6 @@ void Gif::validateRoundingMask(QSize size) const {
}
}
Images::CornersMaskRef Gif::prepareRoundingRef(
std::optional<Ui::BubbleRounding> rounding) const {
using namespace Ui;
using namespace Images;
if (!rounding) {
return CornersMaskRef(CachedCornersMasks(CachedCornerRadius::Small));
}
auto result = CornersMaskRef();
for (auto i = 0; i != 4; ++i) {
const auto corner = (*rounding)[i];
result.p[i] = (corner == BubbleCornerRounding::Large)
? &CachedCornersMasks(CachedCornerRadius::BubbleLarge)[i]
: (corner == BubbleCornerRounding::Small)
? &CachedCornersMasks(CachedCornerRadius::BubbleSmall)[i]
: nullptr;
}
return result;
}
bool Gif::downloadInCorner() const {
return _data->isVideoFile()
&& (_data->loading() || !autoplayEnabled())
@ -429,7 +410,7 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
validateRoundingMask(request.outer);
request.mask = _roundingMask;
} else {
request.rounding = prepareRoundingRef(rounding);
request.rounding = MediaRoundingMask(rounding);
}
if (!activeRoundPlaying && activeOwnPlaying->instance.playerLocked()) {
if (activeOwnPlaying->frozenFrame.isNull()) {
@ -1020,7 +1001,7 @@ void Gif::drawGrouped(
const PaintContext &context,
const QRect &geometry,
RectParts sides,
RectParts corners,
Ui::BubbleRounding rounding,
float64 highlightOpacity,
not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const {
@ -1081,8 +1062,7 @@ void Gif::drawGrouped(
auto request = ::Media::Streaming::FrameRequest{
.resize = pixSize * cIntRetinaFactor(),
.outer = geometry.size() * cIntRetinaFactor(),
//.radius = roundRadius, // #TODO rounding
//.corners = corners,
.rounding = MediaRoundingMask(rounding),
};
if (activeOwnPlaying->instance.playerLocked()) {
if (activeOwnPlaying->frozenFrame.isNull()) {
@ -1105,7 +1085,7 @@ void Gif::drawGrouped(
}
}
} else {
validateGroupedCache(geometry, corners, cacheKey, cache);
validateGroupedCache(geometry, rounding, cacheKey, cache);
p.drawPixmap(geometry, *cache);
}
@ -1114,11 +1094,10 @@ void Gif::drawGrouped(
: highlightOpacity;
if (overlayOpacity > 0.) {
p.setOpacity(overlayOpacity);
// #TODO rounding
//Ui::FillComplexOverlayRect(p, st, geometry, roundRadius, corners);
//if (!context.selected()) {
// Ui::FillComplexOverlayRect(p, st, geometry, roundRadius, corners);
//}
fillImageOverlay(p, geometry, rounding, context);
if (!context.selected()) {
fillImageOverlay(p, geometry, rounding, context);
}
p.setOpacity(1.);
}
@ -1355,7 +1334,7 @@ bool Gif::isUnwrapped() const {
void Gif::validateGroupedCache(
const QRect &geometry,
RectParts corners,
Ui::BubbleRounding rounding,
not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const {
using Option = Images::Option;
@ -1377,18 +1356,11 @@ void Gif::validateGroupedCache(
const auto loadLevel = good ? 3 : thumb ? 2 : image ? 1 : 0;
const auto width = geometry.width();
const auto height = geometry.height();
const auto corner = [&](RectPart part, Option skip) {
return !(corners & part) ? skip : Option();
};
const auto options = Option::RoundLarge
| (blur ? Option::Blur : Option(0))
| corner(RectPart::TopLeft, Option::RoundSkipTopLeft)
| corner(RectPart::TopRight, Option::RoundSkipTopRight)
| corner(RectPart::BottomLeft, Option::RoundSkipBottomLeft)
| corner(RectPart::BottomRight, Option::RoundSkipBottomRight);
const auto options = (blur ? Option::Blur : Option(0));
const auto key = (uint64(width) << 48)
| (uint64(height) << 32)
| (uint64(options) << 16)
| (uint64(rounding.key()) << 8)
| (uint64(loadLevel));
if (*cacheKey == key) {
return;
@ -1403,9 +1375,14 @@ void Gif::validateGroupedCache(
const auto ratio = style::DevicePixelRatio();
*cacheKey = key;
*cache = (image ? image : Image::BlankMedia().get())->pixNoCache(
auto scaled = Images::Prepare(
(image ? image : Image::BlankMedia().get())->original(),
pixSize * ratio,
{ .options = options, .outer = { width, height } });
auto rounded = Images::Round(
std::move(scaled),
MediaRoundingMask(rounding));
*cache = Ui::PixmapFromImage(std::move(rounded));
}
void Gif::setStatusSize(int64 newSize) const {

View File

@ -76,7 +76,7 @@ public:
const PaintContext &context,
const QRect &geometry,
RectParts sides,
RectParts corners,
Ui::BubbleRounding rounding,
float64 highlightOpacity,
not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const override;
@ -169,7 +169,7 @@ private:
void validateGroupedCache(
const QRect &geometry,
RectParts corners,
Ui::BubbleRounding rounding,
not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const;
void setStatusSize(int64 newSize) const;
@ -177,8 +177,6 @@ private:
[[nodiscard]] QSize sizeForAspectRatio() const;
void validateRoundingMask(QSize size) const;
[[nodiscard]] Images::CornersMaskRef prepareRoundingRef(
std::optional<Ui::BubbleRounding> rounding) const;
[[nodiscard]] bool downloadInCorner() const;
void drawCornerStatus(

View File

@ -189,7 +189,7 @@ public:
const PaintContext &context,
const QRect &geometry,
RectParts sides,
RectParts corners,
Ui::BubbleRounding rounding,
float64 highlightOpacity,
not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const {

View File

@ -245,15 +245,23 @@ void GroupedMedia::refreshParentId(
}
}
RectParts GroupedMedia::cornersFromSides(RectParts sides) const {
Ui::BubbleRounding GroupedMedia::applyRoundingSides(
Ui::BubbleRounding already,
RectParts sides) const {
auto result = Ui::GetCornersFromSides(sides);
if (!isBubbleTop()) {
result &= ~(RectPart::TopLeft | RectPart::TopRight);
if (!(result & RectPart::TopLeft)) {
already.topLeft = Ui::BubbleCornerRounding::None;
}
if (!isRoundedInBubbleBottom() || !_caption.isEmpty()) {
result &= ~(RectPart::BottomLeft | RectPart::BottomRight);
if (!(result & RectPart::TopRight)) {
already.topRight = Ui::BubbleCornerRounding::None;
}
return result;
if (!(result & RectPart::BottomLeft)) {
already.bottomLeft = Ui::BubbleCornerRounding::None;
}
if (!(result & RectPart::BottomRight)) {
already.bottomRight = Ui::BubbleCornerRounding::None;
}
return already;
}
QMargins GroupedMedia::groupedPadding() const {
@ -302,6 +310,11 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const {
const auto textSelection = (_mode == Mode::Column)
&& !fullSelection
&& !IsSubGroupSelection(selection);
const auto inWebPage = (_parent->media() != this);
constexpr auto kSmall = Ui::BubbleCornerRounding::Small;
const auto rounding = inWebPage
? Ui::BubbleRounding{ kSmall, kSmall, kSmall, kSmall }
: adjustedBubbleRoundingWithCaption(_caption);
for (auto i = 0, count = int(_parts.size()); i != count; ++i) {
const auto &part = _parts[i];
const auto partContext = context.withSelection(fullSelection
@ -325,7 +338,7 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const {
partContext,
part.geometry.translated(0, groupPadding.top()),
part.sides,
cornersFromSides(part.sides),
applyRoundingSides(rounding, part.sides),
highlightOpacity,
&part.cacheKey,
&part.cache);

View File

@ -141,7 +141,9 @@ private:
void refreshCaption();
[[nodiscard]] RectParts cornersFromSides(RectParts sides) const;
[[nodiscard]] Ui::BubbleRounding applyRoundingSides(
Ui::BubbleRounding already,
RectParts sides) const;
[[nodiscard]] QMargins groupedPadding() const;
Ui::Text::String _caption;

View File

@ -543,14 +543,14 @@ void Photo::drawGrouped(
const PaintContext &context,
const QRect &geometry,
RectParts sides,
RectParts corners,
Ui::BubbleRounding rounding,
float64 highlightOpacity,
not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const {
ensureDataMediaCreated();
_dataMedia->automaticLoad(_realParent->fullId(), _parent->data());
validateGroupedCache(geometry, corners, cacheKey, cache);
validateGroupedCache(geometry, rounding, cacheKey, cache);
const auto st = context.st;
const auto sti = context.imageStyle();
@ -573,11 +573,10 @@ void Photo::drawGrouped(
if (overlayOpacity > 0.) {
p.setOpacity(overlayOpacity);
const auto roundRadius = ImageRoundRadius::Large;
// #TODO rounding
//Ui::FillComplexOverlayRect(p, st, geometry, roundRadius, corners);
//if (!context.selected()) {
// Ui::FillComplexOverlayRect(p, st, geometry, roundRadius, corners);
//}
fillImageOverlay(p, geometry, rounding, context);
if (!context.selected()) {
fillImageOverlay(p, geometry, rounding, context);
}
p.setOpacity(1.);
}
@ -680,7 +679,7 @@ bool Photo::needInfoDisplay() const {
void Photo::validateGroupedCache(
const QRect &geometry,
RectParts corners,
Ui::BubbleRounding rounding,
not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const {
using Option = Images::Option;
@ -697,18 +696,11 @@ void Photo::validateGroupedCache(
: 0;
const auto width = geometry.width();
const auto height = geometry.height();
const auto corner = [&](RectPart part, Option skip) {
return !(corners & part) ? skip : Option();
};
const auto options = Option::RoundLarge
| (loaded ? Option() : Option::Blur)
| corner(RectPart::TopLeft, Option::RoundSkipTopLeft)
| corner(RectPart::TopRight, Option::RoundSkipTopRight)
| corner(RectPart::BottomLeft, Option::RoundSkipBottomLeft)
| corner(RectPart::BottomRight, Option::RoundSkipBottomRight);
const auto options = (loaded ? Option() : Option::Blur);
const auto key = (uint64(width) << 48)
| (uint64(height) << 32)
| (uint64(options) << 16)
| (uint64(rounding.key()) << 8)
| (uint64(loadLevel));
if (*cacheKey == key) {
return;
@ -731,9 +723,14 @@ void Photo::validateGroupedCache(
: Image::BlankMedia().get();
*cacheKey = key;
*cache = image->pixNoCache(
auto scaled = Images::Prepare(
image->original(),
pixSize * ratio,
{ .options = options, .outer = { width, height } });
auto rounded = Images::Round(
std::move(scaled),
MediaRoundingMask(rounding));
*cache = Ui::PixmapFromImage(std::move(rounded));
}
bool Photo::createStreamingObjects() {

View File

@ -67,7 +67,7 @@ public:
const PaintContext &context,
const QRect &geometry,
RectParts sides,
RectParts corners,
Ui::BubbleRounding rounding,
float64 highlightOpacity,
not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const override;
@ -123,7 +123,7 @@ private:
bool needInfoDisplay() const;
void validateGroupedCache(
const QRect &geometry,
RectParts corners,
Ui::BubbleRounding rounding,
not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const;
void validateImageCache(

View File

@ -72,6 +72,11 @@ struct BubbleRounding {
return { this, index };
}
[[nodiscard]] uchar key() const {
static_assert(sizeof(*this) == sizeof(uchar));
return uchar(*reinterpret_cast<const std::byte*>(this));
}
inline friend constexpr auto operator<=>(
BubbleRounding,
BubbleRounding) = default;