Stickers box redesigned.

This commit is contained in:
John Preston 2016-11-22 12:48:13 +03:00
parent 38d20c506e
commit 6e0394dd42
49 changed files with 1525 additions and 1204 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

View File

@ -708,7 +708,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_box_remove" = "Remove"; "lng_box_remove" = "Remove";
"lng_custom_stickers" = "Custom stickers"; "lng_stickers_installed_tab" = "Stickers";
"lng_stickers_featured_tab" = "Trending";
"lng_stickers_archived_tab" = "Archived";
"lng_stickers_remove_pack" = "Remove «{sticker_pack}»?"; "lng_stickers_remove_pack" = "Remove «{sticker_pack}»?";
"lng_stickers_add_pack" = "Add stickers"; "lng_stickers_add_pack" = "Add stickers";
"lng_stickers_share_pack" = "Share Stickers"; "lng_stickers_share_pack" = "Share Stickers";
@ -718,14 +720,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_stickers_copied" = "Sticker pack link copied to clipboard."; "lng_stickers_copied" = "Sticker pack link copied to clipboard.";
"lng_stickers_default_set" = "Great Minds"; "lng_stickers_default_set" = "Great Minds";
"lng_stickers_you_have" = "Manage and reorder sticker packs"; "lng_stickers_you_have" = "Manage and reorder sticker packs";
"lng_stickers_packs" = "Sticker Packs";
"lng_stickers_reorder" = "Click and drag to reorder sticker packs";
"lng_stickers_featured" = "Trending Stickers"; "lng_stickers_featured" = "Trending Stickers";
"lng_stickers_clear_recent" = "Clear";
"lng_stickers_clear_recent_sure" = "Are you sure you want to clear your frequently used stickers list?";
"lng_stickers_remove" = "Delete";
"lng_stickers_return" = "Undo"; "lng_stickers_return" = "Undo";
"lng_stickers_restore" = "Restore";
"lng_stickers_count" = "{count:Loading...|# sticker|# stickers}"; "lng_stickers_count" = "{count:Loading...|# sticker|# stickers}";
"lng_stickers_masks_pack" = "This is a pack of mask stickers. You can use them in the photo editor on our mobile apps."; "lng_stickers_masks_pack" = "This is a pack of mask stickers. You can use them in the photo editor on our mobile apps.";

View File

@ -692,6 +692,109 @@ void ApiWrap::requestStickerSets() {
} }
} }
void ApiWrap::saveStickerSets(const Stickers::Order &localOrder, const Stickers::Order &localRemoved) {
for (auto requestId : base::take(_stickerSetDisenableRequests)) {
MTP::cancel(requestId);
}
MTP::cancel(base::take(_stickersReorderRequestId));
MTP::cancel(base::take(_stickersClearRecentRequestId));
auto writeInstalled = true, writeRecent = false, writeCloudRecent = false, writeArchived = false;
auto &recent = cGetRecentStickers();
auto &sets = Global::RefStickerSets();
_stickersOrder = localOrder;
for_const (auto removedSetId, localRemoved) {
if (removedSetId == Stickers::CloudRecentSetId) {
if (sets.remove(Stickers::CloudRecentSetId) != 0) {
writeCloudRecent = true;
}
if (sets.remove(Stickers::CustomSetId)) {
writeInstalled = true;
}
if (!recent.isEmpty()) {
recent.clear();
writeRecent = true;
}
MTPmessages_ClearRecentStickers::Flags flags = 0;
_stickersClearRecentRequestId = MTP::send(MTPmessages_ClearRecentStickers(MTP_flags(flags)), rpcDone(&ApiWrap::stickersClearRecentDone), rpcFail(&ApiWrap::stickersClearRecentFail));
continue;
}
auto it = sets.find(removedSetId);
if (it != sets.cend()) {
for (auto i = recent.begin(); i != recent.cend();) {
if (it->stickers.indexOf(i->first) >= 0) {
i = recent.erase(i);
writeRecent = true;
} else {
++i;
}
}
if (!(it->flags & MTPDstickerSet::Flag::f_archived)) {
MTPInputStickerSet setId = (it->id && it->access) ? MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access)) : MTP_inputStickerSetShortName(MTP_string(it->shortName));
_stickerSetDisenableRequests.insert(MTP::send(MTPmessages_UninstallStickerSet(setId), rpcDone(&ApiWrap::stickerSetDisenableDone), rpcFail(&ApiWrap::stickerSetDisenableFail), 0, 5));
int removeIndex = Global::StickerSetsOrder().indexOf(it->id);
if (removeIndex >= 0) Global::RefStickerSetsOrder().removeAt(removeIndex);
if (!(it->flags & MTPDstickerSet_ClientFlag::f_featured) && !(it->flags & MTPDstickerSet_ClientFlag::f_special)) {
sets.erase(it);
} else {
if (it->flags & MTPDstickerSet::Flag::f_archived) {
writeArchived = true;
}
it->flags &= ~(MTPDstickerSet::Flag::f_installed | MTPDstickerSet::Flag::f_archived);
}
}
}
}
// Clear all installed flags, set only for sets from order.
for (auto &set : sets) {
if (!(set.flags & MTPDstickerSet::Flag::f_archived)) {
set.flags &= ~MTPDstickerSet::Flag::f_installed;
}
}
auto &order(Global::RefStickerSetsOrder());
order.clear();
for_const (auto setId, _stickersOrder) {
auto it = sets.find(setId);
if (it != sets.cend()) {
if ((it->flags & MTPDstickerSet::Flag::f_archived) && !localRemoved.contains(it->id)) {
MTPInputStickerSet mtpSetId = (it->id && it->access) ? MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access)) : MTP_inputStickerSetShortName(MTP_string(it->shortName));
_stickerSetDisenableRequests.insert(MTP::send(MTPmessages_InstallStickerSet(mtpSetId, MTP_boolFalse()), rpcDone(&ApiWrap::stickerSetDisenableDone), rpcFail(&ApiWrap::stickerSetDisenableFail), 0, 5));
it->flags &= ~MTPDstickerSet::Flag::f_archived;
writeArchived = true;
}
order.push_back(setId);
it->flags |= MTPDstickerSet::Flag::f_installed;
}
}
for (auto it = sets.begin(); it != sets.cend();) {
if ((it->flags & MTPDstickerSet_ClientFlag::f_featured)
|| (it->flags & MTPDstickerSet::Flag::f_installed)
|| (it->flags & MTPDstickerSet::Flag::f_archived)
|| (it->flags & MTPDstickerSet_ClientFlag::f_special)) {
++it;
} else {
it = sets.erase(it);
}
}
if (writeInstalled) Local::writeInstalledStickers();
if (writeRecent) Local::writeUserSettings();
if (writeArchived) Local::writeArchivedStickers();
if (writeCloudRecent) Local::writeRecentStickers();
emit App::main()->stickersUpdated();
if (_stickerSetDisenableRequests.isEmpty()) {
stickersSaveOrder();
} else {
MTP::sendAnything();
}
}
void ApiWrap::joinChannel(ChannelData *channel) { void ApiWrap::joinChannel(ChannelData *channel) {
if (channel->amIn()) { if (channel->amIn()) {
channelAmInUpdated(channel); channelAmInUpdated(channel);
@ -1180,3 +1283,57 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs
ApiWrap::~ApiWrap() { ApiWrap::~ApiWrap() {
App::clearHistories(); App::clearHistories();
} }
void ApiWrap::stickerSetDisenableDone(const MTPmessages_StickerSetInstallResult &result, mtpRequestId req) {
_stickerSetDisenableRequests.remove(req);
if (_stickerSetDisenableRequests.isEmpty()) {
stickersSaveOrder();
}
}
bool ApiWrap::stickerSetDisenableFail(const RPCError &error, mtpRequestId req) {
if (MTP::isDefaultHandledError(error)) return false;
_stickerSetDisenableRequests.remove(req);
if (_stickerSetDisenableRequests.isEmpty()) {
stickersSaveOrder();
}
return true;
}
void ApiWrap::stickersSaveOrder() {
if (_stickersOrder.size() > 1) {
QVector<MTPlong> mtpOrder;
mtpOrder.reserve(_stickersOrder.size());
for_const (auto setId, _stickersOrder) {
mtpOrder.push_back(MTP_long(setId));
}
MTPmessages_ReorderStickerSets::Flags flags = 0;
_stickersReorderRequestId = MTP::send(MTPmessages_ReorderStickerSets(MTP_flags(flags), MTP_vector<MTPlong>(mtpOrder)), rpcDone(&ApiWrap::stickersReorderDone), rpcFail(&ApiWrap::stickersReorderFail));
} else {
stickersReorderDone(MTP_boolTrue());
}
}
void ApiWrap::stickersReorderDone(const MTPBool &result) {
_stickersReorderRequestId = 0;
}
bool ApiWrap::stickersReorderFail(const RPCError &result) {
if (MTP::isDefaultHandledError(result)) return false;
_stickersReorderRequestId = 0;
Global::SetLastStickersUpdate(0);
App::main()->updateStickers();
return true;
}
void ApiWrap::stickersClearRecentDone(const MTPBool &result) {
_stickersClearRecentRequestId = 0;
}
bool ApiWrap::stickersClearRecentFail(const RPCError &result) {
if (MTP::isDefaultHandledError(result)) return false;
_stickersClearRecentRequestId = 0;
return true;
}

View File

@ -26,7 +26,6 @@ class ApiWrap : public QObject, public RPCSender {
Q_OBJECT Q_OBJECT
public: public:
ApiWrap(QObject *parent); ApiWrap(QObject *parent);
void init(); void init();
@ -51,6 +50,7 @@ public:
void scheduleStickerSetRequest(uint64 setId, uint64 access); void scheduleStickerSetRequest(uint64 setId, uint64 access);
void requestStickerSets(); void requestStickerSets();
void saveStickerSets(const Stickers::Order &localOrder, const Stickers::Order &localRemoved);
void joinChannel(ChannelData *channel); void joinChannel(ChannelData *channel);
void leaveChannel(ChannelData *channel); void leaveChannel(ChannelData *channel);
@ -67,11 +67,9 @@ public:
~ApiWrap(); ~ApiWrap();
signals: signals:
void fullPeerUpdated(PeerData *peer); void fullPeerUpdated(PeerData *peer);
public slots: public slots:
void resolveMessageDatas(); void resolveMessageDatas();
void resolveWebPages(); void resolveWebPages();
@ -79,7 +77,6 @@ public slots:
void saveDraftsToCloud(); void saveDraftsToCloud();
private: private:
void updatesReceived(const MTPUpdates &updates); void updatesReceived(const MTPUpdates &updates);
void gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req); void gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req);
@ -158,4 +155,16 @@ private:
void saveCloudDraftDone(History *history, const MTPBool &result, mtpRequestId requestId); void saveCloudDraftDone(History *history, const MTPBool &result, mtpRequestId requestId);
bool saveCloudDraftFail(History *history, const RPCError &error, mtpRequestId requestId); bool saveCloudDraftFail(History *history, const RPCError &error, mtpRequestId requestId);
OrderedSet<mtpRequestId> _stickerSetDisenableRequests;
void stickerSetDisenableDone(const MTPmessages_StickerSetInstallResult &result, mtpRequestId req);
bool stickerSetDisenableFail(const RPCError &error, mtpRequestId req);
Stickers::Order _stickersOrder;
mtpRequestId _stickersReorderRequestId = 0;
void stickersSaveOrder();
void stickersReorderDone(const MTPBool &result);
bool stickersReorderFail(const RPCError &result);
mtpRequestId _stickersClearRecentRequestId = 0;
void stickersClearRecentDone(const MTPBool &result);
bool stickersClearRecentFail(const RPCError &result);
}; };

View File

@ -2093,7 +2093,10 @@ namespace {
Global::SetLastStickersUpdate(0); Global::SetLastStickersUpdate(0);
Global::SetLastRecentStickersUpdate(0); Global::SetLastRecentStickersUpdate(0);
Global::SetFeaturedStickerSetsOrder(Stickers::Order()); Global::SetFeaturedStickerSetsOrder(Stickers::Order());
Global::SetFeaturedStickerSetsUnreadCount(0); if (Global::FeaturedStickerSetsUnreadCount() != 0) {
Global::SetFeaturedStickerSetsUnreadCount(0);
Global::RefFeaturedStickerSetsUnreadCountChanged().notify();
}
Global::SetLastFeaturedStickersUpdate(0); Global::SetLastFeaturedStickersUpdate(0);
Global::SetArchivedStickerSetsOrder(Stickers::Order()); Global::SetArchivedStickerSetsOrder(Stickers::Order());
cSetSavedGifs(SavedGifs()); cSetSavedGifs(SavedGifs());

View File

@ -60,7 +60,7 @@ void AboutBox::resizeEvent(QResizeEvent *e) {
void AboutBox::onVersion() { void AboutBox::onVersion() {
if (cRealBetaVersion()) { if (cRealBetaVersion()) {
QString url = qsl("https://tdesktop.com/"); auto url = qsl("https://tdesktop.com/");
switch (cPlatform()) { switch (cPlatform()) {
case dbipWindows: url += qsl("win/%1.zip"); break; case dbipWindows: url += qsl("win/%1.zip"); break;
case dbipMac: url += qsl("mac/%1.zip"); break; case dbipMac: url += qsl("mac/%1.zip"); break;

View File

@ -58,13 +58,17 @@ void AbstractBox::keyPressEvent(QKeyEvent *e) {
} }
void AbstractBox::resizeEvent(QResizeEvent *e) { void AbstractBox::resizeEvent(QResizeEvent *e) {
updateBlockTitleGeometry();
LayerWidget::resizeEvent(e);
}
void AbstractBox::updateBlockTitleGeometry() {
if (_blockClose) { if (_blockClose) {
_blockClose->moveToRight(0, 0); _blockClose->moveToRight(0, 0);
} }
if (_blockShadow) { if (_blockShadow) {
_blockShadow->setGeometry(0, st::boxBlockTitleHeight, width(), st::boxBlockTitleShadow.height()); _blockShadow->setGeometry(0, st::boxBlockTitleHeight, width(), st::boxBlockTitleShadow.height());
} }
LayerWidget::resizeEvent(e);
} }
void AbstractBox::parentResized() { void AbstractBox::parentResized() {
@ -143,11 +147,22 @@ void AbstractBox::onClose() {
emit closed(this); emit closed(this);
} }
void AbstractBox::setBlockTitle(bool block) { void AbstractBox::setBlockTitle(bool block, bool withClose, bool withShadow) {
_blockTitle = block; _blockTitle = block;
_blockShadow.create(this, st::boxBlockTitleShadow); if (withClose) {
_blockClose.create(this, st::boxBlockTitleClose); _blockClose.create(this, st::boxBlockTitleClose);
_blockClose->setClickedCallback([this] { onClose(); }); _blockClose->setClickedCallback([this] { onClose(); });
_blockClose->show();
} else {
_blockClose.destroy();
}
if (withShadow) {
_blockShadow.create(this, st::boxBlockTitleShadow);
_blockShadow->show();
} else {
_blockShadow.destroy();
}
updateBlockTitleGeometry();
} }
void AbstractBox::raiseShadow() { void AbstractBox::raiseShadow() {

View File

@ -38,7 +38,7 @@ public:
void setTitleText(const QString &title); void setTitleText(const QString &title);
void setAdditionalTitle(const QString &additionalTitle); void setAdditionalTitle(const QString &additionalTitle);
void setBlockTitle(bool block); void setBlockTitle(bool block, bool withClose = true, bool withShadow = true);
void raiseShadow(); void raiseShadow();
public slots: public slots:
@ -59,9 +59,11 @@ protected:
} }
private: private:
int _maxHeight = 0; void updateBlockTitleGeometry();
int countHeight() const; int countHeight() const;
int _maxHeight = 0;
bool _closed = false; bool _closed = false;
QString _title; QString _title;

View File

@ -470,7 +470,7 @@ confirmCaptionArea: InputArea(defaultInputArea) {
textMargins: margins(1px, 6px, 1px, 4px); textMargins: margins(1px, 6px, 1px, 4px);
heightMax: 56px; heightMax: 56px;
} }
confirmBg: #f2f2f2; confirmBg: windowBgOver;
confirmMaxHeight: 245px; confirmMaxHeight: 245px;
confirmCompressedSkip: 10px; confirmCompressedSkip: 10px;

View File

@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "lang.h" #include "lang.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/discrete_slider.h" #include "ui/widgets/discrete_sliders.h"
#include "styles/style_boxes.h" #include "styles/style_boxes.h"
#include "styles/style_dialogs.h" #include "styles/style_dialogs.h"
#include "styles/style_window.h" #include "styles/style_window.h"

View File

@ -25,7 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
namespace Ui { namespace Ui {
class RoundButton; class RoundButton;
class LinkButton; class LinkButton;
class DiscreteSlider; class SettingsSlider;
} // namespace Ui } // namespace Ui
class NotificationsBox : public AbstractBox { class NotificationsBox : public AbstractBox {
@ -70,7 +70,7 @@ private:
ScreenCorner _downCorner = ScreenCorner::TopLeft; ScreenCorner _downCorner = ScreenCorner::TopLeft;
int _oldCount; int _oldCount;
ChildWidget<Ui::DiscreteSlider> _countSlider; ChildWidget<Ui::SettingsSlider> _countSlider;
ChildWidget<Ui::RoundButton> _done; ChildWidget<Ui::RoundButton> _done;
QVector<SampleWidget*> _cornerSamples[4]; QVector<SampleWidget*> _cornerSamples[4];

File diff suppressed because it is too large Load Diff

View File

@ -24,10 +24,15 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
class ConfirmBox; class ConfirmBox;
namespace style {
struct RippleAnimation;
} // namespace style
namespace Ui { namespace Ui {
class PlainShadow; class PlainShadow;
class RoundButton; class RoundButton;
class RippleAnimation; class RippleAnimation;
class SettingsSlider;
} // namespace Ui } // namespace Ui
class StickersBox : public ItemListBox, public RPCSender { class StickersBox : public ItemListBox, public RPCSender {
@ -43,8 +48,6 @@ public:
StickersBox(Section section = Section::Installed); StickersBox(Section section = Section::Installed);
StickersBox(const Stickers::Order &archivedIds); StickersBox(const Stickers::Order &archivedIds);
~StickersBox();
public slots: public slots:
void onStickersUpdated(); void onStickersUpdated();
@ -52,8 +55,6 @@ public slots:
void onNoDraggingScroll(); void onNoDraggingScroll();
void onScrollTimer(); void onScrollTimer();
void onSave();
private slots: private slots:
void onScroll(); void onScroll();
@ -64,31 +65,56 @@ protected:
void closePressed() override; void closePressed() override;
private: private:
void refreshTabs();
void setup(); void setup();
int32 countHeight() const;
void rebuildList(); void rebuildList();
void updateTabsGeometry();
void switchTab();
void installSet(uint64 setId);
void disenableDone(const MTPmessages_StickerSetInstallResult &result, mtpRequestId req); QPixmap grabContentCache();
bool disenableFail(const RPCError &error, mtpRequestId req);
void reorderDone(const MTPBool &result); void installDone(const MTPmessages_StickerSetInstallResult &result);
bool reorderFail(const RPCError &result); bool installFail(uint64 setId, const RPCError &error);
void saveOrder();
void updateVisibleTopBottom(); void updateVisibleTopBottom();
void preloadArchivedSets();
void requestArchivedSets();
void checkLoadMoreArchived(); void checkLoadMoreArchived();
void getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedStickers &result); void getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedStickers &result);
ChildWidget<Ui::PlainShadow> _topShadow;
ChildWidget<Ui::SettingsSlider> _tabs = { nullptr };
QList<Section> _tabIndices;
class CounterWidget;
ChildWidget<CounterWidget> _unreadBadge = { nullptr };
Section _section; Section _section;
class Inner; class Inner;
ChildWidget<Inner> _inner; struct Tab {
ChildWidget<Ui::RoundButton> _save = { nullptr }; Tab() : widget(nullptr) {
ChildWidget<Ui::RoundButton> _cancel = { nullptr }; }
OrderedSet<mtpRequestId> _disenableRequests; template <typename ...Args>
mtpRequestId _reorderRequest = 0; Tab(int index, Args&&... args) : index(index), widget(std_::forward<Args>(args)...) {
ChildWidget<Ui::PlainShadow> _topShadow = { nullptr }; }
int index = 0;
ChildWidget<Inner> widget = { nullptr };
int scrollTop = 0;
};
Tab _installed;
Tab _featured;
Tab _archived;
Tab *_tab = nullptr;
ChildWidget<Ui::RoundButton> _done = { nullptr };
ChildWidget<ScrollableBoxShadow> _bottomShadow = { nullptr }; ChildWidget<ScrollableBoxShadow> _bottomShadow = { nullptr };
FloatAnimation _a_slide;
bool _slideLeft = false;
QPixmap _leftCache, _rightCache;
QTimer _scrollTimer; QTimer _scrollTimer;
int32 _scrollDelta = 0; int32 _scrollDelta = 0;
@ -97,14 +123,19 @@ private:
int _aboutHeight = 0; int _aboutHeight = 0;
mtpRequestId _archivedRequestId = 0; mtpRequestId _archivedRequestId = 0;
bool _archivedLoaded = false;
bool _allArchivedLoaded = false; bool _allArchivedLoaded = false;
bool _someArchivedLoaded = false;
Stickers::Order _localOrder;
Stickers::Order _localRemoved;
}; };
int32 stickerPacksCount(bool includeDisabledOfficial = false); int stickerPacksCount(bool includeArchivedOfficial = false);
// This class is hold in header because it requires Qt preprocessing. // This class is hold in header because it requires Qt preprocessing.
class StickersBox::Inner : public TWidget, public RPCSender, private base::Subscriber { class StickersBox::Inner : public TWidget, private base::Subscriber {
Q_OBJECT Q_OBJECT
public: public:
@ -116,14 +147,17 @@ public:
void updateSize(); void updateSize();
void updateRows(); // refresh only pack cover stickers void updateRows(); // refresh only pack cover stickers
bool appendSet(const Stickers::Set &set); bool appendSet(const Stickers::Set &set);
bool savingStart() {
if (_saving) return false;
_saving = true;
return true;
}
Stickers::Order getOrder() const; Stickers::Order getOrder() const;
Stickers::Order getDisabledSets() const; Stickers::Order getFullOrder() const;
Stickers::Order getRemovedSets() const;
void setFullOrder(const Stickers::Order &order);
void setRemovedSets(const Stickers::Order &removed);
void setInstallSetCallback(base::lambda<void(uint64 setId)> &&callback) {
_installSetCallback = std_::move(callback);
}
void setVisibleScrollbar(int32 width); void setVisibleScrollbar(int32 width);
void setVisibleTopBottom(int visibleTop, int visibleBottom) override; void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
@ -143,37 +177,34 @@ signals:
public slots: public slots:
void onUpdateSelected(); void onUpdateSelected();
void onClearRecent();
void onClearBoxDestroyed(QObject *box);
private slots:
void onImageLoaded();
private: private:
template <typename Check>
Stickers::Order collectSets(Check check) const;
int getRowIndex(uint64 setId) const;
void setRowRemoved(int index, bool removed);
void setActionDown(int newActionDown); void setActionDown(int newActionDown);
void setPressed(int newPressed);
void setup(); void setup();
QRect relativeAddButtonRect() const; QRect relativeButtonRect(bool removeButton) const;
void paintButton(Painter &p, int y, bool selected, std_::unique_ptr<Ui::RippleAnimation> &ripple, const QString &text, int badgeCounter) const; void ensureRipple(const style::RippleAnimation &st, QImage mask, bool removeButton);
void step_shifting(uint64 ms, bool timer); void step_shifting(uint64 ms, bool timer);
void paintRow(Painter &p, int32 index, uint64 ms); void paintRow(Painter &p, int index, uint64 ms);
void paintFakeButton(Painter &p, int index, uint64 ms);
void clear(); void clear();
void setActionSel(int32 actionSel); void setActionSel(int32 actionSel);
float64 aboveShadowOpacity() const; float64 aboveShadowOpacity() const;
void readVisibleSets(); void readVisibleSets();
void installSet(uint64 setId);
void installDone(const MTPmessages_StickerSetInstallResult &result);
bool installFail(uint64 setId, const RPCError &error);
Section _section; Section _section;
Stickers::Order _archivedIds; Stickers::Order _archivedIds;
int32 _rowHeight; int32 _rowHeight;
struct StickerSetRow { struct Row {
StickerSetRow(uint64 id, DocumentData *sticker, int32 count, const QString &title, int titleWidth, bool installed, bool official, bool unread, bool disabled, bool recent, int32 pixw, int32 pixh) : id(id) Row(uint64 id, DocumentData *sticker, int32 count, const QString &title, int titleWidth, bool installed, bool official, bool unread, bool archived, bool removed, int32 pixw, int32 pixh) : id(id)
, sticker(sticker) , sticker(sticker)
, count(count) , count(count)
, title(title) , title(title)
@ -181,66 +212,66 @@ private:
, installed(installed) , installed(installed)
, official(official) , official(official)
, unread(unread) , unread(unread)
, disabled(disabled) , archived(archived)
, recent(recent) , removed(removed)
, pixw(pixw) , pixw(pixw)
, pixh(pixh) , pixh(pixh)
, yadd(0, 0) { , yadd(0, 0) {
} }
bool isRecentSet() const {
return (id == Stickers::CloudRecentSetId);
}
uint64 id; uint64 id;
DocumentData *sticker; DocumentData *sticker;
int32 count; int32 count;
QString title; QString title;
int titleWidth; int titleWidth;
bool installed, official, unread, disabled, recent; bool installed, official, unread, archived, removed;
int32 pixw, pixh; int32 pixw, pixh;
anim::ivalue yadd; anim::ivalue yadd;
QSharedPointer<Ui::RippleAnimation> ripple; QSharedPointer<Ui::RippleAnimation> ripple;
}; };
using StickerSetRows = QList<StickerSetRow*>; using Rows = QList<Row*>;
void rebuildAppendSet(const Stickers::Set &set, int maxNameWidth); void rebuildAppendSet(const Stickers::Set &set, int maxNameWidth);
void fillSetCover(const Stickers::Set &set, DocumentData **outSticker, int *outWidth, int *outHeight) const; void fillSetCover(const Stickers::Set &set, DocumentData **outSticker, int *outWidth, int *outHeight) const;
int fillSetCount(const Stickers::Set &set) const; int fillSetCount(const Stickers::Set &set) const;
QString fillSetTitle(const Stickers::Set &set, int maxNameWidth, int *outTitleWidth) const; QString fillSetTitle(const Stickers::Set &set, int maxNameWidth, int *outTitleWidth) const;
void fillSetFlags(const Stickers::Set &set, bool *outRecent, bool *outInstalled, bool *outOfficial, bool *outUnread, bool *outDisabled); void fillSetFlags(const Stickers::Set &set, bool *outInstalled, bool *outOfficial, bool *outUnread, bool *outArchived);
int countMaxNameWidth() const; int countMaxNameWidth() const;
StickerSetRows _rows; Rows _rows;
QList<uint64> _animStartTimes; QList<uint64> _animStartTimes;
uint64 _aboveShadowFadeStart = 0; uint64 _aboveShadowFadeStart = 0;
anim::fvalue _aboveShadowFadeOpacity = { 0., 0. }; anim::fvalue _aboveShadowFadeOpacity = { 0., 0. };
Animation _a_shifting; Animation _a_shifting;
base::lambda<void(uint64 setId)> _installSetCallback;
int _visibleTop = 0; int _visibleTop = 0;
int _visibleBottom = 0; int _visibleBottom = 0;
int _itemsTop = 0; int _itemsTop = 0;
bool _saving = false;
int _actionSel = -1; int _actionSel = -1;
int _actionDown = -1; int _actionDown = -1;
int _clearWidth, _removeWidth, _returnWidth, _restoreWidth; QString _addText;
int _addWidth = 0;
ConfirmBox *_clearBox = nullptr; QString _undoText;
int _undoWidth = 0;
int _buttonHeight = 0; int _buttonHeight = 0;
bool _hasFeaturedButton = false;
bool _hasArchivedButton = false;
QPoint _mouse; QPoint _mouse;
int _selected = -3; // -2 - featured stickers button, -1 - archived stickers button bool _inDragArea = false;
int _pressed = -2; int _selected = -1;
int _pressed = -1;
QPoint _dragStart; QPoint _dragStart;
int _started = -1; int _started = -1;
int _dragging = -1; int _dragging = -1;
int _above = -1; int _above = -1;
std_::unique_ptr<Ui::RippleAnimation> _archivedRipple;
std_::unique_ptr<Ui::RippleAnimation> _featuredRipple;
Ui::RectShadow _aboveShadow; Ui::RectShadow _aboveShadow;
int _scrollbar = 0; int _scrollbar = 0;

View File

@ -100,7 +100,6 @@ dialogsUnlockIconOver: icon {{ "dialogs_unlock", dialogsMenuIconFgOver }};
dialogsFilter: FlatInput(defaultFlatInput) { dialogsFilter: FlatInput(defaultFlatInput) {
font: font(fsize); font: font(fsize);
bgColor: #f2f2f2;
phColor: #949494; phColor: #949494;
phFocusColor: #a4a4a4; phFocusColor: #a4a4a4;

View File

@ -214,13 +214,14 @@ UnreadBadgeStyle::UnreadBadgeStyle()
, selected(false) , selected(false)
, muted(false) , muted(false)
, size(st::dialogsUnreadHeight) , size(st::dialogsUnreadHeight)
, padding(st::dialogsUnreadPadding)
, sizeId(UnreadBadgeInDialogs) , sizeId(UnreadBadgeInDialogs)
, font(st::dialogsUnreadFont) { , font(st::dialogsUnreadFont) {
} }
void paintUnreadCount(Painter &p, const QString &text, int x, int y, const UnreadBadgeStyle &st, int *outUnreadWidth) { void paintUnreadCount(Painter &p, const QString &text, int x, int y, const UnreadBadgeStyle &st, int *outUnreadWidth) {
int unreadWidth = st.font->width(text); int unreadWidth = st.font->width(text);
int unreadRectWidth = unreadWidth + 2 * st::dialogsUnreadPadding; int unreadRectWidth = unreadWidth + 2 * st.padding;
int unreadRectHeight = st.size; int unreadRectHeight = st.size;
accumulate_max(unreadRectWidth, unreadRectHeight); accumulate_max(unreadRectWidth, unreadRectHeight);
@ -237,9 +238,10 @@ void paintUnreadCount(Painter &p, const QString &text, int x, int y, const Unrea
paintUnreadBadge(p, QRect(unreadRectLeft, unreadRectTop, unreadRectWidth, unreadRectHeight), st); paintUnreadBadge(p, QRect(unreadRectLeft, unreadRectTop, unreadRectWidth, unreadRectHeight), st);
auto textTop = st.textTop ? st.textTop : (unreadRectHeight - st.font->height) / 2;
p.setFont(st.font); p.setFont(st.font);
p.setPen(st.active ? st::dialogsUnreadFgActive : (st.selected ? st::dialogsUnreadFgOver : st::dialogsUnreadFg)); p.setPen(st.active ? st::dialogsUnreadFgActive : (st.selected ? st::dialogsUnreadFgOver : st::dialogsUnreadFg));
p.drawText(unreadRectLeft + (unreadRectWidth - unreadWidth) / 2, unreadRectTop + (unreadRectHeight - st.font->height) / 2 + st.font->ascent, text); p.drawText(unreadRectLeft + (unreadRectWidth - unreadWidth) / 2, unreadRectTop + textTop + st.font->ascent, text);
} }
void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool selected, bool onlyBackground) { void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool selected, bool onlyBackground) {
@ -282,7 +284,7 @@ void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool sele
st.active = active; st.active = active;
st.muted = history->mute(); st.muted = history->mute();
paintUnreadCount(p, counter, unreadRight, unreadTop, st, &unreadWidth); paintUnreadCount(p, counter, unreadRight, unreadTop, st, &unreadWidth);
availableWidth -= unreadWidth + st::dialogsUnreadPadding; availableWidth -= unreadWidth + st.padding;
} }
if (history->typing.isEmpty() && history->sendActions.isEmpty()) { if (history->typing.isEmpty() && history->sendActions.isEmpty()) {
item->drawInDialog(p, QRect(nameleft, texttop, availableWidth, st::dialogsTextFont->height), active, selected, history->textCachedFor, history->lastItemTextCache); item->drawInDialog(p, QRect(nameleft, texttop, availableWidth, st::dialogsTextFont->height), active, selected, history->textCachedFor, history->lastItemTextCache);

View File

@ -52,7 +52,9 @@ struct UnreadBadgeStyle {
bool active; bool active;
bool selected; bool selected;
bool muted; bool muted;
int textTop = 0;
int size; int size;
int padding;
UnreadBadgeSize sizeId; UnreadBadgeSize sizeId;
style::font font; style::font font;
}; };

View File

@ -637,6 +637,7 @@ struct Data {
uint64 LastRecentStickersUpdate = 0; uint64 LastRecentStickersUpdate = 0;
Stickers::Order FeaturedStickerSetsOrder; Stickers::Order FeaturedStickerSetsOrder;
int FeaturedStickerSetsUnreadCount = 0; int FeaturedStickerSetsUnreadCount = 0;
base::Observable<void> FeaturedStickerSetsUnreadCountChanged;
uint64 LastFeaturedStickersUpdate = 0; uint64 LastFeaturedStickersUpdate = 0;
Stickers::Order ArchivedStickerSetsOrder; Stickers::Order ArchivedStickerSetsOrder;
@ -754,6 +755,7 @@ DefineVar(Global, uint64, LastStickersUpdate);
DefineVar(Global, uint64, LastRecentStickersUpdate); DefineVar(Global, uint64, LastRecentStickersUpdate);
DefineVar(Global, Stickers::Order, FeaturedStickerSetsOrder); DefineVar(Global, Stickers::Order, FeaturedStickerSetsOrder);
DefineVar(Global, int, FeaturedStickerSetsUnreadCount); DefineVar(Global, int, FeaturedStickerSetsUnreadCount);
DefineRefVar(Global, base::Observable<void>, FeaturedStickerSetsUnreadCountChanged);
DefineVar(Global, uint64, LastFeaturedStickersUpdate); DefineVar(Global, uint64, LastFeaturedStickersUpdate);
DefineVar(Global, Stickers::Order, ArchivedStickerSetsOrder); DefineVar(Global, Stickers::Order, ArchivedStickerSetsOrder);

View File

@ -317,6 +317,7 @@ DeclareVar(uint64, LastStickersUpdate);
DeclareVar(uint64, LastRecentStickersUpdate); DeclareVar(uint64, LastRecentStickersUpdate);
DeclareVar(Stickers::Order, FeaturedStickerSetsOrder); DeclareVar(Stickers::Order, FeaturedStickerSetsOrder);
DeclareVar(int, FeaturedStickerSetsUnreadCount); DeclareVar(int, FeaturedStickerSetsUnreadCount);
DeclareRefVar(base::Observable<void>, FeaturedStickerSetsUnreadCountChanged);
DeclareVar(uint64, LastFeaturedStickersUpdate); DeclareVar(uint64, LastFeaturedStickersUpdate);
DeclareVar(Stickers::Order, ArchivedStickerSetsOrder); DeclareVar(Stickers::Order, ArchivedStickerSetsOrder);

View File

@ -701,10 +701,10 @@ void HistoryItem::nextItemChanged() {
void HistoryItem::recountAttachToPrevious() { void HistoryItem::recountAttachToPrevious() {
bool attach = false; bool attach = false;
if (auto previous = previousItem()) { if (auto previous = previousItem()) {
if (!isPost() && !Has<HistoryMessageDate>() && !Has<HistoryMessageUnreadBar>()) { if (!Has<HistoryMessageDate>() && !Has<HistoryMessageUnreadBar>()) {
attach = !previous->isPost() attach = !isPost() && !previous->isPost()
&& !previous->serviceMsg() && !serviceMsg() && !previous->serviceMsg()
&& !previous->isEmpty() && !isEmpty() && !previous->isEmpty()
&& previous->from() == from() && previous->from() == from()
&& (qAbs(previous->date.secsTo(date)) < kAttachMessageToPreviousSecondsDelta); && (qAbs(previous->date.secsTo(date)) < kAttachMessageToPreviousSecondsDelta);
} }

View File

@ -3992,7 +3992,10 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic
it = sets.erase(it); it = sets.erase(it);
} }
} }
Global::SetFeaturedStickerSetsUnreadCount(unreadCount); if (Global::FeaturedStickerSetsUnreadCount() != unreadCount) {
Global::SetFeaturedStickerSetsUnreadCount(unreadCount);
Global::RefFeaturedStickerSetsUnreadCountChanged().notify();
}
if (Local::countFeaturedStickersHash() != d.vhash.v) { if (Local::countFeaturedStickersHash() != d.vhash.v) {
LOG(("API Error: received featured stickers hash %1 while counted hash is %2").arg(d.vhash.v).arg(Local::countFeaturedStickersHash())); LOG(("API Error: received featured stickers hash %1 while counted hash is %2").arg(d.vhash.v).arg(Local::countFeaturedStickersHash()));

View File

@ -36,7 +36,7 @@ introCountry: countryInput {
width: 300px; width: 300px;
height: 41px; height: 41px;
top: 33px; top: 33px;
bgColor: #f2f2f2; bgColor: windowBgOver;
ptrSize: size(15px, 8px); ptrSize: size(15px, 8px);
textMrg: margins(16px, 5px, 16px, 15px); textMrg: margins(16px, 5px, 16px, 15px);
font: defaultInputFont; font: defaultInputFont;

View File

@ -3224,7 +3224,7 @@ void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr,
outOrder->push_front(setId); outOrder->push_front(setId);
} }
} else if (setId == Stickers::CustomSetId) { } else if (setId == Stickers::CustomSetId) {
setTitle = lang(lng_custom_stickers); setTitle = qsl("Custom stickers");
setFlags |= qFlags(MTPDstickerSet_ClientFlag::f_special); setFlags |= qFlags(MTPDstickerSet_ClientFlag::f_special);
} else if (setId == Stickers::CloudRecentSetId) { } else if (setId == Stickers::CloudRecentSetId) {
setTitle = lang(lng_recent_stickers); setTitle = lang(lng_recent_stickers);
@ -3404,7 +3404,7 @@ void importOldRecentStickers() {
recent.clear(); recent.clear();
auto &def = sets.insert(Stickers::DefaultSetId, Stickers::Set(Stickers::DefaultSetId, 0, lang(lng_stickers_default_set), QString(), 0, 0, MTPDstickerSet::Flag::f_official | MTPDstickerSet::Flag::f_installed | MTPDstickerSet_ClientFlag::f_special)).value(); auto &def = sets.insert(Stickers::DefaultSetId, Stickers::Set(Stickers::DefaultSetId, 0, lang(lng_stickers_default_set), QString(), 0, 0, MTPDstickerSet::Flag::f_official | MTPDstickerSet::Flag::f_installed | MTPDstickerSet_ClientFlag::f_special)).value();
auto &custom = sets.insert(Stickers::CustomSetId, Stickers::Set(Stickers::CustomSetId, 0, lang(lng_custom_stickers), QString(), 0, 0, MTPDstickerSet::Flag::f_installed | MTPDstickerSet_ClientFlag::f_special)).value(); auto &custom = sets.insert(Stickers::CustomSetId, Stickers::Set(Stickers::CustomSetId, 0, qsl("Custom stickers"), QString(), 0, 0, MTPDstickerSet::Flag::f_installed | MTPDstickerSet_ClientFlag::f_special)).value();
QMap<uint64, bool> read; QMap<uint64, bool> read;
while (!stickers.stream.atEnd()) { while (!stickers.stream.atEnd()) {
@ -3480,7 +3480,10 @@ void readFeaturedStickers() {
++unreadCount; ++unreadCount;
} }
} }
Global::SetFeaturedStickerSetsUnreadCount(unreadCount); if (Global::FeaturedStickerSetsUnreadCount() != unreadCount) {
Global::SetFeaturedStickerSetsUnreadCount(unreadCount);
Global::RefFeaturedStickerSetsUnreadCountChanged().notify();
}
} }
void readRecentStickers() { void readRecentStickers() {

View File

@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "media/player/media_player_cover.h" #include "media/player/media_player_cover.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/widgets/media_slider.h" #include "ui/widgets/continuous_sliders.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "media/media_audio.h" #include "media/media_audio.h"
#include "media/view/media_clip_playback.h" #include "media/view/media_clip_playback.h"

View File

@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "media/media_audio.h" #include "media/media_audio.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/media_slider.h" #include "ui/widgets/continuous_sliders.h"
#include "styles/style_media_player.h" #include "styles/style_media_player.h"
#include "styles/style_widgets.h" #include "styles/style_widgets.h"
#include "mainwindow.h" #include "mainwindow.h"

View File

@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "media/player/media_player_widget.h" #include "media/player/media_player_widget.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/widgets/filled_slider.h" #include "ui/widgets/continuous_sliders.h"
#include "ui/widgets/shadow.h" #include "ui/widgets/shadow.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "media/media_audio.h" #include "media/media_audio.h"

View File

@ -25,7 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "media/view/media_clip_volume_controller.h" #include "media/view/media_clip_volume_controller.h"
#include "styles/style_mediaview.h" #include "styles/style_mediaview.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/widgets/media_slider.h" #include "ui/widgets/continuous_sliders.h"
#include "ui/effects/widget_fade_wrap.h" #include "ui/effects/widget_fade_wrap.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "media/media_audio.h" #include "media/media_audio.h"

View File

@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "ui/widgets/continuous_slider.h" #include "ui/widgets/continuous_sliders.h"
struct AudioPlaybackState; struct AudioPlaybackState;

View File

@ -94,7 +94,7 @@ overviewLoader: size(34px, 14px);
overviewLoaderPoint: size(4px, 4px); overviewLoaderPoint: size(4px, 4px);
overviewLoaderSkip: 4px; overviewLoaderSkip: 4px;
playlistHoverBg: #f2f2f2; playlistHoverBg: windowBgOver;
playlistPadding: 10px; playlistPadding: 10px;
linksSearchMargin: margins(20px, 20px, 20px, 0px); linksSearchMargin: margins(20px, 20px, 20px, 0px);
@ -121,7 +121,6 @@ overviewLinksChecked: icon {
overviewFilter: FlatInput(defaultFlatInput) { overviewFilter: FlatInput(defaultFlatInput) {
font: font(fsize); font: font(fsize);
bgColor: #f2f2f2;
phColor: #949494; phColor: #949494;
phFocusColor: #a4a4a4; phFocusColor: #a4a4a4;
icon: fieldSearchIcon; icon: fieldSearchIcon;

View File

@ -28,7 +28,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "mainwindow.h" #include "mainwindow.h"
#include "boxes/confirmbox.h" #include "boxes/confirmbox.h"
#include "application.h" #include "application.h"
#include "ui/widgets/discrete_slider.h" #include "ui/widgets/discrete_sliders.h"
namespace Settings { namespace Settings {
namespace { namespace {
@ -52,7 +52,7 @@ ScaleWidget::ScaleWidget(QWidget *parent, UserData *self) : BlockWidget(parent,
void ScaleWidget::createControls() { void ScaleWidget::createControls() {
style::margins margin(0, 0, 0, st::settingsSmallSkip); style::margins margin(0, 0, 0, st::settingsSmallSkip);
addChildRow(_auto, margin, lng_settings_scale_auto(lt_cur, scaleLabel(cScreenScale())), SLOT(onAutoChosen()), (cConfigScale() == dbisAuto)); addChildRow(_auto, margin, lng_settings_scale_auto(lt_cur, scaleLabel(cScreenScale())), SLOT(onAutoChanged()), (cConfigScale() == dbisAuto));
addChildRow(_scale, style::margins(0, 0, 0, 0)); addChildRow(_scale, style::margins(0, 0, 0, 0));
_scale->addSection(scaleLabel(dbisOne)); _scale->addSection(scaleLabel(dbisOne));
@ -63,7 +63,7 @@ void ScaleWidget::createControls() {
_scale->setSectionActivatedCallback([this] { scaleChanged(); }); _scale->setSectionActivatedCallback([this] { scaleChanged(); });
} }
void ScaleWidget::onAutoChosen() { void ScaleWidget::onAutoChanged() {
auto newScale = _auto->checked() ? dbisAuto : cEvalScale(cConfigScale()); auto newScale = _auto->checked() ? dbisAuto : cEvalScale(cConfigScale());
if (newScale == cScreenScale()) { if (newScale == cScreenScale()) {
if (newScale != cScale()) { if (newScale != cScale()) {
@ -81,6 +81,11 @@ void ScaleWidget::onAutoChosen() {
} }
void ScaleWidget::setScale(DBIScale newScale) { void ScaleWidget::setScale(DBIScale newScale) {
if (_inSetScale) return;
_inSetScale = true;
auto guard = base::scope_guard([this] { _inSetScale = false; });
if (newScale == cScreenScale()) newScale = dbisAuto;
if (newScale == dbisAuto && !_auto->checked()) { if (newScale == dbisAuto && !_auto->checked()) {
_auto->setChecked(true); _auto->setChecked(true);
} else if (newScale != dbisAuto && _auto->checked()) { } else if (newScale != dbisAuto && _auto->checked()) {
@ -111,9 +116,6 @@ void ScaleWidget::scaleChanged() {
case 2: newScale = dbisOneAndHalf; break; case 2: newScale = dbisOneAndHalf; break;
case 3: newScale = dbisTwo; break; case 3: newScale = dbisTwo; break;
} }
if (newScale == cScreenScale()) {
newScale = dbisAuto;
}
setScale(newScale); setScale(newScale);
} }

View File

@ -24,7 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
namespace Ui { namespace Ui {
class Checkbox; class Checkbox;
class DiscreteSlider; class SettingsSlider;
} // namespace Ui } // namespace Ui
namespace Settings { namespace Settings {
@ -36,7 +36,7 @@ public:
ScaleWidget(QWidget *parent, UserData *self); ScaleWidget(QWidget *parent, UserData *self);
private slots: private slots:
void onAutoChosen(); void onAutoChanged();
void onRestartNow(); void onRestartNow();
void onCancel(); void onCancel();
@ -46,9 +46,10 @@ private:
void setScale(DBIScale newScale); void setScale(DBIScale newScale);
ChildWidget<Ui::Checkbox> _auto = { nullptr }; ChildWidget<Ui::Checkbox> _auto = { nullptr };
ChildWidget<Ui::DiscreteSlider> _scale = { nullptr }; ChildWidget<Ui::SettingsSlider> _scale = { nullptr };
DBIScale _newScale = dbisAuto; DBIScale _newScale = dbisAuto;
bool _inSetScale = false;
}; };

View File

@ -2530,7 +2530,6 @@ void EmojiPan::SlideAnimation::paintFrame(QPainter &p, float64 dt, float64 opaci
t_assert(started()); t_assert(started());
t_assert(dt >= 0.); t_assert(dt >= 0.);
auto &transition = anim::easeOutCirc;
_frameAlpha = anim::interpolate(1, 256, opacity); _frameAlpha = anim::interpolate(1, 256, opacity);
auto frameInts = _frameInts + _innerLeft + _innerTop * _frameIntsPerLine; auto frameInts = _frameInts + _innerLeft + _innerTop * _frameIntsPerLine;

View File

@ -83,6 +83,26 @@ void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d) {
emit App::main()->stickersUpdated(); emit App::main()->stickersUpdated();
} }
// For testing: Just apply random subset or your sticker sets as archived.
bool applyArchivedResultFake() {
if (rand_value<uint32>() % 128 < 64) {
return false;
}
auto sets = QVector<MTPStickerSetCovered>();
for (auto &set : Global::RefStickerSets()) {
if ((set.flags & MTPDstickerSet::Flag::f_installed) && !(set.flags & MTPDstickerSet_ClientFlag::f_special)) {
if (rand_value<uint32>() % 128 < 64) {
auto data = MTP_stickerSet(MTP_flags(set.flags | MTPDstickerSet::Flag::f_archived), MTP_long(set.id), MTP_long(set.access), MTP_string(set.title), MTP_string(set.shortName), MTP_int(set.count), MTP_int(set.hash));
sets.push_back(MTP_stickerSetCovered(data, MTP_documentEmpty(MTP_long(0))));
}
}
}
if (sets.size() > 3) sets = sets.mid(0, 3);
auto fakeResult = MTP_messages_stickerSetInstallResultArchive(MTP_vector<MTPStickerSetCovered>(sets));
applyArchivedResult(fakeResult.c_messages_stickerSetInstallResultArchive());
return true;
}
void installLocally(uint64 setId) { void installLocally(uint64 setId) {
auto &sets = Global::RefStickerSets(); auto &sets = Global::RefStickerSets();
auto it = sets.find(setId); auto it = sets.find(setId);
@ -199,7 +219,10 @@ void FeaturedReader::onReadSets() {
if (!wrappedIds.empty()) { if (!wrappedIds.empty()) {
MTP::send(MTPmessages_ReadFeaturedStickers(MTP_vector<MTPlong>(wrappedIds)), rpcDone(&readFeaturedDone)); MTP::send(MTPmessages_ReadFeaturedStickers(MTP_vector<MTPlong>(wrappedIds)), rpcDone(&readFeaturedDone));
Global::SetFeaturedStickerSetsUnreadCount(count); if (Global::FeaturedStickerSetsUnreadCount() != count) {
Global::SetFeaturedStickerSetsUnreadCount(count);
Global::RefFeaturedStickerSetsUnreadCountChanged().notify();
}
} }
} }

View File

@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
namespace Stickers { namespace Stickers {
void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d); void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d);
bool applyArchivedResultFake(); // For testing.
void installLocally(uint64 setId); void installLocally(uint64 setId);
void undoInstallLocally(uint64 setId); void undoInstallLocally(uint64 setId);
void markFeaturedAsRead(uint64 setId); void markFeaturedAsRead(uint64 setId);

View File

@ -41,27 +41,46 @@ stickersTrendingSubheaderTop: 20px;
stickersTrendingAddTop: 3px; stickersTrendingAddTop: 3px;
stickersTrendingAdd: RoundButton(defaultActiveButton) { stickersTrendingAdd: RoundButton(defaultActiveButton) {
width: -17px; width: -16px;
height: 26px; height: 26px;
textTop: 4px; textTop: 4px;
} }
stickersRemove: IconButton(defaultIconButton) {
width: 40px;
height: 40px;
icon: icon {{ "stickers_remove", menuIconFg }};
iconOver: icon {{ "stickers_remove", menuIconFgOver }};
rippleAreaSize: 40px;
rippleAreaPosition: point(0px, 0px);
ripple: RippleAnimation(defaultRippleAnimation) {
color: windowBgOver;
}
}
stickersUndoRemove: RoundButton(defaultLightButton) {
width: -16px;
height: 26px;
textTop: 4px;
}
stickersRemoveSkip: 4px;
stickersReorderIcon: icon {{ "stickers_reorder", menuIconFg }};
stickersReorderSkip: 13px;
stickerEmojiSkip: 5px; stickerEmojiSkip: 5px;
stickersAddIcon: icon {{ "stickers_add", #ffffff }}; stickersFeaturedBadgeFont: font(12px bold);
stickersAddSize: size(30px, 24px); stickersFeaturedBadgeSize: 15px;
stickersFeaturedBadgeTextTop: -1px;
stickersFeaturedHeight: 32px; stickersFeaturedBadgePadding: 4px;
stickersFeaturedFont: contactsNameFont; stickersFeaturedBadgeSkip: 4px;
stickersFeaturedPosition: point(16px, 6px); stickersFeaturedBadgeTop: 9px;
stickersFeaturedBadgeFont: semiboldFont;
stickersFeaturedBadgeSize: 21px;
stickersFeaturedPen: lightButtonFg; stickersFeaturedPen: lightButtonFg;
stickersFeaturedUnreadBg: msgFileInBg; stickersFeaturedUnreadBg: msgFileInBg;
stickersFeaturedUnreadSize: 5px; stickersFeaturedUnreadSize: 5px;
stickersFeaturedUnreadSkip: 5px; stickersFeaturedUnreadSkip: 5px;
stickersFeaturedUnreadTop: 7px; stickersFeaturedUnreadTop: 7px;
stickersFeaturedInstalled: icon {{ "mediaview_save_check", lightButtonFg }}; stickersFeaturedInstalled: icon {{ "send_control_save", lightButtonFg }};
stickersMaxHeight: 440px; stickersMaxHeight: 440px;
stickersPadding: margins(19px, 17px, 19px, 17px); stickersPadding: margins(19px, 17px, 19px, 17px);

View File

@ -744,7 +744,7 @@ public:
return flags & MTPDchannel::Flag::f_verified; return flags & MTPDchannel::Flag::f_verified;
} }
bool canAddMembers() const { bool canAddMembers() const {
return amCreator() || amEditor() || (flags & MTPDchannel::Flag::f_democracy); return amCreator() || amEditor() || (amIn() && (flags & MTPDchannel::Flag::f_democracy));
} }
bool canEditPhoto() const { bool canEditPhoto() const {
return amCreator() || (amEditor() && isMegagroup()); return amCreator() || (amEditor() && isMegagroup());

View File

@ -1,175 +0,0 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "ui/widgets/continuous_slider.h"
namespace Ui {
namespace {
constexpr auto kByWheelFinishedTimeout = 1000;
} // namespace
ContinuousSlider::ContinuousSlider(QWidget *parent) : TWidget(parent)
, _a_value(animation(this, &ContinuousSlider::step_value)) {
setCursor(style::cur_pointer);
}
float64 ContinuousSlider::value() const {
return a_value.current();
}
void ContinuousSlider::setDisabled(bool disabled) {
if (_disabled != disabled) {
_disabled = disabled;
setCursor(_disabled ? style::cur_default : style::cur_pointer);
update();
}
}
void ContinuousSlider::setMoveByWheel(bool move) {
if (move != moveByWheel()) {
if (move) {
_byWheelFinished = std_::make_unique<SingleTimer>();
_byWheelFinished->setTimeoutHandler([this] {
if (_changeFinishedCallback) {
_changeFinishedCallback(getCurrentValue(getms()));
}
});
} else {
_byWheelFinished.reset();
}
}
}
void ContinuousSlider::setValue(float64 value, bool animated) {
if (animated) {
a_value.start(value);
_a_value.start();
} else {
a_value = anim::fvalue(value, value);
_a_value.stop();
}
update();
}
void ContinuousSlider::setFadeOpacity(float64 opacity) {
_fadeOpacity = opacity;
update();
}
void ContinuousSlider::step_value(float64 ms, bool timer) {
float64 dt = ms / (2 * AudioVoiceMsgUpdateView);
if (dt >= 1) {
_a_value.stop();
a_value.finish();
} else {
a_value.update(qMin(dt, 1.), anim::linear);
}
if (timer) update();
}
void ContinuousSlider::mouseMoveEvent(QMouseEvent *e) {
if (_mouseDown) {
updateDownValueFromPos(e->pos());
}
}
float64 ContinuousSlider::computeValue(const QPoint &pos) const {
auto seekRect = myrtlrect(getSeekRect());
auto result = isHorizontal() ?
(pos.x() - seekRect.x()) / float64(seekRect.width()) :
(1. - (pos.y() - seekRect.y()) / float64(seekRect.height()));
return snap(result, 0., 1.);
}
void ContinuousSlider::mousePressEvent(QMouseEvent *e) {
_mouseDown = true;
_downValue = computeValue(e->pos());
update();
if (_changeProgressCallback) {
_changeProgressCallback(_downValue);
}
}
void ContinuousSlider::mouseReleaseEvent(QMouseEvent *e) {
if (_mouseDown) {
_mouseDown = false;
if (_changeFinishedCallback) {
_changeFinishedCallback(_downValue);
}
a_value = anim::fvalue(_downValue, _downValue);
_a_value.stop();
update();
}
}
void ContinuousSlider::wheelEvent(QWheelEvent *e) {
if (_mouseDown || !moveByWheel()) {
return;
}
#ifdef OS_MAC_OLD
constexpr auto step = 120;
#else // OS_MAC_OLD
constexpr auto step = static_cast<int>(QWheelEvent::DefaultDeltasPerStep);
#endif // OS_MAC_OLD
constexpr auto coef = 1. / (step * 10.);
auto deltaX = e->angleDelta().x(), deltaY = e->angleDelta().y();
if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
deltaY *= -1;
} else {
deltaX *= -1;
}
auto delta = (qAbs(deltaX) > qAbs(deltaY)) ? deltaX : deltaY;
auto finalValue = snap(a_value.to() + delta * coef, 0., 1.);
setValue(finalValue, false);
if (_changeProgressCallback) {
_changeProgressCallback(finalValue);
}
_byWheelFinished->start(kByWheelFinishedTimeout);
}
void ContinuousSlider::updateDownValueFromPos(const QPoint &pos) {
_downValue = computeValue(pos);
update();
if (_changeProgressCallback) {
_changeProgressCallback(_downValue);
}
}
void ContinuousSlider::enterEvent(QEvent *e) {
setOver(true);
}
void ContinuousSlider::leaveEvent(QEvent *e) {
setOver(false);
}
void ContinuousSlider::setOver(bool over) {
if (_over == over) return;
_over = over;
auto from = _over ? 0. : 1., to = _over ? 1. : 0.;
_a_over.start([this] { update(); }, from, to, getOverDuration());
}
} // namespace Ui

View File

@ -0,0 +1,293 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "ui/widgets/continuous_sliders.h"
namespace Ui {
namespace {
constexpr auto kByWheelFinishedTimeout = 1000;
} // namespace
ContinuousSlider::ContinuousSlider(QWidget *parent) : TWidget(parent)
, _a_value(animation(this, &ContinuousSlider::step_value)) {
setCursor(style::cur_pointer);
}
float64 ContinuousSlider::value() const {
return a_value.current();
}
void ContinuousSlider::setDisabled(bool disabled) {
if (_disabled != disabled) {
_disabled = disabled;
setCursor(_disabled ? style::cur_default : style::cur_pointer);
update();
}
}
void ContinuousSlider::setMoveByWheel(bool move) {
if (move != moveByWheel()) {
if (move) {
_byWheelFinished = std_::make_unique<SingleTimer>();
_byWheelFinished->setTimeoutHandler([this] {
if (_changeFinishedCallback) {
_changeFinishedCallback(getCurrentValue(getms()));
}
});
} else {
_byWheelFinished.reset();
}
}
}
void ContinuousSlider::setValue(float64 value, bool animated) {
if (animated) {
a_value.start(value);
_a_value.start();
} else {
a_value = anim::fvalue(value, value);
_a_value.stop();
}
update();
}
void ContinuousSlider::setFadeOpacity(float64 opacity) {
_fadeOpacity = opacity;
update();
}
void ContinuousSlider::step_value(float64 ms, bool timer) {
float64 dt = ms / (2 * AudioVoiceMsgUpdateView);
if (dt >= 1) {
_a_value.stop();
a_value.finish();
} else {
a_value.update(qMin(dt, 1.), anim::linear);
}
if (timer) update();
}
void ContinuousSlider::mouseMoveEvent(QMouseEvent *e) {
if (_mouseDown) {
updateDownValueFromPos(e->pos());
}
}
float64 ContinuousSlider::computeValue(const QPoint &pos) const {
auto seekRect = myrtlrect(getSeekRect());
auto result = isHorizontal() ?
(pos.x() - seekRect.x()) / float64(seekRect.width()) :
(1. - (pos.y() - seekRect.y()) / float64(seekRect.height()));
return snap(result, 0., 1.);
}
void ContinuousSlider::mousePressEvent(QMouseEvent *e) {
_mouseDown = true;
_downValue = computeValue(e->pos());
update();
if (_changeProgressCallback) {
_changeProgressCallback(_downValue);
}
}
void ContinuousSlider::mouseReleaseEvent(QMouseEvent *e) {
if (_mouseDown) {
_mouseDown = false;
if (_changeFinishedCallback) {
_changeFinishedCallback(_downValue);
}
a_value = anim::fvalue(_downValue, _downValue);
_a_value.stop();
update();
}
}
void ContinuousSlider::wheelEvent(QWheelEvent *e) {
if (_mouseDown || !moveByWheel()) {
return;
}
#ifdef OS_MAC_OLD
constexpr auto step = 120;
#else // OS_MAC_OLD
constexpr auto step = static_cast<int>(QWheelEvent::DefaultDeltasPerStep);
#endif // OS_MAC_OLD
constexpr auto coef = 1. / (step * 10.);
auto deltaX = e->angleDelta().x(), deltaY = e->angleDelta().y();
if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
deltaY *= -1;
} else {
deltaX *= -1;
}
auto delta = (qAbs(deltaX) > qAbs(deltaY)) ? deltaX : deltaY;
auto finalValue = snap(a_value.to() + delta * coef, 0., 1.);
setValue(finalValue, false);
if (_changeProgressCallback) {
_changeProgressCallback(finalValue);
}
_byWheelFinished->start(kByWheelFinishedTimeout);
}
void ContinuousSlider::updateDownValueFromPos(const QPoint &pos) {
_downValue = computeValue(pos);
update();
if (_changeProgressCallback) {
_changeProgressCallback(_downValue);
}
}
void ContinuousSlider::enterEvent(QEvent *e) {
setOver(true);
}
void ContinuousSlider::leaveEvent(QEvent *e) {
setOver(false);
}
void ContinuousSlider::setOver(bool over) {
if (_over == over) return;
_over = over;
auto from = _over ? 0. : 1., to = _over ? 1. : 0.;
_a_over.start([this] { update(); }, from, to, getOverDuration());
}
FilledSlider::FilledSlider(QWidget *parent, const style::FilledSlider &st) : ContinuousSlider(parent)
, _st(st) {
}
QRect FilledSlider::getSeekRect() const {
return QRect(0, 0, width(), height());
}
float64 FilledSlider::getOverDuration() const {
return _st.duration;
}
void FilledSlider::paintEvent(QPaintEvent *e) {
Painter p(this);
p.setPen(Qt::NoPen);
p.setRenderHint(QPainter::HighQualityAntialiasing);
auto masterOpacity = fadeOpacity();
auto ms = getms();
auto disabled = isDisabled();
auto over = getCurrentOverFactor(ms);
auto lineWidth = _st.lineWidth + ((_st.fullWidth - _st.lineWidth) * over);
auto lineWidthRounded = qFloor(lineWidth);
auto lineWidthPartial = lineWidth - lineWidthRounded;
auto seekRect = getSeekRect();
auto value = getCurrentValue(ms);
auto from = seekRect.x(), mid = qRound(from + value * seekRect.width()), end = from + seekRect.width();
if (mid > from) {
p.setOpacity(masterOpacity);
p.fillRect(from, height() - lineWidthRounded, (mid - from), lineWidthRounded, disabled ? _st.disabledFg : _st.activeFg);
if (lineWidthPartial > 0.01) {
p.setOpacity(masterOpacity * lineWidthPartial);
p.fillRect(from, height() - lineWidthRounded - 1, (mid - from), 1, disabled ? _st.disabledFg : _st.activeFg);
}
}
if (end > mid && over > 0) {
p.setOpacity(masterOpacity * over);
p.fillRect(mid, height() - lineWidthRounded, (end - mid), lineWidthRounded, _st.inactiveFg);
if (lineWidthPartial > 0.01) {
p.setOpacity(masterOpacity * over * lineWidthPartial);
p.fillRect(mid, height() - lineWidthRounded - 1, (end - mid), 1, _st.inactiveFg);
}
}
}
MediaSlider::MediaSlider(QWidget *parent, const style::MediaSlider &st) : ContinuousSlider(parent)
, _st(st) {
}
QRect MediaSlider::getSeekRect() const {
return isHorizontal()
? QRect(_st.seekSize.width() / 2, 0, width() - _st.seekSize.width(), height())
: QRect(0, _st.seekSize.height() / 2, width(), height() - _st.seekSize.width());
}
float64 MediaSlider::getOverDuration() const {
return _st.duration;
}
void MediaSlider::paintEvent(QPaintEvent *e) {
Painter p(this);
p.setPen(Qt::NoPen);
p.setRenderHint(QPainter::HighQualityAntialiasing);
p.setOpacity(fadeOpacity());
auto horizontal = isHorizontal();
auto ms = getms();
auto radius = _st.width / 2;
auto disabled = isDisabled();
auto over = getCurrentOverFactor(ms);
auto seekRect = getSeekRect();
auto value = getCurrentValue(ms);
// invert colors and value for vertical
if (!horizontal) value = 1. - value;
auto markerFrom = (horizontal ? seekRect.x() : seekRect.y());
auto markerLength = (horizontal ? seekRect.width() : seekRect.height());
auto from = _alwaysDisplayMarker ? 0 : markerFrom;
auto length = _alwaysDisplayMarker ? (horizontal ? width() : height()) : markerLength;
auto mid = qRound(from + value * length);
auto end = from + length;
auto activeFg = disabled ? _st.activeFgDisabled : anim::brush(_st.activeFg, _st.activeFgOver, over);
auto inactiveFg = disabled ? _st.inactiveFgDisabled : anim::brush(_st.inactiveFg, _st.inactiveFgOver, over);
if (mid > from) {
auto fromClipRect = horizontal ? QRect(0, 0, mid, height()) : QRect(0, 0, width(), mid);
auto fromRect = horizontal
? QRect(from, (height() - _st.width) / 2, mid + radius - from, _st.width)
: QRect((width() - _st.width) / 2, from, _st.width, mid + radius - from);
p.setClipRect(fromClipRect);
p.setBrush(horizontal ? activeFg : inactiveFg);
p.drawRoundedRect(fromRect, radius, radius);
}
if (end > mid) {
auto endClipRect = horizontal ? QRect(mid, 0, width() - mid, height()) : QRect(0, mid, width(), height() - mid);
auto endRect = horizontal
? QRect(mid - radius, (height() - _st.width) / 2, end - (mid - radius), _st.width)
: QRect((width() - _st.width) / 2, mid - radius, _st.width, end - (mid - radius));
p.setClipRect(endClipRect);
p.setBrush(horizontal ? inactiveFg : activeFg);
p.drawRoundedRect(endRect, radius, radius);
}
auto markerSizeRatio = disabled ? 0. : (_alwaysDisplayMarker ? 1. : over);
if (markerSizeRatio > 0) {
auto position = qRound(markerFrom + value * markerLength) - (horizontal ? seekRect.x() : seekRect.y());
auto seekButton = horizontal
? QRect(position, (height() - _st.seekSize.height()) / 2, _st.seekSize.width(), _st.seekSize.height())
: QRect((width() - _st.seekSize.width()) / 2, position, _st.seekSize.width(), _st.seekSize.height());
auto size = horizontal ? _st.seekSize.width() : _st.seekSize.height();
auto remove = static_cast<int>(((1. - markerSizeRatio) * size) / 2.);
if (remove * 2 < size) {
p.setClipRect(rect());
p.setBrush(activeFg);
p.drawEllipse(seekButton.marginsRemoved(QMargins(remove, remove, remove, remove)));
}
}
}
} // namespace Ui

View File

@ -20,6 +20,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "styles/style_widgets.h"
namespace Ui { namespace Ui {
class ContinuousSlider : public TWidget { class ContinuousSlider : public TWidget {
@ -115,4 +117,40 @@ private:
}; };
class FilledSlider : public ContinuousSlider {
public:
FilledSlider(QWidget *parent, const style::FilledSlider &st);
protected:
void paintEvent(QPaintEvent *e) override;
private:
QRect getSeekRect() const override;
float64 getOverDuration() const override;
const style::FilledSlider &_st;
};
class MediaSlider : public ContinuousSlider {
public:
MediaSlider(QWidget *parent, const style::MediaSlider &st);
void setAlwaysDisplayMarker(bool alwaysDisplayMarker) {
_alwaysDisplayMarker = alwaysDisplayMarker;
update();
}
protected:
void paintEvent(QPaintEvent *e) override;
private:
QRect getSeekRect() const override;
float64 getOverDuration() const override;
const style::MediaSlider &_st;
bool _alwaysDisplayMarker = false;
};
} // namespace Ui } // namespace Ui

View File

@ -19,14 +19,13 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#include "stdafx.h" #include "stdafx.h"
#include "ui/widgets/discrete_slider.h" #include "ui/widgets/discrete_sliders.h"
#include "styles/style_widgets.h" #include "styles/style_widgets.h"
namespace Ui { namespace Ui {
DiscreteSlider::DiscreteSlider(QWidget *parent) : TWidget(parent) DiscreteSlider::DiscreteSlider(QWidget *parent) : TWidget(parent) {
, _a_left(animation(this, &DiscreteSlider::step_left)) {
setCursor(style::cur_pointer); setCursor(style::cur_pointer);
} }
@ -35,54 +34,70 @@ void DiscreteSlider::setSectionActivatedCallback(SectionActivatedCallback &&call
} }
void DiscreteSlider::setActiveSection(int index) { void DiscreteSlider::setActiveSection(int index) {
setSelectedSection(index);
if (_activeIndex != index) { if (_activeIndex != index) {
_activeIndex = index; _activeIndex = index;
if (_callback) { if (_callback) {
_callback(); _callback();
} }
} }
setSelectedSection(index);
} }
void DiscreteSlider::setActiveSectionFast(int index) { void DiscreteSlider::setActiveSectionFast(int index) {
setActiveSection(index); setActiveSection(index);
a_left.finish(); _a_left.finish();
_a_left.stop();
update(); update();
} }
void DiscreteSlider::addSection(const QString &label) { void DiscreteSlider::setSelectOnPress(bool selectOnPress) {
auto section = Section(label); _selectOnPress = selectOnPress;
_sections.push_back(section);
} }
void DiscreteSlider::resizeSections(int newWidth) { void DiscreteSlider::addSection(const QString &label) {
auto count = _sections.size(); _sections.push_back(Section(label, getLabelFont()));
if (!count) return; resizeToWidth(width());
}
auto skips = count - 1; void DiscreteSlider::setSections(const QStringList &labels) {
auto sectionsWidth = newWidth - skips * st::discreteSliderSkip; t_assert(!labels.isEmpty());
auto sectionWidth = sectionsWidth / float64(count);
auto x = 0.; _sections.clear();
for (int i = 0; i != count; ++i) { for_const (auto &label, labels) {
auto &section = _sections[i]; _sections.push_back(Section(label, getLabelFont()));
auto skip = i * st::discreteSliderThickness; }
section.left = qFloor(x) + skip; stopAnimation();
x += sectionWidth; if (_activeIndex >= _sections.size()) {
section.width = qRound(x) - (section.left - skip); _activeIndex = 0;
}
if (_selected >= _sections.size()) {
_selected = 0;
}
resizeToWidth(width());
}
int DiscreteSlider::getCurrentActiveLeft(uint64 ms) {
return _a_left.current(ms, _sections.isEmpty() ? 0 : _sections[_selected].left);
}
template <typename Lambda>
void DiscreteSlider::enumerateSections(Lambda callback) {
for (auto &section : _sections) {
callback(section);
} }
a_left = anim::ivalue(_sections[_activeIndex].left, _sections[_activeIndex].left);
_a_left.stop();
} }
void DiscreteSlider::mousePressEvent(QMouseEvent *e) { void DiscreteSlider::mousePressEvent(QMouseEvent *e) {
setSelectedSection(getIndexFromPosition(e->pos())); if (_selectOnPress) {
setSelectedSection(getIndexFromPosition(e->pos()));
}
_pressed = true; _pressed = true;
} }
void DiscreteSlider::mouseMoveEvent(QMouseEvent *e) { void DiscreteSlider::mouseMoveEvent(QMouseEvent *e) {
if (!_pressed) return; if (!_pressed) return;
setSelectedSection(getIndexFromPosition(e->pos())); if (_selectOnPress) {
setSelectedSection(getIndexFromPosition(e->pos()));
}
} }
void DiscreteSlider::mouseReleaseEvent(QMouseEvent *e) { void DiscreteSlider::mouseReleaseEvent(QMouseEvent *e) {
@ -92,50 +107,16 @@ void DiscreteSlider::mouseReleaseEvent(QMouseEvent *e) {
} }
void DiscreteSlider::setSelectedSection(int index) { void DiscreteSlider::setSelectedSection(int index) {
if (index < 0) return; if (index < 0 || index >= _sections.size()) return;
if (_selected != index) { if (_selected != index) {
auto from = _sections[_selected].left;
_selected = index; _selected = index;
a_left.start(_sections[_selected].left); auto to = _sections[_selected].left;
_a_left.start(); _a_left.start([this] { update(); }, from, to, getAnimationDuration());
} }
} }
void DiscreteSlider::paintEvent(QPaintEvent *e) {
Painter p(this);
int activeLeft = a_left.current();
p.setFont(st::discreteSliderLabelFont);
p.setPen(st::discreteSliderLabelFg);
for (int i = 0, count = _sections.size(); i != count; ++i) {
auto &section = _sections.at(i);
auto from = section.left, tofill = section.width;
if (activeLeft > from) {
auto fill = qMin(tofill, activeLeft - from);
p.fillRect(myrtlrect(from, st::discreteSliderTop, fill, st::discreteSliderThickness), st::discreteSliderInactiveFg);
from += fill;
tofill -= fill;
}
if (activeLeft + section.width > from) {
if (auto fill = qMin(tofill, activeLeft + section.width - from)) {
p.fillRect(myrtlrect(from, st::discreteSliderTop, fill, st::discreteSliderThickness), st::discreteSliderActiveFg);
from += fill;
tofill -= fill;
}
}
if (tofill) {
p.fillRect(myrtlrect(from, st::discreteSliderTop, tofill, st::discreteSliderThickness), st::discreteSliderInactiveFg);
}
p.drawTextLeft(section.left + (section.width - section.labelWidth) / 2, st::discreteSliderLabelTop, width(), section.label, section.labelWidth);
}
}
int DiscreteSlider::resizeGetHeight(int newWidth) {
resizeSections(newWidth);
return st::discreteSliderHeight;
}
int DiscreteSlider::getIndexFromPosition(QPoint pos) { int DiscreteSlider::getIndexFromPosition(QPoint pos) {
int count = _sections.size(); int count = _sections.size();
for (int i = 0; i != count; ++i) { for (int i = 0; i != count; ++i) {
@ -146,22 +127,73 @@ int DiscreteSlider::getIndexFromPosition(QPoint pos) {
return count - 1; return count - 1;
} }
void DiscreteSlider::step_left(float64 ms, bool timer) { DiscreteSlider::Section::Section(const QString &label, const style::font &font)
auto dt = ms / st::discreteSliderDuration; : label(label)
if (dt >= 1) { , labelWidth(font->width(label)) {
a_left.finish();
_a_left.stop();
} else {
a_left.update(dt, anim::linear);
}
if (timer) {
update();
}
} }
DiscreteSlider::Section::Section(const QString &label) SettingsSlider::SettingsSlider(QWidget *parent, const style::SettingsSlider &st) : DiscreteSlider(parent)
: label(label) , _st(st) {
, labelWidth(st::discreteSliderLabelFont->width(label)) { }
const style::font &SettingsSlider::getLabelFont() const {
return _st.labelFont;
}
int SettingsSlider::getAnimationDuration() const {
return _st.duration;
}
void SettingsSlider::resizeSections(int newWidth) {
auto count = getSectionsCount();
if (!count) return;
auto sectionsWidth = newWidth - (count - 1) * _st.barSkip;
auto sectionWidth = sectionsWidth / float64(count);
auto skip = 0;
auto x = 0.;
enumerateSections([this, &x, &skip, sectionWidth](Section &section) {
section.left = qFloor(x) + skip;
x += sectionWidth;
section.width = qRound(x) - (section.left - skip);
skip += _st.barSkip;
});
stopAnimation();
}
int SettingsSlider::resizeGetHeight(int newWidth) {
resizeSections(newWidth);
return _st.height;
}
void SettingsSlider::paintEvent(QPaintEvent *e) {
Painter p(this);
auto activeLeft = getCurrentActiveLeft(getms());
p.setFont(_st.labelFont);
enumerateSections([this, &p, activeLeft](Section &section) {
auto from = section.left, tofill = section.width;
if (activeLeft > from) {
auto fill = qMin(tofill, activeLeft - from);
p.fillRect(myrtlrect(from, _st.barTop, fill, _st.barStroke), _st.barFg);
from += fill;
tofill -= fill;
}
auto active = 1. - snap(qAbs(activeLeft - section.left) / float64(section.width), 0., 1.);
if (activeLeft + section.width > from) {
if (auto fill = qMin(tofill, activeLeft + section.width - from)) {
p.fillRect(myrtlrect(from, _st.barTop, fill, _st.barStroke), _st.barFgActive);
from += fill;
tofill -= fill;
}
}
if (tofill) {
p.fillRect(myrtlrect(from, _st.barTop, tofill, _st.barStroke), _st.barFg);
}
p.setPen(anim::pen(_st.labelFg, _st.labelFgActive, active));
p.drawTextLeft(section.left + (section.width - section.labelWidth) / 2, _st.labelTop, width(), section.label, section.labelWidth);
});
} }
} // namespace Ui } // namespace Ui

View File

@ -20,6 +20,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "styles/style_widgets.h"
namespace Ui { namespace Ui {
class DiscreteSlider : public TWidget { class DiscreteSlider : public TWidget {
@ -27,46 +29,80 @@ public:
DiscreteSlider(QWidget *parent); DiscreteSlider(QWidget *parent);
void addSection(const QString &label); void addSection(const QString &label);
void setSections(const QStringList &labels);
int activeSection() const { int activeSection() const {
return _activeIndex; return _activeIndex;
} }
void setActiveSection(int index); void setActiveSection(int index);
void setActiveSectionFast(int index); void setActiveSectionFast(int index);
void setSelectOnPress(bool selectOnPress);
using SectionActivatedCallback = base::lambda<void()>; using SectionActivatedCallback = base::lambda<void()>;
void setSectionActivatedCallback(SectionActivatedCallback &&callback); void setSectionActivatedCallback(SectionActivatedCallback &&callback);
protected: protected:
void paintEvent(QPaintEvent *e) override;
void mousePressEvent(QMouseEvent *e) override; void mousePressEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override;
int resizeGetHeight(int newWidth) override; int resizeGetHeight(int newWidth) override = 0;
private:
void resizeSections(int newWidth);
int getIndexFromPosition(QPoint pos);
void setSelectedSection(int index);
void step_left(float64 ms, bool timer);
struct Section { struct Section {
Section(const QString &label); Section(const QString &label, const style::font &font);
int left, width; int left, width;
QString label; QString label;
int labelWidth; int labelWidth;
}; };
int getCurrentActiveLeft(uint64 ms);
int getSectionsCount() const {
return _sections.size();
}
template <typename Lambda>
void enumerateSections(Lambda callback);
void stopAnimation() {
_a_left.finish();
}
private:
virtual const style::font &getLabelFont() const = 0;
virtual int getAnimationDuration() const = 0;
int getIndexFromPosition(QPoint pos);
void setSelectedSection(int index);
QList<Section> _sections; QList<Section> _sections;
int _activeIndex = 0; int _activeIndex = 0;
bool _selectOnPress = true;
SectionActivatedCallback _callback; SectionActivatedCallback _callback;
bool _pressed = false; bool _pressed = false;
int _selected = 0; int _selected = 0;
anim::ivalue a_left = { 0 }; FloatAnimation _a_left;
Animation _a_left;
};
class SettingsSlider : public DiscreteSlider {
public:
SettingsSlider(QWidget *parent, const style::SettingsSlider &st = st::defaultSettingsSlider);
protected:
void paintEvent(QPaintEvent *e) override;
int resizeGetHeight(int newWidth) override;
private:
const style::font &getLabelFont() const override;
int getAnimationDuration() const override;
void resizeSections(int newWidth);
const style::SettingsSlider &_st;
}; };

View File

@ -1,73 +0,0 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "ui/widgets/filled_slider.h"
#include "styles/style_widgets.h"
namespace Ui {
FilledSlider::FilledSlider(QWidget *parent, const style::FilledSlider &st) : ContinuousSlider(parent)
, _st(st) {
}
QRect FilledSlider::getSeekRect() const {
return QRect(0, 0, width(), height());
}
float64 FilledSlider::getOverDuration() const {
return _st.duration;
}
void FilledSlider::paintEvent(QPaintEvent *e) {
Painter p(this);
p.setPen(Qt::NoPen);
p.setRenderHint(QPainter::HighQualityAntialiasing);
auto masterOpacity = fadeOpacity();
auto ms = getms();
auto disabled = isDisabled();
auto over = getCurrentOverFactor(ms);
auto lineWidth = _st.lineWidth + ((_st.fullWidth - _st.lineWidth) * over);
auto lineWidthRounded = qFloor(lineWidth);
auto lineWidthPartial = lineWidth - lineWidthRounded;
auto seekRect = getSeekRect();
auto value = getCurrentValue(ms);
auto from = seekRect.x(), mid = qRound(from + value * seekRect.width()), end = from + seekRect.width();
if (mid > from) {
p.setOpacity(masterOpacity);
p.fillRect(from, height() - lineWidthRounded, (mid - from), lineWidthRounded, disabled ? _st.disabledFg : _st.activeFg);
if (lineWidthPartial > 0.01) {
p.setOpacity(masterOpacity * lineWidthPartial);
p.fillRect(from, height() - lineWidthRounded - 1, (mid - from), 1, disabled ? _st.disabledFg : _st.activeFg);
}
}
if (end > mid && over > 0) {
p.setOpacity(masterOpacity * over);
p.fillRect(mid, height() - lineWidthRounded, (end - mid), lineWidthRounded, _st.inactiveFg);
if (lineWidthPartial > 0.01) {
p.setOpacity(masterOpacity * over * lineWidthPartial);
p.fillRect(mid, height() - lineWidthRounded - 1, (end - mid), 1, _st.inactiveFg);
}
}
}
} // namespace Ui

View File

@ -1,43 +0,0 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "ui/widgets/continuous_slider.h"
#include "styles/style_widgets.h"
namespace Ui {
class FilledSlider : public ContinuousSlider {
public:
FilledSlider(QWidget *parent, const style::FilledSlider &st);
protected:
void paintEvent(QPaintEvent *e) override;
private:
QRect getSeekRect() const override;
float64 getOverDuration() const override;
const style::FilledSlider &_st;
};
} // namespace Ui

View File

@ -1,101 +0,0 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "ui/widgets/media_slider.h"
#include "styles/style_widgets.h"
namespace Ui {
MediaSlider::MediaSlider(QWidget *parent, const style::MediaSlider &st) : ContinuousSlider(parent)
, _st(st) {
}
QRect MediaSlider::getSeekRect() const {
return isHorizontal()
? QRect(_st.seekSize.width() / 2, 0, width() - _st.seekSize.width(), height())
: QRect(0, _st.seekSize.height() / 2, width(), height() - _st.seekSize.width());
}
float64 MediaSlider::getOverDuration() const {
return _st.duration;
}
void MediaSlider::paintEvent(QPaintEvent *e) {
Painter p(this);
p.setPen(Qt::NoPen);
p.setRenderHint(QPainter::HighQualityAntialiasing);
p.setOpacity(fadeOpacity());
auto horizontal = isHorizontal();
auto ms = getms();
auto radius = _st.width / 2;
auto disabled = isDisabled();
auto over = getCurrentOverFactor(ms);
auto seekRect = getSeekRect();
auto value = getCurrentValue(ms);
// invert colors and value for vertical
if (!horizontal) value = 1. - value;
auto markerFrom = (horizontal ? seekRect.x() : seekRect.y());
auto markerLength = (horizontal ? seekRect.width() : seekRect.height());
auto from = _alwaysDisplayMarker ? 0 : markerFrom;
auto length = _alwaysDisplayMarker ? (horizontal ? width() : height()) : markerLength;
auto mid = qRound(from + value * length);
auto end = from + length;
auto activeFg = disabled ? _st.activeFgDisabled : anim::brush(_st.activeFg, _st.activeFgOver, over);
auto inactiveFg = disabled ? _st.inactiveFgDisabled : anim::brush(_st.inactiveFg, _st.inactiveFgOver, over);
if (mid > from) {
auto fromClipRect = horizontal ? QRect(0, 0, mid, height()) : QRect(0, 0, width(), mid);
auto fromRect = horizontal
? QRect(from, (height() - _st.width) / 2, mid + radius - from, _st.width)
: QRect((width() - _st.width) / 2, from, _st.width, mid + radius - from);
p.setClipRect(fromClipRect);
p.setBrush(horizontal ? activeFg : inactiveFg);
p.drawRoundedRect(fromRect, radius, radius);
}
if (end > mid) {
auto endClipRect = horizontal ? QRect(mid, 0, width() - mid, height()) : QRect(0, mid, width(), height() - mid);
auto endRect = horizontal
? QRect(mid - radius, (height() - _st.width) / 2, end - (mid - radius), _st.width)
: QRect((width() - _st.width) / 2, mid - radius, _st.width, end - (mid - radius));
p.setClipRect(endClipRect);
p.setBrush(horizontal ? inactiveFg : activeFg);
p.drawRoundedRect(endRect, radius, radius);
}
auto markerSizeRatio = disabled ? 0. : (_alwaysDisplayMarker ? 1. : over);
if (markerSizeRatio > 0) {
auto position = qRound(markerFrom + value * markerLength) - (horizontal ? seekRect.x() : seekRect.y());
auto seekButton = horizontal
? QRect(position, (height() - _st.seekSize.height()) / 2, _st.seekSize.width(), _st.seekSize.height())
: QRect((width() - _st.seekSize.width()) / 2, position, _st.seekSize.width(), _st.seekSize.height());
auto size = horizontal ? _st.seekSize.width() : _st.seekSize.height();
auto remove = static_cast<int>(((1. - markerSizeRatio) * size) / 2.);
if (remove * 2 < size) {
p.setClipRect(rect());
p.setBrush(activeFg);
p.drawEllipse(seekButton.marginsRemoved(QMargins(remove, remove, remove, remove)));
}
}
}
} // namespace Ui

View File

@ -1,49 +0,0 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "ui/widgets/continuous_slider.h"
#include "styles/style_widgets.h"
namespace Ui {
class MediaSlider : public ContinuousSlider {
public:
MediaSlider(QWidget *parent, const style::MediaSlider &st);
void setAlwaysDisplayMarker(bool alwaysDisplayMarker) {
_alwaysDisplayMarker = alwaysDisplayMarker;
update();
}
protected:
void paintEvent(QPaintEvent *e) override;
private:
QRect getSeekRect() const override;
float64 getOverDuration() const override;
const style::MediaSlider &_st;
bool _alwaysDisplayMarker = false;
};
} // namespace Ui

View File

@ -566,7 +566,7 @@ defaultSolidScroll: FlatScroll(defaultFlatScroll) {
defaultInputFont: font(17px); defaultInputFont: font(17px);
defaultFlatInput: FlatInput { defaultFlatInput: FlatInput {
textColor: #000000; textColor: #000000;
bgColor: #f2f2f2; bgColor: windowBgOver;
bgActive: #ffffff; bgActive: #ffffff;
width: 210px; width: 210px;
height: 40px; height: 40px;
@ -575,7 +575,7 @@ defaultFlatInput: FlatInput {
font: defaultInputFont; font: defaultInputFont;
borderWidth: 2px; borderWidth: 2px;
borderColor: #f2f2f2; borderColor: windowBgOver;
borderActive: #54c3f3; borderActive: #54c3f3;
borderError: #ed8080; borderError: #ed8080;
@ -724,16 +724,47 @@ widgetFadeDuration: 200;
fieldSearchIcon: icon {{ "box_search", #aaaaaa, point(9px, 8px) }}; fieldSearchIcon: icon {{ "box_search", #aaaaaa, point(9px, 8px) }};
boxFieldSearchIcon: icon {{ "box_search", #aaaaaa, point(10px, 9px) }}; boxFieldSearchIcon: icon {{ "box_search", #aaaaaa, point(10px, 9px) }};
discreteSliderHeight: 39px; SettingsSlider {
discreteSliderTop: 5px; height: pixels;
discreteSliderSkip: 3px; barTop: pixels;
discreteSliderThickness: 3px; barSkip: pixels;
discreteSliderActiveFg: #4bb5e7; barStroke: pixels;
discreteSliderInactiveFg: #e1eaef; barFg: color;
discreteSliderLabelTop: 17px; barFgActive: color;
discreteSliderLabelFont: normalFont; labelTop: pixels;
discreteSliderLabelFg: #1485c2; labelFont: font;
discreteSliderDuration: 200; labelFg: color;
labelFgActive: color;
duration: int;
}
defaultSettingsSlider: SettingsSlider {
height: 39px;
barTop: 5px;
barSkip: 3px;
barStroke: 3px;
barFg: #e1eaef;
barFgActive: windowBgActive;
labelTop: 17px;
labelFont: semiboldFont;
// labelFont: normalFont;
labelFg: #999999;
labelFgActive: lightButtonFg;
// labelFg: #1485c2;
// labelFgActive: #1485c2;
duration: 150;
}
defaultTabsSlider: SettingsSlider(defaultSettingsSlider) {
height: 49px;
barTop: 46px;
barSkip: 0px;
barFg: transparent;
labelTop: 16px;
labelFont: semiboldFont;
labelFg: #999999;
labelFgActive: lightButtonFg;
}
defaultRoundShadow: Shadow { defaultRoundShadow: Shadow {
left: icon {{ "round_shadow_left", windowShadowFg }}; left: icon {{ "round_shadow_left", windowShadowFg }};

View File

@ -496,22 +496,18 @@
'<(src_loc)/ui/widgets/buttons.h', '<(src_loc)/ui/widgets/buttons.h',
'<(src_loc)/ui/widgets/checkbox.cpp', '<(src_loc)/ui/widgets/checkbox.cpp',
'<(src_loc)/ui/widgets/checkbox.h', '<(src_loc)/ui/widgets/checkbox.h',
'<(src_loc)/ui/widgets/continuous_slider.cpp', '<(src_loc)/ui/widgets/continuous_sliders.cpp',
'<(src_loc)/ui/widgets/continuous_slider.h', '<(src_loc)/ui/widgets/continuous_sliders.h',
'<(src_loc)/ui/widgets/discrete_slider.cpp', '<(src_loc)/ui/widgets/discrete_sliders.cpp',
'<(src_loc)/ui/widgets/discrete_slider.h', '<(src_loc)/ui/widgets/discrete_sliders.h',
'<(src_loc)/ui/widgets/dropdown_menu.cpp', '<(src_loc)/ui/widgets/dropdown_menu.cpp',
'<(src_loc)/ui/widgets/dropdown_menu.h', '<(src_loc)/ui/widgets/dropdown_menu.h',
'<(src_loc)/ui/widgets/filled_slider.cpp',
'<(src_loc)/ui/widgets/filled_slider.h',
'<(src_loc)/ui/widgets/inner_dropdown.cpp', '<(src_loc)/ui/widgets/inner_dropdown.cpp',
'<(src_loc)/ui/widgets/inner_dropdown.h', '<(src_loc)/ui/widgets/inner_dropdown.h',
'<(src_loc)/ui/widgets/input_fields.cpp', '<(src_loc)/ui/widgets/input_fields.cpp',
'<(src_loc)/ui/widgets/input_fields.h', '<(src_loc)/ui/widgets/input_fields.h',
'<(src_loc)/ui/widgets/labels.cpp', '<(src_loc)/ui/widgets/labels.cpp',
'<(src_loc)/ui/widgets/labels.h', '<(src_loc)/ui/widgets/labels.h',
'<(src_loc)/ui/widgets/media_slider.cpp',
'<(src_loc)/ui/widgets/media_slider.h',
'<(src_loc)/ui/widgets/menu.cpp', '<(src_loc)/ui/widgets/menu.cpp',
'<(src_loc)/ui/widgets/menu.h', '<(src_loc)/ui/widgets/menu.h',
'<(src_loc)/ui/widgets/multi_select.cpp', '<(src_loc)/ui/widgets/multi_select.cpp',