mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Show segments in expanded stories list.
This commit is contained in:
parent
89bd3c10c5
commit
5f4dcc5eb6
11 changed files with 218 additions and 72 deletions
|
@ -2408,8 +2408,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_add_contact" = "Create";
|
"lng_add_contact" = "Create";
|
||||||
"lng_add_contact_button" = "New contact";
|
"lng_add_contact_button" = "New contact";
|
||||||
"lng_contacts_header" = "Contacts";
|
"lng_contacts_header" = "Contacts";
|
||||||
"lng_contacts_by_online" = "Sorted by last seen time";
|
|
||||||
"lng_contacts_by_name" = "Sorted by name";
|
|
||||||
"lng_contacts_hidden_stories" = "Hidden Stories";
|
"lng_contacts_hidden_stories" = "Hidden Stories";
|
||||||
"lng_contacts_stories_status#one" = "{count} story";
|
"lng_contacts_stories_status#one" = "{count} story";
|
||||||
"lng_contacts_stories_status#other" = "{count} stories";
|
"lng_contacts_stories_status#other" = "{count} stories";
|
||||||
|
|
|
@ -10,13 +10,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "main/session/session_show.h"
|
#include "main/session/session_show.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
|
#include "ui/effects/loading_element.h"
|
||||||
|
#include "ui/effects/outline_segments.h"
|
||||||
|
#include "ui/effects/round_checkbox.h"
|
||||||
|
#include "ui/effects/ripple_animation.h"
|
||||||
#include "ui/widgets/multi_select.h"
|
#include "ui/widgets/multi_select.h"
|
||||||
#include "ui/widgets/labels.h"
|
#include "ui/widgets/labels.h"
|
||||||
#include "ui/widgets/scroll_area.h"
|
#include "ui/widgets/scroll_area.h"
|
||||||
#include "ui/widgets/popup_menu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
#include "ui/effects/loading_element.h"
|
|
||||||
#include "ui/effects/round_checkbox.h"
|
|
||||||
#include "ui/effects/ripple_animation.h"
|
|
||||||
#include "ui/empty_userpic.h"
|
#include "ui/empty_userpic.h"
|
||||||
#include "ui/wrap/slide_wrap.h"
|
#include "ui/wrap/slide_wrap.h"
|
||||||
#include "ui/text/text_options.h"
|
#include "ui/text/text_options.h"
|
||||||
|
@ -894,7 +895,7 @@ void PeerListRow::setCheckedInternal(bool checked, anim::type animated) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeerListRow::setCustomizedCheckSegments(
|
void PeerListRow::setCustomizedCheckSegments(
|
||||||
std::vector<Ui::RoundImageCheckboxSegment> segments) {
|
std::vector<Ui::OutlineSegment> segments) {
|
||||||
Expects(_checkbox != nullptr);
|
Expects(_checkbox != nullptr);
|
||||||
|
|
||||||
_checkbox->setCustomizedSegments(std::move(segments));
|
_checkbox->setCustomizedSegments(std::move(segments));
|
||||||
|
|
|
@ -36,7 +36,7 @@ class SlideWrap;
|
||||||
class FlatLabel;
|
class FlatLabel;
|
||||||
struct ScrollToRequest;
|
struct ScrollToRequest;
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
struct RoundImageCheckboxSegment;
|
struct OutlineSegment;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
using PaintRoundImageCallback = Fn<void(
|
using PaintRoundImageCallback = Fn<void(
|
||||||
|
@ -204,7 +204,7 @@ public:
|
||||||
setCheckedInternal(checked, animated);
|
setCheckedInternal(checked, animated);
|
||||||
}
|
}
|
||||||
void setCustomizedCheckSegments(
|
void setCustomizedCheckSegments(
|
||||||
std::vector<Ui::RoundImageCheckboxSegment> segments);
|
std::vector<Ui::OutlineSegment> segments);
|
||||||
void setHidden(bool hidden) {
|
void setHidden(bool hidden) {
|
||||||
_hidden = hidden;
|
_hidden = hidden;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
#include "dialogs/dialogs_main_list.h"
|
#include "dialogs/dialogs_main_list.h"
|
||||||
|
#include "ui/effects/outline_segments.h"
|
||||||
#include "ui/wrap/slide_wrap.h"
|
#include "ui/wrap/slide_wrap.h"
|
||||||
#include "window/window_session_controller.h" // showAddContact()
|
#include "window/window_session_controller.h" // showAddContact()
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
|
@ -53,14 +54,14 @@ namespace {
|
||||||
constexpr auto kSortByOnlineThrottle = 3 * crl::time(1000);
|
constexpr auto kSortByOnlineThrottle = 3 * crl::time(1000);
|
||||||
constexpr auto kSearchPerPage = 50;
|
constexpr auto kSearchPerPage = 50;
|
||||||
|
|
||||||
[[nodiscard]] std::vector<Ui::RoundImageCheckboxSegment> PrepareSegments(
|
[[nodiscard]] std::vector<Ui::OutlineSegment> PrepareSegments(
|
||||||
int count,
|
int count,
|
||||||
int unread,
|
int unread,
|
||||||
const QBrush &unreadBrush) {
|
const QBrush &unreadBrush) {
|
||||||
Expects(unread <= count);
|
Expects(unread <= count);
|
||||||
Expects(count > 0);
|
Expects(count > 0);
|
||||||
|
|
||||||
auto result = std::vector<Ui::RoundImageCheckboxSegment>();
|
auto result = std::vector<Ui::OutlineSegment>();
|
||||||
const auto add = [&](bool unread) {
|
const auto add = [&](bool unread) {
|
||||||
result.push_back({
|
result.push_back({
|
||||||
.brush = unread ? unreadBrush : st::dialogsUnreadBgMuted->b,
|
.brush = unread ? unreadBrush : st::dialogsUnreadBgMuted->b,
|
||||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "dialogs/ui/dialogs_stories_list.h"
|
#include "dialogs/ui/dialogs_stories_list.h"
|
||||||
|
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
|
#include "ui/effects/outline_segments.h"
|
||||||
#include "ui/widgets/menu/menu_add_action_callback_factory.h"
|
#include "ui/widgets/menu/menu_add_action_callback_factory.h"
|
||||||
#include "ui/widgets/popup_menu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
|
@ -41,6 +42,7 @@ struct List::Layout {
|
||||||
QPointF geometryShift;
|
QPointF geometryShift;
|
||||||
float64 expandedRatio = 0.;
|
float64 expandedRatio = 0.;
|
||||||
float64 ratio = 0.;
|
float64 ratio = 0.;
|
||||||
|
float64 segmentsSpinProgress = 0.;
|
||||||
float64 thumbnailLeft = 0.;
|
float64 thumbnailLeft = 0.;
|
||||||
float64 photoLeft = 0.;
|
float64 photoLeft = 0.;
|
||||||
float64 left = 0.;
|
float64 left = 0.;
|
||||||
|
@ -72,6 +74,8 @@ List::List(
|
||||||
resize(0, _data.empty() ? 0 : st.full.height);
|
resize(0, _data.empty() ? 0 : st.full.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List::~List() = default;
|
||||||
|
|
||||||
void List::showContent(Content &&content) {
|
void List::showContent(Content &&content) {
|
||||||
if (_content == content) {
|
if (_content == content) {
|
||||||
return;
|
return;
|
||||||
|
@ -151,12 +155,13 @@ void List::requestExpanded(bool expanded) {
|
||||||
if (_expanded != expanded) {
|
if (_expanded != expanded) {
|
||||||
_expanded = expanded;
|
_expanded = expanded;
|
||||||
const auto from = _expanded ? 0. : 1.;
|
const auto from = _expanded ? 0. : 1.;
|
||||||
const auto till = _expanded ? 1. : 0.;
|
const auto till = _expanded ? 2. : 0.;
|
||||||
|
const auto duration = (_expanded ? 2 : 1) * st::slideWrapDuration;
|
||||||
_expandedAnimation.start([=] {
|
_expandedAnimation.start([=] {
|
||||||
checkForFullState();
|
checkForFullState();
|
||||||
update();
|
update();
|
||||||
_collapsedGeometryChanged.fire({});
|
_collapsedGeometryChanged.fire({});
|
||||||
}, from, till, st::slideWrapDuration, anim::sineInOut);
|
}, from, till, duration, anim::sineInOut);
|
||||||
}
|
}
|
||||||
_toggleExpandedRequests.fire_copy(_expanded);
|
_toggleExpandedRequests.fire_copy(_expanded);
|
||||||
}
|
}
|
||||||
|
@ -192,10 +197,13 @@ List::Layout List::computeLayout() {
|
||||||
updateExpanding(
|
updateExpanding(
|
||||||
_lastExpandedHeight * _expandCatchUpAnimation.value(1.),
|
_lastExpandedHeight * _expandCatchUpAnimation.value(1.),
|
||||||
_st.full.height);
|
_st.full.height);
|
||||||
return computeLayout(_expandedAnimation.value(_expanded ? 1. : 0.));
|
return computeLayout(_expandedAnimation.value(_expanded ? 2. : 0.));
|
||||||
}
|
}
|
||||||
|
|
||||||
List::Layout List::computeLayout(float64 expanded) const {
|
List::Layout List::computeLayout(float64 expanded) const {
|
||||||
|
const auto segmentsSpinProgress = expanded / 2.;
|
||||||
|
expanded = std::min(expanded, 1.);
|
||||||
|
|
||||||
const auto &st = _st.small;
|
const auto &st = _st.small;
|
||||||
const auto &full = _st.full;
|
const auto &full = _st.full;
|
||||||
const auto expandedRatio = _lastRatio;
|
const auto expandedRatio = _lastRatio;
|
||||||
|
@ -251,6 +259,7 @@ List::Layout List::computeLayout(float64 expanded) const {
|
||||||
: 0.)),
|
: 0.)),
|
||||||
.expandedRatio = expandedRatio,
|
.expandedRatio = expandedRatio,
|
||||||
.ratio = ratio,
|
.ratio = ratio,
|
||||||
|
.segmentsSpinProgress = segmentsSpinProgress,
|
||||||
.thumbnailLeft = thumbnailLeft,
|
.thumbnailLeft = thumbnailLeft,
|
||||||
.photoLeft = photoLeft,
|
.photoLeft = photoLeft,
|
||||||
.left = thumbnailLeft - photoLeft,
|
.left = thumbnailLeft - photoLeft,
|
||||||
|
@ -385,6 +394,11 @@ void List::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
auto gradient = QLinearGradient();
|
||||||
|
gradient.setStops({
|
||||||
|
{ 0., st::groupCallLive1->c },
|
||||||
|
{ 1., st::groupCallMuted1->c },
|
||||||
|
});
|
||||||
enumerate([&](Single single) {
|
enumerate([&](Single single) {
|
||||||
// Name.
|
// Name.
|
||||||
if (const auto full = single.itemFull) {
|
if (const auto full = single.itemFull) {
|
||||||
|
@ -409,30 +423,35 @@ void List::paintEvent(QPaintEvent *e) {
|
||||||
photo);
|
photo);
|
||||||
const auto small = single.itemSmall;
|
const auto small = single.itemSmall;
|
||||||
const auto itemFull = single.itemFull;
|
const auto itemFull = single.itemFull;
|
||||||
const auto smallUnread = small && small->element.unreadCount;
|
const auto smallUnread = (small && small->element.unreadCount);
|
||||||
const auto fullUnread = itemFull && itemFull->element.unreadCount;
|
const auto fullUnreadCount = itemFull
|
||||||
const auto unreadOpacity = (smallUnread && fullUnread)
|
? itemFull->element.unreadCount
|
||||||
|
: 0;
|
||||||
|
const auto unreadOpacity = (smallUnread && fullUnreadCount)
|
||||||
? 1.
|
? 1.
|
||||||
: smallUnread
|
: smallUnread
|
||||||
? (1. - expandRatio)
|
? (1. - expandRatio)
|
||||||
: fullUnread
|
: fullUnreadCount
|
||||||
? expandRatio
|
? expandRatio
|
||||||
: 0.;
|
: 0.;
|
||||||
if (unreadOpacity > 0.) {
|
if (unreadOpacity > 0.) {
|
||||||
p.setOpacity(unreadOpacity);
|
p.setOpacity(unreadOpacity);
|
||||||
const auto outerAdd = 2 * line;
|
const auto outerAdd = 1.5 * line;
|
||||||
const auto outer = userpic.marginsAdded(
|
const auto outer = userpic.marginsAdded(
|
||||||
{ outerAdd, outerAdd, outerAdd, outerAdd });
|
{ outerAdd, outerAdd, outerAdd, outerAdd });
|
||||||
p.setPen(Qt::NoPen);
|
gradient.setStart(userpic.topRight());
|
||||||
auto gradient = QLinearGradient(
|
gradient.setFinalStop(userpic.bottomLeft());
|
||||||
userpic.topRight(),
|
if (!fullUnreadCount) {
|
||||||
userpic.bottomLeft());
|
p.setPen(QPen(gradient, line));
|
||||||
gradient.setStops({
|
p.drawEllipse(outer);
|
||||||
{ 0., st::groupCallLive1->c },
|
} else {
|
||||||
{ 1., st::groupCallMuted1->c },
|
validateSegments(itemFull, gradient, line, true);
|
||||||
});
|
Ui::PaintOutlineSegments(
|
||||||
p.setBrush(gradient);
|
p,
|
||||||
p.drawEllipse(outer);
|
outer,
|
||||||
|
itemFull->segments,
|
||||||
|
layout.segmentsSpinProgress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
p.setOpacity(1.);
|
p.setOpacity(1.);
|
||||||
}, [&](Single single) {
|
}, [&](Single single) {
|
||||||
|
@ -447,30 +466,37 @@ void List::paintEvent(QPaintEvent *e) {
|
||||||
const auto small = single.itemSmall;
|
const auto small = single.itemSmall;
|
||||||
const auto itemFull = single.itemFull;
|
const auto itemFull = single.itemFull;
|
||||||
const auto smallUnread = small && small->element.unreadCount;
|
const auto smallUnread = small && small->element.unreadCount;
|
||||||
const auto fullUnread = itemFull && itemFull->element.unreadCount;
|
const auto fullUnreadCount = itemFull
|
||||||
|
? itemFull->element.unreadCount
|
||||||
|
: 0;
|
||||||
|
const auto fullCount = itemFull ? itemFull->element.count : 0;
|
||||||
|
|
||||||
// White circle with possible read gray line.
|
// White circle with possible read gray line.
|
||||||
const auto hasReadLine = (itemFull && !fullUnread);
|
const auto hasReadLine = (itemFull && fullUnreadCount < fullCount);
|
||||||
p.setOpacity((small && itemFull)
|
p.setOpacity((small && itemFull)
|
||||||
? 1.
|
? 1.
|
||||||
: small
|
: small
|
||||||
? (1. - expandRatio)
|
? (1. - expandRatio)
|
||||||
: expandRatio);
|
: expandRatio);
|
||||||
if (hasReadLine) {
|
|
||||||
auto color = st::dialogsUnreadBgMuted->c;
|
|
||||||
if (small) {
|
|
||||||
color.setAlphaF(color.alphaF() * expandRatio);
|
|
||||||
}
|
|
||||||
auto pen = QPen(color);
|
|
||||||
pen.setWidthF(lineRead);
|
|
||||||
p.setPen(pen);
|
|
||||||
} else {
|
|
||||||
p.setPen(Qt::NoPen);
|
|
||||||
}
|
|
||||||
const auto add = line + (hasReadLine ? (lineRead / 2.) : 0.);
|
const auto add = line + (hasReadLine ? (lineRead / 2.) : 0.);
|
||||||
const auto rect = userpic.marginsAdded({ add, add, add, add });
|
const auto rect = userpic.marginsAdded({ add, add, add, add });
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
p.setBrush(st::dialogsBg);
|
p.setBrush(st::dialogsBg);
|
||||||
p.drawEllipse(rect);
|
p.drawEllipse(rect);
|
||||||
|
if (hasReadLine) {
|
||||||
|
if (small && !small->element.unreadCount) {
|
||||||
|
p.setOpacity(expandRatio);
|
||||||
|
}
|
||||||
|
validateSegments(
|
||||||
|
itemFull,
|
||||||
|
st::dialogsUnreadBgMuted->b,
|
||||||
|
lineRead,
|
||||||
|
false);
|
||||||
|
Ui::PaintOutlineSegments(
|
||||||
|
p,
|
||||||
|
rect,
|
||||||
|
itemFull->segments);
|
||||||
|
}
|
||||||
|
|
||||||
// Userpic.
|
// Userpic.
|
||||||
if (itemFull == small) {
|
if (itemFull == small) {
|
||||||
|
@ -514,6 +540,36 @@ void List::validateThumbnail(not_null<Item*> item) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void List::validateSegments(
|
||||||
|
not_null<Item*> item,
|
||||||
|
const QBrush &brush,
|
||||||
|
float64 line,
|
||||||
|
bool forUnread) {
|
||||||
|
const auto count = item->element.count;
|
||||||
|
const auto unread = item->element.unreadCount;
|
||||||
|
if (int(item->segments.size()) != count) {
|
||||||
|
item->segments.resize(count);
|
||||||
|
}
|
||||||
|
auto i = 0;
|
||||||
|
if (forUnread) {
|
||||||
|
for (; i != count - unread; ++i) {
|
||||||
|
item->segments[i].width = 0.;
|
||||||
|
}
|
||||||
|
for (; i != count; ++i) {
|
||||||
|
item->segments[i].brush = brush;
|
||||||
|
item->segments[i].width = line;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (; i != count - unread; ++i) {
|
||||||
|
item->segments[i].brush = brush;
|
||||||
|
item->segments[i].width = line;
|
||||||
|
}
|
||||||
|
for (; i != count; ++i) {
|
||||||
|
item->segments[i].width = 0.;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void List::validateName(not_null<Item*> item) {
|
void List::validateName(not_null<Item*> item) {
|
||||||
const auto &color = st::dialogsNameFg;
|
const auto &color = st::dialogsNameFg;
|
||||||
if (!item->nameCache.isNull() && item->nameCacheColor == color->c) {
|
if (!item->nameCache.isNull() && item->nameCacheColor == color->c) {
|
||||||
|
@ -680,8 +736,8 @@ void List::setLayoutConstraints(
|
||||||
}
|
}
|
||||||
|
|
||||||
List::CollapsedGeometry List::collapsedGeometryCurrent() const {
|
List::CollapsedGeometry List::collapsedGeometryCurrent() const {
|
||||||
const auto expanded = _expandedAnimation.value(_expanded ? 1. : 0.);
|
const auto expanded = _expandedAnimation.value(_expanded ? 2. : 0.);
|
||||||
if (expanded == 1.) {
|
if (expanded >= 1.) {
|
||||||
return { QRect(), 1. };
|
return { QRect(), 1. };
|
||||||
}
|
}
|
||||||
const auto layout = computeLayout(0.);
|
const auto layout = computeLayout(0.);
|
||||||
|
|
|
@ -22,6 +22,7 @@ struct DialogsStoriesList;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
|
struct OutlineSegment;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Dialogs::Stories {
|
namespace Dialogs::Stories {
|
||||||
|
@ -64,6 +65,7 @@ public:
|
||||||
not_null<QWidget*> parent,
|
not_null<QWidget*> parent,
|
||||||
const style::DialogsStoriesList &st,
|
const style::DialogsStoriesList &st,
|
||||||
rpl::producer<Content> content);
|
rpl::producer<Content> content);
|
||||||
|
~List();
|
||||||
|
|
||||||
void setExpandedHeight(int height, bool momentum = false);
|
void setExpandedHeight(int height, bool momentum = false);
|
||||||
void setLayoutConstraints(
|
void setLayoutConstraints(
|
||||||
|
@ -100,6 +102,7 @@ private:
|
||||||
Element element;
|
Element element;
|
||||||
QImage nameCache;
|
QImage nameCache;
|
||||||
QColor nameCacheColor;
|
QColor nameCacheColor;
|
||||||
|
std::vector<Ui::OutlineSegment> segments;
|
||||||
bool subscribed = false;
|
bool subscribed = false;
|
||||||
};
|
};
|
||||||
struct Data {
|
struct Data {
|
||||||
|
@ -134,6 +137,11 @@ private:
|
||||||
void updateGeometry();
|
void updateGeometry();
|
||||||
[[nodiscard]] QRect countSmallGeometry() const;
|
[[nodiscard]] QRect countSmallGeometry() const;
|
||||||
void updateExpanding(int expandingHeight, int expandedHeight);
|
void updateExpanding(int expandingHeight, int expandedHeight);
|
||||||
|
void validateSegments(
|
||||||
|
not_null<Item*> item,
|
||||||
|
const QBrush &brush,
|
||||||
|
float64 line,
|
||||||
|
bool forUnread);
|
||||||
|
|
||||||
[[nodiscard]] Layout computeLayout();
|
[[nodiscard]] Layout computeLayout();
|
||||||
[[nodiscard]] Layout computeLayout(float64 expanded) const;
|
[[nodiscard]] Layout computeLayout(float64 expanded) const;
|
||||||
|
|
73
Telegram/SourceFiles/ui/effects/outline_segments.cpp
Normal file
73
Telegram/SourceFiles/ui/effects/outline_segments.cpp
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#include "ui/effects/outline_segments.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
void PaintOutlineSegments(
|
||||||
|
QPainter &p,
|
||||||
|
QRectF ellipse,
|
||||||
|
const std::vector<OutlineSegment> &segments,
|
||||||
|
float64 fromFullProgress) {
|
||||||
|
Expects(!segments.empty());
|
||||||
|
|
||||||
|
p.setBrush(Qt::NoBrush);
|
||||||
|
const auto count = int(segments.size());
|
||||||
|
if (count == 1) {
|
||||||
|
p.setPen(QPen(segments.front().brush, segments.front().width));
|
||||||
|
p.drawEllipse(ellipse);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto small = 160;
|
||||||
|
const auto full = arc::kFullLength;
|
||||||
|
const auto separator = (full > 1.1 * small * count)
|
||||||
|
? small
|
||||||
|
: (full / (count * 1.1));
|
||||||
|
const auto left = full - (separator * count);
|
||||||
|
const auto length = left / float64(count);
|
||||||
|
const auto step = length + separator;
|
||||||
|
const auto spin = separator * (1. - fromFullProgress);
|
||||||
|
|
||||||
|
auto start = 0. + (arc::kQuarterLength + (separator / 2)) + (3. * spin);
|
||||||
|
auto pen = QPen(
|
||||||
|
segments.back().brush,
|
||||||
|
segments.back().width,
|
||||||
|
Qt::SolidLine,
|
||||||
|
Qt::RoundCap);
|
||||||
|
p.setPen(pen);
|
||||||
|
for (auto i = 0; i != count;) {
|
||||||
|
const auto &segment = segments[count - (++i)];
|
||||||
|
if (!segment.width) {
|
||||||
|
start += length + separator;
|
||||||
|
continue;
|
||||||
|
} else if (pen.brush() != segment.brush
|
||||||
|
|| pen.widthF() != segment.width) {
|
||||||
|
pen = QPen(
|
||||||
|
segment.brush,
|
||||||
|
segment.width,
|
||||||
|
Qt::SolidLine,
|
||||||
|
Qt::RoundCap);
|
||||||
|
p.setPen(pen);
|
||||||
|
}
|
||||||
|
const auto from = int(base::SafeRound(start));
|
||||||
|
const auto till = start + length;
|
||||||
|
auto added = spin;
|
||||||
|
for (; i != count;) {
|
||||||
|
start += length + separator;
|
||||||
|
const auto &next = segments[count - (++i)];
|
||||||
|
if (next.width) {
|
||||||
|
--i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
added += (separator + length) * (1. - fromFullProgress);
|
||||||
|
}
|
||||||
|
p.drawArc(ellipse, from, int(base::SafeRound(till + added)) - from);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Ui
|
23
Telegram/SourceFiles/ui/effects/outline_segments.h
Normal file
23
Telegram/SourceFiles/ui/effects/outline_segments.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
struct OutlineSegment {
|
||||||
|
QBrush brush;
|
||||||
|
float64 width = 0.;
|
||||||
|
};
|
||||||
|
|
||||||
|
void PaintOutlineSegments(
|
||||||
|
QPainter &p,
|
||||||
|
QRectF ellipse,
|
||||||
|
const std::vector<OutlineSegment> &segments,
|
||||||
|
float64 fromFullProgress = 1.);
|
||||||
|
|
||||||
|
} // namespace Ui
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/rp_widget.h"
|
#include "ui/rp_widget.h"
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
|
#include "ui/effects/outline_segments.h"
|
||||||
#include "ui/image/image_prepare.h"
|
#include "ui/image/image_prepare.h"
|
||||||
|
|
||||||
#include <QtCore/QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
|
@ -368,6 +369,10 @@ RoundImageCheckbox::RoundImageCheckbox(
|
||||||
, _check(_st.check, _updateCallback) {
|
, _check(_st.check, _updateCallback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RoundImageCheckbox::RoundImageCheckbox(RoundImageCheckbox&&) = default;
|
||||||
|
|
||||||
|
RoundImageCheckbox::~RoundImageCheckbox() = default;
|
||||||
|
|
||||||
void RoundImageCheckbox::paint(Painter &p, int x, int y, int outerWidth) const {
|
void RoundImageCheckbox::paint(Painter &p, int x, int y, int outerWidth) const {
|
||||||
auto selectionLevel = _selection.value(checked() ? 1. : 0.);
|
auto selectionLevel = _selection.value(checked() ? 1. : 0.);
|
||||||
if (_selection.animating()) {
|
if (_selection.animating()) {
|
||||||
|
@ -416,26 +421,7 @@ void RoundImageCheckbox::paint(Painter &p, int x, int y, int outerWidth) const {
|
||||||
p.drawRoundedRect(outline, *radius, *radius);
|
p.drawRoundedRect(outline, *radius, *radius);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const auto small = 160;
|
PaintOutlineSegments(p, outline, _segments);
|
||||||
const auto full = arc::kFullLength;
|
|
||||||
const auto separator = (full > 1.1 * small * segments)
|
|
||||||
? small
|
|
||||||
: full / (segments * 1.1);
|
|
||||||
const auto left = full - (separator * segments);
|
|
||||||
const auto length = left / float64(segments);
|
|
||||||
|
|
||||||
auto start = 0. + (arc::kQuarterLength + (separator / 2));
|
|
||||||
for (const auto &segment : ranges::views::reverse(_segments)) {
|
|
||||||
p.setPen(QPen(
|
|
||||||
segment.brush,
|
|
||||||
segment.width,
|
|
||||||
Qt::SolidLine,
|
|
||||||
Qt::RoundCap));
|
|
||||||
const auto from = int(base::SafeRound(start));
|
|
||||||
const auto till = int(base::SafeRound(start + length));
|
|
||||||
p.drawArc(outline, from, till - from);
|
|
||||||
start += length + separator;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
p.setOpacity(1.);
|
p.setOpacity(1.);
|
||||||
}
|
}
|
||||||
|
@ -511,7 +497,7 @@ void RoundImageCheckbox::setColorOverride(std::optional<QBrush> fg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RoundImageCheckbox::setCustomizedSegments(
|
void RoundImageCheckbox::setCustomizedSegments(
|
||||||
std::vector<Segment> segments) {
|
std::vector<Ui::OutlineSegment> segments) {
|
||||||
_segments = std::move(segments);
|
_segments = std::move(segments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@ enum class ImageRoundRadius;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
|
||||||
|
struct OutlineSegment;
|
||||||
|
|
||||||
class RoundCheckbox {
|
class RoundCheckbox {
|
||||||
public:
|
public:
|
||||||
RoundCheckbox(const style::RoundCheckbox &st, Fn<void()> updateCallback);
|
RoundCheckbox(const style::RoundCheckbox &st, Fn<void()> updateCallback);
|
||||||
|
@ -45,26 +47,22 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RoundImageCheckboxSegment {
|
|
||||||
QBrush brush;
|
|
||||||
float64 width = 0.;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RoundImageCheckbox {
|
class RoundImageCheckbox {
|
||||||
public:
|
public:
|
||||||
using Segment = RoundImageCheckboxSegment;
|
|
||||||
using PaintRoundImage = Fn<void(Painter &p, int x, int y, int outerWidth, int size)>;
|
using PaintRoundImage = Fn<void(Painter &p, int x, int y, int outerWidth, int size)>;
|
||||||
RoundImageCheckbox(
|
RoundImageCheckbox(
|
||||||
const style::RoundImageCheckbox &st,
|
const style::RoundImageCheckbox &st,
|
||||||
Fn<void()> updateCallback,
|
Fn<void()> updateCallback,
|
||||||
PaintRoundImage &&paintRoundImage,
|
PaintRoundImage &&paintRoundImage,
|
||||||
Fn<std::optional<int>(int size)> roundingRadius = nullptr);
|
Fn<std::optional<int>(int size)> roundingRadius = nullptr);
|
||||||
|
RoundImageCheckbox(RoundImageCheckbox&&);
|
||||||
|
~RoundImageCheckbox();
|
||||||
|
|
||||||
void paint(Painter &p, int x, int y, int outerWidth) const;
|
void paint(Painter &p, int x, int y, int outerWidth) const;
|
||||||
float64 checkedAnimationRatio() const;
|
float64 checkedAnimationRatio() const;
|
||||||
|
|
||||||
void setColorOverride(std::optional<QBrush> fg);
|
void setColorOverride(std::optional<QBrush> fg);
|
||||||
void setCustomizedSegments(std::vector<Segment> segments);
|
void setCustomizedSegments(std::vector<OutlineSegment> segments);
|
||||||
|
|
||||||
bool checked() const {
|
bool checked() const {
|
||||||
return _check.checked();
|
return _check.checked();
|
||||||
|
@ -91,7 +89,7 @@ private:
|
||||||
RoundCheckbox _check;
|
RoundCheckbox _check;
|
||||||
|
|
||||||
//std::optional<QBrush> _fgOverride;
|
//std::optional<QBrush> _fgOverride;
|
||||||
std::vector<Segment> _segments;
|
std::vector<OutlineSegment> _segments;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -267,6 +267,8 @@ PRIVATE
|
||||||
ui/effects/glare.h
|
ui/effects/glare.h
|
||||||
ui/effects/loading_element.cpp
|
ui/effects/loading_element.cpp
|
||||||
ui/effects/loading_element.h
|
ui/effects/loading_element.h
|
||||||
|
ui/effects/outline_segments.cpp
|
||||||
|
ui/effects/outline_segments.h
|
||||||
ui/effects/premium_graphics.cpp
|
ui/effects/premium_graphics.cpp
|
||||||
ui/effects/premium_graphics.h
|
ui/effects/premium_graphics.h
|
||||||
ui/effects/premium_stars.cpp
|
ui/effects/premium_stars.cpp
|
||||||
|
|
Loading…
Add table
Reference in a new issue