[Option][GUI] Profile pic rounding

This commit is contained in:
Eric Kotato 2022-08-30 14:24:47 +03:00
parent 2b9f1ec0f8
commit 061b38ea98
45 changed files with 849 additions and 80 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -80,6 +80,12 @@
"ktg_settings_recent_stickers_limit_none": "Recent stickers: hide all", "ktg_settings_recent_stickers_limit_none": "Recent stickers: hide all",
"ktg_settings_filters": "Folders", "ktg_settings_filters": "Folders",
"ktg_settings_messages": "Messages", "ktg_settings_messages": "Messages",
"ktg_settings_userpic_rounding": "Profile pictures rounding",
"ktg_settings_userpic_rounding_none": "Square",
"ktg_settings_userpic_rounding_small": "Small",
"ktg_settings_userpic_rounding_big": "Big",
"ktg_settings_userpic_rounding_full": "Circle",
"ktg_settings_userpic_rounding_desc": "You'll need to restart app to save changes.",
"ktg_settings_chat_id": "Chat ID in profile", "ktg_settings_chat_id": "Chat ID in profile",
"ktg_settings_chat_id_desc": "You can choose desired format here.\n\nTelegram API uses IDs as-is, but Bot API adds minus in the beginning for groups, and -100 for channels and supergroups to fit it in one field.\n\nIf you have profile panel opened, re-open it to see changes.", "ktg_settings_chat_id_desc": "You can choose desired format here.\n\nTelegram API uses IDs as-is, but Bot API adds minus in the beginning for groups, and -100 for channels and supergroups to fit it in one field.\n\nIf you have profile panel opened, re-open it to see changes.",
"ktg_settings_chat_id_disable": "Hide", "ktg_settings_chat_id_disable": "Hide",

View file

@ -252,13 +252,15 @@ void ConfirmInviteBox::paintEvent(QPaintEvent *e) {
if (_photo) { if (_photo) {
if (const auto image = _photo->image(Data::PhotoSize::Small)) { if (const auto image = _photo->image(Data::PhotoSize::Small)) {
const auto size = st::confirmInvitePhotoSize; auto source = [=] {
const auto size = st::confirmInvitePhotoSize;
const auto roundOption = KotatoImageRoundOption();
return image->pix(size, size, { .options = roundOption });
}();
p.drawPixmap( p.drawPixmap(
(width() - size) / 2, (width() - st::confirmInvitePhotoSize) / 2,
st::confirmInvitePhotoTop, st::confirmInvitePhotoTop,
image->pix( source);
{ size, size },
{ .options = Images::Option::RoundCircle }));
} }
} else if (_photoEmpty) { } else if (_photoEmpty) {
_photoEmpty->paint( _photoEmpty->paint(

View file

@ -287,7 +287,24 @@ void PaintFilterChatsTypeIcon(
auto hq = PainterHighQualityEnabler(p); auto hq = PainterHighQualityEnabler(p);
p.setBrush(color->b); p.setBrush(color->b);
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.drawEllipse(rect); switch (KotatoImageRoundRadius()) {
case ImageRoundRadius::None:
p.drawRoundedRect(rect, 0, 0);
break;
case ImageRoundRadius::Small:
p.drawRoundedRect(rect,
st::buttonRadius, st::buttonRadius);
break;
case ImageRoundRadius::Large:
p.drawRoundedRect(rect,
st::dateRadius, st::dateRadius);
break;
default:
p.drawEllipse(rect);
}
icon.paintInCenter(p, rect); icon.paintInCenter(p, rect);
} }

View file

@ -727,7 +727,24 @@ void PeerListRow::paintDisabledCheckUserpic(
p.setPen(userpicBorderPen); p.setPen(userpicBorderPen);
p.setBrush(Qt::NoBrush); p.setBrush(Qt::NoBrush);
p.drawEllipse(userpicEllipse); switch (KotatoImageRoundRadius()) {
case ImageRoundRadius::None:
p.drawRoundedRect(userpicEllipse, 0, 0);
break;
case ImageRoundRadius::Small:
p.drawRoundedRect(userpicEllipse,
st::buttonRadius, st::buttonRadius);
break;
case ImageRoundRadius::Large:
p.drawRoundedRect(userpicEllipse,
st::dateRadius, st::dateRadius);
break;
default:
p.drawEllipse(userpicEllipse);
}
p.setPen(iconBorderPen); p.setPen(iconBorderPen);
p.setBrush(st.disabledCheckFg); p.setBrush(st.disabledCheckFg);

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "calls/calls_top_bar.h" #include "calls/calls_top_bar.h"
#include "kotato/kotato_settings.h"
#include "ui/effects/cross_line.h" #include "ui/effects/cross_line.h"
#include "ui/paint/blobs_linear.h" #include "ui/paint/blobs_linear.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
@ -249,7 +250,8 @@ TopBar::TopBar(
: std::make_unique<Ui::GroupCallUserpics>( : std::make_unique<Ui::GroupCallUserpics>(
st::groupCallTopBarUserpics, st::groupCallTopBarUserpics,
rpl::single(true), rpl::single(true),
[=] { updateUserpics(); })) [=] { updateUserpics(); },
::Kotato::JsonSettings::GetInt("userpic_corner_type")))
, _durationLabel(_call , _durationLabel(_call
? object_ptr<Ui::LabelSimple>(this, st::callBarLabel) ? object_ptr<Ui::LabelSimple>(this, st::callBarLabel)
: object_ptr<Ui::LabelSimple>(nullptr)) : object_ptr<Ui::LabelSimple>(nullptr))

View file

@ -16,8 +16,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_photo_media.h" #include "data/data_photo_media.h"
#include "data/data_file_origin.h" #include "data/data_file_origin.h"
#include "ui/empty_userpic.h" #include "ui/empty_userpic.h"
#include "ui/rect_part.h"
#include "apiwrap.h" // requestFullPeer. #include "apiwrap.h" // requestFullPeer.
#include "styles/style_calls.h" #include "styles/style_calls.h"
#include "styles/style_widgets.h"
namespace Calls { namespace Calls {
namespace { namespace {
@ -104,7 +106,25 @@ void Userpic::paint() {
_mutePosition.y() - _muteSize / 2, _mutePosition.y() - _muteSize / 2,
_muteSize, _muteSize,
_muteSize); _muteSize);
p.drawEllipse(rect); switch (KotatoImageRoundRadius()) {
case ImageRoundRadius::None:
p.drawRoundedRect(rect, 0, 0);
break;
case ImageRoundRadius::Small:
p.drawRoundedRect(rect,
st::buttonRadius, st::buttonRadius);
break;
case ImageRoundRadius::Large:
p.drawRoundedRect(rect,
st::dateRadius, st::dateRadius);
break;
default:
p.drawEllipse(rect);
}
st::callMutedPeerIcon.paintInCenter(p, rect); st::callMutedPeerIcon.paintInCenter(p, rect);
} }
} }
@ -180,13 +200,10 @@ void Userpic::createCache(Image *image) {
height = qMax((height * real) / width, 1); height = qMax((height * real) / width, 1);
width = real; width = real;
} }
_userPhoto = image->pixNoCache( const auto roundOption = KotatoImageRoundOption();
{ width, height }, _userPhoto = image->pix(size, size, {
{ .options = roundOption,
.options = Images::Option::RoundCircle, .outer = { size, size }});
.outer = { size, size },
});
_userPhoto.setDevicePixelRatio(cRetinaFactor());
} else { } else {
auto filled = QImage( auto filled = QImage(
QSize(real, real), QSize(real, real),

View file

@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h" #include "apiwrap.h"
#include "mainwidget.h" #include "mainwidget.h"
#include "styles/style_dialogs.h" #include "styles/style_dialogs.h"
#include "styles/style_widgets.h"
namespace Data { namespace Data {
namespace { namespace {
@ -247,7 +248,24 @@ void Folder::paintUserpic(
p.setBrush(overrideBg ? *overrideBg : st::historyPeerArchiveUserpicBg); p.setBrush(overrideBg ? *overrideBg : st::historyPeerArchiveUserpicBg);
{ {
PainterHighQualityEnabler hq(p); PainterHighQualityEnabler hq(p);
p.drawEllipse(x, y, size, size); switch (KotatoImageRoundRadius()) {
case ImageRoundRadius::None:
p.drawRoundedRect(QRect{ x, y, size, size }, 0, 0);
break;
case ImageRoundRadius::Small:
p.drawRoundedRect(QRect{ x, y, size, size },
st::buttonRadius, st::buttonRadius);
break;
case ImageRoundRadius::Large:
p.drawRoundedRect(QRect{ x, y, size, size },
st::dateRadius, st::dateRadius);
break;
default:
p.drawEllipse(x, y, size, size);
}
} }
if (size == st::dialogsPhotoSize) { if (size == st::dialogsPhotoSize) {
const auto rect = QRect{ x, y, size, size }; const auto rect = QRect{ x, y, size, size };

View file

@ -319,6 +319,30 @@ void PeerData::paintUserpic(
int x, int x,
int y, int y,
int size) const { int size) const {
switch (KotatoImageRoundRadius()) {
case ImageRoundRadius::None:
paintUserpicSquare(p, view, x, y, size);
break;
case ImageRoundRadius::Small:
paintUserpicRounded(p, view, x, y, size);
break;
case ImageRoundRadius::Large:
paintUserpicRoundedLarge(p, view, x, y, size);
break;
default:
paintUserpicCircled(p, view, x, y, size);
}
}
void PeerData::paintUserpicCircled(
Painter &p,
std::shared_ptr<Data::CloudImageView> &view,
int x,
int y,
int size) const {
if (const auto userpic = currentUserpic(view)) { if (const auto userpic = currentUserpic(view)) {
const auto circled = Images::Option::RoundCircle; const auto circled = Images::Option::RoundCircle;
p.drawPixmap( p.drawPixmap(
@ -330,6 +354,47 @@ void PeerData::paintUserpic(
} }
} }
void PeerData::paintUserpicRoundedLarge(
Painter &p,
std::shared_ptr<Data::CloudImageView> &view,
int x,
int y,
int size) const {
if (const auto userpic = currentUserpic(view)) {
const auto rounded = Images::Option::RoundLarge;
p.drawPixmap(x, y, userpic->pix(size, size, { .options = rounded }));
} else {
ensureEmptyUserpic()->paintRoundedLarge(p, x, y, x + size + x, size);
}
}
void PeerData::paintUserpicRounded(
Painter &p,
std::shared_ptr<Data::CloudImageView> &view,
int x,
int y,
int size) const {
if (const auto userpic = currentUserpic(view)) {
const auto rounded = Images::Option::RoundSmall;
p.drawPixmap(x, y, userpic->pix(size, size, { .options = rounded }));
} else {
ensureEmptyUserpic()->paintRounded(p, x, y, x + size + x, size);
}
}
void PeerData::paintUserpicSquare(
Painter &p,
std::shared_ptr<Data::CloudImageView> &view,
int x,
int y,
int size) const {
if (const auto userpic = currentUserpic(view)) {
p.drawPixmap(x, y, userpic->pix(size, size));
} else {
ensureEmptyUserpic()->paintSquare(p, x, y, x + size + x, size);
}
}
void PeerData::loadUserpic() { void PeerData::loadUserpic() {
_userpic.load(&session(), userpicOrigin()); _userpic.load(&session(), userpicOrigin());
} }
@ -384,7 +449,7 @@ QPixmap PeerData::genUserpic(
std::shared_ptr<Data::CloudImageView> &view, std::shared_ptr<Data::CloudImageView> &view,
int size) const { int size) const {
if (const auto userpic = currentUserpic(view)) { if (const auto userpic = currentUserpic(view)) {
const auto circle = Images::Option::RoundCircle; const auto circle = KotatoImageRoundOption();
return userpic->pix(size, size, { .options = circle }); return userpic->pix(size, size, { .options = circle });
} }
const auto ratio = style::DevicePixelRatio(); const auto ratio = style::DevicePixelRatio();
@ -403,7 +468,7 @@ QPixmap PeerData::genUserpic(
QImage PeerData::generateUserpicImage( QImage PeerData::generateUserpicImage(
std::shared_ptr<Data::CloudImageView> &view, std::shared_ptr<Data::CloudImageView> &view,
int size) const { int size) const {
return generateUserpicImage(view, size, ImageRoundRadius::Ellipse); return generateUserpicImage(view, size, KotatoImageRoundRadius());
} }
QImage PeerData::generateUserpicImage( QImage PeerData::generateUserpicImage(
@ -413,6 +478,8 @@ QImage PeerData::generateUserpicImage(
if (const auto userpic = currentUserpic(view)) { if (const auto userpic = currentUserpic(view)) {
const auto options = (radius == ImageRoundRadius::Ellipse) const auto options = (radius == ImageRoundRadius::Ellipse)
? Images::Option::RoundCircle ? Images::Option::RoundCircle
: (radius == ImageRoundRadius::Large)
? Images::Option::RoundLarge
: (radius == ImageRoundRadius::None) : (radius == ImageRoundRadius::None)
? Images::Option() ? Images::Option()
: Images::Option::RoundSmall; : Images::Option::RoundSmall;
@ -428,6 +495,8 @@ QImage PeerData::generateUserpicImage(
Painter p(&result); Painter p(&result);
if (radius == ImageRoundRadius::Ellipse) { if (radius == ImageRoundRadius::Ellipse) {
ensureEmptyUserpic()->paint(p, 0, 0, size, size); ensureEmptyUserpic()->paint(p, 0, 0, size, size);
} else if (radius == ImageRoundRadius::Large) {
ensureEmptyUserpic()->paintRoundedLarge(p, 0, 0, size, size);
} else if (radius == ImageRoundRadius::None) { } else if (radius == ImageRoundRadius::None) {
ensureEmptyUserpic()->paintSquare(p, 0, 0, size, size); ensureEmptyUserpic()->paintSquare(p, 0, 0, size, size);
} else { } else {

View file

@ -275,6 +275,30 @@ public:
int size) const { int size) const {
paintUserpic(p, view, rtl() ? (w - x - size) : x, y, size); paintUserpic(p, view, rtl() ? (w - x - size) : x, y, size);
} }
void paintUserpicCircled(
Painter &p,
std::shared_ptr<Data::CloudImageView> &view,
int x,
int y,
int size) const;
void paintUserpicRoundedLarge(
Painter &p,
std::shared_ptr<Data::CloudImageView> &view,
int x,
int y,
int size) const;
void paintUserpicRounded(
Painter &p,
std::shared_ptr<Data::CloudImageView> &view,
int x,
int y,
int size) const;
void paintUserpicSquare(
Painter &p,
std::shared_ptr<Data::CloudImageView> &view,
int x,
int y,
int size) const;
void loadUserpic(); void loadUserpic();
[[nodiscard]] bool hasUserpic() const; [[nodiscard]] bool hasUserpic() const;
[[nodiscard]] std::shared_ptr<Data::CloudImageView> activeUserpicView(); [[nodiscard]] std::shared_ptr<Data::CloudImageView> activeUserpicView();

View file

@ -455,7 +455,7 @@ bool ChannelHasActiveCall(not_null<ChannelData*> channel) {
rpl::producer<QImage> PeerUserpicImageValue( rpl::producer<QImage> PeerUserpicImageValue(
not_null<PeerData*> peer, not_null<PeerData*> peer,
int size) { int size) {
return PeerUserpicImageValue(peer, size, ImageRoundRadius::Ellipse); return PeerUserpicImageValue(peer, size, KotatoImageRoundRadius());
} }
rpl::producer<QImage> PeerUserpicImageValue( rpl::producer<QImage> PeerUserpicImageValue(

View file

@ -204,8 +204,12 @@ void BasicRow::PaintCornerBadgeFrame(
? st::dialogsOnlineBadgeFgActive ? st::dialogsOnlineBadgeFgActive
: st::dialogsOnlineBadgeFg); : st::dialogsOnlineBadgeFg);
q.drawEllipse(QRectF( q.drawEllipse(QRectF(
st::dialogsPhotoSize - skip.x() - size, st::dialogsPhotoSize - size -
st::dialogsPhotoSize - skip.y() - size, (KotatoImageRoundRadius() == ImageRoundRadius::Ellipse
? skip.x() : -(stroke / 2)),
st::dialogsPhotoSize - size -
(KotatoImageRoundRadius() == ImageRoundRadius::Ellipse
? skip.y() : -(stroke / 2)),
size, size,
size size
).marginsRemoved({ shrink, shrink, shrink, shrink })); ).marginsRemoved({ shrink, shrink, shrink, shrink }));
@ -266,12 +270,17 @@ void BasicRow::paintUserpic(
: st::dialogsBg; : st::dialogsBg;
const auto size = st::dialogsCallBadgeSize; const auto size = st::dialogsCallBadgeSize;
const auto skip = st::dialogsCallBadgeSkip; const auto skip = st::dialogsCallBadgeSkip;
const auto stroke = st::dialogsOnlineBadgeStroke;
p.setOpacity(shown); p.setOpacity(shown);
p.translate(st::dialogsPadding); p.translate(st::dialogsPadding);
actionPainter->paintSpeaking( actionPainter->paintSpeaking(
p, p,
st::dialogsPhotoSize - skip.x() - size, st::dialogsPhotoSize - size -
st::dialogsPhotoSize - skip.y() - size, (KotatoImageRoundRadius() == ImageRoundRadius::Ellipse
? skip.x() : -(stroke / 2)),
st::dialogsPhotoSize - size -
(KotatoImageRoundRadius() == ImageRoundRadius::Ellipse
? skip.y() : -(stroke / 2)),
fullWidth, fullWidth,
bg, bg,
now); now);

View file

@ -2563,7 +2563,7 @@ void HistoryWidget::refreshSendAsToggle() {
} else if (_sendAs) { } else if (_sendAs) {
return; return;
} }
_sendAs.create(this, st::sendAsButton); _sendAs.create(this, st::sendAsButton, ::Kotato::JsonSettings::GetInt("userpic_corner_type"));
Ui::SetupSendAsButton(_sendAs.data(), controller()); Ui::SetupSendAsButton(_sendAs.data(), controller());
} }
@ -6346,7 +6346,8 @@ void HistoryWidget::setupGroupCallBar() {
HistoryView::GroupCallBarContentByPeer( HistoryView::GroupCallBarContentByPeer(
peer, peer,
st::historyGroupCallUserpics.size), st::historyGroupCallUserpics.size),
Core::App().appDeactivatedValue()); Core::App().appDeactivatedValue(),
::Kotato::JsonSettings::GetInt("userpic_corner_type"));
controller()->adaptive().oneColumnValue( controller()->adaptive().oneColumnValue(
) | rpl::start_with_next([=](bool one) { ) | rpl::start_with_next([=](bool one) {
@ -6397,7 +6398,8 @@ void HistoryWidget::setupRequestsBar() {
this, this,
HistoryView::RequestsBarContentByPeer( HistoryView::RequestsBarContentByPeer(
peer, peer,
st::historyRequestsUserpics.size)); st::historyRequestsUserpics.size),
::Kotato::JsonSettings::GetInt("userpic_corner_type"));
controller()->adaptive().oneColumnValue( controller()->adaptive().oneColumnValue(
) | rpl::start_with_next([=](bool one) { ) | rpl::start_with_next([=](bool one) {

View file

@ -1974,7 +1974,8 @@ bool ComposeControls::updateSendAsButton() {
} }
_sendAs = std::make_unique<Ui::SendAsButton>( _sendAs = std::make_unique<Ui::SendAsButton>(
_wrap.get(), _wrap.get(),
st::sendAsButton); st::sendAsButton,
::Kotato::JsonSettings::GetInt("userpic_corner_type"));
Ui::SetupSendAsButton( Ui::SetupSendAsButton(
_sendAs.get(), _sendAs.get(),
rpl::single(peer.get()), rpl::single(peer.get()),

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "history/view/history_view_context_menu.h" #include "history/view/history_view_context_menu.h"
#include "kotato/kotato_settings.h"
#include "api/api_attached_stickers.h" #include "api/api_attached_stickers.h"
#include "api/api_editing.h" #include "api/api_editing.h"
#include "api/api_polls.h" #include "api/api_polls.h"
@ -1100,7 +1101,8 @@ void AddWhoReactedAction(
menu.get(), menu.get(),
Api::WhoReacted(item, context, st::defaultWhoRead, whoReadIds), Api::WhoReacted(item, context, st::defaultWhoRead, whoReadIds),
participantChosen, participantChosen,
showAllChosen)); showAllChosen,
::Kotato::JsonSettings::GetInt("userpic_corner_type")));
} }
void ShowWhoReactedMenu( void ShowWhoReactedMenu(

View file

@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "calls/calls_instance.h" #include "calls/calls_instance.h"
#include "core/application.h" #include "core/application.h"
#include "styles/style_chat.h" #include "styles/style_chat.h"
#include "styles/style_widgets.h"
namespace HistoryView { namespace HistoryView {
@ -57,7 +58,24 @@ void GenerateUserpicsInRow(
q.setCompositionMode(QPainter::CompositionMode_Source); q.setCompositionMode(QPainter::CompositionMode_Source);
q.setBrush(Qt::NoBrush); q.setBrush(Qt::NoBrush);
q.setPen(pen); q.setPen(pen);
q.drawEllipse(x, 0, single, single); switch (KotatoImageRoundRadius()) {
case ImageRoundRadius::None:
q.drawRoundedRect(QRect{ x, 0, single, single }, 0, 0);
break;
case ImageRoundRadius::Small:
q.drawRoundedRect(QRect{ x, 0, single, single },
st::buttonRadius, st::buttonRadius);
break;
case ImageRoundRadius::Large:
q.drawRoundedRect(QRect{ x, 0, single, single },
st::dateRadius, st::dateRadius);
break;
default:
q.drawEllipse(x, 0, single, single);
}
x -= single - shift; x -= single - shift;
} }
} }

View file

@ -188,7 +188,25 @@ void Contact::draw(Painter &p, const PaintContext &context) const {
PainterHighQualityEnabler hq(p); PainterHighQualityEnabler hq(p);
p.setBrush(p.textPalette().selectOverlay); p.setBrush(p.textPalette().selectOverlay);
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.drawEllipse(rthumb); switch (KotatoImageRoundRadius()) {
case ImageRoundRadius::None:
p.drawRoundedRect(rthumb, 0, 0);
break;
case ImageRoundRadius::Small:
p.drawRoundedRect(rthumb,
st::buttonRadius, st::buttonRadius);
break;
case ImageRoundRadius::Large:
p.drawRoundedRect(rthumb,
st::dateRadius, st::dateRadius);
break;
default:
p.drawEllipse(rthumb);
}
} }
bool over = ClickHandler::showAsActive(_linkl); bool over = ClickHandler::showAsActive(_linkl);

View file

@ -894,7 +894,24 @@ void Poll::paintRecentVoters(
p.setPen(pen); p.setPen(pen);
p.setBrush(Qt::NoBrush); p.setBrush(Qt::NoBrush);
PainterHighQualityEnabler hq(p); PainterHighQualityEnabler hq(p);
p.drawEllipse(x, y, size, size); switch (KotatoImageRoundRadius()) {
case ImageRoundRadius::None:
p.drawRoundedRect(QRect{ x, y, size, size }, 0, 0);
break;
case ImageRoundRadius::Small:
p.drawRoundedRect(QRect{ x, y, size, size },
st::buttonRadius, st::buttonRadius);
break;
case ImageRoundRadius::Large:
p.drawRoundedRect(QRect{ x, y, size, size },
st::dateRadius, st::dateRadius);
break;
default:
p.drawEllipse(x, y, size, size);
}
}; };
if (usesBubblePattern(context)) { if (usesBubblePattern(context)) {
const auto add = st::lineWidth * 2; const auto add = st::lineWidth * 2;

View file

@ -90,11 +90,39 @@ void PeerListDummy::paintEvent(QPaintEvent *e) {
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
for (auto i = from; i != till; ++i) { for (auto i = from; i != till; ++i) {
p.setBrush(st::windowBgOver); p.setBrush(st::windowBgOver);
p.drawEllipse( switch (KotatoImageRoundRadius()) {
_st.item.photoPosition.x(), case ImageRoundRadius::None:
_st.item.photoPosition.y(), p.drawRoundedRect(QRect{
_st.item.photoSize, _st.item.photoPosition.x(),
_st.item.photoSize); _st.item.photoPosition.y(),
_st.item.photoSize,
_st.item.photoSize }, 0, 0);
break;
case ImageRoundRadius::Small:
p.drawRoundedRect(QRect{
_st.item.photoPosition.x(),
_st.item.photoPosition.y(),
_st.item.photoSize,
_st.item.photoSize },
st::buttonRadius, st::buttonRadius);
break;
case ImageRoundRadius::Large:
p.drawRoundedRect(QRect{
_st.item.photoPosition.x(),
_st.item.photoPosition.y(),
_st.item.photoSize,
_st.item.photoSize },
st::dateRadius, st::dateRadius);
break;
default:
p.drawEllipse(_st.item.photoPosition.x(),
_st.item.photoPosition.y(),
_st.item.photoSize,
_st.item.photoSize);
}
const auto small = int(1.5 * _st.item.photoSize); const auto small = int(1.5 * _st.item.photoSize);
const auto large = 2 * small; const auto large = 2 * small;

View file

@ -363,6 +363,10 @@ const std::map<QString, Definition, std::greater<QString>> DefinitionMap {
.type = SettingType::IntSetting, .type = SettingType::IntSetting,
.defaultValue = 20, .defaultValue = 20,
.limitHandler = IntLimit(0, 200, 20), }}, .limitHandler = IntLimit(0, 200, 20), }},
{ "userpic_corner_type", {
.type = SettingType::IntSetting,
.defaultValue = 3,
.limitHandler = IntLimit(0, 3, 3), }},
}; };
using OldOptionKey = QString; using OldOptionKey = QString;

View file

@ -66,6 +66,26 @@ QString NetBoostLabel(int boost) {
return QString(); return QString();
} }
QString UserpicRoundingLabel(int rounding) {
switch (rounding) {
case 0:
return ktr("ktg_settings_userpic_rounding_none");
case 1:
return ktr("ktg_settings_userpic_rounding_small");
case 2:
return ktr("ktg_settings_userpic_rounding_big");
case 3:
return ktr("ktg_settings_userpic_rounding_full");
default:
Unexpected("Rounding in Settings::UserpicRoundingLabel.");
}
return QString();
}
QString ChatIdLabel(int option) { QString ChatIdLabel(int option) {
switch (option) { switch (option) {
case 0: case 0:
@ -176,6 +196,38 @@ void SetupKotatoChats(
Ui::show(Box<FontsBox>()); Ui::show(Box<FontsBox>());
}); });
const auto userpicCornerButton = container->add(
object_ptr<Button>(
container,
rktr("ktg_settings_userpic_rounding"),
st::settingsButton));
auto userpicCornerText = rpl::single(
UserpicRoundingLabel(::Kotato::JsonSettings::GetIntWithPending("userpic_corner_type"))
) | rpl::then(
::Kotato::JsonSettings::EventsWithPending(
"userpic_corner_type"
) | rpl::map([] {
return UserpicRoundingLabel(::Kotato::JsonSettings::GetIntWithPending("userpic_corner_type"));
})
);
CreateRightLabel(
userpicCornerButton,
std::move(userpicCornerText),
st::settingsButton,
rktr("ktg_settings_userpic_rounding"));
userpicCornerButton->addClickHandler([=] {
Ui::show(Box<::Kotato::RadioBox>(
ktr("ktg_settings_userpic_rounding"),
ktr("ktg_settings_userpic_rounding_desc"),
::Kotato::JsonSettings::GetIntWithPending("userpic_corner_type"),
4,
UserpicRoundingLabel,
[=] (int value) {
::Kotato::JsonSettings::SetAfterRestart("userpic_corner_type", value);
::Kotato::JsonSettings::Write();
}, true));
});
AddSkip(container); AddSkip(container);
AddDivider(container); AddDivider(container);

View file

@ -55,6 +55,7 @@ namespace {
[[nodiscard]] std::wstring NotificationTemplate( [[nodiscard]] std::wstring NotificationTemplate(
QString id, QString id,
Window::Notifications::Manager::DisplayOptions options) { Window::Notifications::Manager::DisplayOptions options) {
const auto crop = (KotatoImageRoundRadius() == ImageRoundRadius::Ellipse) ? L"circle" : L"none";
const auto wid = id.replace('&', "&amp;").toStdWString(); const auto wid = id.replace('&', "&amp;").toStdWString();
const auto fastReply = LR"( const auto fastReply = LR"(
<input id="fastReply" type="text" placeHolderContent=""/> <input id="fastReply" type="text" placeHolderContent=""/>
@ -77,7 +78,7 @@ namespace {
<toast launch="action=open&amp;)" + wid + LR"("> <toast launch="action=open&amp;)" + wid + LR"(">
<visual> <visual>
<binding template="ToastGeneric"> <binding template="ToastGeneric">
<image placement="appLogoOverride" hint-crop="circle" src=""/> <image placement="appLogoOverride" hint-crop=")" + crop + LR"( src=""/>
<text hint-maxLines="1"></text> <text hint-maxLines="1"></text>
<text></text> <text></text>
<text></text> <text></text>

View file

@ -535,6 +535,24 @@ historyBubbleTailInRightSelected: icon {{ "bubble_tail-flip_horizontal", msgInBg
historyBubbleTailOutRight: icon {{ "bubble_tail-flip_horizontal", msgOutBg }}; historyBubbleTailOutRight: icon {{ "bubble_tail-flip_horizontal", msgOutBg }};
historyBubbleTailOutRightSelected: icon {{ "bubble_tail-flip_horizontal", msgOutBgSelected }}; historyBubbleTailOutRightSelected: icon {{ "bubble_tail-flip_horizontal", msgOutBgSelected }};
historyBubbleTail1InLeft: icon {{ "bubble_tail1", msgInBg }};
historyBubbleTail1InLeftSelected: icon {{ "bubble_tail1", msgInBgSelected }};
historyBubbleTail1OutLeft: icon {{ "bubble_tail1", msgOutBg }};
historyBubbleTail1OutLeftSelected: icon {{ "bubble_tail1", msgOutBgSelected }};
historyBubbleTail1InRight: icon {{ "bubble_tail1-flip_horizontal", msgInBg }};
historyBubbleTail1InRightSelected: icon {{ "bubble_tail1-flip_horizontal", msgInBgSelected }};
historyBubbleTail1OutRight: icon {{ "bubble_tail1-flip_horizontal", msgOutBg }};
historyBubbleTail1OutRightSelected: icon {{ "bubble_tail1-flip_horizontal", msgOutBgSelected }};
historyBubbleTail2InLeft: icon {{ "bubble_tail2", msgInBg }};
historyBubbleTail2InLeftSelected: icon {{ "bubble_tail2", msgInBgSelected }};
historyBubbleTail2OutLeft: icon {{ "bubble_tail2", msgOutBg }};
historyBubbleTail2OutLeftSelected: icon {{ "bubble_tail2", msgOutBgSelected }};
historyBubbleTail2InRight: icon {{ "bubble_tail2-flip_horizontal", msgInBg }};
historyBubbleTail2InRightSelected: icon {{ "bubble_tail2-flip_horizontal", msgInBgSelected }};
historyBubbleTail2OutRight: icon {{ "bubble_tail2-flip_horizontal", msgOutBg }};
historyBubbleTail2OutRightSelected: icon {{ "bubble_tail2-flip_horizontal", msgOutBgSelected }};
historyPeerUserpicFont: semiboldFont; historyPeerUserpicFont: semiboldFont;
historyPsaIconIn: icon {{ "message_psa_tooltip", msgFileThumbLinkInFg }}; historyPsaIconIn: icon {{ "message_psa_tooltip", msgFileThumbLinkInFg }};

View file

@ -107,14 +107,16 @@ void GroupCallScheduledLeft::update() {
GroupCallBar::GroupCallBar( GroupCallBar::GroupCallBar(
not_null<QWidget*> parent, not_null<QWidget*> parent,
rpl::producer<GroupCallBarContent> content, rpl::producer<GroupCallBarContent> content,
rpl::producer<bool> &&hideBlobs) rpl::producer<bool> &&hideBlobs,
int userpicsRadius)
: _wrap(parent, object_ptr<RpWidget>(parent)) : _wrap(parent, object_ptr<RpWidget>(parent))
, _inner(_wrap.entity()) , _inner(_wrap.entity())
, _shadow(std::make_unique<PlainShadow>(_wrap.parentWidget())) , _shadow(std::make_unique<PlainShadow>(_wrap.parentWidget()))
, _userpics(std::make_unique<GroupCallUserpics>( , _userpics(std::make_unique<GroupCallUserpics>(
st::historyGroupCallUserpics, st::historyGroupCallUserpics,
std::move(hideBlobs), std::move(hideBlobs),
[=] { updateUserpics(); })) { [=] { updateUserpics(); },
userpicsRadius)) {
_wrap.hide(anim::type::instant); _wrap.hide(anim::type::instant);
_shadow->hide(); _shadow->hide();

View file

@ -63,7 +63,8 @@ public:
GroupCallBar( GroupCallBar(
not_null<QWidget*> parent, not_null<QWidget*> parent,
rpl::producer<GroupCallBarContent> content, rpl::producer<GroupCallBarContent> content,
rpl::producer<bool> &&hideBlobs); rpl::producer<bool> &&hideBlobs,
int userpicsRadius);
~GroupCallBar(); ~GroupCallBar();
void show(); void show();

View file

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/paint/blobs.h" #include "ui/paint/blobs.h"
#include "base/random.h" #include "base/random.h"
#include "styles/style_chat.h" #include "styles/style_chat.h"
#include "styles/style_widgets.h"
namespace Ui { namespace Ui {
namespace { namespace {
@ -81,10 +82,12 @@ struct GroupCallUserpics::Userpic {
GroupCallUserpics::GroupCallUserpics( GroupCallUserpics::GroupCallUserpics(
const style::GroupCallUserpics &st, const style::GroupCallUserpics &st,
rpl::producer<bool> &&hideBlobs, rpl::producer<bool> &&hideBlobs,
Fn<void()> repaint) Fn<void()> repaint,
int userpicRadius)
: _st(st) : _st(st)
, _randomSpeakingTimer([=] { sendRandomLevels(); }) , _randomSpeakingTimer([=] { sendRandomLevels(); })
, _repaint(std::move(repaint)) { , _repaint(std::move(repaint))
, _userpicRadius(userpicRadius) {
const auto limit = kMaxUserpics; const auto limit = kMaxUserpics;
const auto single = _st.size; const auto single = _st.size;
const auto shift = _st.shift; const auto shift = _st.shift;
@ -270,7 +273,20 @@ void GroupCallUserpics::validateCache(Userpic &userpic) {
p.setCompositionMode(QPainter::CompositionMode_Source); p.setCompositionMode(QPainter::CompositionMode_Source);
p.setBrush(Qt::transparent); p.setBrush(Qt::transparent);
p.setPen(pen); p.setPen(pen);
p.drawEllipse(skip - size + shift, skip, size, size); switch (_userpicRadius) {
case 0:
p.drawRoundedRect(skip - size + shift, skip, size, size, 0, 0);
break;
case 1:
p.drawRoundedRect(skip - size + shift, skip, size, size, st::buttonRadius, st::buttonRadius);
break;
case 2:
p.drawRoundedRect(skip - size + shift, skip, size, size, st::dateRadius, st::dateRadius);
break;
default:
p.drawEllipse(skip - size + shift, skip, size, size);
}
} }
} }
} }

View file

@ -27,7 +27,8 @@ public:
GroupCallUserpics( GroupCallUserpics(
const style::GroupCallUserpics &st, const style::GroupCallUserpics &st,
rpl::producer<bool> &&hideBlobs, rpl::producer<bool> &&hideBlobs,
Fn<void()> repaint); Fn<void()> repaint,
int userpicRadius);
~GroupCallUserpics(); ~GroupCallUserpics();
void update( void update(
@ -63,6 +64,7 @@ private:
int _maxWidth = 0; int _maxWidth = 0;
bool _skipLevelUpdate = false; bool _skipLevelUpdate = false;
crl::time _speakingAnimationHideLastTime = 0; crl::time _speakingAnimationHideLastTime = 0;
int _userpicRadius = 3;
rpl::variable<int> _width; rpl::variable<int> _width;

View file

@ -22,14 +22,16 @@ namespace Ui {
RequestsBar::RequestsBar( RequestsBar::RequestsBar(
not_null<QWidget*> parent, not_null<QWidget*> parent,
rpl::producer<RequestsBarContent> content) rpl::producer<RequestsBarContent> content,
int userpicRadius)
: _wrap(parent, object_ptr<RpWidget>(parent)) : _wrap(parent, object_ptr<RpWidget>(parent))
, _inner(_wrap.entity()) , _inner(_wrap.entity())
, _shadow(std::make_unique<PlainShadow>(_wrap.parentWidget())) , _shadow(std::make_unique<PlainShadow>(_wrap.parentWidget()))
, _userpics(std::make_unique<GroupCallUserpics>( , _userpics(std::make_unique<GroupCallUserpics>(
st::historyRequestsUserpics, st::historyRequestsUserpics,
rpl::single(false), rpl::single(false),
[=] { _inner->update(); })) { [=] { _inner->update(); },
userpicRadius)) {
_wrap.hide(anim::type::instant); _wrap.hide(anim::type::instant);
_shadow->hide(); _shadow->hide();

View file

@ -33,7 +33,8 @@ class RequestsBar final {
public: public:
RequestsBar( RequestsBar(
not_null<QWidget*> parent, not_null<QWidget*> parent,
rpl::producer<RequestsBarContent> content); rpl::producer<RequestsBarContent> content,
int userpicRadius);
~RequestsBar(); ~RequestsBar();
void show(); void show();

View file

@ -12,9 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Ui { namespace Ui {
SendAsButton::SendAsButton(QWidget *parent, const style::SendAsButton &st) SendAsButton::SendAsButton(QWidget *parent, const style::SendAsButton &st, int radius)
: AbstractButton(parent) : AbstractButton(parent)
, _st(st) { , _st(st)
, _radius(radius) {
resize(_st.width, _st.height); resize(_st.width, _st.height);
} }
@ -52,7 +53,28 @@ void SendAsButton::paintEvent(QPaintEvent *e) {
p.setBrush(_st.activeBg); p.setBrush(_st.activeBg);
{ {
PainterHighQualityEnabler hq(p); PainterHighQualityEnabler hq(p);
p.drawEllipse(left, top, _st.size, _st.size); switch (_radius) {
case 0:
p.drawRoundedRect(
left, top, _st.size, _st.size,
0, 0);
break;
case 1:
p.drawRoundedRect(
left, top, _st.size, _st.size,
st::buttonRadius, st::buttonRadius);
break;
case 2:
p.drawRoundedRect(
left, top, _st.size, _st.size,
st::dateRadius, st::dateRadius);
break;
default:
p.drawEllipse(left, top, _st.size, _st.size);
}
} }
CrossAnimation::paint( CrossAnimation::paint(

View file

@ -18,7 +18,7 @@ namespace Ui {
class SendAsButton final : public AbstractButton { class SendAsButton final : public AbstractButton {
public: public:
SendAsButton(QWidget *parent, const style::SendAsButton &st); SendAsButton(QWidget *parent, const style::SendAsButton &st, int radius);
void setUserpic(QImage userpic); void setUserpic(QImage userpic);
@ -33,6 +33,7 @@ private:
bool _active = false; bool _active = false;
QImage _userpic; QImage _userpic;
int _radius;
}; };

View file

@ -80,7 +80,8 @@ public:
not_null<PopupMenu*> parentMenu, not_null<PopupMenu*> parentMenu,
rpl::producer<WhoReadContent> content, rpl::producer<WhoReadContent> content,
Fn<void(uint64)> participantChosen, Fn<void(uint64)> participantChosen,
Fn<void()> showAllChosen); Fn<void()> showAllChosen,
int userpicsRadius);
bool isEnabled() const override; bool isEnabled() const override;
not_null<QAction*> action() const override; not_null<QAction*> action() const override;
@ -144,7 +145,8 @@ Action::Action(
not_null<PopupMenu*> parentMenu, not_null<PopupMenu*> parentMenu,
rpl::producer<WhoReadContent> content, rpl::producer<WhoReadContent> content,
Fn<void(uint64)> participantChosen, Fn<void(uint64)> participantChosen,
Fn<void()> showAllChosen) Fn<void()> showAllChosen,
int userpicsRadius)
: ItemBase(parentMenu->menu(), parentMenu->menu()->st()) : ItemBase(parentMenu->menu(), parentMenu->menu()->st())
, _parentMenu(parentMenu) , _parentMenu(parentMenu)
, _dummyAction(CreateChild<QAction>(parentMenu->menu().get())) , _dummyAction(CreateChild<QAction>(parentMenu->menu().get()))
@ -153,7 +155,8 @@ Action::Action(
, _userpics(std::make_unique<GroupCallUserpics>( , _userpics(std::make_unique<GroupCallUserpics>(
st::defaultWhoRead.userpics, st::defaultWhoRead.userpics,
rpl::never<bool>(), rpl::never<bool>(),
[=] { update(); })) [=] { update(); },
userpicsRadius))
, _st(parentMenu->menu()->st()) , _st(parentMenu->menu()->st())
, _submenu(_participantChosen, _showAllChosen) , _submenu(_participantChosen, _showAllChosen)
, _height(st::defaultWhoRead.itemPadding.top() , _height(st::defaultWhoRead.itemPadding.top()
@ -584,12 +587,14 @@ base::unique_qptr<Menu::ItemBase> WhoReactedContextAction(
not_null<PopupMenu*> menu, not_null<PopupMenu*> menu,
rpl::producer<WhoReadContent> content, rpl::producer<WhoReadContent> content,
Fn<void(uint64)> participantChosen, Fn<void(uint64)> participantChosen,
Fn<void()> showAllChosen) { Fn<void()> showAllChosen,
int userpicsRadius) {
return base::make_unique_q<Action>( return base::make_unique_q<Action>(
menu, menu,
std::move(content), std::move(content),
std::move(participantChosen), std::move(participantChosen),
std::move(showAllChosen)); std::move(showAllChosen),
userpicsRadius);
} }
WhoReactedListMenu::WhoReactedListMenu( WhoReactedListMenu::WhoReactedListMenu(

View file

@ -50,7 +50,8 @@ struct WhoReadContent {
not_null<PopupMenu*> menu, not_null<PopupMenu*> menu,
rpl::producer<WhoReadContent> content, rpl::producer<WhoReadContent> content,
Fn<void(uint64)> participantChosen, Fn<void(uint64)> participantChosen,
Fn<void()> showAllChosen); Fn<void()> showAllChosen,
int userpicsRadius);
class WhoReactedListMenu final { class WhoReactedListMenu final {
public: public:

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "ui/effects/round_checkbox.h" #include "ui/effects/round_checkbox.h"
#include "ui/image/image.h"
#include "ui/rp_widget.h" #include "ui/rp_widget.h"
#include "ui/ui_utility.h" #include "ui/ui_utility.h"
@ -390,7 +391,25 @@ void RoundImageCheckbox::paint(Painter &p, int x, int y, int outerWidth) {
auto pen = _st.selectFg->p; auto pen = _st.selectFg->p;
pen.setWidth(_st.selectWidth); pen.setWidth(_st.selectWidth);
p.setPen(pen); p.setPen(pen);
p.drawEllipse(style::rtlrect(x, y, _st.imageRadius * 2, _st.imageRadius * 2, outerWidth)); switch (KotatoImageRoundRadius()) {
case ImageRoundRadius::None:
p.drawRoundedRect(style::rtlrect(x, y, _st.imageRadius * 2, _st.imageRadius * 2, outerWidth),
0, 0);
break;
case ImageRoundRadius::Small:
p.drawRoundedRect(style::rtlrect(x, y, _st.imageRadius * 2, _st.imageRadius * 2, outerWidth),
st::buttonRadius, st::buttonRadius);
break;
case ImageRoundRadius::Large:
p.drawRoundedRect(style::rtlrect(x, y, _st.imageRadius * 2, _st.imageRadius * 2, outerWidth),
st::dateRadius, st::dateRadius);
break;
default:
p.drawEllipse(style::rtlrect(x, y, _st.imageRadius * 2, _st.imageRadius * 2, outerWidth));
}
p.setOpacity(1.); p.setOpacity(1.);
} }
if (_st.check.size > 0) { if (_st.check.size > 0) {

View file

@ -222,8 +222,29 @@ void EmptyUserpic::paint(
int y, int y,
int outerWidth, int outerWidth,
int size) const { int size) const {
switch (KotatoImageRoundRadius()) {
case ImageRoundRadius::None:
paintSquare(p, x, y, outerWidth, size);
break;
case ImageRoundRadius::Small:
paintRounded(p, x, y, outerWidth, size);
break;
case ImageRoundRadius::Large:
paintRoundedLarge(p, x, y, outerWidth, size);
break;
default:
paint(p, x, y, outerWidth, size, [&p, x, y, size] {
p.drawEllipse(x, y, size, size);
});
}
}
void EmptyUserpic::paintRoundedLarge(Painter &p, int x, int y, int outerWidth, int size) const {
paint(p, x, y, outerWidth, size, [&p, x, y, size] { paint(p, x, y, outerWidth, size, [&p, x, y, size] {
p.drawEllipse(x, y, size, size); p.drawRoundedRect(x, y, size, size, st::dateRadius, st::dateRadius);
}); });
} }
@ -245,9 +266,35 @@ void EmptyUserpic::PaintSavedMessages(
int y, int y,
int outerWidth, int outerWidth,
int size) { int size) {
switch (KotatoImageRoundRadius()) {
case ImageRoundRadius::None:
PaintSavedMessagesSquared(p, x, y, outerWidth, size);
break;
case ImageRoundRadius::Small:
PaintSavedMessagesRounded(p, x, y, outerWidth, size);
break;
case ImageRoundRadius::Large:
PaintSavedMessagesRoundedLarge(p, x, y, outerWidth, size);
break;
default:
const auto &bg = st::historyPeerSavedMessagesBg;
const auto &fg = st::historyPeerUserpicFg;
PaintSavedMessages(p, x, y, outerWidth, size, bg, fg);
}
}
void EmptyUserpic::PaintSavedMessagesRoundedLarge(
Painter &p,
int x,
int y,
int outerWidth,
int size) {
const auto &bg = st::historyPeerSavedMessagesBg; const auto &bg = st::historyPeerSavedMessagesBg;
const auto &fg = st::historyPeerUserpicFg; const auto &fg = st::historyPeerUserpicFg;
PaintSavedMessages(p, x, y, outerWidth, size, bg, fg); PaintSavedMessagesRoundedLarge(p, x, y, outerWidth, size, bg, fg);
} }
void EmptyUserpic::PaintSavedMessagesRounded( void EmptyUserpic::PaintSavedMessagesRounded(
@ -261,6 +308,17 @@ void EmptyUserpic::PaintSavedMessagesRounded(
PaintSavedMessagesRounded(p, x, y, outerWidth, size, bg, fg); PaintSavedMessagesRounded(p, x, y, outerWidth, size, bg, fg);
} }
void EmptyUserpic::PaintSavedMessagesSquared(
Painter &p,
int x,
int y,
int outerWidth,
int size) {
const auto &bg = st::historyPeerSavedMessagesBg;
const auto &fg = st::historyPeerUserpicFg;
PaintSavedMessagesSquared(p, x, y, outerWidth, size, bg, fg);
}
void EmptyUserpic::PaintSavedMessages( void EmptyUserpic::PaintSavedMessages(
Painter &p, Painter &p,
int x, int x,
@ -269,12 +327,45 @@ void EmptyUserpic::PaintSavedMessages(
int size, int size,
const style::color &bg, const style::color &bg,
const style::color &fg) { const style::color &fg) {
switch (KotatoImageRoundRadius()) {
case ImageRoundRadius::None:
PaintSavedMessagesSquared(p, x, y, outerWidth, size, bg, fg);
break;
case ImageRoundRadius::Small:
PaintSavedMessagesRounded(p, x, y, outerWidth, size, bg, fg);
break;
case ImageRoundRadius::Large:
PaintSavedMessagesRoundedLarge(p, x, y, outerWidth, size, bg, fg);
break;
default:
x = rtl() ? (outerWidth - x - size) : x;
PainterHighQualityEnabler hq(p);
p.setBrush(bg);
p.setPen(Qt::NoPen);
p.drawEllipse(x, y, size, size);
PaintSavedMessagesInner(p, x, y, size, fg);
}
}
void EmptyUserpic::PaintSavedMessagesRoundedLarge(
Painter &p,
int x,
int y,
int outerWidth,
int size,
const style::color &bg,
const style::color &fg) {
x = rtl() ? (outerWidth - x - size) : x; x = rtl() ? (outerWidth - x - size) : x;
PainterHighQualityEnabler hq(p); PainterHighQualityEnabler hq(p);
p.setBrush(bg); p.setBrush(bg);
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.drawEllipse(x, y, size, size); p.drawRoundedRect(x, y, size, size, st::dateRadius, st::dateRadius);
PaintSavedMessagesInner(p, x, y, size, fg); PaintSavedMessagesInner(p, x, y, size, fg);
} }
@ -297,6 +388,24 @@ void EmptyUserpic::PaintSavedMessagesRounded(
PaintSavedMessagesInner(p, x, y, size, fg); PaintSavedMessagesInner(p, x, y, size, fg);
} }
void EmptyUserpic::PaintSavedMessagesSquared(
Painter &p,
int x,
int y,
int outerWidth,
int size,
const style::color &bg,
const style::color &fg) {
x = rtl() ? (outerWidth - x - size) : x;
PainterHighQualityEnabler hq(p);
p.setBrush(bg);
p.setPen(Qt::NoPen);
p.drawRoundedRect(x, y, size, size, 0, 0);
PaintSavedMessagesInner(p, x, y, size, fg);
}
QPixmap EmptyUserpic::GenerateSavedMessages(int size) { QPixmap EmptyUserpic::GenerateSavedMessages(int size) {
return Generate(size, [&](Painter &p) { return Generate(size, [&](Painter &p) {
PaintSavedMessages(p, 0, 0, size, size); PaintSavedMessages(p, 0, 0, size, size);
@ -315,9 +424,35 @@ void EmptyUserpic::PaintRepliesMessages(
int y, int y,
int outerWidth, int outerWidth,
int size) { int size) {
switch (KotatoImageRoundRadius()) {
case ImageRoundRadius::None:
PaintRepliesMessagesSquared(p, x, y, outerWidth, size);
break;
case ImageRoundRadius::Small:
PaintRepliesMessagesRounded(p, x, y, outerWidth, size);
break;
case ImageRoundRadius::Large:
PaintRepliesMessagesRoundedLarge(p, x, y, outerWidth, size);
break;
default:
const auto &bg = st::historyPeerSavedMessagesBg;
const auto &fg = st::historyPeerUserpicFg;
PaintRepliesMessages(p, x, y, outerWidth, size, bg, fg);
}
}
void EmptyUserpic::PaintRepliesMessagesRoundedLarge(
Painter &p,
int x,
int y,
int outerWidth,
int size) {
const auto &bg = st::historyPeerSavedMessagesBg; const auto &bg = st::historyPeerSavedMessagesBg;
const auto &fg = st::historyPeerUserpicFg; const auto &fg = st::historyPeerUserpicFg;
PaintRepliesMessages(p, x, y, outerWidth, size, bg, fg); PaintRepliesMessagesRoundedLarge(p, x, y, outerWidth, size, bg, fg);
} }
void EmptyUserpic::PaintRepliesMessagesRounded( void EmptyUserpic::PaintRepliesMessagesRounded(
@ -331,6 +466,17 @@ void EmptyUserpic::PaintRepliesMessagesRounded(
PaintRepliesMessagesRounded(p, x, y, outerWidth, size, bg, fg); PaintRepliesMessagesRounded(p, x, y, outerWidth, size, bg, fg);
} }
void EmptyUserpic::PaintRepliesMessagesSquared(
Painter &p,
int x,
int y,
int outerWidth,
int size) {
const auto &bg = st::historyPeerSavedMessagesBg;
const auto &fg = st::historyPeerUserpicFg;
PaintRepliesMessagesSquared(p, x, y, outerWidth, size, bg, fg);
}
void EmptyUserpic::PaintRepliesMessages( void EmptyUserpic::PaintRepliesMessages(
Painter &p, Painter &p,
int x, int x,
@ -349,6 +495,24 @@ void EmptyUserpic::PaintRepliesMessages(
PaintRepliesMessagesInner(p, x, y, size, fg); PaintRepliesMessagesInner(p, x, y, size, fg);
} }
void EmptyUserpic::PaintRepliesMessagesRoundedLarge(
Painter &p,
int x,
int y,
int outerWidth,
int size,
const style::color &bg,
const style::color &fg) {
x = rtl() ? (outerWidth - x - size) : x;
PainterHighQualityEnabler hq(p);
p.setBrush(bg);
p.setPen(Qt::NoPen);
p.drawRoundedRect(x, y, size, size, st::dateRadius, st::dateRadius);
PaintRepliesMessagesInner(p, x, y, size, fg);
}
void EmptyUserpic::PaintRepliesMessagesRounded( void EmptyUserpic::PaintRepliesMessagesRounded(
Painter &p, Painter &p,
int x, int x,
@ -367,6 +531,24 @@ void EmptyUserpic::PaintRepliesMessagesRounded(
PaintRepliesMessagesInner(p, x, y, size, fg); PaintRepliesMessagesInner(p, x, y, size, fg);
} }
void EmptyUserpic::PaintRepliesMessagesSquared(
Painter &p,
int x,
int y,
int outerWidth,
int size,
const style::color &bg,
const style::color &fg) {
x = rtl() ? (outerWidth - x - size) : x;
PainterHighQualityEnabler hq(p);
p.setBrush(bg);
p.setPen(Qt::NoPen);
p.drawRoundedRect(x, y, size, size, 0, 0);
PaintRepliesMessagesInner(p, x, y, size, fg);
}
QPixmap EmptyUserpic::GenerateRepliesMessages(int size) { QPixmap EmptyUserpic::GenerateRepliesMessages(int size) {
return Generate(size, [&](Painter &p) { return Generate(size, [&](Painter &p) {
PaintRepliesMessages(p, 0, 0, size, size); PaintRepliesMessages(p, 0, 0, size, size);

View file

@ -21,6 +21,12 @@ public:
int y, int y,
int outerWidth, int outerWidth,
int size) const; int size) const;
void paintRoundedLarge(
Painter &p,
int x,
int y,
int outerWidth,
int size) const;
void paintRounded( void paintRounded(
Painter &p, Painter &p,
int x, int x,
@ -42,12 +48,24 @@ public:
int y, int y,
int outerWidth, int outerWidth,
int size); int size);
static void PaintSavedMessagesRoundedLarge(
Painter &p,
int x,
int y,
int outerWidth,
int size);
static void PaintSavedMessagesRounded( static void PaintSavedMessagesRounded(
Painter &p, Painter &p,
int x, int x,
int y, int y,
int outerWidth, int outerWidth,
int size); int size);
static void PaintSavedMessagesSquared(
Painter &p,
int x,
int y,
int outerWidth,
int size);
static void PaintSavedMessages( static void PaintSavedMessages(
Painter &p, Painter &p,
int x, int x,
@ -56,6 +74,14 @@ public:
int size, int size,
const style::color &bg, const style::color &bg,
const style::color &fg); const style::color &fg);
static void PaintSavedMessagesRoundedLarge(
Painter &p,
int x,
int y,
int outerWidth,
int size,
const style::color &bg,
const style::color &fg);
static void PaintSavedMessagesRounded( static void PaintSavedMessagesRounded(
Painter &p, Painter &p,
int x, int x,
@ -64,6 +90,14 @@ public:
int size, int size,
const style::color &bg, const style::color &bg,
const style::color &fg); const style::color &fg);
static void PaintSavedMessagesSquared(
Painter &p,
int x,
int y,
int outerWidth,
int size,
const style::color &bg,
const style::color &fg);
static QPixmap GenerateSavedMessages(int size); static QPixmap GenerateSavedMessages(int size);
static QPixmap GenerateSavedMessagesRounded(int size); static QPixmap GenerateSavedMessagesRounded(int size);
@ -73,12 +107,24 @@ public:
int y, int y,
int outerWidth, int outerWidth,
int size); int size);
static void PaintRepliesMessagesRoundedLarge(
Painter &p,
int x,
int y,
int outerWidth,
int size);
static void PaintRepliesMessagesRounded( static void PaintRepliesMessagesRounded(
Painter &p, Painter &p,
int x, int x,
int y, int y,
int outerWidth, int outerWidth,
int size); int size);
static void PaintRepliesMessagesSquared(
Painter &p,
int x,
int y,
int outerWidth,
int size);
static void PaintRepliesMessages( static void PaintRepliesMessages(
Painter &p, Painter &p,
int x, int x,
@ -87,6 +133,14 @@ public:
int size, int size,
const style::color &bg, const style::color &bg,
const style::color &fg); const style::color &fg);
static void PaintRepliesMessagesRoundedLarge(
Painter &p,
int x,
int y,
int outerWidth,
int size,
const style::color &bg,
const style::color &fg);
static void PaintRepliesMessagesRounded( static void PaintRepliesMessagesRounded(
Painter &p, Painter &p,
int x, int x,
@ -95,6 +149,14 @@ public:
int size, int size,
const style::color &bg, const style::color &bg,
const style::color &fg); const style::color &fg);
static void PaintRepliesMessagesSquared(
Painter &p,
int x,
int y,
int outerWidth,
int size,
const style::color &bg,
const style::color &fg);
static QPixmap GenerateRepliesMessages(int size); static QPixmap GenerateRepliesMessages(int size);
static QPixmap GenerateRepliesMessagesRounded(int size); static QPixmap GenerateRepliesMessagesRounded(int size);

View file

@ -7,11 +7,30 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "ui/image/image.h" #include "ui/image/image.h"
#include "kotato/kotato_settings.h"
#include "storage/cache/storage_cache_database.h" #include "storage/cache/storage_cache_database.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "ui/ui_utility.h" #include "ui/ui_utility.h"
ImageRoundRadius KotatoImageRoundRadius() {
switch (::Kotato::JsonSettings::GetInt("userpic_corner_type")) {
case 0: return ImageRoundRadius::None;
case 1: return ImageRoundRadius::Small;
case 2: return ImageRoundRadius::Large;
default: return ImageRoundRadius::Ellipse;
}
}
Images::Option KotatoImageRoundOption() {
switch (::Kotato::JsonSettings::GetInt("userpic_corner_type")) {
case 0: return Images::Option::None;
case 1: return Images::Option::RoundSmall;
case 2: return Images::Option::RoundLarge;
default: return Images::Option::RoundCircle;
}
}
using namespace Images; using namespace Images;
namespace Images { namespace Images {

View file

@ -9,6 +9,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/image/image_prepare.h" #include "ui/image/image_prepare.h"
ImageRoundRadius KotatoImageRoundRadius();
Images::Option KotatoImageRoundOption();
class QPainterPath; class QPainterPath;
namespace Images { namespace Images {

View file

@ -317,11 +317,24 @@ void UserpicButton::paintEvent(QPaintEvent *e) {
p.setBrush(_userpicHasImage p.setBrush(_userpicHasImage
? st::msgDateImgBg ? st::msgDateImgBg
: _st.changeButton.textBgOver); : _st.changeButton.textBgOver);
p.drawEllipse( switch (KotatoImageRoundRadius()) {
photoLeft, case ImageRoundRadius::None:
photoTop, p.drawRoundedRect(QRect{ photoLeft, photoTop, _st.photoSize, _st.photoSize }, 0, 0);
_st.photoSize, break;
_st.photoSize);
case ImageRoundRadius::Small:
p.drawRoundedRect(QRect{ photoLeft, photoTop, _st.photoSize, _st.photoSize },
st::buttonRadius, st::buttonRadius);
break;
case ImageRoundRadius::Large:
p.drawRoundedRect(QRect{ photoLeft, photoTop, _st.photoSize, _st.photoSize },
st::dateRadius, st::dateRadius);
break;
default:
p.drawEllipse(photoLeft, photoTop, _st.photoSize, _st.photoSize);
}
} }
paintRipple( paintRipple(
p, p,
@ -363,11 +376,24 @@ void UserpicButton::paintEvent(QPaintEvent *e) {
PainterHighQualityEnabler hq(p); PainterHighQualityEnabler hq(p);
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.setBrush(_st.uploadBg); p.setBrush(_st.uploadBg);
p.drawEllipse( switch (KotatoImageRoundRadius()) {
photoLeft, case ImageRoundRadius::None:
photoTop, p.drawRoundedRect(QRect{ photoLeft, photoTop, _st.photoSize, _st.photoSize }, 0, 0);
_st.photoSize, break;
_st.photoSize);
case ImageRoundRadius::Small:
p.drawRoundedRect(QRect{ photoLeft, photoTop, _st.photoSize, _st.photoSize },
st::buttonRadius, st::buttonRadius);
break;
case ImageRoundRadius::Large:
p.drawRoundedRect(QRect{ photoLeft, photoTop, _st.photoSize, _st.photoSize },
st::dateRadius, st::dateRadius);
break;
default:
p.drawEllipse(photoLeft, photoTop, _st.photoSize, _st.photoSize);
}
} }
auto iconLeft = (_st.uploadIconPosition.x() < 0) auto iconLeft = (_st.uploadIconPosition.x() < 0)
? (_st.photoSize - _st.uploadIcon.width()) / 2 ? (_st.photoSize - _st.uploadIcon.width()) / 2
@ -399,7 +425,7 @@ void UserpicButton::paintUserpicFrame(Painter &p, QPoint photoPosition) {
auto size = QSize{ _st.photoSize, _st.photoSize }; auto size = QSize{ _st.photoSize, _st.photoSize };
request.outer = size * cIntRetinaFactor(); request.outer = size * cIntRetinaFactor();
request.resize = size * cIntRetinaFactor(); request.resize = size * cIntRetinaFactor();
request.radius = ImageRoundRadius::Ellipse; request.radius = KotatoImageRoundRadius();
p.drawImage(QRect(photoPosition, size), _streamed->frame(request)); p.drawImage(QRect(photoPosition, size), _streamed->frame(request));
if (!paused) { if (!paused) {
_streamed->markFrameShown(); _streamed->markFrameShown();
@ -420,9 +446,21 @@ QPoint UserpicButton::countPhotoPosition() const {
} }
QImage UserpicButton::prepareRippleMask() const { QImage UserpicButton::prepareRippleMask() const {
return Ui::RippleAnimation::ellipseMask(QSize( const auto size = QSize(_st.photoSize, _st.photoSize);
_st.photoSize,
_st.photoSize)); switch (KotatoImageRoundRadius()) {
case ImageRoundRadius::None:
return Ui::RippleAnimation::rectMask(size);
case ImageRoundRadius::Small:
return Ui::RippleAnimation::roundRectMask(size, st::buttonRadius);
case ImageRoundRadius::Large:
return Ui::RippleAnimation::roundRectMask(size, st::dateRadius);
default:
return Ui::RippleAnimation::ellipseMask(size);
}
} }
QPoint UserpicButton::prepareRippleStartPosition() const { QPoint UserpicButton::prepareRippleStartPosition() const {
@ -696,7 +734,9 @@ void UserpicButton::setImage(QImage &&image) {
size * cIntRetinaFactor(), size * cIntRetinaFactor(),
Qt::IgnoreAspectRatio, Qt::IgnoreAspectRatio,
Qt::SmoothTransformation); Qt::SmoothTransformation);
_userpic = Ui::PixmapFromImage(Images::Circle(std::move(small))); small = Images::Round(std::move(small), KotatoImageRoundRadius());
_userpic = Ui::PixmapFromImage(std::move(small));
_userpic.setDevicePixelRatio(cRetinaFactor()); _userpic.setDevicePixelRatio(cRetinaFactor());
_userpicCustom = _userpicHasImage = true; _userpicCustom = _userpicHasImage = true;
_result = std::move(image); _result = std::move(image);
@ -713,7 +753,24 @@ void UserpicButton::prepareUserpicPixmap() {
PainterHighQualityEnabler hq(p); PainterHighQualityEnabler hq(p);
p.setBrush(color); p.setBrush(color);
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.drawEllipse(0, 0, size, size); switch (KotatoImageRoundRadius()) {
case ImageRoundRadius::None:
p.drawRoundedRect(QRect{ 0, 0, size, size }, 0, 0);
break;
case ImageRoundRadius::Small:
p.drawRoundedRect(QRect{ 0, 0, size, size },
st::buttonRadius, st::buttonRadius);
break;
case ImageRoundRadius::Large:
p.drawRoundedRect(QRect{ 0, 0, size, size },
st::dateRadius, st::dateRadius);
break;
default:
p.drawEllipse(0, 0, size, size);
}
}; };
_userpicHasImage = _peer _userpicHasImage = _peer
? (_peer->currentUserpic(_userpicView) || _role != Role::ChangePhoto) ? (_peer->currentUserpic(_userpicView) || _role != Role::ChangePhoto)

View file

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/multi_select.h" #include "ui/widgets/multi_select.h"
#include "styles/style_widgets.h" #include "styles/style_widgets.h"
#include "ui/image/image.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/input_fields.h"
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
@ -72,6 +73,20 @@ void MultiSelect::Item::paintOnce(Painter &p, int x, int y, int outerWidth) {
} }
auto radius = _st.height / 2; auto radius = _st.height / 2;
switch (KotatoImageRoundRadius()) {
case ImageRoundRadius::None:
radius = 0;
break;
case ImageRoundRadius::Small:
radius = st::buttonRadius;
break;
case ImageRoundRadius::Large:
radius = st::dateRadius;
break;
}
auto inner = style::rtlrect(x + radius, y, _width - radius, _st.height, outerWidth); auto inner = style::rtlrect(x + radius, y, _width - radius, _st.height, outerWidth);
auto clipEnabled = p.hasClipping(); auto clipEnabled = p.hasClipping();
@ -112,7 +127,24 @@ void MultiSelect::Item::paintDeleteButton(Painter &p, int x, int y, int outerWid
p.setBrush(_color); p.setBrush(_color);
{ {
PainterHighQualityEnabler hq(p); PainterHighQualityEnabler hq(p);
p.drawEllipse(style::rtlrect(x, y, _st.height, _st.height, outerWidth)); switch (KotatoImageRoundRadius()) {
case ImageRoundRadius::None:
p.drawRoundedRect(style::rtlrect(x, y, _st.height, _st.height, outerWidth), 0, 0);
break;
case ImageRoundRadius::Small:
p.drawRoundedRect(style::rtlrect(x, y, _st.height, _st.height, outerWidth),
st::buttonRadius, st::buttonRadius);
break;
case ImageRoundRadius::Large:
p.drawRoundedRect(style::rtlrect(x, y, _st.height, _st.height, outerWidth),
st::dateRadius, st::dateRadius);
break;
default:
p.drawEllipse(style::rtlrect(x, y, _st.height, _st.height, outerWidth));
}
} }
CrossAnimation::paint(p, _st.deleteCross, _st.deleteFg, x, y, outerWidth, overOpacity); CrossAnimation::paint(p, _st.deleteCross, _st.deleteFg, x, y, outerWidth, overOpacity);