mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-19 15:47:11 +02:00
Improve design for all controls states.
This commit is contained in:
parent
d4b8fa70a7
commit
4971e281fa
7 changed files with 274 additions and 98 deletions
|
@ -18,8 +18,6 @@ CallSignalBars {
|
|||
inactiveOpacity: double;
|
||||
}
|
||||
|
||||
callWidth: 960px;
|
||||
callHeight: 540px;
|
||||
callRadius: 6px;
|
||||
callShadow: Shadow {
|
||||
left: icon {{ "call_shadow_left", windowShadowFg }};
|
||||
|
@ -33,22 +31,60 @@ callShadow: Shadow {
|
|||
extend: margins(9px, 8px, 9px, 10px);
|
||||
fallback: windowShadowFgFallback;
|
||||
}
|
||||
callPhotoSize: 180px;
|
||||
callPhotoSmallSize: 100px;
|
||||
|
||||
callOutgoingPreviewSize: size(340px, 180px);
|
||||
callWidthMin: 380px;
|
||||
callHeightMin: 440px;
|
||||
callWidth: 960px;
|
||||
callHeight: 540px;
|
||||
|
||||
callBottomControlsHeight: 85px;
|
||||
|
||||
CallBodyLayout {
|
||||
height: pixels;
|
||||
photoTop: pixels;
|
||||
photoSize: pixels;
|
||||
nameTop: pixels;
|
||||
statusTop: pixels;
|
||||
}
|
||||
|
||||
callBodyLayout: CallBodyLayout {
|
||||
height: 284px;
|
||||
photoTop: 21px;
|
||||
photoSize: 180px;
|
||||
nameTop: 221px;
|
||||
statusTop: 254px;
|
||||
}
|
||||
callBodyWithPreview: CallBodyLayout {
|
||||
height: 185px;
|
||||
photoTop: 21px;
|
||||
photoSize: 100px;
|
||||
nameTop: 132px;
|
||||
statusTop: 163px;
|
||||
}
|
||||
|
||||
callOutgoingPreviewMin: size(360px, 120px);
|
||||
callOutgoingPreview: size(540px, 180px); // default, for height == callHeight.
|
||||
callOutgoingPreviewMax: size(1080px, 360px);
|
||||
callOutgoingDefaultSize: size(160px, 110px);
|
||||
|
||||
callFingerprintPadding: margins(9px, 4px, 9px, 5px);
|
||||
callFingerprintTop: 11px;
|
||||
callFingerprintSkip: 3px;
|
||||
callFingerprintBottom: -16px;
|
||||
|
||||
callButton: IconButton {
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
|
||||
iconPosition: point(-1px, -1px);
|
||||
|
||||
rippleAreaPosition: point(12px, 12px);
|
||||
rippleAreaSize: 48px;
|
||||
rippleAreaPosition: point(10px, 10px);
|
||||
rippleAreaSize: 44px;
|
||||
ripple: defaultRippleAnimation;
|
||||
}
|
||||
callButtonLabel: FlatLabel(defaultFlatLabel) {
|
||||
textFg: callNameFg;
|
||||
}
|
||||
|
||||
callAnswer: CallButton {
|
||||
button: IconButton(callButton) {
|
||||
|
@ -61,6 +97,7 @@ callAnswer: CallButton {
|
|||
angle: 135.;
|
||||
outerRadius: 12px;
|
||||
outerBg: callAnswerBgOuter;
|
||||
label: callButtonLabel;
|
||||
}
|
||||
callHangup: CallButton {
|
||||
button: IconButton(callButton) {
|
||||
|
@ -71,6 +108,7 @@ callHangup: CallButton {
|
|||
}
|
||||
bg: callHangupBg;
|
||||
outerBg: callHangupBg;
|
||||
label: callButtonLabel;
|
||||
}
|
||||
callCancel: CallButton {
|
||||
button: IconButton(callButton) {
|
||||
|
@ -81,27 +119,30 @@ callCancel: CallButton {
|
|||
}
|
||||
bg: callCancelBg;
|
||||
outerBg: callCancelBg;
|
||||
label: callButtonLabel;
|
||||
}
|
||||
callMuteToggle: IconButton(callButton) {
|
||||
icon: icon {{ "call_record_active", callIconFg }};
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: callMuteRipple;
|
||||
callMuteToggle: CallButton {
|
||||
button: IconButton(callButton) {
|
||||
icon: icon {{ "call_record_active", callIconFg }};
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: callMuteRipple;
|
||||
}
|
||||
}
|
||||
bg: callMuteRipple;
|
||||
outerBg: callMuteRipple;
|
||||
label: callButtonLabel;
|
||||
}
|
||||
callUnmuteIcon: icon {{ "call_record_muted", callIconFg }};
|
||||
callCameraToggle: IconButton(callButton) {
|
||||
icon: icon {{ "call_camera_active", callIconFg }};
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: callMuteRipple;
|
||||
callCameraToggle: CallButton(callMuteToggle) {
|
||||
button: IconButton(callButton) {
|
||||
icon: icon {{ "call_camera_active", callIconFg }};
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: callMuteRipple;
|
||||
}
|
||||
}
|
||||
}
|
||||
callNoCameraIcon: icon {{ "call_camera_muted", callIconFg }};
|
||||
|
||||
callControlsTop: 460px;
|
||||
callControlsSkip: 0px;
|
||||
callMuteRight: 8px;
|
||||
|
||||
callNameTop: 15px;
|
||||
callName: FlatLabel(defaultFlatLabel) {
|
||||
minWidth: 260px;
|
||||
maxHeight: 30px;
|
||||
|
@ -113,7 +154,6 @@ callName: FlatLabel(defaultFlatLabel) {
|
|||
linkFontOver: font(21px semibold underline);
|
||||
}
|
||||
}
|
||||
callStatusTop: 46px;
|
||||
callStatus: FlatLabel(defaultFlatLabel) {
|
||||
minWidth: 260px;
|
||||
maxHeight: 20px;
|
||||
|
@ -126,10 +166,6 @@ callStatus: FlatLabel(defaultFlatLabel) {
|
|||
}
|
||||
}
|
||||
|
||||
callFingerprintPadding: margins(9px, 4px, 9px, 5px);
|
||||
callFingerprintSkip: 3px;
|
||||
callFingerprintBottom: 8px;
|
||||
|
||||
callBarHeight: 38px;
|
||||
callBarMuteToggle: IconButton {
|
||||
width: 41px;
|
||||
|
|
|
@ -57,6 +57,8 @@ public:
|
|||
void setProgress(float64 progress);
|
||||
void setOuterValue(float64 value);
|
||||
|
||||
void setIconOverride(const style::icon *iconOverride);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
|
@ -73,6 +75,8 @@ private:
|
|||
const style::CallButton *_stTo = nullptr;
|
||||
float64 _progress = 0.;
|
||||
|
||||
const style::icon *_iconOverride = nullptr;
|
||||
|
||||
QImage _bgMask, _bg;
|
||||
QPixmap _bgFrom, _bgTo;
|
||||
QImage _iconMixedMask, _iconFrom, _iconTo, _iconMixed;
|
||||
|
@ -130,6 +134,11 @@ void Panel::Button::setOuterValue(float64 value) {
|
|||
}
|
||||
}
|
||||
|
||||
void Panel::Button::setIconOverride(const style::icon *iconOverride) {
|
||||
_iconOverride = iconOverride;
|
||||
update();
|
||||
}
|
||||
|
||||
void Panel::Button::setProgress(float64 progress) {
|
||||
_progress = progress;
|
||||
update();
|
||||
|
@ -183,7 +192,8 @@ void Panel::Button::paintEvent(QPaintEvent *e) {
|
|||
|
||||
auto positionFrom = iconPosition(_stFrom);
|
||||
if (paintFrom) {
|
||||
_stFrom->button.icon.paint(p, positionFrom, width());
|
||||
const auto icon = _iconOverride ? _iconOverride : &_stFrom->button.icon;
|
||||
icon->paint(p, positionFrom, width());
|
||||
} else {
|
||||
auto positionTo = iconPosition(_stTo);
|
||||
if (paintTo) {
|
||||
|
@ -248,6 +258,7 @@ Panel::Panel(not_null<Call*> call)
|
|||
: RpWidget(Core::App().getModalParent())
|
||||
, _call(call)
|
||||
, _user(call->user())
|
||||
, _bodySt(&st::callBodyLayout)
|
||||
, _answerHangupRedial(this, st::callAnswer, &st::callHangup)
|
||||
, _decline(this, object_ptr<Button>(this, st::callHangup))
|
||||
, _cancel(this, object_ptr<Button>(this, st::callCancel))
|
||||
|
@ -381,8 +392,6 @@ void Panel::reinitWithCall(Call *call) {
|
|||
_outgoingVideoBubble = std::make_unique<VideoBubble>(
|
||||
this,
|
||||
_call->videoOutgoing());
|
||||
_outgoingVideoBubble->setSizeConstraints(
|
||||
st::callOutgoingPreviewSize);
|
||||
|
||||
_call->mutedValue(
|
||||
) | rpl::start_with_next([=](bool mute) {
|
||||
|
@ -414,6 +423,19 @@ void Panel::reinitWithCall(Call *call) {
|
|||
checkForInactiveShow();
|
||||
}, _callLifetime);
|
||||
|
||||
rpl::combine(
|
||||
_call->stateValue(),
|
||||
_call->videoOutgoing()->renderNextFrame()
|
||||
) | rpl::start_with_next([=](State state, auto) {
|
||||
if (state != State::Ended
|
||||
&& state != State::EndedByOtherDevice
|
||||
&& state != State::Failed
|
||||
&& state != State::FailedHangingUp
|
||||
&& state != State::HangingUp) {
|
||||
refreshOutgoingPreviewInBody(state);
|
||||
}
|
||||
}, _callLifetime);
|
||||
|
||||
_name->setText(_user->name);
|
||||
updateStatusText(_call->state());
|
||||
}
|
||||
|
@ -512,8 +534,6 @@ void Panel::initGeometry() {
|
|||
_useTransparency = Ui::Platform::TranslucentWindowsSupported(center);
|
||||
setAttribute(Qt::WA_OpaquePaintEvent, !_useTransparency);
|
||||
_padding = _useTransparency ? st::callShadow.extend : style::margins(st::lineWidth, st::lineWidth, st::lineWidth, st::lineWidth);
|
||||
_controlsTop = _padding.top() + st::callControlsTop;
|
||||
_contentTop = _padding.top() + 2 * st::callPhotoSize;
|
||||
const auto rect = [&] {
|
||||
const QRect initRect(0, 0, st::callWidth, st::callHeight);
|
||||
return initRect.translated(center - initRect.center()).marginsAdded(_padding);
|
||||
|
@ -525,6 +545,18 @@ void Panel::initGeometry() {
|
|||
updateControlsGeometry();
|
||||
}
|
||||
|
||||
void Panel::refreshOutgoingPreviewInBody(State state) {
|
||||
const auto inBody = (state != State::Established)
|
||||
&& (_call->videoOutgoing()->state() != webrtc::VideoState::Inactive)
|
||||
&& !_call->videoOutgoing()->frameSize().isEmpty();
|
||||
if (_outgoingPreviewInBody == inBody) {
|
||||
return;
|
||||
}
|
||||
_outgoingPreviewInBody = inBody;
|
||||
_bodySt = inBody ? &st::callBodyWithPreview : &st::callBodyLayout;
|
||||
updateControlsGeometry();
|
||||
}
|
||||
|
||||
void Panel::createBottomImage() {
|
||||
if (!_useTransparency) {
|
||||
return;
|
||||
|
@ -571,22 +603,54 @@ void Panel::resizeEvent(QResizeEvent *e) {
|
|||
}
|
||||
|
||||
void Panel::updateControlsGeometry() {
|
||||
const auto size = st::callPhotoSize;
|
||||
_userpic->setGeometry((width() - size) / 2, st::callPhotoSize, size);
|
||||
_name->moveToLeft((width() - _name->width()) / 2, _contentTop + st::callNameTop);
|
||||
const auto innerHeight = height() - _padding.top() - _padding.bottom();
|
||||
const auto availableTop = _padding.top() + _fingerprintHeight;
|
||||
const auto available = height()
|
||||
- (st::callBottomControlsHeight + _padding.bottom())
|
||||
- availableTop;
|
||||
const auto bodyPreviewSizeMax = st::callOutgoingPreviewMin
|
||||
+ ((st::callOutgoingPreview
|
||||
- st::callOutgoingPreviewMin)
|
||||
* (innerHeight - st::callHeightMin)
|
||||
/ (st::callHeight - st::callHeightMin));
|
||||
const auto bodyPreviewSize = QSize(
|
||||
std::min(bodyPreviewSizeMax.width(), st::callOutgoingPreviewMax.width()),
|
||||
std::min(bodyPreviewSizeMax.height(), st::callOutgoingPreviewMax.height()));
|
||||
const auto contentHeight = _bodySt->height
|
||||
+ (_outgoingPreviewInBody ? bodyPreviewSize.height() : 0);
|
||||
const auto remainingHeight = available - contentHeight;
|
||||
const auto skipHeight = remainingHeight
|
||||
/ (_outgoingPreviewInBody ? 3 : 2);
|
||||
|
||||
_bodyTop = availableTop + skipHeight;
|
||||
_buttonsTop = availableTop + available;
|
||||
const auto previewTop = _bodyTop + _bodySt->height + skipHeight;
|
||||
|
||||
_userpic->setGeometry(
|
||||
(width() - _bodySt->photoSize) / 2,
|
||||
_bodyTop + _bodySt->photoTop,
|
||||
_bodySt->photoSize);
|
||||
|
||||
_name->moveToLeft(
|
||||
(width() - _name->width()) / 2,
|
||||
_bodyTop + _bodySt->nameTop);
|
||||
updateStatusGeometry();
|
||||
|
||||
_outgoingVideoBubble->setBoundingRect({
|
||||
(width() - st::callOutgoingPreviewSize.width()) / 2,
|
||||
_contentTop + st::callStatusTop + _status->height(),
|
||||
st::callOutgoingPreviewSize.width(),
|
||||
st::callOutgoingPreviewSize.height()
|
||||
});
|
||||
if (_outgoingPreviewInBody) {
|
||||
_outgoingVideoBubble->updateGeometry(
|
||||
VideoBubble::DragMode::None,
|
||||
QRect(
|
||||
(width() - bodyPreviewSize.width()) / 2,
|
||||
previewTop,
|
||||
bodyPreviewSize.width(),
|
||||
bodyPreviewSize.height()));
|
||||
} else {
|
||||
updateOutgoingVideoBubbleGeometry();
|
||||
}
|
||||
|
||||
auto controlsTop = _padding.top() + st::callControlsTop;
|
||||
auto bothWidth = _answerHangupRedial->width() + st::callControlsSkip + st::callCancel.button.width;
|
||||
_decline->moveToLeft((width() - bothWidth) / 2, controlsTop);
|
||||
_cancel->moveToLeft((width() - bothWidth) / 2, controlsTop);
|
||||
auto bothWidth = _answerHangupRedial->width() + st::callCancel.button.width;
|
||||
_decline->moveToLeft((width() - bothWidth) / 2, _buttonsTop);
|
||||
_cancel->moveToLeft((width() - bothWidth) / 2, _buttonsTop);
|
||||
|
||||
updateHangupGeometry();
|
||||
|
||||
|
@ -597,22 +661,37 @@ void Panel::updateControlsGeometry() {
|
|||
_padding.top() + skip + delta / 2);
|
||||
}
|
||||
|
||||
void Panel::updateOutgoingVideoBubbleGeometry() {
|
||||
Expects(!_outgoingPreviewInBody);
|
||||
|
||||
const auto size = st::callOutgoingDefaultSize;
|
||||
const auto availableHeight = height() - st::callBottomControlsHeight;
|
||||
const auto padding = 2 * _padding;
|
||||
_outgoingVideoBubble->updateGeometry(
|
||||
VideoBubble::DragMode::SnapToCorners,
|
||||
QRect(
|
||||
padding.left(),
|
||||
padding.top(),
|
||||
width() - padding.left() - padding.right(),
|
||||
height() - padding.left() - padding.bottom()),
|
||||
size);
|
||||
}
|
||||
|
||||
void Panel::updateHangupGeometry() {
|
||||
auto singleWidth = _answerHangupRedial->width();
|
||||
auto bothWidth = singleWidth + st::callControlsSkip + st::callCancel.button.width;
|
||||
auto bothWidth = singleWidth + st::callCancel.button.width;
|
||||
auto rightFrom = (width() - bothWidth) / 2;
|
||||
auto rightTo = (width() - singleWidth) / 2;
|
||||
auto hangupProgress = _hangupShownProgress.value(_hangupShown ? 1. : 0.);
|
||||
auto hangupRight = anim::interpolate(rightFrom, rightTo, hangupProgress);
|
||||
auto controlsTop = _padding.top() + st::callControlsTop;
|
||||
_answerHangupRedial->moveToRight(hangupRight, controlsTop);
|
||||
_answerHangupRedial->moveToRight(hangupRight, _buttonsTop);
|
||||
_answerHangupRedial->setProgress(hangupProgress);
|
||||
_mute->moveToRight(hangupRight - _mute->width(), controlsTop);
|
||||
_camera->moveToLeft(hangupRight - _mute->width(), controlsTop);
|
||||
_mute->moveToRight(hangupRight - _mute->width(), _buttonsTop);
|
||||
_camera->moveToLeft(hangupRight - _mute->width(), _buttonsTop);
|
||||
}
|
||||
|
||||
void Panel::updateStatusGeometry() {
|
||||
_status->moveToLeft((width() - _status->width()) / 2, _contentTop + st::callStatusTop);
|
||||
_status->moveToLeft((width() - _status->width()) / 2, _bodyTop + _bodySt->statusTop);
|
||||
}
|
||||
|
||||
void Panel::paintEvent(QPaintEvent *e) {
|
||||
|
@ -707,10 +786,6 @@ void Panel::mousePressEvent(QMouseEvent *e) {
|
|||
_dragging = true;
|
||||
_dragStartMousePosition = e->globalPos();
|
||||
_dragStartMyPosition = QPoint(x(), y());
|
||||
} else if (!rect().contains(e->pos())) {
|
||||
if (_call && _call->state() == State::Established) {
|
||||
hideDeactivated();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -833,8 +908,14 @@ void Panel::fillFingerprint() {
|
|||
auto rectWidth = count * size + (count - 1) * st::callFingerprintSkip;
|
||||
auto rectHeight = size;
|
||||
auto left = (width() - rectWidth) / 2;
|
||||
auto top = _padding.top() + st::callFingerprintBottom;
|
||||
_fingerprintArea = QRect(left, top, rectWidth, rectHeight).marginsAdded(st::callFingerprintPadding);
|
||||
_fingerprintArea = QRect(
|
||||
left,
|
||||
_padding.top() + st::callFingerprintTop + st::callFingerprintPadding.top(),
|
||||
rectWidth,
|
||||
rectHeight
|
||||
).marginsAdded(st::callFingerprintPadding);
|
||||
_fingerprintHeight = st::callFingerprintTop + _fingerprintArea.height() + st::callFingerprintBottom;
|
||||
updateControlsGeometry();
|
||||
|
||||
update();
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ class FadeWrap;
|
|||
|
||||
namespace style {
|
||||
struct CallSignalBars;
|
||||
struct CallBodyLayout;
|
||||
} // namespace style
|
||||
|
||||
namespace Calls {
|
||||
|
@ -60,6 +61,7 @@ protected:
|
|||
bool eventHook(QEvent *e) override;
|
||||
|
||||
private:
|
||||
class Button;
|
||||
using State = Call::State;
|
||||
using Type = Call::Type;
|
||||
|
||||
|
@ -82,6 +84,7 @@ private:
|
|||
void updateControlsGeometry();
|
||||
void updateHangupGeometry();
|
||||
void updateStatusGeometry();
|
||||
void updateOutgoingVideoBubbleGeometry();
|
||||
void stateChanged(State state);
|
||||
void showControls();
|
||||
void updateStatusText(State state);
|
||||
|
@ -95,6 +98,7 @@ private:
|
|||
[[nodiscard]] bool hasActiveVideo() const;
|
||||
void checkForInactiveHide();
|
||||
void checkForInactiveShow();
|
||||
void refreshOutgoingPreviewInBody(State state);
|
||||
|
||||
Call *_call = nullptr;
|
||||
not_null<UserData*> _user;
|
||||
|
@ -102,8 +106,6 @@ private:
|
|||
bool _useTransparency = true;
|
||||
bool _incomingShown = false;
|
||||
style::margins _padding;
|
||||
int _contentTop = 0;
|
||||
int _controlsTop = 0;
|
||||
|
||||
bool _dragging = false;
|
||||
QPoint _dragStartMousePosition;
|
||||
|
@ -111,14 +113,15 @@ private:
|
|||
|
||||
rpl::lifetime _callLifetime;
|
||||
|
||||
class Button;
|
||||
not_null<const style::CallBodyLayout*> _bodySt;
|
||||
object_ptr<Button> _answerHangupRedial;
|
||||
object_ptr<Ui::FadeWrap<Button>> _decline;
|
||||
object_ptr<Ui::FadeWrap<Button>> _cancel;
|
||||
bool _hangupShown = false;
|
||||
bool _outgoingPreviewInBody = false;
|
||||
Ui::Animations::Simple _hangupShownProgress;
|
||||
object_ptr<Ui::IconButton> _camera;
|
||||
object_ptr<Ui::IconButton> _mute;
|
||||
object_ptr<Button> _camera;
|
||||
object_ptr<Button> _mute;
|
||||
object_ptr<Ui::FlatLabel> _name;
|
||||
object_ptr<Ui::FlatLabel> _status;
|
||||
object_ptr<SignalBars> _signalBars = { nullptr };
|
||||
|
@ -126,6 +129,9 @@ private:
|
|||
std::unique_ptr<VideoBubble> _outgoingVideoBubble;
|
||||
std::vector<EmojiPtr> _fingerprint;
|
||||
QRect _fingerprintArea;
|
||||
int _bodyTop = 0;
|
||||
int _buttonsTop = 0;
|
||||
int _fingerprintHeight = 0;
|
||||
|
||||
base::Timer _updateDurationTimer;
|
||||
base::Timer _updateOuterRippleTimer;
|
||||
|
|
|
@ -44,10 +44,12 @@ void Userpic::setGeometry(int x, int y, int size) {
|
|||
if (this->size() != size) {
|
||||
_userPhoto = QPixmap();
|
||||
_userPhotoFull = false;
|
||||
refreshPhoto();
|
||||
}
|
||||
_content.setGeometry(x, y, size, size);
|
||||
_content.update();
|
||||
if (_userPhoto.isNull()) {
|
||||
refreshPhoto();
|
||||
}
|
||||
}
|
||||
|
||||
void Userpic::setup(rpl::producer<bool> muted) {
|
||||
|
@ -139,28 +141,29 @@ void Userpic::refreshPhoto() {
|
|||
}
|
||||
|
||||
void Userpic::createCache(Image *image) {
|
||||
auto size = this->size() * cIntRetinaFactor();
|
||||
const auto size = this->size();
|
||||
const auto real = size * cIntRetinaFactor();
|
||||
auto options = Images::Option::Smooth | Images::Option::Circled;
|
||||
// _useTransparency ? (Images::Option::RoundedLarge | Images::Option::RoundedTopLeft | Images::Option::RoundedTopRight | Images::Option::Smooth) : Images::Option::None;
|
||||
if (image) {
|
||||
auto width = image->width();
|
||||
auto height = image->height();
|
||||
if (width > height) {
|
||||
width = qMax((width * size) / height, 1);
|
||||
height = size;
|
||||
width = qMax((width * real) / height, 1);
|
||||
height = real;
|
||||
} else {
|
||||
height = qMax((height * size) / width, 1);
|
||||
width = size;
|
||||
height = qMax((height * real) / width, 1);
|
||||
width = real;
|
||||
}
|
||||
_userPhoto = image->pixNoCache(
|
||||
width,
|
||||
height,
|
||||
options,
|
||||
st::callPhotoSize,
|
||||
st::callPhotoSize);
|
||||
size,
|
||||
size);
|
||||
_userPhoto.setDevicePixelRatio(cRetinaFactor());
|
||||
} else {
|
||||
auto filled = QImage(QSize(st::callPhotoSize, st::callPhotoSize) * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
|
||||
auto filled = QImage(QSize(real, real), QImage::Format_ARGB32_Premultiplied);
|
||||
filled.setDevicePixelRatio(cRetinaFactor());
|
||||
filled.fill(Qt::transparent);
|
||||
{
|
||||
|
@ -168,7 +171,7 @@ void Userpic::createCache(Image *image) {
|
|||
Ui::EmptyUserpic(
|
||||
Data::PeerUserpicColor(_peer->id),
|
||||
_peer->name
|
||||
).paint(p, 0, 0, st::callPhotoSize, st::callPhotoSize);
|
||||
).paint(p, 0, 0, size, size);
|
||||
}
|
||||
//Images::prepareRound(filled, ImageRoundRadius::Large, RectPart::TopLeft | RectPart::TopRight);
|
||||
_userPhoto = Images::PixmapFast(std::move(filled));
|
||||
|
|
|
@ -47,15 +47,39 @@ void VideoBubble::setup() {
|
|||
}, lifetime());
|
||||
}
|
||||
|
||||
void VideoBubble::setDragMode(DragMode mode) {
|
||||
void VideoBubble::updateGeometry(
|
||||
DragMode mode,
|
||||
QRect boundingRect,
|
||||
QSize sizeMin,
|
||||
QSize sizeMax) {
|
||||
Expects(!boundingRect.isEmpty());
|
||||
Expects(sizeMax.isEmpty() || !sizeMin.isEmpty());
|
||||
Expects(sizeMax.isEmpty() || sizeMin.width() <= sizeMax.width());
|
||||
Expects(sizeMax.isEmpty() || sizeMin.height() <= sizeMax.height());
|
||||
|
||||
if (sizeMin.isEmpty()) {
|
||||
sizeMin = boundingRect.size();
|
||||
}
|
||||
if (sizeMax.isEmpty()) {
|
||||
sizeMax = sizeMin;
|
||||
}
|
||||
if (_dragMode != mode) {
|
||||
applyDragMode(mode);
|
||||
}
|
||||
if (_boundingRect != boundingRect) {
|
||||
applyBoundingRect(boundingRect);
|
||||
}
|
||||
if (_min != sizeMin || _max != sizeMax) {
|
||||
applySizeConstraints(sizeMin, sizeMax);
|
||||
}
|
||||
if (_geometryDirty && !_lastFrameSize.isEmpty()) {
|
||||
updateSizeToFrame(base::take(_lastFrameSize));
|
||||
}
|
||||
}
|
||||
|
||||
void VideoBubble::setBoundingRect(QRect rect) {
|
||||
void VideoBubble::applyBoundingRect(QRect rect) {
|
||||
_boundingRect = rect;
|
||||
setSizeConstraints(rect.size());
|
||||
_geometryDirty = true;
|
||||
}
|
||||
|
||||
void VideoBubble::applyDragMode(DragMode mode) {
|
||||
|
@ -66,23 +90,21 @@ void VideoBubble::applyDragMode(DragMode mode) {
|
|||
}
|
||||
_content.setAttribute(
|
||||
Qt::WA_TransparentForMouseEvents,
|
||||
(_dragMode == DragMode::None));
|
||||
}
|
||||
|
||||
void VideoBubble::setSizeConstraints(QSize min, QSize max) {
|
||||
Expects(!min.isEmpty());
|
||||
Expects(max.isEmpty() || min.width() <= max.width());
|
||||
Expects(max.isEmpty() || min.height() <= max.height());
|
||||
|
||||
if (max.isEmpty()) {
|
||||
max = min;
|
||||
true/*(_dragMode == DragMode::None)*/);
|
||||
if (_dragMode == DragMode::SnapToCorners) {
|
||||
_corner = RectPart::BottomRight;
|
||||
} else {
|
||||
_corner = RectPart::None;
|
||||
_lastDraggableSize = _size;
|
||||
}
|
||||
applySizeConstraints(min, max);
|
||||
_size = QSize();
|
||||
_geometryDirty = true;
|
||||
}
|
||||
|
||||
void VideoBubble::applySizeConstraints(QSize min, QSize max) {
|
||||
_min = min;
|
||||
_max = max;
|
||||
_geometryDirty = true;
|
||||
}
|
||||
|
||||
void VideoBubble::paint() {
|
||||
|
@ -114,7 +136,11 @@ void VideoBubble::updateSizeToFrame(QSize frame) {
|
|||
}
|
||||
_lastFrameSize = frame;
|
||||
|
||||
auto size = _size;
|
||||
auto size = !_size.isEmpty()
|
||||
? _size
|
||||
: (_dragMode == DragMode::None || _lastDraggableSize.isEmpty())
|
||||
? QSize()
|
||||
: _lastDraggableSize;
|
||||
if (size.isEmpty()) {
|
||||
size = frame.scaled((_min + _max) / 2, Qt::KeepAspectRatio);
|
||||
} else {
|
||||
|
@ -130,15 +156,34 @@ void VideoBubble::updateSizeToFrame(QSize frame) {
|
|||
}
|
||||
|
||||
void VideoBubble::setInnerSize(QSize size) {
|
||||
if (_size == size) {
|
||||
if (_size == size && !_geometryDirty) {
|
||||
return;
|
||||
}
|
||||
_geometryDirty = false;
|
||||
_size = size;
|
||||
_content.setGeometry(
|
||||
_boundingRect.x() + (_boundingRect.width() - size.width()) / 2,
|
||||
_boundingRect.y() + (_boundingRect.height() - size.height()) / 2,
|
||||
size.width(),
|
||||
size.height());
|
||||
_content.setGeometry(QRect([&] {
|
||||
switch (_corner) {
|
||||
case RectPart::None:
|
||||
return _boundingRect.topLeft() + QPoint(
|
||||
(_boundingRect.width() - size.width()) / 2,
|
||||
(_boundingRect.height() - size.height()) / 2);
|
||||
case RectPart::TopLeft:
|
||||
return _boundingRect.topLeft();
|
||||
case RectPart::TopRight:
|
||||
return QPoint(
|
||||
_boundingRect.x() + _boundingRect.width() - size.width(),
|
||||
_boundingRect.y());
|
||||
case RectPart::BottomRight:
|
||||
return QPoint(
|
||||
_boundingRect.x() + _boundingRect.width() - size.width(),
|
||||
_boundingRect.y() + _boundingRect.height() - size.height());
|
||||
case RectPart::BottomLeft:
|
||||
return QPoint(
|
||||
_boundingRect.x(),
|
||||
_boundingRect.y() + _boundingRect.height() - size.height());
|
||||
}
|
||||
Unexpected("Corner value in VideoBubble::setInnerSize.");
|
||||
}(), size));
|
||||
}
|
||||
|
||||
void VideoBubble::updateVisibility() {
|
||||
|
|
|
@ -26,9 +26,11 @@ public:
|
|||
None,
|
||||
SnapToCorners,
|
||||
};
|
||||
void setDragMode(DragMode mode);
|
||||
void setBoundingRect(QRect rect);
|
||||
void setSizeConstraints(QSize min, QSize max = QSize());
|
||||
void updateGeometry(
|
||||
DragMode mode,
|
||||
QRect boundingRect,
|
||||
QSize sizeMin = QSize(),
|
||||
QSize sizeMax = QSize());
|
||||
|
||||
[[nodiscard]] rpl::lifetime &lifetime() {
|
||||
return _content.lifetime();
|
||||
|
@ -39,6 +41,7 @@ private:
|
|||
void paint();
|
||||
void setState(webrtc::VideoState state);
|
||||
void applyDragMode(DragMode mode);
|
||||
void applyBoundingRect(QRect rect);
|
||||
void applySizeConstraints(QSize min, QSize max);
|
||||
void updateSizeToFrame(QSize frame);
|
||||
void updateVisibility();
|
||||
|
@ -48,10 +51,12 @@ private:
|
|||
const not_null<webrtc::VideoTrack*> _track;
|
||||
webrtc::VideoState _state = webrtc::VideoState();
|
||||
QImage _pausedFrame;
|
||||
QSize _min, _max, _size, _lastFrameSize;
|
||||
QSize _min, _max, _size, _lastDraggableSize, _lastFrameSize;
|
||||
QRect _boundingRect;
|
||||
DragMode _dragMode = DragMode::None;
|
||||
RectPart _corner = RectPart::None;
|
||||
bool _dragging = false;
|
||||
bool _geometryDirty = false;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 697f2851b0625ae784e405e7fc596d1629e8668a
|
||||
Subproject commit c9235ec9c25565516da04abf083e9c0500de58bc
|
Loading…
Add table
Reference in a new issue