Improve narrow participants column design.

This commit is contained in:
John Preston 2021-05-06 19:57:40 +04:00
parent 0dcc7a05f7
commit 00ce302b38
12 changed files with 271 additions and 116 deletions

View File

@ -2069,8 +2069,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_group_call_context_remove_hand" = "Cancel request to speak";
"lng_group_call_context_mute_for_me" = "Mute for me";
"lng_group_call_context_unmute_for_me" = "Unmute for me";
"lng_group_call_context_pin_video" = "Pin video";
"lng_group_call_context_unpin_video" = "Unpin video";
"lng_group_call_context_pin_camera" = "Pin video";
"lng_group_call_context_unpin_camera" = "Unpin video";
"lng_group_call_context_pin_screen" = "Pin screencast";
"lng_group_call_context_unpin_screen" = "Unpin screencast";
"lng_group_call_context_remove" = "Remove";
"lng_group_call_remove_channel" = "Remove {channel} from the voice chat?";
"lng_group_call_duration_days#one" = "{count} day";

View File

@ -811,9 +811,6 @@ groupCallHangupSmall: CallButton(groupCallHangup) {
groupCallVideoSmallInner: IconButton(groupCallSettingsInner) {
icon: icon {{ "calls/call_camera_muted", groupCallIconFg }};
iconPosition: point(-1px, 16px);
ripple: RippleAnimation(defaultRippleAnimation) {
color: groupCallLeaveBgRipple;
}
height: 76px;
}
groupCallVideoSmall: CallButton(groupCallShareSmall) {
@ -1136,6 +1133,19 @@ desktopCaptureSubmit: RoundButton(desktopCaptureCancel) {
groupCallNarrowSkip: 9px;
groupCallNarrowRowSkip: 8px;
groupCallNarrowSize: size(90px, 90px);
groupCallNarrowSize: size(144px, 90px);
groupCallWideModeWidthMin: 520px;
groupCallWideModeSize: size(720px, 480px);
groupCallNarrowAddMemberHeight: 32px;
groupCallNarrowAddMember: RoundButton(defaultActiveButton) {
textFg: groupCallMemberNotJoinedStatus;
textFgOver: groupCallMemberNotJoinedStatus;
textBg: groupCallMembersBg;
textBgOver: groupCallMembersBgOver;
height: 32px;
radius: roundRadiusLarge;
ripple: groupCallRipple;
}

View File

@ -388,6 +388,10 @@ GroupCall::GroupCall(
, _joinHash(info.joinHash)
, _id(inputCall.c_inputGroupCall().vid().v)
, _scheduleDate(info.scheduleDate)
, _cameraOutgoing(std::make_unique<Webrtc::VideoTrack>(
Webrtc::VideoState::Inactive))
, _screenOutgoing(std::make_unique<Webrtc::VideoTrack>(
Webrtc::VideoState::Inactive))
, _lastSpokeCheckTimer([=] { checkLastSpoke(); })
, _checkJoinedTimer([=] { checkJoined(); })
, _pushToTalkCancelTimer([=] { pushToTalkCancel(); })
@ -460,8 +464,15 @@ GroupCall::~GroupCall() {
}
bool GroupCall::isSharingScreen() const {
return _screenOutgoing
&& (_screenOutgoing->state() == Webrtc::VideoState::Active);
return (_screenOutgoing->state() == Webrtc::VideoState::Active);
}
rpl::producer<bool> GroupCall::isSharingScreenValue() const {
using namespace rpl::mappers;
return _screenOutgoing->stateValue(
) | rpl::map(
_1 == Webrtc::VideoState::Active
) | rpl::distinct_until_changed();
}
const std::string &GroupCall::screenSharingEndpoint() const {
@ -469,8 +480,15 @@ const std::string &GroupCall::screenSharingEndpoint() const {
}
bool GroupCall::isSharingCamera() const {
return _cameraOutgoing
&& (_cameraOutgoing->state() == Webrtc::VideoState::Active);
return (_cameraOutgoing->state() == Webrtc::VideoState::Active);
}
rpl::producer<bool> GroupCall::isSharingCameraValue() const {
using namespace rpl::mappers;
return _cameraOutgoing->stateValue(
) | rpl::map(
_1 == Webrtc::VideoState::Active
) | rpl::distinct_until_changed();
}
const std::string &GroupCall::cameraSharingEndpoint() const {
@ -611,7 +629,7 @@ void GroupCall::subscribeToReal(not_null<Data::GroupCall*> real) {
const auto wasSounding = data.was && data.was->sounding;
if (nowSpeaking == wasSpeaking && nowSounding == wasSounding) {
return;
} else if (!_videoEndpointPinned.empty()) {
} else if (!_videoEndpointPinned.current().empty()) {
return;
}
if (nowScreenEndpoint != newLarge
@ -876,7 +894,7 @@ void GroupCall::setMyEndpointType(
}
const auto nowLarge = activeVideoEndpointType(
_videoEndpointLarge.current());
if (_videoEndpointPinned.empty()
if (_videoEndpointPinned.current().empty()
&& ((type == EndpointType::Screen
&& nowLarge != EndpointType::Screen)
|| (type == EndpointType::Camera
@ -1604,14 +1622,10 @@ void GroupCall::setupMediaDevices() {
void GroupCall::ensureOutgoingVideo() {
Expects(_id != 0);
if (_cameraOutgoing) {
if (_videoInited) {
return;
}
_cameraOutgoing = std::make_unique<Webrtc::VideoTrack>(
Webrtc::VideoState::Inactive);
_screenOutgoing = std::make_unique<Webrtc::VideoTrack>(
Webrtc::VideoState::Inactive);
_videoInited = true;
//static const auto hasDevices = [] {
// return !Webrtc::GetVideoInputList().empty();
@ -2057,7 +2071,7 @@ void GroupCall::setIncomingVideoEndpoints(
feedOne(cameraSharingEndpoint());
feedOne(screenSharingEndpoint());
if (!newLarge.empty() && !newLargeFound) {
newLarge = _videoEndpointPinned = std::string();
_videoEndpointPinned = newLarge = std::string();
}
if (newLarge.empty()) {
_videoEndpointLarge = chooseLargeVideoEndpoint();
@ -2105,7 +2119,7 @@ void GroupCall::fillActiveVideoEndpoints() {
feedOne(cameraSharingEndpoint(), EndpointType::Camera);
feedOne(screenSharingEndpoint(), EndpointType::Screen);
if (!newLarge.empty() && !newLargeFound) {
newLarge = _videoEndpointPinned = std::string();
_videoEndpointPinned = newLarge = std::string();
}
if (newLarge.empty()) {
_videoEndpointLarge = chooseLargeVideoEndpoint();
@ -2453,8 +2467,7 @@ void GroupCall::sendSelfUpdate(SendUpdateType type) {
MTP_bool(muted() != MuteState::Active),
MTP_int(100000), // volume
MTP_bool(muted() == MuteState::RaisedHand),
MTP_bool(!_cameraOutgoing
|| _cameraOutgoing->state() != Webrtc::VideoState::Active)
MTP_bool(_cameraOutgoing->state() != Webrtc::VideoState::Active)
)).done([=](const MTPUpdates &result) {
_updateMuteRequestId = 0;
_peer->session().api().applyUpdates(result);
@ -2472,7 +2485,9 @@ void GroupCall::pinVideoEndpoint(const std::string &endpoint) {
if (endpoint.empty()) {
_videoEndpointPinned = endpoint;
} else if (streamsVideo(endpoint)) {
_videoEndpointLarge = _videoEndpointPinned = endpoint;
_videoEndpointPinned = std::string();
_videoEndpointLarge = endpoint;
_videoEndpointPinned = endpoint;
}
}

View File

@ -235,10 +235,13 @@ public:
&& activeVideoEndpointType(endpoint) != EndpointType::None;
}
[[nodiscard]] const std::string &videoEndpointPinned() const {
return _videoEndpointPinned;
return _videoEndpointPinned.current();
}
[[nodiscard]] rpl::producer<std::string> videoEndpointPinnedValue() const {
return _videoEndpointPinned.value();
}
void pinVideoEndpoint(const std::string &endpoint);
[[nodiscard]] std::string videoEndpointLarge() const {
[[nodiscard]] const std::string &videoEndpointLarge() const {
return _videoEndpointLarge.current();
}
[[nodiscard]] auto videoEndpointLargeValue() const
@ -266,8 +269,10 @@ public:
void setCurrentAudioDevice(bool input, const QString &deviceId);
void setCurrentVideoDevice(const QString &deviceId);
[[nodiscard]] bool isSharingScreen() const;
[[nodiscard]] rpl::producer<bool> isSharingScreenValue() const;
[[nodiscard]] const std::string &screenSharingEndpoint() const;
[[nodiscard]] bool isSharingCamera() const;
[[nodiscard]] rpl::producer<bool> isSharingCameraValue() const;
[[nodiscard]] const std::string &cameraSharingEndpoint() const;
[[nodiscard]] QString screenSharingDeviceId() const;
void toggleVideo(bool active);
@ -462,12 +467,14 @@ private:
std::unique_ptr<Webrtc::VideoTrack> _screenOutgoing;
QString _screenDeviceId;
bool _videoInited = false;
rpl::event_stream<LevelUpdate> _levelUpdates;
rpl::event_stream<StreamsVideoUpdate> _streamsVideoUpdated;
base::flat_set<std::string> _incomingVideoEndpoints;
base::flat_map<std::string, EndpointType> _activeVideoEndpoints;
rpl::variable<std::string> _videoEndpointLarge;
std::string _videoEndpointPinned;
rpl::variable<std::string> _videoEndpointPinned;
std::unique_ptr<LargeTrack> _videoLargeTrackWrap;
rpl::variable<Webrtc::VideoTrack*> _videoLargeTrack;
base::flat_map<uint32, Data::LastSpokeTimes> _lastSpoke;

View File

@ -185,7 +185,8 @@ public:
int x,
int y,
int outerWidth,
int size,
int sizew,
int sizeh,
PanelMode mode,
bool selected = false);
@ -256,19 +257,32 @@ private:
void ensureUserpicCache(
std::shared_ptr<Data::CloudImageView> &view,
int size);
bool paintVideo(Painter &p, int x, int y, int size, PanelMode mode);
bool paintVideo(
Painter &p,
int x,
int y,
int sizew,
int sizeh,
PanelMode mode);
[[nodiscard]] static std::tuple<int, int, int> UserpicInWideMode(
int x,
int y,
int size);
void paintBlobs(Painter &p, int x, int y, int size, PanelMode mode);
int sizew,
int sizeh);
void paintBlobs(
Painter &p,
int x,
int y,
int sizew,
int sizeh, PanelMode mode);
void paintScaledUserpic(
Painter &p,
std::shared_ptr<Data::CloudImageView> &userpic,
int x,
int y,
int outerWidth,
int size,
int sizew,
int sizeh,
PanelMode mode);
const not_null<RowDelegate*> _delegate;
@ -694,7 +708,13 @@ void Row::ensureUserpicCache(
}
}
bool Row::paintVideo(Painter &p, int x, int y, int size, PanelMode mode) {
bool Row::paintVideo(
Painter &p,
int x,
int y,
int sizew,
int sizeh,
PanelMode mode) {
if (!_videoTrackShown) {
return false;
}
@ -706,12 +726,14 @@ bool Row::paintVideo(Painter &p, int x, int y, int size, PanelMode mode) {
|| _videoTrackShown->state() != Webrtc::VideoState::Active) {
return false;
}
const auto resize = (videoSize.width() > videoSize.height())
? QSize(videoSize.width() * size / videoSize.height(), size)
: QSize(size, videoSize.height() * size / videoSize.width());
const auto videow = videoSize.width();
const auto videoh = videoSize.height();
const auto resize = (videow * sizeh > videoh * sizew)
? QSize(videow * sizeh / videoh, sizeh)
: QSize(sizew, videoh * sizew / videow);
const auto request = Webrtc::FrameRequest{
.resize = resize * cIntRetinaFactor(),
.outer = QSize(size, size) * cIntRetinaFactor(),
.outer = QSize(sizew, sizeh) * cIntRetinaFactor(),
};
const auto frame = _videoTrackShown->frame(request);
auto copy = frame; // #TODO calls optimize.
@ -727,18 +749,30 @@ bool Row::paintVideo(Painter &p, int x, int y, int size, PanelMode mode) {
return true;
}
std::tuple<int, int, int> Row::UserpicInWideMode(int x, int y, int size) {
std::tuple<int, int, int> Row::UserpicInWideMode(
int x,
int y,
int sizew,
int sizeh) {
const auto useSize = st::groupCallMembersList.item.photoSize;
const auto skip = (size - useSize) / 2;
return { x + skip, y + skip, useSize };
const auto skipx = (sizew - useSize) / 2;
const auto skipy = (sizeh - useSize) / 2;
return { x + skipx, y + skipy, useSize };
}
void Row::paintBlobs(Painter &p, int x, int y, int size, PanelMode mode) {
void Row::paintBlobs(
Painter &p,
int x,
int y,
int sizew,
int sizeh,
PanelMode mode) {
if (!_blobsAnimation) {
return;
}
auto size = sizew;
if (mode == PanelMode::Wide) {
std::tie(x, y, size) = UserpicInWideMode(x, y, size);
std::tie(x, y, size) = UserpicInWideMode(x, y, sizew, sizeh);
}
const auto mutedByMe = (_state == State::MutedByMe);
const auto shift = QPointF(x + size / 2., y + size / 2.);
@ -761,10 +795,12 @@ void Row::paintScaledUserpic(
int x,
int y,
int outerWidth,
int size,
int sizew,
int sizeh,
PanelMode mode) {
auto size = sizew;
if (mode == PanelMode::Wide) {
std::tie(x, y, size) = UserpicInWideMode(x, y, size);
std::tie(x, y, size) = UserpicInWideMode(x, y, sizew, sizeh);
}
if (!_blobsAnimation) {
peer()->paintUserpicLeft(p, userpic, x, y, outerWidth, size);
@ -800,7 +836,8 @@ void Row::paintScaledUserpic(
auto Row::generatePaintUserpicCallback() -> PaintRoundImageCallback {
return [=](Painter &p, int x, int y, int outerWidth, int size) {
paintComplexUserpic(p, x, y, outerWidth, size, PanelMode::Default);
const auto outer = outerWidth;
paintComplexUserpic(p, x, y, outer, size, size, PanelMode::Default);
};
}
@ -809,18 +846,20 @@ void Row::paintComplexUserpic(
int x,
int y,
int outerWidth,
int size,
int sizew,
int sizeh,
PanelMode mode,
bool selected) {
if (mode == PanelMode::Wide) {
if (paintVideo(p, x, y, size, mode)) {
if (paintVideo(p, x, y, sizew, sizeh, mode)) {
return;
}
_delegate->rowPaintWideBackground(p, selected);
paintRipple(p, x, y, outerWidth);
}
paintBlobs(p, x, y, size, mode);
if (mode == PanelMode::Default && paintVideo(p, x, y, size, mode)) {
paintBlobs(p, x, y, sizew, sizeh, mode);
if (mode == PanelMode::Default
&& paintVideo(p, x, y, sizew, sizeh, mode)) {
return;
}
paintScaledUserpic(
@ -829,7 +868,8 @@ void Row::paintComplexUserpic(
x,
y,
outerWidth,
size,
sizew,
sizeh,
mode);
}
@ -1826,7 +1866,7 @@ void MembersController::rowPaintIcon(
void MembersController::rowPaintWideBackground(Painter &p, bool selected) {
(selected ? _wideRoundRectSelected : _wideRoundRect).paint(
p,
{ QPoint(), st::groupCallNarrowSize });
{ QPoint(st::groupCallNarrowSkip, 0), st::groupCallNarrowSize });
}
int MembersController::customRowHeight() {
@ -1840,12 +1880,14 @@ void MembersController::customRowPaint(
bool selected) {
const auto real = static_cast<Row*>(row.get());
const auto width = st::groupCallNarrowSize.width();
const auto height = st::groupCallNarrowSize.height();
real->paintComplexUserpic(
p,
0,
st::groupCallNarrowSkip,
0,
width,
width,
height,
PanelMode::Wide,
selected);
}
@ -1854,7 +1896,9 @@ bool MembersController::customRowSelectionPoint(
not_null<PeerListRow*> row,
int x,
int y) {
return y < st::groupCallNarrowSize.height();
return x >= st::groupCallNarrowSkip
&& x < st::groupCallNarrowSkip + st::groupCallNarrowSize.width()
&& y < st::groupCallNarrowSize.height();
}
Fn<QImage()> MembersController::customRowRippleMaskGenerator() {
@ -1973,7 +2017,7 @@ base::unique_qptr<Ui::PopupMenu> MembersController::createRowContextMenu(
const auto participant = real->participantByEndpoint(pinnedEndpoint);
if (participant && participant->peer == participantPeer) {
result->addAction(
tr::lng_group_call_context_unpin_video(tr::now),
tr::lng_group_call_context_unpin_camera(tr::now),
[=] { _call->pinVideoEndpoint(std::string()); });
} else {
const auto &participants = real->participants();
@ -1992,7 +2036,7 @@ base::unique_qptr<Ui::PopupMenu> MembersController::createRowContextMenu(
: camera);
};
result->addAction(
tr::lng_group_call_context_pin_video(tr::now),
tr::lng_group_call_context_pin_camera(tr::now),
callback);
}
}
@ -2292,27 +2336,61 @@ void Members::setupAddMember(not_null<GroupCall*> call) {
});
}
_canAddMembers.value(
) | rpl::start_with_next([=](bool can) {
rpl::combine(
_canAddMembers.value(),
_mode.value()
) | rpl::start_with_next([=](bool can, PanelMode mode) {
const auto old = _addMemberButton.current();
delete old;
if (!can) {
delete _addMemberButton.current();
_addMemberButton = nullptr;
updateControlsGeometry();
return;
} else if (_addMemberButton.current()) {
if (old) {
_addMemberButton = nullptr;
updateControlsGeometry();
}
return;
}
auto addMember = Settings::CreateButton(
this,
tr::lng_group_call_invite(),
st::groupCallAddMember,
&st::groupCallAddMemberIcon,
st::groupCallAddMemberIconLeft);
auto addMember = (Ui::AbstractButton*)nullptr;
auto wrap = [&]() -> object_ptr<Ui::RpWidget> {
if (mode == PanelMode::Default) {
auto result = Settings::CreateButton(
this,
tr::lng_group_call_invite(),
st::groupCallAddMember,
&st::groupCallAddMemberIcon,
st::groupCallAddMemberIconLeft,
&st::groupCallMemberInactiveIcon);
addMember = result.data();
return result;
}
auto result = object_ptr<Ui::RpWidget>(_layout.get());
const auto skip = st::groupCallNarrowSkip;
const auto fullwidth = st::groupCallNarrowSize.width()
+ 2 * skip;
const auto fullheight = st::groupCallNarrowAddMember.height
+ st::groupCallNarrowRowSkip;
result->resize(fullwidth, fullheight);
const auto button = Ui::CreateChild<Ui::RoundButton>(
result.data(),
rpl::single(QString()),
st::groupCallNarrowAddMember);
button->move(skip, 0);
const auto width = fullwidth - 2 * skip;
button->setFullWidth(width);
Settings::AddButtonIcon(
button,
&st::groupCallAddMemberIcon,
(width - st::groupCallAddMemberIcon.width()) / 2,
&st::groupCallMemberInactiveIcon);
addMember = button;
return result;
}();
addMember->show();
addMember->addClickHandler([=] { // TODO throttle(ripple duration)
_addMemberRequests.fire({});
});
_addMemberButton = _layout->insert(1, std::move(addMember));
addMember->clicks(
) | rpl::to_empty | rpl::start_to_stream(
_addMemberRequests,
addMember->lifetime());
_addMemberButton = wrap.data();
_layout->insert(1, std::move(wrap));
}, lifetime());
}

View File

@ -87,7 +87,7 @@ private:
std::unique_ptr<PeerListController> _listController;
not_null<Ui::VerticalLayout*> _layout;
const not_null<Ui::RpWidget*> _pinnedVideo;
rpl::variable<Ui::SettingsButton*> _addMemberButton = nullptr;
rpl::variable<Ui::RpWidget*> _addMemberButton = nullptr;
ListWidget *_list = nullptr;
rpl::event_stream<> _addMemberRequests;

View File

@ -65,6 +65,7 @@ constexpr auto kRecordingAnimationDuration = crl::time(1200);
constexpr auto kRecordingOpacity = 0.6;
constexpr auto kStartNoConfirmation = TimeId(10);
constexpr auto kControlsBackgroundOpacity = 0.8;
constexpr auto kOverrideActiveColorBgAlpha = 236;
class InviteController final : public ParticipantsBoxController {
public:
@ -713,8 +714,21 @@ void Panel::refreshLeftButton() {
}
const auto raw = _callShare ? _callShare.data() : _settings.data();
raw->show();
raw->setColorOverrides(_mute->colorOverrides());
auto overrides = _mute->colorOverrides();
raw->setColorOverrides(rpl::duplicate(overrides));
auto toggleableOverrides = [&](rpl::producer<bool> active) {
return rpl::combine(
std::move(active),
rpl::duplicate(overrides)
) | rpl::map([](bool active, Ui::CallButtonColors colors) {
if (active && colors.bg) {
colors.bg->setAlpha(kOverrideActiveColorBgAlpha);
}
return colors;
});
};
if (!_video) {
_video.create(
widget(),
@ -725,7 +739,12 @@ void Panel::refreshLeftButton() {
_call->toggleVideo(!_call->isSharingCamera());
});
_video->setText(tr::lng_group_call_video());
_video->setColorOverrides(_mute->colorOverrides());
_video->setColorOverrides(
toggleableOverrides(_call->isSharingCameraValue()));
_call->isSharingCameraValue(
) | rpl::start_with_next([=](bool sharing) {
_video->setProgress(sharing ? 1. : 0.);
}, _video->lifetime());
}
if (!_screenShare) {
_screenShare.create(widget(), st::groupCallScreenShareSmall);
@ -736,7 +755,12 @@ void Panel::refreshLeftButton() {
#endif // Q_OS_LINUX
});
_screenShare->setText(tr::lng_group_call_screen_share());
_screenShare->setColorOverrides(_mute->colorOverrides());
_screenShare->setColorOverrides(
toggleableOverrides(_call->isSharingScreenValue()));
_call->isSharingScreenValue(
) | rpl::start_with_next([=](bool sharing) {
_screenShare->setProgress(sharing ? 1. : 0.);
}, _screenShare->lifetime());
}
}
@ -1687,19 +1711,19 @@ void Panel::updateMembersGeometry() {
}
const auto desiredHeight = _members->desiredHeight();
if (_mode == PanelMode::Wide) {
const auto skip = st::groupCallNarrowSkip;
const auto membersWidth = st::groupCallNarrowSize.width() + 2 * skip;
const auto top = st::groupCallWideVideoTop;
_members->setGeometry(
st::groupCallNarrowSkip,
0,
st::groupCallNarrowSize.width(),
top,
membersWidth,
std::min(desiredHeight, widget()->height()));
const auto pinnedLeft = st::groupCallNarrowSkip * 2
+ st::groupCallNarrowSize.width();
const auto pinnedTop = st::groupCallWideVideoTop;
_pinnedVideo->setGeometry(
pinnedLeft,
pinnedTop,
widget()->width() - pinnedLeft - st::groupCallNarrowSkip,
widget()->height() - pinnedTop - st::groupCallNarrowSkip);
membersWidth,
top,
widget()->width() - membersWidth - skip,
widget()->height() - top - skip);
} else {
const auto membersBottom = _videoMode.current()
? (widget()->height() - st::groupCallMembersBottomSkipSmall)

View File

@ -35,9 +35,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Settings {
object_ptr<Section> CreateSection(
Type type,
not_null<QWidget*> parent,
not_null<Window::SessionController*> controller) {
Type type,
not_null<QWidget*> parent,
not_null<Window::SessionController*> controller) {
switch (type) {
case Type::Main:
return object_ptr<Main>(parent, controller);
@ -74,8 +74,8 @@ void AddDivider(not_null<Ui::VerticalLayout*> container) {
}
void AddDividerText(
not_null<Ui::VerticalLayout*> container,
rpl::producer<QString> text) {
not_null<Ui::VerticalLayout*> container,
rpl::producer<QString> text) {
container->add(object_ptr<Ui::DividerLabel>(
container,
object_ptr<Ui::FlatLabel>(
@ -85,37 +85,49 @@ void AddDividerText(
st::settingsDividerLabelPadding));
}
not_null<Ui::RpWidget*> AddButtonIcon(
not_null<Ui::AbstractButton*> button,
const style::icon *leftIcon,
int iconLeft,
const style::color *leftIconOver) {
const auto icon = Ui::CreateChild<Ui::RpWidget>(button.get());
icon->setAttribute(Qt::WA_TransparentForMouseEvents);
icon->resize(leftIcon->size());
button->sizeValue(
) | rpl::start_with_next([=](QSize size) {
icon->moveToLeft(
iconLeft ? iconLeft : st::settingsSectionIconLeft,
(size.height() - icon->height()) / 2,
size.width());
}, icon->lifetime());
icon->paintRequest(
) | rpl::start_with_next([=] {
Painter p(icon);
const auto width = icon->width();
const auto paintOver = (button->isOver() || button->isDown())
&& !button->isDisabled();
if (!paintOver) {
leftIcon->paint(p, QPoint(), width);
} else if (leftIconOver) {
leftIcon->paint(p, QPoint(), width, (*leftIconOver)->c);
} else {
leftIcon->paint(p, QPoint(), width, st::menuIconFgOver->c);
}
}, icon->lifetime());
return icon;
}
object_ptr<Button> CreateButton(
not_null<QWidget*> parent,
rpl::producer<QString> text,
const style::SettingsButton &st,
const style::icon *leftIcon,
int iconLeft) {
int iconLeft,
const style::color *leftIconOver) {
auto result = object_ptr<Button>(parent, std::move(text), st);
const auto button = result.data();
if (leftIcon) {
const auto icon = Ui::CreateChild<Ui::RpWidget>(button);
icon->setAttribute(Qt::WA_TransparentForMouseEvents);
icon->resize(leftIcon->size());
button->sizeValue(
) | rpl::start_with_next([=](QSize size) {
icon->moveToLeft(
iconLeft ? iconLeft : st::settingsSectionIconLeft,
(size.height() - icon->height()) / 2,
size.width());
}, icon->lifetime());
icon->paintRequest(
) | rpl::start_with_next([=] {
Painter p(icon);
const auto width = icon->width();
const auto paintOver = (button->isOver() || button->isDown())
&& !button->isDisabled();
if (paintOver) {
leftIcon->paint(p, QPoint(), width, st::menuIconFgOver->c);
} else {
leftIcon->paint(p, QPoint(), width);
}
}, icon->lifetime());
AddButtonIcon(button, leftIcon, iconLeft, leftIconOver);
}
return result;
}

View File

@ -18,6 +18,7 @@ namespace Ui {
class VerticalLayout;
class FlatLabel;
class SettingsButton;
class AbstractButton;
} // namespace Ui
namespace Window {
@ -70,12 +71,18 @@ void AddDivider(not_null<Ui::VerticalLayout*> container);
void AddDividerText(
not_null<Ui::VerticalLayout*> container,
rpl::producer<QString> text);
not_null<Ui::RpWidget*> AddButtonIcon(
not_null<Ui::AbstractButton*> button,
const style::icon *leftIcon,
int iconLeft,
const style::color *leftIconOver);
object_ptr<Button> CreateButton(
not_null<QWidget*> parent,
rpl::producer<QString> text,
const style::SettingsButton &st,
const style::icon *leftIcon = nullptr,
int iconLeft = 0);
int iconLeft = 0,
const style::color *leftIconOver = nullptr);
not_null<Button*> AddButton(
not_null<Ui::VerticalLayout*> container,
rpl::producer<QString> text,

@ -1 +1 @@
Subproject commit 6ee9e983b8eebceb2603633c12d4cf2b973be046
Subproject commit 5c950149f53f109dbac37bde8b1144234e7c3c9a

@ -1 +1 @@
Subproject commit e1b96399d9031c4ef0354631e6bb375029d29d9f
Subproject commit df721be3fa14a27dfc230d2e3c42bb1a7c9d0617

@ -1 +1 @@
Subproject commit 3c1866f52d88f9430341f9a9f1ed3dbbb3b794ea
Subproject commit b0c5d9220bb8f0fc614712167c8276504e60b224