Show shadow below controls in media viewer.

This commit is contained in:
John Preston 2023-02-24 19:25:12 +04:00
parent d1230167bf
commit 122234f55c
28 changed files with 214 additions and 53 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 513 B

After

Width:  |  Height:  |  Size: 366 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 617 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 957 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 296 B

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 497 B

After

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 729 B

After

Width:  |  Height:  |  Size: 880 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 769 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 912 B

After

Width:  |  Height:  |  Size: 680 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 B

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 461 B

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 300 B

After

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 388 B

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 606 B

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 360 B

After

Width:  |  Height:  |  Size: 358 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 554 B

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 722 B

After

Width:  |  Height:  |  Size: 808 B

View file

@ -101,11 +101,17 @@ mediaviewVolumeToggle: IconButton(mediaviewControlsButton) {
}
mediaviewVolumeSkip: 4px;
mediaviewLeft: icon {{ "mediaview/next-flip_horizontal", mediaviewControlFg }};
mediaviewRight: icon {{ "mediaview/next", mediaviewControlFg }};
mediaviewLeft: icon {
{ "mediaview/next_shadow-flip_horizontal", windowShadowFg }
{ "mediaview/next-flip_horizontal", mediaviewControlFg }
};
mediaviewRight: icon {
{ "mediaview/next_shadow", windowShadowFg }
{ "mediaview/next", mediaviewControlFg }
};
mediaviewSave: icon {{ "mediaview/download", mediaviewControlFg }};
mediaviewRotate: icon {{ "mediaview/rotate", mediaviewControlFg }};
mediaviewMore: icon {{ "mediaview/more", mediaviewControlFg }};
mediaviewMore: icon {{ "title_menu_dots", mediaviewControlFg }};
mediaviewFileRed: icon {
{ size(25px, 25px), mediaviewFileBg },
@ -232,15 +238,13 @@ mediaviewThickFont: semiboldFont;
mediaviewFont: normalFont;
mediaviewTextStyle: defaultTextStyle;
mediaviewTextLeft: 16px;
mediaviewTextLeft: 14px;
mediaviewTextSkip: 10px;
mediaviewHeaderTop: 48px;
mediaviewTextTop: 24px;
mediaviewHeaderTop: 47px;
mediaviewTextTop: 26px;
mediaviewIconOpacity: 0.45;
mediaviewIconOverOpacity: 1.;
mediaviewControlSize: 90px;
mediaviewIconSize: size(60px, 56px);
mediaviewIconSize: size(46px, 54px);
mediaviewWaitHide: 2000;
mediaviewHideDuration: 1000;
@ -250,9 +254,9 @@ mediaviewFadeDuration: 150;
mediaviewDeltaFromLastAction: 5px;
mediaviewSwipeDistance: 80px;
mediaviewCaptionPadding: margins(18px, 10px, 18px, 10px);
mediaviewCaptionPadding: margins(11px, 6px, 11px, 6px);
mediaviewCaptionMargin: size(11px, 11px);
mediaviewCaptionRadius: 2px;
mediaviewCaptionRadius: 6px;
mediaviewGroupPadding: margins(0px, 14px, 0px, 14px);
mediaviewGroupHeight: 80px;
@ -317,6 +321,8 @@ mediaviewTitle: WindowTitle(defaultWindowTitle) {
closeIconActive: mediaviewTitleClose;
closeIconActiveOver: mediaviewTitleClose;
}
mediaviewShadowTop: icon{{ "mediaview/shadow_top", windowShadowFg }};
mediaviewShadowBottom: icon{{ "mediaview/shadow_bottom", windowShadowFg }};
themePreviewSize: size(903px, 584px);
themePreviewBg: windowBg;

View file

@ -29,6 +29,31 @@ constexpr auto kGroupThumbsOffset = kCaptionOffset + 4;
constexpr auto kControlsOffset = kGroupThumbsOffset + 4;
constexpr auto kControlValues = 2 * 4 + 4 * 4;
[[nodiscard]] ShaderPart FragmentApplyControlsFade() {
return {
.header = R"(
uniform sampler2D f_texture;
uniform vec4 shadowTopRect;
uniform vec2 shadowBottomAndOpacity;
)",
.body = R"(
float topHeight = shadowTopRect.w;
float bottomHeight = shadowBottomAndOpacity.x;
float opacity = shadowBottomAndOpacity.y;
float viewportHeight = shadowTopRect.y + topHeight;
float fullHeight = topHeight + bottomHeight;
float topY = min(
(viewportHeight - gl_FragCoord.y) / fullHeight,
topHeight / fullHeight);
float topX = (gl_FragCoord.x - shadowTopRect.x) / shadowTopRect.z;
vec4 fadeTop = texture2D(f_texture, vec2(topX, topY)) * opacity;
float bottomY = max(fullHeight - gl_FragCoord.y, topHeight) / fullHeight;
vec4 fadeBottom = texture2D(f_texture, vec2(0.5, bottomY)) * opacity;
result.rgb = result.rgb * (1. - fadeTop.a) * (1. - fadeBottom.a);
)",
};
}
[[nodiscard]] ShaderPart FragmentPlaceOnTransparentBackground() {
return {
.header = R"(
@ -77,6 +102,7 @@ OverlayWidget::RendererGL::RendererGL(not_null<OverlayWidget*> owner)
: _owner(owner) {
style::PaletteChanged(
) | rpl::start_with_next([=] {
_controlsFadeImage.invalidate();
_radialImage.invalidate();
_documentBubbleImage.invalidate();
_themePreviewImage.invalidate();
@ -118,6 +144,15 @@ void OverlayWidget::RendererGL::init(
FragmentSampleARGB32Texture(),
})).vertex;
_staticContentProgram.emplace();
LinkProgram(
&*_staticContentProgram,
_texturedVertexShader,
FragmentShader({
FragmentSampleARGB32Texture(),
FragmentApplyControlsFade()
}));
_withTransparencyProgram.emplace();
LinkProgram(
&*_withTransparencyProgram,
@ -125,6 +160,7 @@ void OverlayWidget::RendererGL::init(
FragmentShader({
FragmentSampleARGB32Texture(),
FragmentPlaceOnTransparentBackground(),
FragmentApplyControlsFade()
}));
_yuv420Program.emplace();
@ -133,6 +169,7 @@ void OverlayWidget::RendererGL::init(
_texturedVertexShader,
FragmentShader({
FragmentSampleYUV420Texture(),
FragmentApplyControlsFade()
}));
_nv12Program.emplace();
@ -141,6 +178,7 @@ void OverlayWidget::RendererGL::init(
_texturedVertexShader,
FragmentShader({
FragmentSampleNV12Texture(),
FragmentApplyControlsFade()
}));
_fillProgram.emplace();
@ -195,6 +233,7 @@ void OverlayWidget::RendererGL::paint(
if (_factor != factor) {
_factor = factor;
_controlsImage.invalidate();
_controlsFadeImage.invalidate();
}
_blendingEnabled = false;
_viewport = widget->size();
@ -283,7 +322,12 @@ void OverlayWidget::RendererGL::paintTransformedVideoFrame(
}
_chromaNV12 = nv12;
}
if (!nv12) {
validateControlsFade();
if (nv12) {
_f->glActiveTexture(GL_TEXTURE2);
_controlsFadeImage.bind(*_f);
} else {
_f->glActiveTexture(GL_TEXTURE2);
_textures.bind(*_f, 3);
if (upload) {
@ -297,6 +341,9 @@ void OverlayWidget::RendererGL::paintTransformedVideoFrame(
_chromaSize = yuv->chromaSize;
_f->glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
}
_f->glActiveTexture(GL_TEXTURE3);
_controlsFadeImage.bind(*_f);
}
program->setUniformValue("y_texture", GLint(0));
if (nv12) {
@ -305,6 +352,7 @@ void OverlayWidget::RendererGL::paintTransformedVideoFrame(
program->setUniformValue("u_texture", GLint(1));
program->setUniformValue("v_texture", GLint(2));
}
program->setUniformValue("f_texture", GLint(nv12 ? 2 : 3));
toggleBlending(false);
paintTransformedContent(program, geometry);
@ -325,7 +373,7 @@ void OverlayWidget::RendererGL::paintTransformedStaticContent(
auto &program = fillTransparentBackground
? _withTransparencyProgram
: _imageProgram;
: _staticContentProgram;
program->bind();
if (fillTransparentBackground) {
program->setUniformValue(
@ -369,7 +417,13 @@ void OverlayWidget::RendererGL::paintTransformedStaticContent(
_rgbaSize = image.size();
}
}
validateControlsFade();
_f->glActiveTexture(GL_TEXTURE1);
_controlsFadeImage.bind(*_f);
program->setUniformValue("s_texture", GLint(0));
program->setUniformValue("f_texture", GLint(1));
toggleBlending(semiTransparent && !fillTransparentBackground);
paintTransformedContent(&*program, geometry);
@ -412,6 +466,15 @@ void OverlayWidget::RendererGL::paintTransformedContent(
_contentBuffer->write(0, coords, sizeof(coords));
program->setUniformValue("viewport", _uniformViewport);
const auto &top = st::mediaviewShadowTop.size();
program->setUniformValue(
"shadowTopRect",
Uniform(transformRect(
QRect(QPoint(_viewport.width() - top.width(), 0), top))));
const auto &bottom = st::mediaviewShadowBottom;
program->setUniformValue(
"shadowBottomAndOpacity",
QVector2D(bottom.height() * _factor, geometry.controlsOpacity));
FillTexturedRectangle(*_f, &*program);
}
@ -607,6 +670,36 @@ void OverlayWidget::RendererGL::invalidateControls() {
ranges::fill(_controlsTextures, QRect());
}
void OverlayWidget::RendererGL::validateControlsFade() {
if (!_controlsFadeImage.image().isNull()) {
return;
}
const auto width = st::mediaviewShadowTop.width();
const auto bottomTop = st::mediaviewShadowTop.height();
const auto height = bottomTop + st::mediaviewShadowBottom.height();
auto image = QImage(
QSize(width, height) * _factor,
QImage::Format_ARGB32_Premultiplied);
image.fill(Qt::transparent);
image.setDevicePixelRatio(_factor);
auto p = QPainter(&image);
st::mediaviewShadowTop.paint(p, 0, 0, width);
st::mediaviewShadowBottom.fill(
p,
QRect(0, bottomTop, width, st::mediaviewShadowBottom.height()));
p.end();
_controlsFadeImage.setImage(std::move(image));
_shadowTopTexture = QRect(
QPoint(),
QSize(width, st::mediaviewShadowTop.height()) * _factor);
_shadowBottomTexture = QRect(
QPoint(0, bottomTop) * _factor,
QSize(width, st::mediaviewShadowBottom.height()) * _factor);
}
void OverlayWidget::RendererGL::paintFooter(QRect outer, float64 opacity) {
paintUsingRaster(_footerImage, outer, [&](Painter &&p) {
const auto newOuter = QRect(QPoint(), outer.size());
@ -699,25 +792,25 @@ void OverlayWidget::RendererGL::paintRoundedCorners(int radius) {
_f->glDisableVertexAttribArray(position);
}
void OverlayWidget::RendererGL::invalidate() {
_trackFrameIndex = -1;
_streamedIndex = -1;
const auto images = {
&_radialImage,
&_documentBubbleImage,
&_themePreviewImage,
&_saveMsgImage,
&_footerImage,
&_captionImage,
&_groupThumbsImage,
&_controlsImage,
};
for (const auto image : images) {
image->setImage(QImage());
}
invalidateControls();
}
//
//void OverlayWidget::RendererGL::invalidate() {
// _trackFrameIndex = -1;
// _streamedIndex = -1;
// const auto images = {
// &_radialImage,
// &_documentBubbleImage,
// &_themePreviewImage,
// &_saveMsgImage,
// &_footerImage,
// &_captionImage,
// &_groupThumbsImage,
// &_controlsImage,
// };
// for (const auto image : images) {
// image->setImage(QImage());
// }
// invalidateControls();
//}
void OverlayWidget::RendererGL::paintUsingRaster(
Ui::GL::Image &image,

View file

@ -70,7 +70,7 @@ private:
void paintGroupThumbs(QRect outer, float64 opacity) override;
void paintRoundedCorners(int radius) override;
void invalidate();
//void invalidate();
void paintUsingRaster(
Ui::GL::Image &image,
@ -79,6 +79,7 @@ private:
int bufferOffset,
bool transparent = false);
void validateControlsFade();
void validateControls();
void invalidateControls();
void toggleBlending(bool enabled);
@ -105,6 +106,7 @@ private:
std::optional<QOpenGLBuffer> _contentBuffer;
std::optional<QOpenGLShaderProgram> _imageProgram;
std::optional<QOpenGLShaderProgram> _staticContentProgram;
QOpenGLShader *_texturedVertexShader = nullptr;
std::optional<QOpenGLShaderProgram> _withTransparencyProgram;
std::optional<QOpenGLShaderProgram> _yuv420Program;
@ -121,6 +123,7 @@ private:
int _streamedIndex = 0;
bool _chromaNV12 = false;
Ui::GL::Image _controlsFadeImage;
Ui::GL::Image _radialImage;
Ui::GL::Image _documentBubbleImage;
Ui::GL::Image _themePreviewImage;
@ -134,6 +137,9 @@ private:
[[nodiscard]] static Control ControlMeta(OverState control);
std::array<QRect, kControlsCount> _controlsTextures;
QRect _shadowTopTexture;
QRect _shadowBottomTexture;
bool _blendingEnabled = false;
rpl::lifetime _lifetime;

View file

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/painter.h"
#include "media/view/media_view_pip.h"
#include "styles/style_media_view.h"
namespace Media::View {
@ -73,6 +74,7 @@ void OverlayWidget::RendererSW::paintTransformedVideoFrame(
return;
}
paintTransformedImage(_owner->videoFrame(), rect, rotation);
paintControlsFade(rect, geometry.controlsOpacity);
}
void OverlayWidget::RendererSW::paintTransformedStaticContent(
@ -89,10 +91,34 @@ void OverlayWidget::RendererSW::paintTransformedStaticContent(
if (fillTransparentBackground) {
_p->fillRect(rect, _transparentBrush);
}
if (image.isNull()) {
return;
if (!image.isNull()) {
paintTransformedImage(image, rect, rotation);
}
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);
}
_p->setClipping(false);
_p->setOpacity(1.);
}
void OverlayWidget::RendererSW::paintTransformedImage(

View file

@ -32,6 +32,7 @@ private:
const QImage &image,
QRect rect,
int rotation);
void paintControlsFade(QRect geometry, float64 opacity);
void paintRadialLoading(
QRect inner,
bool radial,

View file

@ -790,6 +790,11 @@ void OverlayWidget::updateControlsGeometry() {
_saveMsg.moveTo((width() - _saveMsg.width()) / 2, (height() - _saveMsg.height()) / 2);
_photoRadialRect = QRect(QPoint((width() - st::radialSize.width()) / 2, (height() - st::radialSize.height()) / 2), st::radialSize);
const auto bottom = st::mediaviewShadowBottom.height();
const auto top = st::mediaviewShadowTop.size();
_bottomShadowRect = QRect(0, height() - bottom, width(), bottom);
_topShadowRect = QRect(QPoint(width() - top.width(), 0), top);
updateControls();
resizeContentByScreenSize();
update();
@ -1367,6 +1372,7 @@ bool OverlayWidget::updateControlsAnimation(crl::time now) {
_controlsOpacity.update(dt, anim::linear);
}
_helper->setControlsOpacity(_controlsOpacity.current());
const auto content = finalContentRect();
const auto toUpdate = QRegion()
+ (_over == OverLeftNav ? _leftNav : _leftNavIcon)
+ (_over == OverRightNav ? _rightNav : _rightNavIcon)
@ -1377,7 +1383,9 @@ bool OverlayWidget::updateControlsAnimation(crl::time now) {
+ _nameNav
+ _dateNav
+ _captionRect.marginsAdded(st::mediaviewCaptionPadding)
+ _groupThumbsRect;
+ _groupThumbsRect
+ content.intersected(_bottomShadowRect)
+ content.intersected(_topShadowRect);
update(toUpdate);
return (dt < 1);
}
@ -1407,6 +1415,7 @@ QRect OverlayWidget::finalContentRect() const {
}
OverlayWidget::ContentGeometry OverlayWidget::contentGeometry() const {
const auto controlsOpacity = _controlsOpacity.current();
const auto toRotation = qreal(finalContentRotation());
const auto toRectRotated = QRectF(finalContentRect());
const auto toRectCenter = toRectRotated.center();
@ -1418,7 +1427,7 @@ OverlayWidget::ContentGeometry OverlayWidget::contentGeometry() const {
toRectRotated.width())
: toRectRotated;
if (!_geometryAnimation.animating()) {
return { toRect, toRotation };
return { toRect, toRotation, controlsOpacity };
}
const auto fromRect = _oldGeometry.rect;
const auto fromRotation = _oldGeometry.rotation;
@ -1441,7 +1450,7 @@ OverlayWidget::ContentGeometry OverlayWidget::contentGeometry() const {
fromRect.width() + (toRect.width() - fromRect.width()) * progress,
fromRect.height() + (toRect.height() - fromRect.height()) * progress
);
return { useRect, useRotation };
return { useRect, useRotation, controlsOpacity };
}
void OverlayWidget::updateContentRect() {
@ -4152,6 +4161,7 @@ void OverlayWidget::paintControls(
const QRect &outer;
const QRect &inner;
const style::icon &icon;
bool nonbright = false;
};
const QRect kEmpty;
// When adding / removing controls please update RendererGL.
@ -4161,13 +4171,15 @@ void OverlayWidget::paintControls(
_leftNavVisible,
_leftNav,
_leftNavIcon,
st::mediaviewLeft },
st::mediaviewLeft,
true },
{
OverRightNav,
_rightNavVisible,
_rightNav,
_rightNavIcon,
st::mediaviewRight },
st::mediaviewRight,
true },
{
OverSave,
_saveVisible,
@ -4193,9 +4205,9 @@ void OverlayWidget::paintControls(
if (!control.visible) {
continue;
}
const auto bg = overLevel(control.state);
const auto icon = bg * st::mediaviewIconOverOpacity
+ (1 - bg) * st::mediaviewIconOpacity;
const auto progress = overLevel(control.state);
const auto bg = progress;
const auto icon = controlOpacity(progress, control.nonbright);
renderer->paintControl(
control.state,
control.outer,
@ -4206,6 +4218,15 @@ void OverlayWidget::paintControls(
}
}
float64 OverlayWidget::controlOpacity(
float64 progress,
bool nonbright) const {
const auto normal = _windowed
? kNormalIconOpacity
: kMaximizedIconOpacity;
return progress + (1. - progress) * normal;
}
void OverlayWidget::paintFooterContent(
Painter &p,
QRect outer,
@ -4221,7 +4242,7 @@ void OverlayWidget::paintFooterContent(
const auto date = _dateNav.translated(shift);
if (header.intersects(clip)) {
auto o = _headerHasLink ? overLevel(OverHeader) : 0;
p.setOpacity((o * st::mediaviewIconOverOpacity + (1 - o) * st::mediaviewIconOpacity) * opacity);
p.setOpacity(controlOpacity(o) * opacity);
p.drawText(header.left(), header.top() + st::mediaviewThickFont->ascent, _headerText);
if (o > 0) {
@ -4235,7 +4256,7 @@ void OverlayWidget::paintFooterContent(
// name
if (_nameNav.isValid() && name.intersects(clip)) {
float64 o = _from ? overLevel(OverName) : 0.;
p.setOpacity((o * st::mediaviewIconOverOpacity + (1 - o) * st::mediaviewIconOpacity) * opacity);
p.setOpacity(controlOpacity(o) * opacity);
_fromNameLabel.drawElided(p, name.left(), name.top(), name.width());
if (o > 0) {
@ -4247,7 +4268,7 @@ void OverlayWidget::paintFooterContent(
// date
if (date.intersects(clip)) {
float64 o = overLevel(OverDate);
p.setOpacity((o * st::mediaviewIconOverOpacity + (1 - o) * st::mediaviewIconOpacity) * opacity);
p.setOpacity(controlOpacity(o) * opacity);
p.drawText(date.left(), date.top() + st::mediaviewFont->ascent, _dateText);
if (o > 0) {
@ -4323,6 +4344,7 @@ void OverlayWidget::handleKeyPress(not_null<QKeyEvent*> e) {
} else if (_fullScreenVideo) {
if (key == Qt::Key_Escape) {
playbackToggleFullScreen();
} else if (ctrl) {
} else if (key == Qt::Key_0) {
activateControls();
restartAtSeekPosition(0);
@ -4337,7 +4359,6 @@ void OverlayWidget::handleKeyPress(not_null<QKeyEvent*> e) {
activateControls();
seekRelativeTime(kSeekTimeMs);
}
return;
}
}
@ -4379,8 +4400,6 @@ void OverlayWidget::handleKeyPress(not_null<QKeyEvent*> e) {
zoomIn();
} else if (key == Qt::Key_Minus || key == Qt::Key_Underscore) {
zoomOut();
} else if (key == Qt::Key_0) {
zoomReset();
} else if (key == Qt::Key_I) {
update();
}
@ -5090,10 +5109,13 @@ bool OverlayWidget::filterApplicationEvent(
not_null<QEvent*> e) {
const auto type = e->type();
if (type == QEvent::ShortcutOverride) {
const auto keyEvent = static_cast<QKeyEvent*>(e.get());
const auto ctrl = keyEvent->modifiers().testFlag(Qt::ControlModifier);
if (keyEvent->key() == Qt::Key_F && ctrl && _streamed) {
const auto event = static_cast<QKeyEvent*>(e.get());
const auto key = event->key();
const auto ctrl = event->modifiers().testFlag(Qt::ControlModifier);
if (key == Qt::Key_F && ctrl && _streamed) {
playbackToggleFullScreen();
} else if (key == Qt::Key_0 && ctrl) {
zoomReset();
}
return true;
} else if (type == QEvent::MouseMove

View file

@ -154,6 +154,7 @@ private:
struct ContentGeometry {
QRectF rect;
qreal rotation = 0.;
qreal controlsOpacity = 0.;
};
struct StartStreaming {
StartStreaming() : continueStreaming(false), startTime(0) {
@ -417,6 +418,9 @@ private:
QRect clip,
float64 opacity);
[[nodiscard]] float64 controlOpacity(
float64 progress,
bool nonbright = false) const;
[[nodiscard]] bool isSaveMsgShown() const;
void updateOverRect(OverState state);
@ -552,6 +556,9 @@ private:
object_ptr<Ui::LinkButton> _docSaveAs;
object_ptr<Ui::LinkButton> _docCancel;
QRect _bottomShadowRect;
QRect _topShadowRect;
QRect _photoRadialRect;
Ui::RadialAnimation _radial;