From e0bfaad3a2aad5abd8f58590e93da6354203ee02 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 26 Apr 2021 13:21:01 +0400 Subject: [PATCH] Make style of mute button customizable. --- Telegram/Resources/langs/lang.strings | 1 + Telegram/SourceFiles/calls/calls.style | 83 ++++- .../calls/group/calls_group_panel.cpp | 78 +++-- .../calls/group/calls_group_panel.h | 3 + .../ui/controls/call_mute_button.cpp | 299 ++++++++++-------- .../ui/controls/call_mute_button.h | 20 +- 6 files changed, 326 insertions(+), 158 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 6184a552f1..051901579f 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -2010,6 +2010,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_group_call_force_muted_sub" = "You are in Listen Only mode"; "lng_group_call_raise_hand_tip" = "Click if you want to speak"; "lng_group_call_raised_hand" = "You asked to speak"; +"lng_group_call_raised_hand_small" = "Raised hand"; "lng_group_call_raised_hand_sub" = "We let the speakers know"; "lng_group_call_connecting" = "Connecting..."; "lng_group_call_leave" = "Leave"; diff --git a/Telegram/SourceFiles/calls/calls.style b/Telegram/SourceFiles/calls/calls.style index 829b0a83f1..a617e585ef 100644 --- a/Telegram/SourceFiles/calls/calls.style +++ b/Telegram/SourceFiles/calls/calls.style @@ -175,6 +175,87 @@ callCameraUnmute: CallButton(callMicrophoneUnmute) { } callBottomShadowSize: 124px; +CallMuteButton { + active: CallButton; + muted: CallButton; + labelAdditional: pixels; + sublabel: FlatLabel; + labelsSkip: pixels; + sublabelSkip: pixels; + lottieSize: size; + lottieTop: pixels; +} + +callMuteButtonLabel: FlatLabel(defaultFlatLabel) { + textFg: groupCallMembersFg; + style: TextStyle(defaultTextStyle) { + font: font(14px); + linkFont: font(14px); + linkFontOver: font(14px underline); + } +} +callMuteButtonActiveInner: IconButton { + width: 136px; + height: 165px; +} +callMuteButtonSmallActiveInner: IconButton { + width: 68px; + height: 79px; +} +callMuteButtonActive: CallButton { + button: callMuteButtonActiveInner; + bg: groupCallLive1; + bgSize: 100px; + bgPosition: point(18px, 18px); + outerRadius: 18px; + outerBg: callAnswerBgOuter; + label: callMuteButtonLabel; +} +callMuteButton: CallMuteButton { + active: callMuteButtonActive; + muted: CallButton(callMuteButtonActive) { + bg: groupCallMuted1; + label: callMuteButtonLabel; + } + labelAdditional: 5px; + sublabel: FlatLabel(defaultFlatLabel) { + textFg: groupCallMemberNotJoinedStatus; + } + labelsSkip: 5px; + sublabelSkip: 19px; + lottieSize: size(67px, 67px); + lottieTop: 35px; +} +callMuteButtonSmallActive: CallButton(callMuteButtonActive) { + button: callMuteButtonSmallActiveInner; + bgSize: 44px; + bgPosition: point(12px, 12px); + outerRadius: 12px; + label: callButtonLabel; +} +callMuteButtonSmall: CallMuteButton(callMuteButton) { + active: callMuteButtonSmallActive; + muted: CallButton(callMuteButtonSmallActive) { + bg: groupCallMuted1; + label: callButtonLabel; + } + labelsSkip: 0px; + sublabelSkip: 0px; + lottieSize: size(36px, 36px); + lottieTop: 17px; +} + +callMuteMinorBlobMinRadius: 64px; +callMuteMinorBlobMaxRadius: 74px; +callMuteMajorBlobMinRadius: 67px; +callMuteMajorBlobMaxRadius: 77px; +callMuteBlobRadiusForDiameter: 100px; + +callConnectingRadial: InfiniteRadialAnimation(defaultInfiniteRadialAnimation) { + color: lightButtonFg; + thickness: 4px; +} + callName: FlatLabel(defaultFlatLabel) { minWidth: 260px; maxHeight: 30px; @@ -442,8 +523,6 @@ callErrorToast: Toast(defaultToast) { groupCallWidth: 380px; groupCallHeight: 580px; -groupCallMuteButtonIconSize: size(67px, 67px); -groupCallMuteButtonIconTop: 35px; groupCallRipple: RippleAnimation(defaultRippleAnimation) { color: groupCallMembersBgRipple; } diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp index 54db5465bf..cb0e2de1dc 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp @@ -385,8 +385,10 @@ Panel::Panel(not_null call) _window->body(), st::groupCallTitle)) #endif // !Q_OS_MAC +, _videoMode(true) // #TODO calls , _mute(std::make_unique( widget(), + st::callMuteButton, Core::App().appDeactivatedValue(), Ui::CallMuteButtonState{ .text = (_call->scheduleDate() @@ -738,7 +740,8 @@ void Panel::setupRealMuteButtonState(not_null real) { _call->instanceStateValue(), real->scheduleDateValue(), real->scheduleStartSubscribedValue(), - Data::CanManageGroupCallValue(_peer) + Data::CanManageGroupCallValue(_peer), + _videoMode.value() ) | rpl::distinct_until_changed( ) | rpl::filter( _2 != GroupCall::InstanceState::TransitionToRtc @@ -747,7 +750,8 @@ void Panel::setupRealMuteButtonState(not_null real) { GroupCall::InstanceState state, TimeId scheduleDate, bool scheduleStartSubscribed, - bool canManage) { + bool canManage, + bool videoMode) { using Type = Ui::CallMuteButtonType; _mute->setState(Ui::CallMuteButtonState{ .text = (scheduleDate @@ -759,13 +763,19 @@ void Panel::setupRealMuteButtonState(not_null real) { : state == GroupCall::InstanceState::Disconnected ? tr::lng_group_call_connecting(tr::now) : mute == MuteState::ForceMuted - ? tr::lng_group_call_force_muted(tr::now) + ? (videoMode + ? tr::lng_group_call_force_muted_small(tr::now) + : tr::lng_group_call_force_muted(tr::now)) : mute == MuteState::RaisedHand - ? tr::lng_group_call_raised_hand(tr::now) + ? (videoMode + ? tr::lng_group_call_raised_hand_small(tr::now) + : tr::lng_group_call_raised_hand(tr::now)) : mute == MuteState::Muted ? tr::lng_group_call_unmute(tr::now) - : tr::lng_group_call_you_are_live(tr::now)), - .subtext = (scheduleDate + : (videoMode + ? tr::lng_group_call_you_are_live_small(tr::now) + : tr::lng_group_call_you_are_live(tr::now))), + .subtext = ((scheduleDate || videoMode) ? QString() : state == GroupCall::InstanceState::Disconnected ? QString() @@ -1498,22 +1508,48 @@ void Panel::updateControlsGeometry() { if (widget()->size().isEmpty() || (!_settings && !_share)) { return; } - const auto muteTop = widget()->height() - st::groupCallMuteBottomSkip; - const auto buttonsTop = widget()->height() - st::groupCallButtonBottomSkip; - const auto muteSize = _mute->innerSize().width(); - const auto fullWidth = muteSize - + 2 * (_settings ? _settings : _share)->width() - + 2 * st::groupCallButtonSkip; - _mute->moveInner({ (widget()->width() - muteSize) / 2, muteTop }); - const auto leftButtonLeft = (widget()->width() - fullWidth) / 2; - if (_settings) { - _settings->moveToLeft(leftButtonLeft, buttonsTop); + if (_videoMode.current()) { + _mute->setStyle(st::callMuteButtonSmall); + const auto buttonsTop = widget()->height() + - st::groupCallButtonBottomSkip; + const auto muteSize = _mute->innerSize().width(); + const auto fullWidth = muteSize + + 2 * (_settings ? _settings : _share)->width() + + 2 * st::groupCallButtonSkip; + const auto leftButtonLeft = (widget()->width() - fullWidth) / 2; + const auto addSkip = st::callMuteButtonSmall.active.outerRadius; + _mute->moveInner({ leftButtonLeft + addSkip, buttonsTop + addSkip }); + if (_settings) { + _settings->moveToLeft( + (widget()->width() - _settings->width()) / 2, + buttonsTop); + } + if (_share) { + _share->moveToLeft( + (widget()->width() - _share->width()) / 2, + buttonsTop); + } + _hangup->moveToRight(leftButtonLeft, buttonsTop); + } else { + _mute->setStyle(st::callMuteButton); + const auto muteTop = widget()->height() + - st::groupCallMuteBottomSkip; + const auto buttonsTop = widget()->height() + - st::groupCallButtonBottomSkip; + const auto muteSize = _mute->innerSize().width(); + const auto fullWidth = muteSize + + 2 * (_settings ? _settings : _share)->width() + + 2 * st::groupCallButtonSkip; + _mute->moveInner({ (widget()->width() - muteSize) / 2, muteTop }); + const auto leftButtonLeft = (widget()->width() - fullWidth) / 2; + if (_settings) { + _settings->moveToLeft(leftButtonLeft, buttonsTop); + } + if (_share) { + _share->moveToLeft(leftButtonLeft, buttonsTop); + } + _hangup->moveToRight(leftButtonLeft, buttonsTop); } - if (_share) { - _share->moveToLeft(leftButtonLeft, buttonsTop); - } - _hangup->moveToRight(leftButtonLeft, buttonsTop); - updateMembersGeometry(); refreshTitle(); diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.h b/Telegram/SourceFiles/calls/group/calls_group_panel.h index 8b6201ab49..a963fbf62d 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_panel.h +++ b/Telegram/SourceFiles/calls/group/calls_group_panel.h @@ -144,9 +144,12 @@ private: std::shared_ptr _countdownData; object_ptr _startsWhen = { nullptr }; ChooseJoinAsProcess _joinAsProcess; + rpl::variable _videoMode; object_ptr _settings = { nullptr }; object_ptr _share = { nullptr }; + object_ptr _video = { nullptr }; + object_ptr _shareScreen = { nullptr }; std::unique_ptr _mute; object_ptr _hangup; Fn _shareLinkCallback; diff --git a/Telegram/SourceFiles/ui/controls/call_mute_button.cpp b/Telegram/SourceFiles/ui/controls/call_mute_button.cpp index 87fd85e1f2..8a5b6ad0ae 100644 --- a/Telegram/SourceFiles/ui/controls/call_mute_button.cpp +++ b/Telegram/SourceFiles/ui/controls/call_mute_button.cpp @@ -274,8 +274,10 @@ class BlobsWidget final : public RpWidget { public: BlobsWidget( not_null parent, + int diameter, rpl::producer &&hideBlobs); + void setDiameter(int diameter); void setLevel(float level); void setBlobBrush(QBrush brush); void setGlowBrush(QBrush brush); @@ -286,11 +288,12 @@ public: void setSwitchConnectingProgress(float64 progress); private: - void init(); + void init(int diameter); + void computeCircleRect(); Paint::Blobs _blobs; - const float _circleRadius; + float _circleRadius = 0.; QBrush _blobBrush; QBrush _glowBrush; int _center = 0; @@ -312,15 +315,15 @@ private: BlobsWidget::BlobsWidget( not_null parent, + int diameter, rpl::producer &&hideBlobs) : RpWidget(parent) , _blobs(MuteBlobs(), kLevelDuration, kMaxLevel) -, _circleRadius(st::callMuteButtonActive.bgSize / 2.) , _blobBrush(Qt::transparent) , _glowBrush(Qt::transparent) , _blobsLastTime(crl::now()) , _blobsScaleLastTime(crl::now()) { - init(); + init(diameter); std::move( hideBlobs @@ -342,7 +345,27 @@ BlobsWidget::BlobsWidget( }, lifetime()); } -void BlobsWidget::init() { +void BlobsWidget::setDiameter(int diameter) { + _circleRadius = diameter / 2.; + const auto defaultSize = _blobs.maxRadius() * 2 * kGlowPaddingFactor; + const auto s = int(std::ceil((defaultSize * diameter) + / float64(st::callMuteBlobRadiusForDiameter))); + const auto size = QSize{ s, s }; + if (this->size() != size) { + resize(size); + } + computeCircleRect(); +} + +void BlobsWidget::computeCircleRect() { + const auto &r = _circleRadius; + const auto left = (size().width() - r * 2.) / 2.; + const auto add = st::callConnectingRadial.thickness / 2; + _circleRect = QRectF(left, left, r * 2, r * 2).marginsAdded( + style::margins(add, add, add, add)); +} + +void BlobsWidget::init(int diameter) { setAttribute(Qt::WA_TransparentForMouseEvents); const auto cutRect = [](Painter &p, const QRectF &r) { @@ -354,22 +377,12 @@ void BlobsWidget::init() { p.restore(); }; - { - const auto s = _blobs.maxRadius() * 2 * kGlowPaddingFactor; - resize(s, s); - } + setDiameter(diameter); sizeValue( ) | rpl::start_with_next([=](QSize size) { _center = size.width() / 2; - - { - const auto &r = _circleRadius; - const auto left = (size.width() - r * 2.) / 2.; - const auto add = st::callConnectingRadial.thickness / 2; - _circleRect = QRectF(left, left, r * 2, r * 2).marginsAdded( - style::margins(add, add, add, add)); - } + computeCircleRect(); }, lifetime()); paintRequest( @@ -396,7 +409,9 @@ void BlobsWidget::init() { _blobsScaleEnter * (1. - Clamp( _switchConnectingProgress / kBlobPartAnimation))) : _blobsScaleEnter; - _blobs.paint(p, _blobBrush, scale); + const auto sizeScale = (2. * _circleRadius) + / st::callMuteBlobRadiusForDiameter; + _blobs.paint(p, _blobBrush, scale * sizeScale); p.translate(-_center, -_center); if (scale < 1.) { @@ -499,12 +514,14 @@ void BlobsWidget::setSwitchConnectingProgress(float64 progress) { CallMuteButton::CallMuteButton( not_null parent, + const style::CallMuteButton &st, rpl::producer &&hideBlobs, CallMuteButtonState initial) : _state(initial) -, _st(st::callMuteButtonActive) +, _st(&st) , _blobs(base::make_unique_q( parent, + _st->active.bgSize, rpl::combine( rpl::single(anim::Disabled()) | rpl::then(anim::Disables()), std::move(hideBlobs), @@ -516,53 +533,82 @@ CallMuteButton::CallMuteButton( return isBadState || !(!animDisabled && !hide); }))) , _content(base::make_unique_q(parent)) -, _centerLabel(base::make_unique_q( - parent, - _state.value( - ) | rpl::map([](const CallMuteButtonState &state) { - return state.subtext.isEmpty() ? state.text : QString(); - }), - kSwitchLabelDuration, - st::callMuteButtonLabelAdditional, - _st.label)) -, _label(base::make_unique_q( - parent, - _state.value( - ) | rpl::map([](const CallMuteButtonState &state) { - return state.subtext.isEmpty() ? QString() : state.text; - }), - kSwitchLabelDuration, - st::callMuteButtonLabelAdditional, - _st.label)) -, _sublabel(base::make_unique_q( - parent, - _state.value( - ) | rpl::map([](const CallMuteButtonState &state) { - return state.subtext; - }), - kSwitchLabelDuration, - st::callMuteButtonLabelAdditional, - st::callMuteButtonSublabel)) , _colors(Colors()) -, _iconState(initialState()) { +, _iconState(iconStateFrom(initial.type)) { init(); } -CallMuteButton::IconState CallMuteButton::initialState() { - const auto result = iconStateFrom(_state.current().type); +void CallMuteButton::refreshLabels() { + _centerLabel = base::make_unique_q( + _content->parentWidget(), + _state.value( + ) | rpl::map([](const CallMuteButtonState &state) { + return state.subtext.isEmpty() ? state.text : QString(); + }), + kSwitchLabelDuration, + _st->labelAdditional, + _st->active.label); + _label = base::make_unique_q( + _content->parentWidget(), + _state.value( + ) | rpl::map([](const CallMuteButtonState &state) { + return state.subtext.isEmpty() ? QString() : state.text; + }), + kSwitchLabelDuration, + _st->labelAdditional, + _st->active.label); + _sublabel = base::make_unique_q( + _content->parentWidget(), + _state.value( + ) | rpl::map([](const CallMuteButtonState &state) { + return state.subtext; + }), + kSwitchLabelDuration, + _st->labelAdditional, + _st->sublabel); + + _label->show(); + rpl::combine( + _content->geometryValue(), + _label->sizeValue() + ) | rpl::start_with_next([=](QRect my, QSize size) { + updateLabelGeometry(my, size); + }, _label->lifetime()); + _label->setAttribute(Qt::WA_TransparentForMouseEvents); + + _sublabel->show(); + rpl::combine( + _content->geometryValue(), + _sublabel->sizeValue() + ) | rpl::start_with_next([=](QRect my, QSize size) { + updateSublabelGeometry(my, size); + }, _sublabel->lifetime()); + _sublabel->setAttribute(Qt::WA_TransparentForMouseEvents); + + _centerLabel->show(); + rpl::combine( + _content->geometryValue(), + _centerLabel->sizeValue() + ) | rpl::start_with_next([=](QRect my, QSize size) { + updateCenterLabelGeometry(my, size); + }, _centerLabel->lifetime()); + _centerLabel->setAttribute(Qt::WA_TransparentForMouseEvents); +} + +void CallMuteButton::refreshIcons() { _icons[0].emplace(Lottie::IconDescriptor{ .path = u":/gui/icons/calls/voice.lottie"_q, .color = st::groupCallIconFg, - .sizeOverride = st::groupCallMuteButtonIconSize, - .frame = result.frameTo, + .sizeOverride = _st->lottieSize, + .frame = (_iconState.index ? 0 : _iconState.frameTo), }); _icons[1].emplace(Lottie::IconDescriptor{ .path = u":/gui/icons/calls/hands.lottie"_q, .color = st::groupCallIconFg, - .sizeOverride = st::groupCallMuteButtonIconSize, - .frame = 0, + .sizeOverride = _st->lottieSize, + .frame = (_iconState.index ? _iconState.frameTo : 0), }); - return result; + } auto CallMuteButton::iconStateAnimated(CallMuteButtonType previous) @@ -647,35 +693,11 @@ CallMuteButton::IconState CallMuteButton::randomWavingState() { } void CallMuteButton::init() { - _content->resize(_st.button.width, _st.button.height); + refreshLabels(); + refreshIcons(); - // Label text. - _label->show(); - rpl::combine( - _content->geometryValue(), - _label->sizeValue() - ) | rpl::start_with_next([=](QRect my, QSize size) { - updateLabelGeometry(my, size); - }, _label->lifetime()); - _label->setAttribute(Qt::WA_TransparentForMouseEvents); - - _sublabel->show(); - rpl::combine( - _content->geometryValue(), - _sublabel->sizeValue() - ) | rpl::start_with_next([=](QRect my, QSize size) { - updateSublabelGeometry(my, size); - }, _sublabel->lifetime()); - _sublabel->setAttribute(Qt::WA_TransparentForMouseEvents); - - _centerLabel->show(); - rpl::combine( - _content->geometryValue(), - _centerLabel->sizeValue() - ) | rpl::start_with_next([=](QRect my, QSize size) { - updateCenterLabelGeometry(my, size); - }, _centerLabel->lifetime()); - _centerLabel->setAttribute(Qt::WA_TransparentForMouseEvents); + const auto &button = _st->active.button; + _content->resize(button.width, button.height); rpl::combine( _radialInfo.rawShowProgress.value(), @@ -722,36 +744,7 @@ void CallMuteButton::init() { lifetime().make_state(_state.current().type); setHandleMouseState(HandleMouseState::Disabled); - const auto blobsInner = [&] { - // The point of the circle at 45 degrees. - const auto w = _blobs->innerRect().width(); - const auto mF = (1 - std::cos(M_PI / 4.)) * (w / 2.); - return _blobs->innerRect().marginsRemoved(QMarginsF(mF, mF, mF, mF)); - }(); - - auto linearGradients = anim::linear_gradients( - _colors, - QPointF(blobsInner.x() + blobsInner.width(), blobsInner.y()), - QPointF(blobsInner.x(), blobsInner.y() + blobsInner.height())); - - auto glowColors = [&] { - auto copy = _colors; - for (auto &[type, stops] : copy) { - auto firstColor = IsInactive(type) - ? st::groupCallBg->c - : stops.stops[(stops.stops.size() - 1) / 2].second; - firstColor.setAlpha(kGlowAlpha); - stops.stops = QGradientStops{ - { 0., std::move(firstColor) }, - { 1., QColor(Qt::transparent) } - }; - } - return copy; - }(); - auto glows = anim::radial_gradients( - std::move(glowColors), - blobsInner.center(), - _blobs->width() / 2); + refreshGradients(); _state.value( ) | rpl::map([](const CallMuteButtonState &state) { @@ -784,9 +777,9 @@ void CallMuteButton::init() { auto callback = [=](float64 value) { const auto brushProgress = fromConnecting ? 1. : value; _blobs->setBlobBrush(QBrush( - linearGradients.gradient(previous, type, brushProgress))); + _linearGradients.gradient(previous, type, brushProgress))); _blobs->setGlowBrush(QBrush( - glows.gradient(previous, type, value))); + _glowGradients.gradient(previous, type, value))); _blobs->update(); const auto radialShowProgress = (radialShowFrom == radialShowTo) @@ -815,10 +808,10 @@ void CallMuteButton::init() { // Icon rect. _content->sizeValue( ) | rpl::start_with_next([=](QSize size) { - const auto icon = st::groupCallMuteButtonIconSize; + const auto icon = _st->lottieSize; _muteIconRect = QRect( (size.width() - icon.width()) / 2, - st::groupCallMuteButtonIconTop, + _st->lottieTop, icon.width(), icon.height()); }, lifetime()); @@ -850,8 +843,8 @@ void CallMuteButton::init() { InfiniteRadialAnimation::Draw( p, r, - _st.bgPosition, - _radialInfo.st.size, + _st->active.bgPosition, + QSize(_st->active.bgSize, _st->active.bgSize), _content->width(), QPen(_radialInfo.st.color), _radialInfo.st.thickness); @@ -862,8 +855,8 @@ void CallMuteButton::init() { InfiniteRadialAnimation::Draw( p, std::move(state), - _st.bgPosition, - _radialInfo.st.size, + _st->active.bgPosition, + QSize(_st->active.bgSize, _st->active.bgSize), _content->width(), QPen(_radialInfo.st.color), _radialInfo.st.thickness); @@ -871,6 +864,39 @@ void CallMuteButton::init() { }, _content->lifetime()); } +void CallMuteButton::refreshGradients() { + const auto blobsInner = [&] { + // The point of the circle at 45 degrees. + const auto w = _blobs->innerRect().width(); + const auto mF = (1 - std::cos(M_PI / 4.)) * (w / 2.); + return _blobs->innerRect().marginsRemoved(QMarginsF(mF, mF, mF, mF)); + }(); + + _linearGradients = anim::linear_gradients( + _colors, + QPointF(blobsInner.x() + blobsInner.width(), blobsInner.y()), + QPointF(blobsInner.x(), blobsInner.y() + blobsInner.height())); + + auto glowColors = [&] { + auto copy = _colors; + for (auto &[type, stops] : copy) { + auto firstColor = IsInactive(type) + ? st::groupCallBg->c + : stops.stops[(stops.stops.size() - 1) / 2].second; + firstColor.setAlpha(kGlowAlpha); + stops.stops = QGradientStops{ + { 0., std::move(firstColor) }, + { 1., QColor(Qt::transparent) } + }; + } + return copy; + }(); + _glowGradients = anim::radial_gradients( + std::move(glowColors), + blobsInner.center(), + _blobs->width() / 2); +} + void CallMuteButton::scheduleIconState(const IconState &state) { if (_iconState != state) { if (_icons[_iconState.index]->animating()) { @@ -906,28 +932,26 @@ void CallMuteButton::updateLabelsGeometry() { } void CallMuteButton::updateLabelGeometry(QRect my, QSize size) { - const auto skip = st::callMuteButtonSublabelSkip - + st::callMuteButtonLabelsSkip; + const auto skip = _st->sublabelSkip + _st->labelsSkip; _label->moveToLeft( my.x() + (my.width() - size.width()) / 2 + _labelShakeShift, - my.y() + my.height() - _label->height() - skip, + my.y() + my.height() - size.height() - skip, my.width()); } void CallMuteButton::updateCenterLabelGeometry(QRect my, QSize size) { - const auto skip = (st::callMuteButtonSublabelSkip / 2) - + st::callMuteButtonLabelsSkip; + const auto skip = (_st->sublabelSkip / 2) + _st->labelsSkip; _centerLabel->moveToLeft( my.x() + (my.width() - size.width()) / 2 + _labelShakeShift, - my.y() + my.height() - _centerLabel->height() - skip, + my.y() + my.height() - size.height() - skip, my.width()); } void CallMuteButton::updateSublabelGeometry(QRect my, QSize size) { - const auto skip = st::callMuteButtonLabelsSkip; + const auto skip = _st->labelsSkip; _sublabel->moveToLeft( my.x() + (my.width() - size.width()) / 2 + _labelShakeShift, - my.y() + my.height() - _sublabel->height() - skip, + my.y() + my.height() - size.height() - skip, my.width()); } @@ -978,6 +1002,21 @@ CallMuteButton::HandleMouseState CallMuteButton::HandleMouseStateFromType( Unexpected("Type in HandleMouseStateFromType."); } +void CallMuteButton::setStyle(const style::CallMuteButton &st) { + if (_st == &st) { + return; + } + _st = &st; + const auto &button = _st->active.button; + _content->resize(button.width, button.height); + _blobs->setDiameter(_st->active.bgSize); + + refreshIcons(); + refreshLabels(); + updateLabelsGeometry(); + refreshGradients(); +} + void CallMuteButton::setState(const CallMuteButtonState &state) { _state = state; } @@ -1002,7 +1041,7 @@ QSize CallMuteButton::innerSize() const { } QRect CallMuteButton::innerGeometry() const { - const auto &skip = _st.outerRadius; + const auto &skip = _st->active.outerRadius; return QRect( _content->x(), _content->y(), @@ -1011,7 +1050,7 @@ QRect CallMuteButton::innerGeometry() const { } void CallMuteButton::moveInner(QPoint position) { - const auto &skip = _st.outerRadius; + const auto &skip = _st->active.outerRadius; _content->move(position - QPoint(skip, skip)); { diff --git a/Telegram/SourceFiles/ui/controls/call_mute_button.h b/Telegram/SourceFiles/ui/controls/call_mute_button.h index 924489acc2..7759c39429 100644 --- a/Telegram/SourceFiles/ui/controls/call_mute_button.h +++ b/Telegram/SourceFiles/ui/controls/call_mute_button.h @@ -13,6 +13,10 @@ #include "ui/effects/radial_animation.h" #include "lottie/lottie_icon.h" +namespace style { +struct CallMuteButton; +} // namespace style + namespace st { extern const style::InfiniteRadialAnimation &callConnectingRadial; } // namespace st @@ -49,11 +53,13 @@ class CallMuteButton final { public: explicit CallMuteButton( not_null parent, + const style::CallMuteButton &st, rpl::producer &&hideBlobs, CallMuteButtonState initial = CallMuteButtonState()); ~CallMuteButton(); void setState(const CallMuteButtonState &state); + void setStyle(const style::CallMuteButton &st); void setLevel(float level); [[nodiscard]] rpl::producer clicks(); @@ -113,6 +119,9 @@ private: }; void init(); + void refreshIcons(); + void refreshGradients(); + void refreshLabels(); void overridesColors( CallMuteButtonType fromType, CallMuteButtonType toType, @@ -124,7 +133,6 @@ private: void updateSublabelGeometry(QRect my, QSize size); void updateLabelsGeometry(); - [[nodiscard]] IconState initialState(); [[nodiscard]] IconState iconStateFrom(CallMuteButtonType previous); [[nodiscard]] IconState randomWavingState(); [[nodiscard]] IconState iconStateAnimated(CallMuteButtonType previous); @@ -140,18 +148,20 @@ private: QRect _muteIconRect; HandleMouseState _handleMouseState = HandleMouseState::Enabled; - const style::CallButton &_st; + not_null _st; const base::unique_qptr _blobs; const base::unique_qptr _content; - const base::unique_qptr _centerLabel; - const base::unique_qptr _label; - const base::unique_qptr _sublabel; + base::unique_qptr _centerLabel; + base::unique_qptr _label; + base::unique_qptr _sublabel; int _labelShakeShift = 0; RadialInfo _radialInfo; std::unique_ptr _radial; const base::flat_map _colors; + anim::linear_gradients _linearGradients; + anim::radial_gradients _glowGradients; std::array, 2> _icons; IconState _iconState;