2021-06-02 16:36:24 +00:00
|
|
|
/*
|
|
|
|
This file is part of Telegram Desktop,
|
|
|
|
the official desktop application for the Telegram messaging service.
|
|
|
|
|
|
|
|
For license and copyright information please follow this link:
|
|
|
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
|
|
*/
|
|
|
|
#include "media/view/media_view_overlay_raster.h"
|
|
|
|
|
2022-09-16 20:23:27 +00:00
|
|
|
#include "ui/painter.h"
|
2021-06-02 16:36:24 +00:00
|
|
|
#include "media/view/media_view_pip.h"
|
2023-02-28 13:49:18 +00:00
|
|
|
#include "platform/platform_overlay_widget.h"
|
2023-02-24 15:25:12 +00:00
|
|
|
#include "styles/style_media_view.h"
|
2021-06-02 16:36:24 +00:00
|
|
|
|
|
|
|
namespace Media::View {
|
|
|
|
|
|
|
|
OverlayWidget::RendererSW::RendererSW(not_null<OverlayWidget*> owner)
|
|
|
|
: _owner(owner)
|
|
|
|
, _transparentBrush(style::TransparentPlaceholder()) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void OverlayWidget::RendererSW::paintFallback(
|
|
|
|
Painter &&p,
|
|
|
|
const QRegion &clip,
|
|
|
|
Ui::GL::Backend backend) {
|
|
|
|
_p = &p;
|
|
|
|
_clip = &clip;
|
|
|
|
_clipOuter = clip.boundingRect();
|
|
|
|
_owner->paint(this);
|
2021-06-03 07:11:35 +00:00
|
|
|
_p = nullptr;
|
|
|
|
_clip = nullptr;
|
2021-06-02 16:36:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void OverlayWidget::RendererSW::paintBackground() {
|
|
|
|
const auto region = _owner->opaqueContentShown()
|
2021-06-04 15:42:02 +00:00
|
|
|
? (*_clip - _owner->finalContentRect())
|
2021-06-02 16:36:24 +00:00
|
|
|
: *_clip;
|
|
|
|
|
|
|
|
const auto m = _p->compositionMode();
|
|
|
|
_p->setCompositionMode(QPainter::CompositionMode_Source);
|
|
|
|
const auto &bg = _owner->_fullScreenVideo
|
|
|
|
? st::mediaviewVideoBg
|
|
|
|
: st::mediaviewBg;
|
2021-09-08 10:53:54 +00:00
|
|
|
for (const auto &rect : region) {
|
2021-06-02 16:36:24 +00:00
|
|
|
_p->fillRect(rect, bg);
|
|
|
|
}
|
|
|
|
_p->setCompositionMode(m);
|
|
|
|
}
|
|
|
|
|
2021-06-04 15:42:02 +00:00
|
|
|
QRect OverlayWidget::RendererSW::TransformRect(
|
|
|
|
QRectF geometry,
|
2021-06-02 16:36:24 +00:00
|
|
|
int rotation) {
|
2021-06-04 15:42:02 +00:00
|
|
|
const auto center = geometry.center();
|
|
|
|
const auto rect = ((rotation % 180) == 90)
|
|
|
|
? QRectF(
|
|
|
|
center.x() - geometry.height() / 2.,
|
|
|
|
center.y() - geometry.width() / 2.,
|
|
|
|
geometry.height(),
|
|
|
|
geometry.width())
|
|
|
|
: geometry;
|
|
|
|
return QRect(
|
|
|
|
int(rect.x()),
|
|
|
|
int(rect.y()),
|
|
|
|
int(rect.width()),
|
|
|
|
int(rect.height()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void OverlayWidget::RendererSW::paintTransformedVideoFrame(
|
|
|
|
ContentGeometry geometry) {
|
2021-06-02 16:36:24 +00:00
|
|
|
Expects(_owner->_streamed != nullptr);
|
|
|
|
|
2021-06-04 15:42:02 +00:00
|
|
|
const auto rotation = int(geometry.rotation);
|
|
|
|
const auto rect = TransformRect(geometry.rect, rotation);
|
2021-06-02 16:36:24 +00:00
|
|
|
if (!rect.intersects(_clipOuter)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
paintTransformedImage(_owner->videoFrame(), rect, rotation);
|
2023-02-24 15:25:12 +00:00
|
|
|
paintControlsFade(rect, geometry.controlsOpacity);
|
2021-06-02 16:36:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void OverlayWidget::RendererSW::paintTransformedStaticContent(
|
|
|
|
const QImage &image,
|
2021-06-04 15:42:02 +00:00
|
|
|
ContentGeometry geometry,
|
2021-06-14 11:28:39 +00:00
|
|
|
bool semiTransparent,
|
2021-06-02 16:36:24 +00:00
|
|
|
bool fillTransparentBackground) {
|
2021-06-04 15:42:02 +00:00
|
|
|
const auto rotation = int(geometry.rotation);
|
|
|
|
const auto rect = TransformRect(geometry.rect, rotation);
|
2021-06-02 16:36:24 +00:00
|
|
|
if (!rect.intersects(_clipOuter)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fillTransparentBackground) {
|
|
|
|
_p->fillRect(rect, _transparentBrush);
|
|
|
|
}
|
2023-02-24 15:25:12 +00:00
|
|
|
if (!image.isNull()) {
|
|
|
|
paintTransformedImage(image, rect, rotation);
|
|
|
|
}
|
|
|
|
paintControlsFade(rect, geometry.controlsOpacity);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OverlayWidget::RendererSW::paintControlsFade(
|
|
|
|
QRect geometry,
|
|
|
|
float64 opacity) {
|
|
|
|
_p->setOpacity(opacity);
|
|
|
|
_p->setClipRect(geometry);
|
|
|
|
const auto width = _owner->width();
|
|
|
|
const auto &top = st::mediaviewShadowTop;
|
|
|
|
const auto topShadow = QRect(
|
|
|
|
QPoint(width - top.width(), 0),
|
|
|
|
top.size());
|
|
|
|
if (topShadow.intersected(geometry).intersects(_clipOuter)) {
|
|
|
|
top.paint(*_p, topShadow.topLeft(), width);
|
|
|
|
}
|
|
|
|
const auto &bottom = st::mediaviewShadowBottom;
|
|
|
|
const auto bottomShadow = QRect(
|
|
|
|
QPoint(0, _owner->height() - bottom.height()),
|
|
|
|
QSize(width, bottom.height()));
|
|
|
|
if (bottomShadow.intersected(geometry).intersects(_clipOuter)) {
|
|
|
|
bottom.fill(*_p, bottomShadow);
|
2021-06-02 16:36:24 +00:00
|
|
|
}
|
2023-02-24 15:25:12 +00:00
|
|
|
_p->setClipping(false);
|
|
|
|
_p->setOpacity(1.);
|
2021-06-02 16:36:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void OverlayWidget::RendererSW::paintTransformedImage(
|
|
|
|
const QImage &image,
|
|
|
|
QRect rect,
|
|
|
|
int rotation) {
|
|
|
|
PainterHighQualityEnabler hq(*_p);
|
2021-06-10 13:16:17 +00:00
|
|
|
if (UsePainterRotation(rotation)) {
|
2021-06-02 16:36:24 +00:00
|
|
|
if (rotation) {
|
|
|
|
_p->save();
|
|
|
|
_p->rotate(rotation);
|
|
|
|
}
|
|
|
|
_p->drawImage(RotatedRect(rect, rotation), image);
|
|
|
|
if (rotation) {
|
|
|
|
_p->restore();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
_p->drawImage(rect, _owner->transformShownContent(image, rotation));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OverlayWidget::RendererSW::paintRadialLoading(
|
|
|
|
QRect inner,
|
|
|
|
bool radial,
|
|
|
|
float64 radialOpacity) {
|
|
|
|
_owner->paintRadialLoadingContent(*_p, inner, radial, radialOpacity);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OverlayWidget::RendererSW::paintThemePreview(QRect outer) {
|
|
|
|
_owner->paintThemePreviewContent(*_p, outer, _clipOuter);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OverlayWidget::RendererSW::paintDocumentBubble(
|
|
|
|
QRect outer,
|
|
|
|
QRect icon) {
|
|
|
|
if (outer.intersects(_clipOuter)) {
|
|
|
|
_owner->paintDocumentBubbleContent(*_p, outer, icon, _clipOuter);
|
|
|
|
if (icon.intersects(_clipOuter)) {
|
|
|
|
_owner->paintRadialLoading(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OverlayWidget::RendererSW::paintSaveMsg(QRect outer) {
|
|
|
|
if (outer.intersects(_clipOuter)) {
|
|
|
|
_owner->paintSaveMsgContent(*_p, outer, _clipOuter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-04 15:14:42 +00:00
|
|
|
void OverlayWidget::RendererSW::paintControlsStart() {
|
|
|
|
}
|
|
|
|
|
2021-06-02 16:36:24 +00:00
|
|
|
void OverlayWidget::RendererSW::paintControl(
|
|
|
|
OverState control,
|
2023-02-28 13:49:18 +00:00
|
|
|
QRect over,
|
|
|
|
float64 overOpacity,
|
2021-06-02 16:36:24 +00:00
|
|
|
QRect inner,
|
|
|
|
float64 innerOpacity,
|
|
|
|
const style::icon &icon) {
|
2023-02-28 13:49:18 +00:00
|
|
|
if (!over.isEmpty() && !over.intersects(_clipOuter)) {
|
2021-06-02 16:36:24 +00:00
|
|
|
return;
|
|
|
|
}
|
2023-02-28 13:49:18 +00:00
|
|
|
if (!over.isEmpty() && overOpacity > 0) {
|
|
|
|
if (_overControlImage.isNull()) {
|
|
|
|
validateOverControlImage();
|
2021-06-02 16:36:24 +00:00
|
|
|
}
|
2023-02-28 13:49:18 +00:00
|
|
|
_p->setOpacity(overOpacity);
|
|
|
|
_p->drawImage(over.topLeft(), _overControlImage);
|
2021-06-02 16:36:24 +00:00
|
|
|
}
|
|
|
|
if (inner.intersects(_clipOuter)) {
|
|
|
|
_p->setOpacity(innerOpacity);
|
|
|
|
icon.paintInCenter(*_p, inner);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OverlayWidget::RendererSW::paintFooter(QRect outer, float64 opacity) {
|
|
|
|
if (outer.intersects(_clipOuter)) {
|
|
|
|
_owner->paintFooterContent(*_p, outer, _clipOuter, opacity);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OverlayWidget::RendererSW::paintCaption(QRect outer, float64 opacity) {
|
|
|
|
if (outer.intersects(_clipOuter)) {
|
|
|
|
_owner->paintCaptionContent(*_p, outer, _clipOuter, opacity);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OverlayWidget::RendererSW::paintGroupThumbs(
|
|
|
|
QRect outer,
|
|
|
|
float64 opacity) {
|
|
|
|
if (outer.intersects(_clipOuter)) {
|
|
|
|
_owner->paintGroupThumbsContent(*_p, outer, _clipOuter, opacity);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-17 08:11:32 +00:00
|
|
|
void OverlayWidget::RendererSW::paintRoundedCorners(int radius) {
|
|
|
|
// The RpWindow rounding overlay will do the job.
|
|
|
|
}
|
|
|
|
|
2023-02-28 13:49:18 +00:00
|
|
|
void OverlayWidget::RendererSW::validateOverControlImage() {
|
|
|
|
const auto size = QSize(st::mediaviewIconOver, st::mediaviewIconOver);
|
|
|
|
const auto alpha = base::SafeRound(kOverBackgroundOpacity * 255);
|
|
|
|
_overControlImage = QImage(
|
|
|
|
size * style::DevicePixelRatio(),
|
|
|
|
QImage::Format_ARGB32_Premultiplied);
|
|
|
|
_overControlImage.setDevicePixelRatio(style::DevicePixelRatio());
|
|
|
|
_overControlImage.fill(Qt::transparent);
|
|
|
|
|
|
|
|
Painter p(&_overControlImage);
|
|
|
|
PainterHighQualityEnabler hq(p);
|
|
|
|
p.setPen(Qt::NoPen);
|
|
|
|
auto color = OverBackgroundColor();
|
|
|
|
color.setAlpha(alpha);
|
|
|
|
p.setBrush(color);
|
|
|
|
p.drawEllipse(QRect(QPoint(), size));
|
|
|
|
}
|
|
|
|
|
2021-06-02 16:36:24 +00:00
|
|
|
} // namespace Media::View
|