mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-18 23:27:09 +02:00
Show userpic / name on sibling stories.
This commit is contained in:
parent
a0e9e148b0
commit
30871ed116
15 changed files with 469 additions and 120 deletions
|
@ -28,8 +28,11 @@ namespace {
|
|||
|
||||
constexpr auto kPhotoProgressInterval = crl::time(100);
|
||||
constexpr auto kPhotoDuration = 5 * crl::time(1000);
|
||||
constexpr auto kSiblingMultiplier = 0.448;
|
||||
constexpr auto kFullContentFade = 0.2;
|
||||
constexpr auto kSiblingMultiplier = 0.448;
|
||||
constexpr auto kSiblingOutsidePart = 0.24;
|
||||
constexpr auto kSiblingUserpicSize = 0.3;
|
||||
constexpr auto kInnerHeightMultiplier = 1.6;
|
||||
|
||||
} // namespace
|
||||
|
||||
|
@ -210,14 +213,49 @@ void Controller::initLayout() {
|
|||
layout.controlsBottomPosition.y());
|
||||
|
||||
const auto siblingSize = layout.content.size() * kSiblingMultiplier;
|
||||
const auto siblingTop = layout.content.y()
|
||||
+ (layout.content.height() - siblingSize.height()) / 2;
|
||||
layout.siblingLeft = QRect(
|
||||
{ -siblingSize.width() / 3, siblingTop },
|
||||
siblingSize);
|
||||
layout.siblingRight = QRect(
|
||||
{ size.width() - (2 * siblingSize.width() / 3), siblingTop },
|
||||
siblingSize);
|
||||
const auto siblingTop = (size.height() - siblingSize.height()) / 2;
|
||||
const auto outside = int(base::SafeRound(
|
||||
siblingSize.width() * kSiblingOutsidePart));
|
||||
const auto xLeft = -outside;
|
||||
const auto xRight = size.width() - siblingSize.width() + outside;
|
||||
const auto userpicSize = int(base::SafeRound(
|
||||
siblingSize.width() * kSiblingUserpicSize));
|
||||
const auto innerHeight = userpicSize * kInnerHeightMultiplier;
|
||||
const auto userpic = [&](QRect geometry) {
|
||||
return QRect(
|
||||
(geometry.width() - userpicSize) / 2,
|
||||
(geometry.height() - innerHeight) / 2,
|
||||
userpicSize,
|
||||
userpicSize
|
||||
).translated(geometry.topLeft());
|
||||
};
|
||||
const auto nameFontSize = st::storiesMaxNameFontSize * contentHeight
|
||||
/ st::storiesMaxSize.height();
|
||||
const auto nameBoundingRect = [&](QRect geometry, bool left) {
|
||||
const auto skipSmall = nameFontSize;
|
||||
const auto skipBig = skipSmall + outside;
|
||||
const auto top = userpic(geometry).y() + innerHeight;
|
||||
return QRect(
|
||||
left ? skipBig : skipSmall,
|
||||
(geometry.height() - innerHeight) / 2,
|
||||
geometry.width() - skipSmall - skipBig,
|
||||
innerHeight
|
||||
).translated(geometry.topLeft());
|
||||
};
|
||||
const auto left = QRect({ xLeft, siblingTop }, siblingSize);
|
||||
const auto right = QRect({ xRight, siblingTop }, siblingSize);
|
||||
layout.siblingLeft = {
|
||||
.geometry = left,
|
||||
.userpic = userpic(left),
|
||||
.nameBoundingRect = nameBoundingRect(left, true),
|
||||
.nameFontSize = nameFontSize,
|
||||
};
|
||||
layout.siblingRight = {
|
||||
.geometry = right,
|
||||
.userpic = userpic(right),
|
||||
.nameBoundingRect = nameBoundingRect(right, false),
|
||||
.nameFontSize = nameFontSize,
|
||||
};
|
||||
|
||||
return layout;
|
||||
});
|
||||
|
@ -237,9 +275,13 @@ rpl::producer<Layout> Controller::layoutValue() const {
|
|||
return _layout.value() | rpl::filter_optional();
|
||||
}
|
||||
|
||||
float64 Controller::contentFade() const {
|
||||
return _contentFadeAnimation.value(_contentFaded ? 1. : 0.)
|
||||
* kFullContentFade;
|
||||
ContentLayout Controller::contentLayout() const {
|
||||
return {
|
||||
.geometry = _layout.current()->content,
|
||||
.fade = (_contentFadeAnimation.value(_contentFaded ? 1. : 0.)
|
||||
* kFullContentFade),
|
||||
.radius = float64(st::storiesRadius),
|
||||
};
|
||||
}
|
||||
|
||||
std::shared_ptr<ChatHelpers::Show> Controller::uiShow() const {
|
||||
|
@ -349,7 +391,7 @@ bool Controller::subjumpAvailable(int delta) const {
|
|||
bool Controller::subjumpFor(int delta) {
|
||||
const auto index = _index + delta;
|
||||
if (index < 0) {
|
||||
if (_siblingLeft->shownId().valid()) {
|
||||
if (_siblingLeft && _siblingLeft->shownId().valid()) {
|
||||
return jumpFor(-1);
|
||||
} else if (!_list || _list->items.empty()) {
|
||||
return false;
|
||||
|
@ -360,7 +402,9 @@ bool Controller::subjumpFor(int delta) {
|
|||
});
|
||||
return true;
|
||||
} else if (index >= _list->total) {
|
||||
return _siblingRight->shownId().valid() && jumpFor(1);
|
||||
return _siblingRight
|
||||
&& _siblingRight->shownId().valid()
|
||||
&& jumpFor(1);
|
||||
} else if (index < _list->items.size()) {
|
||||
// #TODO stories load more
|
||||
_delegate->storiesJumpTo({
|
||||
|
@ -411,16 +455,16 @@ void Controller::repaintSibling(not_null<Sibling*> sibling) {
|
|||
}
|
||||
}
|
||||
|
||||
SiblingView Controller::siblingLeft() const {
|
||||
if (const auto value = _siblingLeft.get()) {
|
||||
return { value->image(), _layout.current()->siblingLeft };
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
SiblingView Controller::siblingRight() const {
|
||||
if (const auto value = _siblingRight.get()) {
|
||||
return { value->image(), _layout.current()->siblingRight };
|
||||
SiblingView Controller::sibling(SiblingType type) const {
|
||||
const auto &pointer = (type == SiblingType::Left)
|
||||
? _siblingLeft
|
||||
: _siblingRight;
|
||||
if (const auto value = pointer.get()) {
|
||||
const auto over = _delegate->storiesSiblingOver(type);
|
||||
const auto layout = (type == SiblingType::Left)
|
||||
? _layout.current()->siblingLeft
|
||||
: _layout.current()->siblingRight;
|
||||
return value->view(layout, over);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -39,12 +39,21 @@ class ReplyArea;
|
|||
class Sibling;
|
||||
class Delegate;
|
||||
struct SiblingView;
|
||||
enum class SiblingType;
|
||||
struct ContentLayout;
|
||||
|
||||
enum class HeaderLayout {
|
||||
Normal,
|
||||
Outside,
|
||||
};
|
||||
|
||||
struct SiblingLayout {
|
||||
QRect geometry;
|
||||
QRect userpic;
|
||||
QRect nameBoundingRect;
|
||||
int nameFontSize = 0;
|
||||
};
|
||||
|
||||
struct Layout {
|
||||
QRect content;
|
||||
QRect header;
|
||||
|
@ -53,8 +62,8 @@ struct Layout {
|
|||
QPoint controlsBottomPosition;
|
||||
QRect autocompleteRect;
|
||||
HeaderLayout headerLayout = HeaderLayout::Normal;
|
||||
QRect siblingLeft;
|
||||
QRect siblingRight;
|
||||
SiblingLayout siblingLeft;
|
||||
SiblingLayout siblingRight;
|
||||
|
||||
friend inline bool operator==(Layout, Layout) = default;
|
||||
};
|
||||
|
@ -67,7 +76,7 @@ public:
|
|||
[[nodiscard]] not_null<Ui::RpWidget*> wrap() const;
|
||||
[[nodiscard]] Layout layout() const;
|
||||
[[nodiscard]] rpl::producer<Layout> layoutValue() const;
|
||||
[[nodiscard]] float64 contentFade() const;
|
||||
[[nodiscard]] ContentLayout contentLayout() const;
|
||||
|
||||
[[nodiscard]] std::shared_ptr<ChatHelpers::Show> uiShow() const;
|
||||
[[nodiscard]] auto stickerOrEmojiChosen() const
|
||||
|
@ -90,8 +99,7 @@ public:
|
|||
[[nodiscard]] bool canDownload() const;
|
||||
|
||||
void repaintSibling(not_null<Sibling*> sibling);
|
||||
[[nodiscard]] SiblingView siblingLeft() const;
|
||||
[[nodiscard]] SiblingView siblingRight() const;
|
||||
[[nodiscard]] SiblingView sibling(SiblingType type) const;
|
||||
|
||||
void unfocusReply();
|
||||
|
||||
|
|
|
@ -27,6 +27,11 @@ enum class JumpReason {
|
|||
User,
|
||||
};
|
||||
|
||||
enum class SiblingType {
|
||||
Left,
|
||||
Right,
|
||||
};
|
||||
|
||||
class Delegate {
|
||||
public:
|
||||
[[nodiscard]] virtual not_null<Ui::RpWidget*> storiesWrap() = 0;
|
||||
|
@ -36,6 +41,7 @@ public:
|
|||
-> rpl::producer<ChatHelpers::FileChosen> = 0;
|
||||
virtual void storiesJumpTo(Data::FullStoryId id) = 0;
|
||||
[[nodiscard]] virtual bool storiesPaused() = 0;
|
||||
[[nodiscard]] virtual float64 storiesSiblingOver(SiblingType type) = 0;
|
||||
virtual void storiesTogglePaused(bool paused) = 0;
|
||||
virtual void storiesRepaint() = 0;
|
||||
};
|
||||
|
|
|
@ -14,15 +14,23 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_photo.h"
|
||||
#include "data/data_photo_media.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "main/main_session.h"
|
||||
#include "media/stories/media_stories_controller.h"
|
||||
#include "media/stories/media_stories_view.h"
|
||||
#include "media/streaming/media_streaming_instance.h"
|
||||
#include "media/streaming/media_streaming_player.h"
|
||||
#include "ui/painter.h"
|
||||
#include "styles/style_media_view.h"
|
||||
|
||||
namespace Media::Stories {
|
||||
namespace {
|
||||
|
||||
constexpr auto kGoodFadeDuration = crl::time(200);
|
||||
constexpr auto kSiblingFade = 0.5;
|
||||
constexpr auto kSiblingFadeOver = 0.4;
|
||||
constexpr auto kSiblingNameOpacity = 0.8;
|
||||
constexpr auto kSiblingNameOpacityOver = 1.;
|
||||
|
||||
} // namespace
|
||||
|
||||
|
@ -241,8 +249,107 @@ bool Sibling::shows(const Data::StoriesList &list) const {
|
|||
return _id == Data::FullStoryId{ list.user, list.items.front().id };
|
||||
}
|
||||
|
||||
QImage Sibling::image() const {
|
||||
return _good.isNull() ? _blurred : _good;
|
||||
SiblingView Sibling::view(const SiblingLayout &layout, float64 over) {
|
||||
const auto name = nameImage(layout);
|
||||
return {
|
||||
.image = _good.isNull() ? _blurred : _good,
|
||||
.layout = {
|
||||
.geometry = layout.geometry,
|
||||
.fade = kSiblingFade * (1 - over) + kSiblingFadeOver * over,
|
||||
.radius = float64(st::storiesRadius),
|
||||
},
|
||||
.userpic = userpicImage(layout),
|
||||
.userpicPosition = layout.userpic.topLeft(),
|
||||
.name = name,
|
||||
.namePosition = namePosition(layout, name),
|
||||
.nameOpacity = (kSiblingNameOpacity * (1 - over)
|
||||
+ kSiblingNameOpacityOver * over),
|
||||
};
|
||||
}
|
||||
|
||||
QImage Sibling::userpicImage(const SiblingLayout &layout) {
|
||||
Expects(_id.user != nullptr);
|
||||
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
const auto size = layout.userpic.width() * ratio;
|
||||
const auto key = _id.user->userpicUniqueKey(_userpicView);
|
||||
if (_userpicImage.width() != size || _userpicKey != key) {
|
||||
_userpicKey = key;
|
||||
_userpicImage = _id.user->generateUserpicImage(_userpicView, size);
|
||||
_userpicImage.setDevicePixelRatio(ratio);
|
||||
}
|
||||
return _userpicImage;
|
||||
}
|
||||
|
||||
QImage Sibling::nameImage(const SiblingLayout &layout) {
|
||||
Expects(_id.user != nullptr);
|
||||
|
||||
if (_nameFontSize != layout.nameFontSize) {
|
||||
_nameFontSize = layout.nameFontSize;
|
||||
|
||||
const auto family = 0; // Default font family.
|
||||
const auto font = style::font(
|
||||
_nameFontSize,
|
||||
style::internal::FontSemibold,
|
||||
family);
|
||||
_name.reset();
|
||||
_nameStyle = std::make_unique<style::TextStyle>(style::TextStyle{
|
||||
.font = font,
|
||||
.linkFont = font,
|
||||
.linkFontOver = font,
|
||||
});
|
||||
};
|
||||
const auto text = _id.user->shortName();
|
||||
if (_nameText != text) {
|
||||
_name.reset();
|
||||
_nameText = text;
|
||||
}
|
||||
if (!_name) {
|
||||
_nameAvailableWidth = 0;
|
||||
_name.emplace(*_nameStyle, _nameText);
|
||||
}
|
||||
const auto available = layout.nameBoundingRect.width();
|
||||
const auto wasCut = (_nameAvailableWidth < _name->maxWidth());
|
||||
const auto nowCut = (available < _name->maxWidth());
|
||||
if (_nameImage.isNull()
|
||||
|| _nameAvailableWidth != layout.nameBoundingRect.width()) {
|
||||
_nameAvailableWidth = layout.nameBoundingRect.width();
|
||||
if (_nameImage.isNull() || nowCut || wasCut) {
|
||||
const auto w = std::min(_nameAvailableWidth, _name->maxWidth());
|
||||
const auto h = _nameStyle->font->height;
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
_nameImage = QImage(
|
||||
QSize(w, h) * ratio,
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
_nameImage.setDevicePixelRatio(ratio);
|
||||
_nameImage.fill(Qt::transparent);
|
||||
auto p = Painter(&_nameImage);
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
p.setFont(_nameStyle->font);
|
||||
p.setPen(Qt::white);
|
||||
_name->drawLeftElided(p, 0, 0, w, w);
|
||||
}
|
||||
}
|
||||
return _nameImage;
|
||||
}
|
||||
|
||||
QPoint Sibling::namePosition(
|
||||
const SiblingLayout &layout,
|
||||
const QImage &image) const {
|
||||
const auto size = image.size() / image.devicePixelRatio();
|
||||
const auto width = size.width();
|
||||
const auto left = layout.geometry.x()
|
||||
+ (layout.geometry.width() - width) / 2;
|
||||
if (left < layout.nameBoundingRect.x()) {
|
||||
return layout.nameBoundingRect.topLeft();
|
||||
} else if (left + width > layout.nameBoundingRect.x() + layout.nameBoundingRect.width()) {
|
||||
return layout.nameBoundingRect.topLeft()
|
||||
+ QPoint(layout.nameBoundingRect.width() - width, 0);
|
||||
}
|
||||
const auto top = layout.nameBoundingRect.y()
|
||||
+ layout.nameBoundingRect.height()
|
||||
- size.height();
|
||||
return QPoint(left, top);
|
||||
}
|
||||
|
||||
void Sibling::check() {
|
||||
|
|
|
@ -10,10 +10,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_stories.h"
|
||||
|
||||
#include "ui/effects/animations.h"
|
||||
#include "ui/userpic_view.h"
|
||||
|
||||
namespace style {
|
||||
struct TextStyle;
|
||||
} // namespace style
|
||||
|
||||
namespace Media::Stories {
|
||||
|
||||
class Controller;
|
||||
struct SiblingView;
|
||||
struct SiblingLayout;
|
||||
|
||||
class Sibling final {
|
||||
public:
|
||||
|
@ -25,7 +32,9 @@ public:
|
|||
[[nodiscard]] Data::FullStoryId shownId() const;
|
||||
[[nodiscard]] bool shows(const Data::StoriesList &list) const;
|
||||
|
||||
[[nodiscard]] QImage image() const;
|
||||
[[nodiscard]] SiblingView view(
|
||||
const SiblingLayout &layout,
|
||||
float64 over);
|
||||
|
||||
private:
|
||||
class Loader;
|
||||
|
@ -34,6 +43,12 @@ private:
|
|||
|
||||
void check();
|
||||
|
||||
[[nodiscard]] QImage userpicImage(const SiblingLayout &layout);
|
||||
[[nodiscard]] QImage nameImage(const SiblingLayout &layout);
|
||||
[[nodiscard]] QPoint namePosition(
|
||||
const SiblingLayout &layout,
|
||||
const QImage &image) const;
|
||||
|
||||
const not_null<Controller*> _controller;
|
||||
|
||||
Data::FullStoryId _id;
|
||||
|
@ -41,6 +56,17 @@ private:
|
|||
QImage _good;
|
||||
Ui::Animations::Simple _goodShown;
|
||||
|
||||
QImage _userpicImage;
|
||||
InMemoryKey _userpicKey = {};
|
||||
Ui::PeerUserpicView _userpicView;
|
||||
|
||||
QImage _nameImage;
|
||||
std::unique_ptr<style::TextStyle> _nameStyle;
|
||||
std::optional<Ui::Text::String> _name;
|
||||
QString _nameText;
|
||||
int _nameAvailableWidth = 0;
|
||||
int _nameFontSize = 0;
|
||||
|
||||
std::unique_ptr<Loader> _loader;
|
||||
|
||||
};
|
||||
|
|
|
@ -36,19 +36,19 @@ bool View::canDownload() const {
|
|||
return _controller->canDownload();
|
||||
}
|
||||
|
||||
QRect View::contentGeometry() const {
|
||||
QRect View::finalShownGeometry() const {
|
||||
return _controller->layout().content;
|
||||
}
|
||||
|
||||
rpl::producer<QRect> View::contentGeometryValue() const {
|
||||
rpl::producer<QRect> View::finalShownGeometryValue() const {
|
||||
return _controller->layoutValue(
|
||||
) | rpl::map([=](const Layout &layout) {
|
||||
return layout.content;
|
||||
}) | rpl::distinct_until_changed();
|
||||
}
|
||||
|
||||
float64 View::contentFade() const {
|
||||
return _controller->contentFade();
|
||||
ContentLayout View::contentLayout() const {
|
||||
return _controller->contentLayout();
|
||||
}
|
||||
|
||||
void View::updatePlayback(const Player::TrackState &state) {
|
||||
|
@ -75,12 +75,8 @@ void View::togglePaused(bool paused) {
|
|||
_controller->togglePaused(paused);
|
||||
}
|
||||
|
||||
SiblingView View::siblingLeft() const {
|
||||
return _controller->siblingLeft();
|
||||
}
|
||||
|
||||
SiblingView View::siblingRight() const {
|
||||
return _controller->siblingRight();
|
||||
SiblingView View::sibling(SiblingType type) const {
|
||||
return _controller->sibling(type);
|
||||
}
|
||||
|
||||
rpl::lifetime &View::lifetime() {
|
||||
|
|
|
@ -20,9 +20,22 @@ namespace Media::Stories {
|
|||
class Delegate;
|
||||
class Controller;
|
||||
|
||||
struct ContentLayout {
|
||||
QRect geometry;
|
||||
float64 fade = 0.;
|
||||
float64 radius = 0.;
|
||||
};
|
||||
|
||||
enum class SiblingType;
|
||||
|
||||
struct SiblingView {
|
||||
QImage image;
|
||||
QRect geometry;
|
||||
ContentLayout layout;
|
||||
QImage userpic;
|
||||
QPoint userpicPosition;
|
||||
QImage name;
|
||||
QPoint namePosition;
|
||||
float64 nameOpacity = 0.;
|
||||
|
||||
[[nodiscard]] bool valid() const {
|
||||
return !image.isNull();
|
||||
|
@ -44,11 +57,10 @@ public:
|
|||
void ready();
|
||||
|
||||
[[nodiscard]] bool canDownload() const;
|
||||
[[nodiscard]] QRect contentGeometry() const;
|
||||
[[nodiscard]] rpl::producer<QRect> contentGeometryValue() const;
|
||||
[[nodiscard]] float64 contentFade() const;
|
||||
[[nodiscard]] SiblingView siblingLeft() const;
|
||||
[[nodiscard]] SiblingView siblingRight() const;
|
||||
[[nodiscard]] QRect finalShownGeometry() const;
|
||||
[[nodiscard]] rpl::producer<QRect> finalShownGeometryValue() const;
|
||||
[[nodiscard]] ContentLayout contentLayout() const;
|
||||
[[nodiscard]] SiblingView sibling(SiblingType type) const;
|
||||
|
||||
void updatePlayback(const Player::TrackState &state);
|
||||
|
||||
|
|
|
@ -406,6 +406,7 @@ pipVolumeIcon2Over: icon {{ "player/player_volume_on", mediaviewPipControlsFgOve
|
|||
speedSliderDividerSize: size(2px, 8px);
|
||||
|
||||
storiesMaxSize: size(405px, 720px);
|
||||
storiesMaxNameFontSize: 17px;
|
||||
storiesRadius: 8px;
|
||||
storiesControlSize: 64px;
|
||||
storiesLeft: icon {{ "mediaview/stories_next-flip_horizontal", mediaviewControlFg }};
|
||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "ui/gl/gl_shader.h"
|
||||
#include "ui/painter.h"
|
||||
#include "media/stories/media_stories_view.h"
|
||||
#include "media/streaming/media_streaming_common.h"
|
||||
#include "platform/platform_overlay_widget.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
|
@ -133,7 +134,11 @@ void OverlayWidget::RendererGL::init(
|
|||
constexpr auto kRoundingQuads = 4;
|
||||
constexpr auto kRoundingVertices = kRoundingQuads * 6;
|
||||
constexpr auto kRoundingValues = kRoundingVertices * 2;
|
||||
constexpr auto kValues = kQuadValues + kControlsValues + kRoundingValues;
|
||||
constexpr auto kStoriesSiblingValues = kStoriesSiblingPartsCount * 16;
|
||||
constexpr auto kValues = kQuadValues
|
||||
+ kControlsValues
|
||||
+ kRoundingValues
|
||||
+ kStoriesSiblingValues;
|
||||
|
||||
_contentBuffer.emplace();
|
||||
_contentBuffer->setUsagePattern(QOpenGLBuffer::DynamicDraw);
|
||||
|
@ -315,7 +320,7 @@ void OverlayWidget::RendererGL::paintTransformedVideoFrame(
|
|||
_streamedIndex = _owner->streamedIndex();
|
||||
|
||||
_f->glActiveTexture(GL_TEXTURE0);
|
||||
_textures.bind(*_f, 1);
|
||||
_textures.bind(*_f, 3);
|
||||
if (upload) {
|
||||
_f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
uploadTexture(
|
||||
|
@ -328,7 +333,7 @@ void OverlayWidget::RendererGL::paintTransformedVideoFrame(
|
|||
_lumaSize = yuv->size;
|
||||
}
|
||||
_f->glActiveTexture(GL_TEXTURE1);
|
||||
_textures.bind(*_f, 2);
|
||||
_textures.bind(*_f, 4);
|
||||
if (upload) {
|
||||
uploadTexture(
|
||||
nv12 ? GL_RG : GL_ALPHA,
|
||||
|
@ -350,7 +355,7 @@ void OverlayWidget::RendererGL::paintTransformedVideoFrame(
|
|||
_controlsFadeImage.bind(*_f);
|
||||
} else {
|
||||
_f->glActiveTexture(GL_TEXTURE2);
|
||||
_textures.bind(*_f, 3);
|
||||
_textures.bind(*_f, 5);
|
||||
if (upload) {
|
||||
uploadTexture(
|
||||
GL_ALPHA,
|
||||
|
@ -383,7 +388,9 @@ void OverlayWidget::RendererGL::paintTransformedStaticContent(
|
|||
const QImage &image,
|
||||
ContentGeometry geometry,
|
||||
bool semiTransparent,
|
||||
bool fillTransparentBackground) {
|
||||
bool fillTransparentBackground,
|
||||
int index) {
|
||||
Expects(index >= 0 && index < 3);
|
||||
Expects(image.isNull()
|
||||
|| image.format() == QImage::Format_RGB32
|
||||
|| image.format() == QImage::Format_ARGB32_Premultiplied);
|
||||
|
@ -409,11 +416,11 @@ void OverlayWidget::RendererGL::paintTransformedStaticContent(
|
|||
}
|
||||
|
||||
_f->glActiveTexture(GL_TEXTURE0);
|
||||
_textures.bind(*_f, 0);
|
||||
_textures.bind(*_f, index);
|
||||
const auto cacheKey = image.isNull() ? qint64(-1) : image.cacheKey();
|
||||
const auto upload = (_cacheKey != cacheKey);
|
||||
const auto upload = (_cacheKeys[index] != cacheKey);
|
||||
if (upload) {
|
||||
_cacheKey = cacheKey;
|
||||
_cacheKeys[index] = cacheKey;
|
||||
if (image.isNull()) {
|
||||
// Upload transparent 2x2 texture.
|
||||
const auto stride = 2;
|
||||
|
@ -853,6 +860,54 @@ void OverlayWidget::RendererGL::paintRoundedCorners(int radius) {
|
|||
|
||||
_f->glDisableVertexAttribArray(position);
|
||||
}
|
||||
|
||||
void OverlayWidget::RendererGL::paintStoriesSiblingPart(
|
||||
int index,
|
||||
const QImage &image,
|
||||
QRect rect,
|
||||
float64 opacity) {
|
||||
Expects(index >= 0 && index < kStoriesSiblingPartsCount);
|
||||
|
||||
_f->glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
auto &part = _storiesSiblingParts[index];
|
||||
part.setImage(image);
|
||||
part.bind(*_f);
|
||||
|
||||
const auto textured = part.texturedRect(
|
||||
rect,
|
||||
QRect(QPoint(), image.size()));
|
||||
const auto geometry = transformRect(textured.geometry);
|
||||
const GLfloat coords[] = {
|
||||
geometry.left(), geometry.top(),
|
||||
textured.texture.left(), textured.texture.bottom(),
|
||||
|
||||
geometry.right(), geometry.top(),
|
||||
textured.texture.right(), textured.texture.bottom(),
|
||||
|
||||
geometry.right(), geometry.bottom(),
|
||||
textured.texture.right(), textured.texture.top(),
|
||||
|
||||
geometry.left(), geometry.bottom(),
|
||||
textured.texture.left(), textured.texture.top(),
|
||||
};
|
||||
const auto offset = kControlsOffset
|
||||
+ (kControlsCount * kControlValues) / 4
|
||||
+ (6 * 2 * 4) / 4 // rounding
|
||||
+ (index * 4);
|
||||
const auto byteOffset = offset * 4 * sizeof(GLfloat);
|
||||
_contentBuffer->write(byteOffset, coords, sizeof(coords));
|
||||
|
||||
_controlsProgram->bind();
|
||||
_controlsProgram->setUniformValue("viewport", _uniformViewport);
|
||||
_contentBuffer->write(
|
||||
offset * 4 * sizeof(GLfloat),
|
||||
coords,
|
||||
sizeof(coords));
|
||||
_controlsProgram->setUniformValue("g_opacity", GLfloat(opacity));
|
||||
FillTexturedRectangle(*_f, &*_controlsProgram, offset);
|
||||
}
|
||||
|
||||
//
|
||||
//void OverlayWidget::RendererGL::invalidate() {
|
||||
// _trackFrameIndex = -1;
|
||||
|
|
|
@ -48,7 +48,8 @@ private:
|
|||
const QImage &image,
|
||||
ContentGeometry geometry,
|
||||
bool semiTransparent,
|
||||
bool fillTransparentBackground) override;
|
||||
bool fillTransparentBackground,
|
||||
int index = 0) override;
|
||||
void paintTransformedContent(
|
||||
not_null<QOpenGLShaderProgram*> program,
|
||||
ContentGeometry geometry,
|
||||
|
@ -72,6 +73,11 @@ private:
|
|||
void paintCaption(QRect outer, float64 opacity) override;
|
||||
void paintGroupThumbs(QRect outer, float64 opacity) override;
|
||||
void paintRoundedCorners(int radius) override;
|
||||
void paintStoriesSiblingPart(
|
||||
int index,
|
||||
const QImage &image,
|
||||
QRect rect,
|
||||
float64 opacity = 1.) override;
|
||||
|
||||
//void invalidate();
|
||||
|
||||
|
@ -117,11 +123,11 @@ private:
|
|||
std::optional<QOpenGLShaderProgram> _fillProgram;
|
||||
std::optional<QOpenGLShaderProgram> _controlsProgram;
|
||||
std::optional<QOpenGLShaderProgram> _roundedCornersProgram;
|
||||
Ui::GL::Textures<4> _textures;
|
||||
Ui::GL::Textures<6> _textures; // image, sibling, right sibling, y, u, v
|
||||
QSize _rgbaSize;
|
||||
QSize _lumaSize;
|
||||
QSize _chromaSize;
|
||||
qint64 _cacheKey = 0;
|
||||
qint64 _cacheKeys[3] = { 0 }; // image, sibling, right sibling
|
||||
int _trackFrameIndex = 0;
|
||||
int _streamedIndex = 0;
|
||||
bool _chromaNV12 = false;
|
||||
|
@ -136,6 +142,9 @@ private:
|
|||
Ui::GL::Image _groupThumbsImage;
|
||||
Ui::GL::Image _controlsImage;
|
||||
|
||||
static constexpr auto kStoriesSiblingPartsCount = 4;
|
||||
Ui::GL::Image _storiesSiblingParts[kStoriesSiblingPartsCount];
|
||||
|
||||
static constexpr auto kControlsCount = 5;
|
||||
[[nodiscard]] static Control ControlMeta(
|
||||
OverState control,
|
||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "media/view/media_view_overlay_raster.h"
|
||||
|
||||
#include "ui/painter.h"
|
||||
#include "media/stories/media_stories_view.h"
|
||||
#include "media/view/media_view_pip.h"
|
||||
#include "platform/platform_overlay_widget.h"
|
||||
#include "styles/style_media_view.h"
|
||||
|
@ -15,14 +16,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
namespace Media::View {
|
||||
|
||||
OverlayWidget::RendererSW::RendererSW(not_null<OverlayWidget*> owner)
|
||||
: _owner(owner)
|
||||
, _transparentBrush(style::TransparentPlaceholder()) {
|
||||
: _owner(owner)
|
||||
, _transparentBrush(style::TransparentPlaceholder()) {
|
||||
}
|
||||
|
||||
void OverlayWidget::RendererSW::paintFallback(
|
||||
Painter &&p,
|
||||
const QRegion &clip,
|
||||
Ui::GL::Backend backend) {
|
||||
Painter &&p,
|
||||
const QRegion &clip,
|
||||
Ui::GL::Backend backend) {
|
||||
_p = &p;
|
||||
_clip = &clip;
|
||||
_clipOuter = clip.boundingRect();
|
||||
|
@ -48,8 +49,8 @@ void OverlayWidget::RendererSW::paintBackground() {
|
|||
}
|
||||
|
||||
QRect OverlayWidget::RendererSW::TransformRect(
|
||||
QRectF geometry,
|
||||
int rotation) {
|
||||
QRectF geometry,
|
||||
int rotation) {
|
||||
const auto center = geometry.center();
|
||||
const auto rect = ((rotation % 180) == 90)
|
||||
? QRectF(
|
||||
|
@ -66,7 +67,7 @@ QRect OverlayWidget::RendererSW::TransformRect(
|
|||
}
|
||||
|
||||
void OverlayWidget::RendererSW::paintTransformedVideoFrame(
|
||||
ContentGeometry geometry) {
|
||||
ContentGeometry geometry) {
|
||||
Expects(_owner->_streamed != nullptr);
|
||||
|
||||
const auto rotation = int(geometry.rotation);
|
||||
|
@ -79,10 +80,11 @@ void OverlayWidget::RendererSW::paintTransformedVideoFrame(
|
|||
}
|
||||
|
||||
void OverlayWidget::RendererSW::paintTransformedStaticContent(
|
||||
const QImage &image,
|
||||
ContentGeometry geometry,
|
||||
bool semiTransparent,
|
||||
bool fillTransparentBackground) {
|
||||
const QImage &image,
|
||||
ContentGeometry geometry,
|
||||
bool semiTransparent,
|
||||
bool fillTransparentBackground,
|
||||
int index) {
|
||||
const auto rotation = int(geometry.rotation);
|
||||
const auto rect = TransformRect(geometry.rect, rotation);
|
||||
if (!rect.intersects(_clipOuter)) {
|
||||
|
@ -99,8 +101,8 @@ void OverlayWidget::RendererSW::paintTransformedStaticContent(
|
|||
}
|
||||
|
||||
void OverlayWidget::RendererSW::paintControlsFade(
|
||||
QRect geometry,
|
||||
float64 opacity) {
|
||||
QRect geometry,
|
||||
float64 opacity) {
|
||||
_p->setOpacity(opacity);
|
||||
_p->setClipRect(geometry);
|
||||
const auto width = _owner->width();
|
||||
|
@ -134,9 +136,9 @@ void OverlayWidget::RendererSW::paintControlsFade(
|
|||
}
|
||||
|
||||
void OverlayWidget::RendererSW::paintTransformedImage(
|
||||
const QImage &image,
|
||||
QRect rect,
|
||||
int rotation) {
|
||||
const QImage &image,
|
||||
QRect rect,
|
||||
int rotation) {
|
||||
PainterHighQualityEnabler hq(*_p);
|
||||
if (UsePainterRotation(rotation)) {
|
||||
if (rotation) {
|
||||
|
@ -153,9 +155,9 @@ void OverlayWidget::RendererSW::paintTransformedImage(
|
|||
}
|
||||
|
||||
void OverlayWidget::RendererSW::paintRadialLoading(
|
||||
QRect inner,
|
||||
bool radial,
|
||||
float64 radialOpacity) {
|
||||
QRect inner,
|
||||
bool radial,
|
||||
float64 radialOpacity) {
|
||||
_owner->paintRadialLoadingContent(*_p, inner, radial, radialOpacity);
|
||||
}
|
||||
|
||||
|
@ -164,8 +166,8 @@ void OverlayWidget::RendererSW::paintThemePreview(QRect outer) {
|
|||
}
|
||||
|
||||
void OverlayWidget::RendererSW::paintDocumentBubble(
|
||||
QRect outer,
|
||||
QRect icon) {
|
||||
QRect outer,
|
||||
QRect icon) {
|
||||
if (outer.intersects(_clipOuter)) {
|
||||
_owner->paintDocumentBubbleContent(*_p, outer, icon, _clipOuter);
|
||||
if (icon.intersects(_clipOuter)) {
|
||||
|
@ -184,12 +186,12 @@ void OverlayWidget::RendererSW::paintControlsStart() {
|
|||
}
|
||||
|
||||
void OverlayWidget::RendererSW::paintControl(
|
||||
OverState control,
|
||||
QRect over,
|
||||
float64 overOpacity,
|
||||
QRect inner,
|
||||
float64 innerOpacity,
|
||||
const style::icon &icon) {
|
||||
OverState control,
|
||||
QRect over,
|
||||
float64 overOpacity,
|
||||
QRect inner,
|
||||
float64 innerOpacity,
|
||||
const style::icon &icon) {
|
||||
if (!over.isEmpty() && !over.intersects(_clipOuter)) {
|
||||
return;
|
||||
}
|
||||
|
@ -230,6 +232,21 @@ void OverlayWidget::RendererSW::paintRoundedCorners(int radius) {
|
|||
// The RpWindow rounding overlay will do the job.
|
||||
}
|
||||
|
||||
void OverlayWidget::RendererSW::paintStoriesSiblingPart(
|
||||
int index,
|
||||
const QImage &image,
|
||||
QRect rect,
|
||||
float64 opacity) {
|
||||
const auto changeOpacity = (opacity != 1.);
|
||||
if (changeOpacity) {
|
||||
_p->setOpacity(opacity);
|
||||
}
|
||||
_p->drawImage(rect, image);
|
||||
if (changeOpacity) {
|
||||
_p->setOpacity(1.);
|
||||
}
|
||||
}
|
||||
|
||||
void OverlayWidget::RendererSW::validateOverControlImage() {
|
||||
const auto size = QSize(st::mediaviewIconOver, st::mediaviewIconOver);
|
||||
const auto alpha = base::SafeRound(kOverBackgroundOpacity * 255);
|
||||
|
|
|
@ -27,7 +27,8 @@ private:
|
|||
const QImage &image,
|
||||
ContentGeometry geometry,
|
||||
bool semiTransparent,
|
||||
bool fillTransparentBackground) override;
|
||||
bool fillTransparentBackground,
|
||||
int index = 0) override;
|
||||
void paintTransformedImage(
|
||||
const QImage &image,
|
||||
QRect rect,
|
||||
|
@ -52,6 +53,11 @@ private:
|
|||
void paintCaption(QRect outer, float64 opacity) override;
|
||||
void paintGroupThumbs(QRect outer, float64 opacity) override;
|
||||
void paintRoundedCorners(int radius) override;
|
||||
void paintStoriesSiblingPart(
|
||||
int index,
|
||||
const QImage &image,
|
||||
QRect rect,
|
||||
float64 opacity = 1.) override;
|
||||
|
||||
void validateOverControlImage();
|
||||
|
||||
|
|
|
@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "media/view/media_view_overlay_widget.h"
|
||||
|
||||
namespace Media::Stories {
|
||||
struct SiblingView;
|
||||
} // namespace Media::Stories
|
||||
|
||||
namespace Media::View {
|
||||
|
||||
class OverlayWidget::Renderer : public Ui::GL::Renderer {
|
||||
|
@ -19,7 +23,8 @@ public:
|
|||
const QImage &image,
|
||||
ContentGeometry geometry,
|
||||
bool semiTransparent,
|
||||
bool fillTransparentBackground) = 0;
|
||||
bool fillTransparentBackground,
|
||||
int index = 0) = 0; // image, left sibling, right sibling
|
||||
virtual void paintRadialLoading(
|
||||
QRect inner,
|
||||
bool radial,
|
||||
|
@ -39,7 +44,11 @@ public:
|
|||
virtual void paintCaption(QRect outer, float64 opacity) = 0;
|
||||
virtual void paintGroupThumbs(QRect outer, float64 opacity) = 0;
|
||||
virtual void paintRoundedCorners(int radius) = 0;
|
||||
|
||||
virtual void paintStoriesSiblingPart(
|
||||
int index,
|
||||
const QImage &image,
|
||||
QRect rect,
|
||||
float64 opacity = 1.) = 0;
|
||||
};
|
||||
|
||||
} // namespace Media::View
|
||||
|
|
|
@ -125,6 +125,9 @@ constexpr auto kIdsLimit = 48;
|
|||
// Preload next messages if we went further from current than that.
|
||||
constexpr auto kIdsPreloadAfter = 28;
|
||||
|
||||
constexpr auto kLeftSiblingTextureIndex = 1;
|
||||
constexpr auto kRightSiblingTextureIndex = 2;
|
||||
|
||||
class PipDelegate final : public Pip::Delegate {
|
||||
public:
|
||||
PipDelegate(QWidget *parent, not_null<Main::Session*> session);
|
||||
|
@ -1444,17 +1447,18 @@ bool OverlayWidget::updateControlsAnimation(crl::time now) {
|
|||
}
|
||||
_helper->setControlsOpacity(_controlsOpacity.current());
|
||||
const auto content = finalContentRect();
|
||||
const auto siblingType = (_over == OverLeftStories)
|
||||
? Stories::SiblingType::Left
|
||||
: Stories::SiblingType::Right;
|
||||
const auto toUpdate = QRegion()
|
||||
+ (_over == OverLeftNav ? _leftNavOver : _leftNavIcon)
|
||||
+ (_over == OverRightNav ? _rightNavOver : _rightNavIcon)
|
||||
+ (_over == OverSave ? _saveNavOver : _saveNavIcon)
|
||||
+ (_over == OverRotate ? _rotateNavOver : _rotateNavIcon)
|
||||
+ (_over == OverMore ? _moreNavOver : _moreNavIcon)
|
||||
+ ((_stories && _over == OverLeftStories)
|
||||
? _stories->siblingLeft().geometry
|
||||
: QRect())
|
||||
+ ((_stories && _over == OverRightStories)
|
||||
? _stories->siblingRight().geometry
|
||||
+ ((_stories
|
||||
&& (_over == OverLeftStories && _over == OverRightStories))
|
||||
? _stories->sibling(siblingType).layout.geometry
|
||||
: QRect())
|
||||
+ _headerNav
|
||||
+ _nameNav
|
||||
|
@ -1492,8 +1496,9 @@ QRect OverlayWidget::finalContentRect() const {
|
|||
}
|
||||
|
||||
OverlayWidget::ContentGeometry OverlayWidget::contentGeometry() const {
|
||||
const auto fade = _stories ? _stories->contentFade() : 0.;
|
||||
const auto radius = _stories ? float64(st::storiesRadius) : 0.;
|
||||
if (_stories) {
|
||||
return storiesContentGeometry(_stories->contentLayout());
|
||||
}
|
||||
const auto controlsOpacity = _controlsOpacity.current();
|
||||
const auto toRotation = qreal(finalContentRotation());
|
||||
const auto toRectRotated = QRectF(finalContentRect());
|
||||
|
@ -1506,7 +1511,7 @@ OverlayWidget::ContentGeometry OverlayWidget::contentGeometry() const {
|
|||
toRectRotated.width())
|
||||
: toRectRotated;
|
||||
if (!_geometryAnimation.animating()) {
|
||||
return { toRect, toRotation, controlsOpacity, fade, radius };
|
||||
return { toRect, toRotation, controlsOpacity };
|
||||
}
|
||||
const auto fromRect = _oldGeometry.rect;
|
||||
const auto fromRotation = _oldGeometry.rotation;
|
||||
|
@ -1529,7 +1534,17 @@ OverlayWidget::ContentGeometry OverlayWidget::contentGeometry() const {
|
|||
fromRect.width() + (toRect.width() - fromRect.width()) * progress,
|
||||
fromRect.height() + (toRect.height() - fromRect.height()) * progress
|
||||
);
|
||||
return { useRect, useRotation, controlsOpacity, fade, radius };
|
||||
return { useRect, useRotation, controlsOpacity };
|
||||
}
|
||||
|
||||
OverlayWidget::ContentGeometry OverlayWidget::storiesContentGeometry(
|
||||
const Stories::ContentLayout &layout) const {
|
||||
return {
|
||||
.rect = QRectF(layout.geometry),
|
||||
.controlsOpacity = 0., // #TODO stories ?..
|
||||
.fade = layout.fade,
|
||||
.roundRadius = layout.radius,
|
||||
};
|
||||
}
|
||||
|
||||
void OverlayWidget::updateContentRect() {
|
||||
|
@ -1568,7 +1583,7 @@ void OverlayWidget::recountSkipTop() {
|
|||
|
||||
void OverlayWidget::resizeContentByScreenSize() {
|
||||
if (_stories) {
|
||||
const auto content = _stories->contentGeometry();
|
||||
const auto content = _stories->finalShownGeometry();
|
||||
_x = content.x();
|
||||
_y = content.y();
|
||||
_w = content.width();
|
||||
|
@ -4005,6 +4020,11 @@ void OverlayWidget::storiesTogglePaused(bool paused) {
|
|||
}
|
||||
}
|
||||
|
||||
float64 OverlayWidget::storiesSiblingOver(Stories::SiblingType type) {
|
||||
return (type == Stories::SiblingType::Left)
|
||||
? overLevel(OverLeftStories)
|
||||
: overLevel(OverRightStories);
|
||||
}
|
||||
void OverlayWidget::storiesRepaint() {
|
||||
update();
|
||||
}
|
||||
|
@ -4165,20 +4185,34 @@ void OverlayWidget::paint(not_null<Renderer*> renderer) {
|
|||
}
|
||||
paintRadialLoading(renderer);
|
||||
if (_stories) {
|
||||
const auto radius = float64(st::storiesRadius);
|
||||
if (const auto left = _stories->siblingLeft()) {
|
||||
using namespace Stories;
|
||||
const auto paint = [&](const SiblingView &view, int index) {
|
||||
renderer->paintTransformedStaticContent(
|
||||
left.image,
|
||||
{ .rect = left.geometry, .roundRadius = radius },
|
||||
view.image,
|
||||
storiesContentGeometry(view.layout),
|
||||
false, // semi-transparent
|
||||
false); // fill transparent background
|
||||
false, // fill transparent background
|
||||
index);
|
||||
const auto base = (index - 1) * 2;
|
||||
const auto userpicSize = view.userpic.size()
|
||||
/ view.userpic.devicePixelRatio();
|
||||
renderer->paintStoriesSiblingPart(
|
||||
base,
|
||||
view.userpic,
|
||||
QRect(view.userpicPosition, userpicSize));
|
||||
const auto nameSize = view.name.size()
|
||||
/ view.name.devicePixelRatio();
|
||||
renderer->paintStoriesSiblingPart(
|
||||
base + 1,
|
||||
view.name,
|
||||
QRect(view.namePosition, nameSize),
|
||||
view.nameOpacity);
|
||||
};
|
||||
if (const auto left = _stories->sibling(SiblingType::Left)) {
|
||||
paint(left, kLeftSiblingTextureIndex);
|
||||
}
|
||||
if (const auto right = _stories->siblingRight()) {
|
||||
renderer->paintTransformedStaticContent(
|
||||
right.image,
|
||||
{ .rect = right.geometry, .roundRadius = radius },
|
||||
false, // semi-transparent
|
||||
false); // fill transparent background
|
||||
if (const auto right = _stories->sibling(SiblingType::Right)) {
|
||||
paint(right, kRightSiblingTextureIndex);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -4924,7 +4958,7 @@ void OverlayWidget::setStoriesUser(UserData *user) {
|
|||
_storiesSession = session;
|
||||
const auto delegate = static_cast<Stories::Delegate*>(this);
|
||||
_stories = std::make_unique<Stories::View>(delegate);
|
||||
_stories->contentGeometryValue(
|
||||
_stories->finalShownGeometryValue(
|
||||
) | rpl::skip(1) | rpl::start_with_next([=] {
|
||||
updateControlsGeometry();
|
||||
}, _stories->lifetime());
|
||||
|
@ -5155,6 +5189,7 @@ void OverlayWidget::handleMouseMove(QPoint position) {
|
|||
}
|
||||
|
||||
void OverlayWidget::updateOverRect(OverState state) {
|
||||
using Type = Stories::SiblingType;
|
||||
switch (state) {
|
||||
case OverLeftNav:
|
||||
update(_stories ? _leftNavIcon : _leftNavOver);
|
||||
|
@ -5163,10 +5198,14 @@ void OverlayWidget::updateOverRect(OverState state) {
|
|||
update(_stories ? _rightNavIcon : _rightNavOver);
|
||||
break;
|
||||
case OverLeftStories:
|
||||
update(_stories ? _stories->siblingLeft().geometry : QRect());
|
||||
update(_stories
|
||||
? _stories->sibling(Type::Left).layout.geometry :
|
||||
QRect());
|
||||
break;
|
||||
case OverRightStories:
|
||||
update(_stories ? _stories->siblingRight().geometry : QRect());
|
||||
update(_stories
|
||||
? _stories->sibling(Type::Right).layout.geometry
|
||||
: QRect());
|
||||
break;
|
||||
case OverName: update(_nameNav); break;
|
||||
case OverDate: update(_dateNav); break;
|
||||
|
@ -5250,19 +5289,27 @@ void OverlayWidget::updateOver(QPoint pos) {
|
|||
|
||||
if (_pressed || _dragging) return;
|
||||
|
||||
using SiblingType = Stories::SiblingType;
|
||||
if (_fullScreenVideo) {
|
||||
updateOverState(OverVideo);
|
||||
} else if (_leftNavVisible && _leftNav.contains(pos)) {
|
||||
updateOverState(OverLeftNav);
|
||||
} else if (_stories && _stories->siblingLeft().geometry.contains(pos)) {
|
||||
updateOverState(OverLeftStories);
|
||||
} else if (_stories && _stories->siblingRight().geometry.contains(pos)) {
|
||||
updateOverState(OverRightStories);
|
||||
} else if (_rightNavVisible && _rightNav.contains(pos)) {
|
||||
updateOverState(OverRightNav);
|
||||
} else if (_stories
|
||||
&& _stories->sibling(
|
||||
SiblingType::Left).layout.geometry.contains(pos)) {
|
||||
updateOverState(OverLeftStories);
|
||||
} else if (_stories
|
||||
&& _stories->sibling(
|
||||
SiblingType::Right).layout.geometry.contains(pos)) {
|
||||
updateOverState(OverRightStories);
|
||||
} else if (!_stories && _from && _nameNav.contains(pos)) {
|
||||
updateOverState(OverName);
|
||||
} else if (!_stories && _message && _message->isRegular() && _dateNav.contains(pos)) {
|
||||
} else if (!_stories
|
||||
&& _message
|
||||
&& _message->isRegular()
|
||||
&& _dateNav.contains(pos)) {
|
||||
updateOverState(OverDate);
|
||||
} else if (!_stories && _headerHasLink && _headerNav.contains(pos)) {
|
||||
updateOverState(OverHeader);
|
||||
|
@ -5270,7 +5317,9 @@ void OverlayWidget::updateOver(QPoint pos) {
|
|||
updateOverState(OverSave);
|
||||
} else if (_rotateVisible && _rotateNav.contains(pos)) {
|
||||
updateOverState(OverRotate);
|
||||
} else if (_document && documentBubbleShown() && _docIconRect.contains(pos)) {
|
||||
} else if (_document
|
||||
&& documentBubbleShown()
|
||||
&& _docIconRect.contains(pos)) {
|
||||
updateOverState(OverIcon);
|
||||
} else if (_moreNav.contains(pos)) {
|
||||
updateOverState(OverMore);
|
||||
|
|
|
@ -66,6 +66,7 @@ enum class Error;
|
|||
|
||||
namespace Media::Stories {
|
||||
class View;
|
||||
struct ContentLayout;
|
||||
} // namespace Media::Stories
|
||||
|
||||
namespace Media::View {
|
||||
|
@ -235,6 +236,7 @@ private:
|
|||
void storiesJumpTo(Data::FullStoryId id) override;
|
||||
bool storiesPaused() override;
|
||||
void storiesTogglePaused(bool paused) override;
|
||||
float64 storiesSiblingOver(Stories::SiblingType type) override;
|
||||
void storiesRepaint() override;
|
||||
|
||||
void hideControls(bool force = false);
|
||||
|
@ -390,6 +392,8 @@ private:
|
|||
[[nodiscard]] int finalContentRotation() const;
|
||||
[[nodiscard]] QRect finalContentRect() const;
|
||||
[[nodiscard]] ContentGeometry contentGeometry() const;
|
||||
[[nodiscard]] ContentGeometry storiesContentGeometry(
|
||||
const Stories::ContentLayout &layout) const;
|
||||
void updateContentRect();
|
||||
void contentSizeChanged();
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue