Improve box rounding and buttons.

This commit is contained in:
John Preston 2022-02-07 18:35:32 +03:00
parent feb2d3066e
commit 7b0513a1ea
11 changed files with 78 additions and 45 deletions

View file

@ -1381,7 +1381,7 @@ void EditNameBox::prepare() {
newHeight += st::contactSkip + _last->height();
newHeight += st::boxPadding.bottom() + st::contactPadding.bottom();
setDimensions(st::boxWideWidth, newHeight);
setDimensions(st::boxWidth, newHeight);
addButton(tr::lng_settings_save(), [=] { save(); });
addButton(tr::lng_cancel(), [=] { closeBox(); });

View file

@ -139,8 +139,8 @@ contactUserIcon: icon {{ "settings/settings_name", menuIconFg }};
contactPhoneIcon: icon {{ "settings/settings_phone_number", menuIconFg }};
contactIconPosition: point(-5px, 23px);
contactPadding: margins(49px, 2px, 0px, 12px);
contactSkip: 6px;
contactPadding: margins(49px, 2px, 0px, 14px);
contactSkip: 9px;
contactPhoneSkip: 30px;
contactsPhotoSize: 42px;

View file

@ -93,6 +93,7 @@ PeerShortInfoCover::PeerShortInfoCover(
, _name(_widget.get(), std::move(name), _nameStyle->st)
, _statusStyle(std::make_unique<CustomLabelStyle>(_st.status))
, _status(_widget.get(), std::move(status), _statusStyle->st)
, _roundMask(Images::CornersMask(_st.radius))
, _videoPaused(std::move(videoPaused)) {
_widget->setCursor(_cursor);
@ -145,7 +146,7 @@ PeerShortInfoCover::PeerShortInfoCover(
_st.size);
_roundedTopImage = QImage(
QSize(_st.size, st::boxRadius) * style::DevicePixelRatio(),
QSize(_st.size, _st.radius) * style::DevicePixelRatio(),
QImage::Format_ARGB32_Premultiplied);
_roundedTopImage.setDevicePixelRatio(style::DevicePixelRatio());
_roundedTopImage.fill(Qt::transparent);
@ -161,6 +162,10 @@ object_ptr<Ui::RpWidget> PeerShortInfoCover::takeOwned() {
return std::move(_owned);
}
gsl::span<const QImage, 4> PeerShortInfoCover::roundMask() const {
return _roundMask;
}
void PeerShortInfoCover::setScrollTop(int scrollTop) {
_scrollTop = scrollTop;
_widget->update();
@ -176,16 +181,21 @@ rpl::lifetime &PeerShortInfoCover::lifetime() {
void PeerShortInfoCover::paint(QPainter &p) {
checkStreamedIsStarted();
const auto frame = currentVideoFrame();
auto frame = currentVideoFrame();
auto paused = _videoPaused && _videoPaused();
if (frame.isNull() && _userpicImage.isNull()) {
if (!frame.isNull()) {
frame = Images::Round(
std::move(frame),
_roundMask,
RectPart::TopLeft | RectPart::TopRight);
} else if (_userpicImage.isNull()) {
auto image = QImage(
_widget->size() * style::DevicePixelRatio(),
QImage::Format_ARGB32_Premultiplied);
image.fill(Qt::black);
_userpicImage = Images::Round(
std::move(image),
ImageRoundRadius::Small,
_roundMask,
RectPart::TopLeft | RectPart::TopRight);
}
@ -200,7 +210,7 @@ void PeerShortInfoCover::paint(QPainter &p) {
void PeerShortInfoCover::paintCoverImage(QPainter &p, const QImage &image) {
const auto roundedWidth = _st.size;
const auto roundedHeight = st::boxRadius;
const auto roundedHeight = _st.radius;
const auto covered = (_st.size - _scrollTop);
if (covered <= 0) {
return;
@ -230,7 +240,7 @@ void PeerShortInfoCover::paintCoverImage(QPainter &p, const QImage &image) {
q.end();
_roundedTopImage = Images::Round(
std::move(_roundedTopImage),
ImageRoundRadius::Small,
_roundMask,
RectPart::TopLeft | RectPart::TopRight);
p.drawImage(
QRect(0, from, roundedWidth, rounded),
@ -245,7 +255,7 @@ void PeerShortInfoCover::paintBars(QPainter &p) {
_shadowTop = Images::GenerateShadow(height, kShadowMaxAlpha, 0);
_shadowTop = Images::Round(
_shadowTop.scaled(QSize(_st.size, height) * factor),
ImageRoundRadius::Small,
_roundMask,
RectPart::TopLeft | RectPart::TopRight);
}
const auto shadowRect = QRect(0, _scrollTop, _st.size, height);
@ -395,8 +405,6 @@ QImage PeerShortInfoCover::currentVideoFrame() const {
const auto request = Media::Streaming::FrameRequest{
.resize = size * style::DevicePixelRatio(),
.outer = size,
.radius = ImageRoundRadius::Small,
.corners = RectPart::TopLeft | RectPart::TopRight,
};
return (_videoInstance
&& _videoInstance->player().ready()
@ -420,9 +428,12 @@ void PeerShortInfoCover::applyUserpic(PeerShortInfoUserpic &&value) {
const auto videoChanged = _videoInstance
? (_videoInstance->shared() != value.videoDocument)
: (value.videoDocument != nullptr);
const auto frame = videoChanged ? currentVideoFrame() : QImage();
auto frame = videoChanged ? currentVideoFrame() : QImage();
if (!frame.isNull()) {
_userpicImage = frame;
_userpicImage = Images::Round(
std::move(frame),
_roundMask,
RectPart::TopLeft | RectPart::TopRight);
}
} else if (_userpicImage.cacheKey() != value.photo.cacheKey()) {
_userpicImage = std::move(value.photo);
@ -771,7 +782,7 @@ void PeerShortInfoBox::refreshRoundedTopImage(const QColor &color) {
_roundedTop.fill(color);
_roundedTop = Images::Round(
std::move(_roundedTop),
ImageRoundRadius::Small,
_cover.roundMask(),
RectPart::TopLeft | RectPart::TopRight);
}

View file

@ -65,6 +65,8 @@ public:
[[nodiscard]] not_null<Ui::RpWidget*> widget() const;
[[nodiscard]] object_ptr<Ui::RpWidget> takeOwned();
[[nodiscard]] gsl::span<const QImage, 4> roundMask() const;
void setScrollTop(int scrollTop);
[[nodiscard]] rpl::producer<int> moveRequests() const;
@ -106,6 +108,7 @@ private:
std::unique_ptr<CustomLabelStyle> _statusStyle;
object_ptr<Ui::FlatLabel> _status;
std::array<QImage, 4> _roundMask;
QImage _userpicImage;
QImage _roundedTopImage;
QImage _barSmall;

View file

@ -41,6 +41,8 @@ struct UserpicState {
std::vector<std::shared_ptr<Data::PhotoMedia>> photoPreloads;
InMemoryKey userpicKey;
PhotoId photoId = PeerData::kUnknownPhotoId;
std::array<QImage, 4> roundMask;
int size = 0;
bool waitingFull = false;
bool waitingLoad = false;
};
@ -50,16 +52,16 @@ void GenerateImage(
QImage image,
bool blurred = false) {
using namespace Images;
const auto size = st::shortInfoWidth;
const auto size = state->size;
const auto ratio = style::DevicePixelRatio();
const auto options = Option::RoundSmall
| Option::RoundSkipBottomLeft
| Option::RoundSkipBottomRight
| (blurred ? Option::Blur : Option());
state->current.photo = Images::Prepare(
std::move(image),
QSize(size, size) * ratio,
{ .options = options, .outer = { size, size } });
const auto options = blurred ? Option::Blur : Option();
state->current.photo = Images::Round(
Images::Prepare(
std::move(image),
QSize(size, size) * ratio,
{ .options = options, .outer = { size, size } }),
state->roundMask,
RectPart::TopLeft | RectPart::TopRight);
}
void GenerateImage(
@ -350,14 +352,19 @@ bool ProcessCurrent(
}
[[nodiscard]] PreparedShortInfoUserpic UserpicValue(
not_null<PeerData*> peer) {
not_null<PeerData*> peer,
const style::ShortInfoCover &st) {
const auto moveRequests = std::make_shared<rpl::event_stream<int>>();
auto move = [=](int shift) {
moveRequests->fire_copy(shift);
};
const auto size = st.size;
const auto radius = st.radius;
auto value = [=](auto consumer) {
auto lifetime = rpl::lifetime();
const auto state = lifetime.make_state<UserpicState>();
state->size = size;
state->roundMask = Images::CornersMask(radius);
const auto push = [=](bool force = false) {
if (ProcessCurrent(peer, state) || force) {
consumer.put_next_copy(state->current);
@ -421,7 +428,7 @@ object_ptr<Ui::BoxContent> PrepareShortInfoBox(
: peer->isBroadcast()
? PeerShortInfoType::Channel
: PeerShortInfoType::Group;
auto userpic = UserpicValue(peer);
auto userpic = UserpicValue(peer, st::shortInfoCover);
auto result = Box<PeerShortInfoBox>(
type,
FieldsValue(peer),
@ -456,6 +463,8 @@ rpl::producer<QString> PrepareShortInfoStatus(not_null<PeerData*> peer) {
return StatusValue(peer);
}
PreparedShortInfoUserpic PrepareShortInfoUserpic(not_null<PeerData*> peer) {
return UserpicValue(peer);
PreparedShortInfoUserpic PrepareShortInfoUserpic(
not_null<PeerData*> peer,
const style::ShortInfoCover &st) {
return UserpicValue(peer, st);
}

View file

@ -11,6 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class PeerData;
namespace style {
struct ShortInfoCover;
} // namespace style
namespace Ui {
class BoxContent;
} // namespace Ui
@ -39,4 +43,5 @@ struct PreparedShortInfoUserpic {
not_null<PeerData*> peer);
[[nodiscard]] PreparedShortInfoUserpic PrepareShortInfoUserpic(
not_null<PeerData*> peer);
not_null<PeerData*> peer,
const style::ShortInfoCover &st);

View file

@ -916,7 +916,7 @@ void SendFilesBox::paintEvent(QPaintEvent *e) {
p.setPen(st::boxTitleFg);
p.drawTextLeft(
st::boxPhotoTitlePosition.x(),
st::boxTitlePosition.y(),
st::boxTitlePosition.y() - st::boxTopMargin,
width(),
_titleText);
}

View file

@ -553,6 +553,7 @@ groupCallPopupMenuWithCover: PopupMenu(groupCallPopupMenu) {
}
}
groupCallMenuCover: ShortInfoCover(shortInfoCover) {
radius: roundRadiusSmall;
size: groupCallMenuCoverSize;
namePosition: point(17px, 28px);
statusPosition: point(17px, 8px);

View file

@ -1263,7 +1263,9 @@ base::unique_qptr<Ui::PopupMenu> Members::Controller::createRowContextMenu(
participantPeer
) | rpl::map([](const auto &text) { return text.text; }),
PrepareShortInfoStatus(participantPeer),
PrepareShortInfoUserpic(participantPeer)));
PrepareShortInfoUserpic(
participantPeer,
st::groupCallMenuCover)));
if (const auto about = participantPeer->about(); !about.isEmpty()) {
result->addAction(base::make_unique_q<AboutItem>(

View file

@ -199,40 +199,40 @@ infoLayerTopBarBack: IconButton(infoTopBarBack) {
width: infoLayerTopBarHeight;
height: infoLayerTopBarHeight;
iconPosition: point(12px, -1px);
iconPosition: point(10px, -1px);
icon: infoLayerTopBarBackIcon;
iconOver: infoLayerTopBarBackIconOver;
rippleAreaSize: 44px;
rippleAreaSize: 40px;
rippleAreaPosition: point(6px, 4px);
}
infoLayerTopBarMediaCancel: IconButton(infoLayerTopBarBack) {
icon: icon {{ "info_close", boxTitleCloseFg }};
iconOver: icon {{ "info_close", boxTitleCloseFgOver }};
}
infoLayerTopBarClose: IconButton(infoLayerTopBarMediaCancel) {
width: 50px;
iconPosition: point(6px, -1px);
rippleAreaPosition: point(0px, 6px);
iconPosition: point(4px, -1px);
rippleAreaPosition: point(0px, 4px);
}
infoLayerTopBarMenu: IconButton(infoLayerTopBarClose) {
width: 44px;
width: 40px;
icon: icon {{ "title_menu_dots", boxTitleCloseFg }};
iconOver: icon {{ "title_menu_dots", boxTitleCloseFgOver }};
iconPosition: point(18px, -1px);
iconPosition: point(16px, -1px);
}
infoLayerTopBarNotifications: IconButton(infoLayerTopBarMenu) {
icon: icon {{ "info_notifications", boxTitleCloseFg }};
iconOver: icon {{ "info_notifications", boxTitleCloseFgOver }};
iconPosition: point(5px, 11px);
iconPosition: point(3px, 9px);
}
infoLayerTopBarCall: IconButton(infoLayerTopBarMenu) {
icon: icon {{ "top_bar_call", boxTitleCloseFg }};
iconOver: icon {{ "top_bar_call", boxTitleCloseFgOver }};
iconPosition: point(5px, -1px);
iconPosition: point(3px, -1px);
}
infoLayerTopBarSave: IconButton(infoLayerTopBarNotifications) {
icon: icon {{ "passport_ready", windowActiveTextFg }};
iconOver: icon {{ "passport_ready", windowActiveTextFg }};
iconPosition: point(13px, 18px);
iconPosition: point(11px, 16px);
ripple: RippleAnimation(defaultRippleAnimation) {
color: lightButtonBgOver;
}
@ -242,7 +242,7 @@ infoLayerTopBarForward: IconButton(infoLayerTopBarBack) {
icon: icon {{ "info_media_forward", boxTitleCloseFg }};
iconOver: icon {{ "info_media_forward", boxTitleCloseFgOver }};
iconPosition: point(11px, -1px);
rippleAreaPosition: point(1px, 6px);
rippleAreaPosition: point(3px, 4px);
}
infoLayerTopBarDelete: IconButton(infoLayerTopBarForward) {
icon: icon {{ "info_media_delete", boxTitleCloseFg }};
@ -252,7 +252,7 @@ infoLayerTopBar: InfoTopBar(infoTopBar) {
height: infoLayerTopBarHeight;
back: infoLayerTopBarBack;
title: boxTitle;
titlePosition: boxTitlePosition;
titlePosition: point(24px, 13px);
bg: boxBg;
mediaCancel: infoLayerTopBarMediaCancel;
mediaActionsSkip: 6px;
@ -955,7 +955,7 @@ infoScrollDateHideTimeout: historyScrollDateHideTimeout;
infoDateFadeDuration: historyDateFadeDuration;
shortInfoWidth: 304px;
shortInfoLabeledPadding: margins(20px, 16px, 20px, 0px);
shortInfoLabeledPadding: margins(24px, 16px, 24px, 0px);
shortInfoScroll: ScrollArea(defaultScrollArea) {
deltat: 3px;
deltab: 0px;
@ -969,6 +969,7 @@ shortInfoScroll: ScrollArea(defaultScrollArea) {
ShortInfoCover {
size: pixels;
radius: pixels;
name: FlatLabel;
namePosition: point;
status: FlatLabel;
@ -981,6 +982,7 @@ ShortInfoCover {
}
shortInfoCover: ShortInfoCover {
size: shortInfoWidth;
radius: boxRadius;
name: FlatLabel(defaultFlatLabel) {
textFg: groupCallVideoTextFg;
maxHeight: 19px;

@ -1 +1 @@
Subproject commit 7e1effeeebfc411fbdf0370754dc7d9735f33805
Subproject commit 681da392eb0523e87f9c1e9b3c732757e0c18850