mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-01-21 06:51:25 +00:00
Improve pin video button design and controls hiding.
This commit is contained in:
parent
c48c4d4283
commit
445c798bbc
@ -1192,6 +1192,8 @@ GroupCallLargeVideo {
|
||||
shadowHeight: pixels;
|
||||
namePosition: point;
|
||||
pinPosition: point;
|
||||
pinPadding: margins;
|
||||
pinTextPosition: point;
|
||||
iconPosition: point;
|
||||
}
|
||||
|
||||
@ -1199,6 +1201,8 @@ groupCallLargeVideoWide: GroupCallLargeVideo {
|
||||
shadowHeight: 40px;
|
||||
namePosition: point(15px, 8px);
|
||||
pinPosition: point(18px, 18px);
|
||||
pinPadding: margins(6px, 2px, 12px, 1px);
|
||||
pinTextPosition: point(1px, 3px);
|
||||
iconPosition: point(10px, 5px);
|
||||
}
|
||||
groupCallLargeVideoNarrow: GroupCallLargeVideo(groupCallLargeVideoWide) {
|
||||
@ -1214,9 +1218,10 @@ groupCallLargeVideoNarrow: GroupCallLargeVideo(groupCallLargeVideoWide) {
|
||||
groupCallLargeVideoPin: CrossLineAnimation {
|
||||
fg: groupCallVideoTextFg;
|
||||
icon: icon {{ "calls/video_over_pin", groupCallVideoTextFg }};
|
||||
startPosition: point(5px, 2px);
|
||||
endPosition: point(20px, 17px);
|
||||
stroke: 2px;
|
||||
startPosition: point(7px, 4px);
|
||||
endPosition: point(17px, 14px);
|
||||
stroke: 3px;
|
||||
strokeDenominator: 2;
|
||||
}
|
||||
|
||||
groupCallVideoSmallSkip: 4px;
|
||||
|
@ -804,10 +804,14 @@ void GroupCall::markEndpointActive(VideoEndpoint endpoint, bool active) {
|
||||
if (!endpoint) {
|
||||
return;
|
||||
}
|
||||
const auto i = _activeVideoTracks.find(endpoint);
|
||||
const auto changed = active
|
||||
? !_activeVideoTracks.contains(endpoint)
|
||||
: _activeVideoTracks.remove(endpoint);
|
||||
if (active && changed) {
|
||||
? (i == end(_activeVideoTracks))
|
||||
: (i != end(_activeVideoTracks));
|
||||
if (!changed) {
|
||||
return;
|
||||
}
|
||||
if (active) {
|
||||
const auto i = _activeVideoTracks.emplace(
|
||||
endpoint,
|
||||
VideoTrack{
|
||||
@ -816,13 +820,14 @@ void GroupCall::markEndpointActive(VideoEndpoint endpoint, bool active) {
|
||||
.peer = endpoint.peer,
|
||||
}).first;
|
||||
addVideoOutput(i->first.id, { i->second.track->sink() });
|
||||
} else if (!active && _videoEndpointPinned.current() == endpoint) {
|
||||
_videoEndpointPinned = VideoEndpoint();
|
||||
} else {
|
||||
if (_videoEndpointPinned.current() == endpoint) {
|
||||
_videoEndpointPinned = VideoEndpoint();
|
||||
}
|
||||
_activeVideoTracks.erase(i);
|
||||
}
|
||||
updateRequestedVideoChannelsDelayed();
|
||||
if (changed) {
|
||||
_videoStreamActiveUpdates.fire(std::move(endpoint));
|
||||
}
|
||||
_videoStreamActiveUpdates.fire(std::move(endpoint));
|
||||
}
|
||||
|
||||
void GroupCall::rejoin() {
|
||||
|
@ -13,6 +13,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "webrtc/webrtc_video_track.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/abstract_button.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "ui/effects/cross_line.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "styles/style_calls.h"
|
||||
|
||||
namespace Calls::Group {
|
||||
@ -22,6 +25,32 @@ constexpr auto kShadowMaxAlpha = 80;
|
||||
|
||||
} // namespace
|
||||
|
||||
struct LargeVideo::PinButton {
|
||||
PinButton(
|
||||
not_null<QWidget*> parent,
|
||||
const style::GroupCallLargeVideo &st);
|
||||
|
||||
Ui::AbstractButton area;
|
||||
Ui::CrossLineAnimation icon;
|
||||
Ui::RoundRect background;
|
||||
Ui::Text::String text;
|
||||
QRect rect;
|
||||
Ui::Animations::Simple shownAnimation;
|
||||
bool shown = false;
|
||||
};
|
||||
|
||||
LargeVideo::PinButton::PinButton(
|
||||
not_null<QWidget*> parent,
|
||||
const style::GroupCallLargeVideo &st)
|
||||
: area(parent)
|
||||
, icon(st::groupCallLargeVideoPin)
|
||||
, background(
|
||||
(st.pinPadding.top()
|
||||
+ st::groupCallLargeVideoPin.icon.height()
|
||||
+ st.pinPadding.bottom()) / 2,
|
||||
st::radialBg) {
|
||||
}
|
||||
|
||||
LargeVideo::LargeVideo(
|
||||
QWidget *parent,
|
||||
const style::GroupCallLargeVideo &st,
|
||||
@ -30,9 +59,8 @@ LargeVideo::LargeVideo(
|
||||
rpl::producer<bool> pinned)
|
||||
: _content(parent, [=](QRect clip) { paint(clip); })
|
||||
, _st(st)
|
||||
, _pin(st::groupCallLargeVideoPin)
|
||||
, _pinButton((_st.pinPosition.x() >= 0)
|
||||
? std::make_unique<Ui::AbstractButton>(&_content)
|
||||
? std::make_unique<PinButton>(&_content, st)
|
||||
: nullptr)
|
||||
, _smallLayout(!_pinButton) {
|
||||
_content.setVisible(visible);
|
||||
@ -42,6 +70,8 @@ LargeVideo::LargeVideo(
|
||||
setup(std::move(track), std::move(pinned));
|
||||
}
|
||||
|
||||
LargeVideo::~LargeVideo() = default;
|
||||
|
||||
void LargeVideo::raise() {
|
||||
_content.raise();
|
||||
}
|
||||
@ -74,7 +104,7 @@ void LargeVideo::setControlsShown(float64 shown) {
|
||||
|
||||
rpl::producer<bool> LargeVideo::pinToggled() const {
|
||||
return _pinButton
|
||||
? _pinButton->clicks() | rpl::map([=] { return !_pinned; })
|
||||
? _pinButton->area.clicks() | rpl::map([=] { return !_pinned; })
|
||||
: rpl::never<bool>() | rpl::type_erased();
|
||||
}
|
||||
|
||||
@ -103,11 +133,16 @@ void LargeVideo::setup(
|
||||
|
||||
_content.events(
|
||||
) | rpl::start_with_next([=](not_null<QEvent*> e) {
|
||||
if (e->type() == QEvent::MouseButtonPress
|
||||
const auto type = e->type();
|
||||
if (type == QEvent::Enter && _pinButton) {
|
||||
togglePinShown(true);
|
||||
} else if (type == QEvent::Leave && _pinButton) {
|
||||
togglePinShown(false);
|
||||
} else if (type == QEvent::MouseButtonPress
|
||||
&& static_cast<QMouseEvent*>(
|
||||
e.get())->button() == Qt::LeftButton) {
|
||||
_mouseDown = true;
|
||||
} else if (e->type() == QEvent::MouseButtonRelease
|
||||
} else if (type == QEvent::MouseButtonRelease
|
||||
&& static_cast<QMouseEvent*>(
|
||||
e.get())->button() == Qt::LeftButton
|
||||
&& _mouseDown) {
|
||||
@ -151,9 +186,31 @@ void LargeVideo::setup(
|
||||
setupControls(std::move(pinned));
|
||||
}
|
||||
|
||||
void LargeVideo::togglePinShown(bool shown) {
|
||||
Expects(_pinButton != nullptr);
|
||||
|
||||
if (_pinButton->shown == shown) {
|
||||
return;
|
||||
}
|
||||
_pinButton->shown = shown;
|
||||
_pinButton->shownAnimation.start(
|
||||
[=] { updateControlsGeometry(); _content.update(); },
|
||||
shown ? 0. : 1.,
|
||||
shown ? 1. : 0.,
|
||||
st::slideWrapDuration);
|
||||
}
|
||||
|
||||
void LargeVideo::setupControls(rpl::producer<bool> pinned) {
|
||||
std::move(pinned) | rpl::start_with_next([=](bool pinned) {
|
||||
_pinned = pinned;
|
||||
if (_pinButton) {
|
||||
_pinButton->text.setText(
|
||||
st::semiboldTextStyle,
|
||||
(pinned
|
||||
? tr::lng_pinned_unpin
|
||||
: tr::lng_pinned_pin)(tr::now));
|
||||
updateControlsGeometry();
|
||||
}
|
||||
_content.update();
|
||||
}, _content.lifetime());
|
||||
|
||||
@ -165,14 +222,29 @@ void LargeVideo::setupControls(rpl::producer<bool> pinned) {
|
||||
|
||||
void LargeVideo::updateControlsGeometry() {
|
||||
if (_pinButton) {
|
||||
const auto &pin = st::groupCallLargeVideoPin.icon;
|
||||
const auto buttonWidth = pin.width() + 2 * _st.pinPosition.x();
|
||||
const auto buttonHeight = pin.height() + 2 * _st.pinPosition.y();
|
||||
_pinButton->setGeometry(
|
||||
_content.width() - buttonWidth,
|
||||
const auto &icon = st::groupCallLargeVideoPin.icon;
|
||||
const auto innerWidth = icon.width()
|
||||
+ _st.pinTextPosition.x()
|
||||
+ _pinButton->text.maxWidth();
|
||||
const auto innerHeight = icon.height();
|
||||
const auto buttonWidth = _st.pinPadding.left() + innerWidth + _st.pinPadding.right();
|
||||
const auto buttonHeight = _st.pinPadding.top() + innerHeight + _st.pinPadding.bottom();
|
||||
const auto fullWidth = _st.pinPosition.x() * 2 + buttonWidth;
|
||||
const auto fullHeight = _st.pinPosition.y() * 2 + buttonHeight;
|
||||
const auto slide = anim::interpolate(
|
||||
_st.pinPosition.y() + buttonHeight,
|
||||
0,
|
||||
_pinButton->shownAnimation.value(_pinButton->shown ? 1. : 0.));
|
||||
_pinButton->rect = QRect(
|
||||
_content.width() - _st.pinPosition.x() - buttonWidth,
|
||||
_st.pinPosition.y() - slide,
|
||||
buttonWidth,
|
||||
buttonHeight);
|
||||
_pinButton->area.setGeometry(
|
||||
_content.width() - fullWidth,
|
||||
-slide,
|
||||
fullWidth,
|
||||
fullHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,14 +307,37 @@ void LargeVideo::paint(QRect clip) {
|
||||
}
|
||||
|
||||
void LargeVideo::paintControls(Painter &p, QRect clip) {
|
||||
const auto width = _content.width();
|
||||
const auto height = _content.height();
|
||||
|
||||
// Pin.
|
||||
if (_pinButton && _pinButton->rect.intersects(clip)) {
|
||||
const auto &icon = st::groupCallLargeVideoPin.icon;
|
||||
_pinButton->background.paint(p, _pinButton->rect);
|
||||
_pinButton->icon.paint(
|
||||
p,
|
||||
_pinButton->rect.marginsRemoved(_st.pinPadding).topLeft(),
|
||||
_pinned ? 1. : 0.);
|
||||
p.setPen(st::groupCallVideoTextFg);
|
||||
_pinButton->text.drawLeft(
|
||||
p,
|
||||
(_pinButton->rect.x()
|
||||
+ _st.pinPadding.left()
|
||||
+ icon.width()
|
||||
+ _st.pinTextPosition.x()),
|
||||
(_pinButton->rect.y()
|
||||
+ _st.pinPadding.top()
|
||||
+ _st.pinTextPosition.y()),
|
||||
_pinButton->text.maxWidth(),
|
||||
width);
|
||||
}
|
||||
|
||||
const auto fullShift = _st.namePosition.y() + st::normalFont->height;
|
||||
const auto shown = _controlsShownRatio;
|
||||
if (shown == 0.) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto width = _content.width();
|
||||
const auto height = _content.height();
|
||||
const auto fullShift = _st.namePosition.y() + st::normalFont->height;
|
||||
const auto shift = anim::interpolate(fullShift, 0, shown);
|
||||
|
||||
// Shadow.
|
||||
@ -255,7 +350,7 @@ void LargeVideo::paintControls(Painter &p, QRect clip) {
|
||||
width,
|
||||
_st.shadowHeight);
|
||||
const auto shadowFill = shadowRect.intersected(clip);
|
||||
if (shadowFill.isEmpty() && _smallLayout) {
|
||||
if (shadowFill.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
const auto factor = style::DevicePixelRatio();
|
||||
@ -292,18 +387,6 @@ void LargeVideo::paintControls(Painter &p, QRect clip) {
|
||||
- st::semiboldFont->height
|
||||
+ shift);
|
||||
_track.row->name().drawLeftElided(p, nameLeft, nameTop, hasWidth, width);
|
||||
|
||||
// Pin.
|
||||
if (_pinButton) {
|
||||
const auto &pin = st::groupCallLargeVideoPin.icon;
|
||||
const auto pinLeft = (width - _st.pinPosition.x() - pin.width());
|
||||
const auto pinShift = anim::interpolate(
|
||||
_st.pinPosition.y() + pin.height(),
|
||||
0,
|
||||
shown);
|
||||
const auto pinTop = (_st.pinPosition.y() - pinShift);
|
||||
_pin.paint(p, pinLeft, pinTop, _pinned ? 1. : 0.);
|
||||
}
|
||||
}
|
||||
|
||||
QImage GenerateShadow(int height, int topAlpha, int bottomAlpha) {
|
||||
|
@ -8,8 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#pragma once
|
||||
|
||||
#include "ui/rp_widget.h"
|
||||
#include "ui/effects/cross_line.h"
|
||||
#include "ui/effects/animations.h"
|
||||
|
||||
#if 1
|
||||
#define USE_OPENGL_LARGE_VIDEO 1
|
||||
@ -63,6 +61,7 @@ public:
|
||||
bool visible,
|
||||
rpl::producer<LargeVideoTrack> track,
|
||||
rpl::producer<bool> pinned);
|
||||
~LargeVideo();
|
||||
|
||||
void raise();
|
||||
void setVisible(bool visible);
|
||||
@ -105,6 +104,8 @@ private:
|
||||
|
||||
};
|
||||
|
||||
struct PinButton;
|
||||
|
||||
void setup(
|
||||
rpl::producer<LargeVideoTrack> track,
|
||||
rpl::producer<bool> pinned);
|
||||
@ -112,13 +113,13 @@ private:
|
||||
void paint(QRect clip);
|
||||
void paintControls(Painter &p, QRect clip);
|
||||
void updateControlsGeometry();
|
||||
void togglePinShown(bool shown);
|
||||
|
||||
Content _content;
|
||||
const style::GroupCallLargeVideo &_st;
|
||||
LargeVideoTrack _track;
|
||||
QImage _shadow;
|
||||
Ui::CrossLineAnimation _pin;
|
||||
std::unique_ptr<Ui::AbstractButton> _pinButton;
|
||||
std::unique_ptr<PinButton> _pinButton;
|
||||
rpl::event_stream<> _clicks;
|
||||
const bool _smallLayout = true;
|
||||
bool _pinned = false;
|
||||
|
@ -1085,10 +1085,8 @@ void Panel::refreshTilesGeometry() {
|
||||
if (_videoTiles.empty()
|
||||
|| outer.isEmpty()
|
||||
|| _mode == PanelMode::Default) {
|
||||
trackControls(false);
|
||||
return;
|
||||
}
|
||||
trackControls(true);
|
||||
struct Geometry {
|
||||
QSize size;
|
||||
QRect columns;
|
||||
@ -1265,9 +1263,11 @@ void Panel::setupPinnedVideo() {
|
||||
raw->events(
|
||||
) | rpl::start_with_next([=](not_null<QEvent*> e) {
|
||||
if (e->type() == QEvent::Enter) {
|
||||
LOG(("Track Enter"));
|
||||
Ui::Integration::Instance().registerLeaveSubscription(raw);
|
||||
toggleWideControls(true);
|
||||
} else if (e->type() == QEvent::Leave) {
|
||||
LOG(("Track Leave"));
|
||||
Ui::Integration::Instance().unregisterLeaveSubscription(raw);
|
||||
toggleWideControls(false);
|
||||
}
|
||||
@ -1277,15 +1277,23 @@ void Panel::setupPinnedVideo() {
|
||||
}
|
||||
|
||||
void Panel::toggleWideControls(bool shown) {
|
||||
if (_wideControlsShown == shown) {
|
||||
if (_showWideControls == shown) {
|
||||
return;
|
||||
}
|
||||
_wideControlsShown = shown;
|
||||
_wideControlsAnimation.start(
|
||||
[=] { updateButtonsGeometry(); },
|
||||
shown ? 0. : 1.,
|
||||
shown ? 1. : 0.,
|
||||
st::slideWrapDuration);
|
||||
_showWideControls = shown;
|
||||
LOG(("On Main Scheduled"));
|
||||
crl::on_main(widget(), [=] {
|
||||
if (_wideControlsShown == _showWideControls) {
|
||||
return;
|
||||
}
|
||||
LOG(("On Main Fired: %1").arg(Logs::b(_showWideControls)));
|
||||
_wideControlsShown = _showWideControls;
|
||||
_wideControlsAnimation.start(
|
||||
[=] { updateButtonsGeometry(); },
|
||||
_wideControlsShown ? 0. : 1.,
|
||||
_wideControlsShown ? 1. : 0.,
|
||||
st::slideWrapDuration);
|
||||
});
|
||||
}
|
||||
|
||||
void Panel::setupJoinAsChangedToasts() {
|
||||
@ -1795,8 +1803,8 @@ bool Panel::updateMode() {
|
||||
_members->setMode(mode);
|
||||
}
|
||||
if (_pinnedVideoWrap) {
|
||||
_wideControlsShown = _showWideControls = true;
|
||||
_wideControlsAnimation.stop();
|
||||
_wideControlsShown = true;
|
||||
_pinnedVideoWrap->setVisible(mode == PanelMode::Wide);
|
||||
for (const auto &tile : _videoTiles) {
|
||||
tile.video->setVisible(mode == PanelMode::Wide);
|
||||
@ -1810,7 +1818,7 @@ bool Panel::updateMode() {
|
||||
|
||||
void Panel::refreshControlsBackground() {
|
||||
if (_mode != PanelMode::Wide) {
|
||||
_trackControlsLifetime.destroy();
|
||||
trackControls(false);
|
||||
_controlsBackground.destroy();
|
||||
} else if (_controlsBackground) {
|
||||
return;
|
||||
@ -1832,6 +1840,7 @@ void Panel::refreshControlsBackground() {
|
||||
corners->paint(p, _controlsBackground->rect());
|
||||
}, lifetime);
|
||||
|
||||
trackControls(true);
|
||||
raiseControls();
|
||||
}
|
||||
|
||||
@ -1857,8 +1866,10 @@ void Panel::trackControls(bool track) {
|
||||
raw->events(
|
||||
) | rpl::start_with_next([=](not_null<QEvent*> e) {
|
||||
if (e->type() == QEvent::Enter) {
|
||||
LOG(("Track Enter"));
|
||||
toggleWideControls(true);
|
||||
} else if (e->type() == QEvent::Leave) {
|
||||
LOG(("Track Leave"));
|
||||
toggleWideControls(false);
|
||||
}
|
||||
}, _trackControlsOverStateLifetime);
|
||||
|
@ -162,8 +162,9 @@ private:
|
||||
std::optional<QRect> _lastSmallGeometry;
|
||||
std::optional<QRect> _lastLargeGeometry;
|
||||
bool _lastLargeMaximized = false;
|
||||
bool _wideControlsShown = false;
|
||||
bool _showWideControls = false;
|
||||
bool _trackControls = false;
|
||||
bool _wideControlsShown = false;
|
||||
Ui::Animations::Simple _wideControlsAnimation;
|
||||
|
||||
object_ptr<Ui::RpWidget> _controlsBackground = { nullptr };
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit aeeb13bd029597da8cf5104c2e7c56f4641cd6b6
|
||||
Subproject commit e9fcbfcbacfe9f2f454a7bd34f1a3c5403245523
|
Loading…
Reference in New Issue
Block a user