mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-02-05 06:38:21 +00:00
Stickers box redesigned.
This commit is contained in:
parent
38d20c506e
commit
6e0394dd42
BIN
Telegram/Resources/icons/stickers_remove.png
Normal file
BIN
Telegram/Resources/icons/stickers_remove.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 168 B |
BIN
Telegram/Resources/icons/stickers_remove@2x.png
Normal file
BIN
Telegram/Resources/icons/stickers_remove@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 260 B |
BIN
Telegram/Resources/icons/stickers_reorder.png
Normal file
BIN
Telegram/Resources/icons/stickers_reorder.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 134 B |
BIN
Telegram/Resources/icons/stickers_reorder@2x.png
Normal file
BIN
Telegram/Resources/icons/stickers_reorder@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 183 B |
@ -708,7 +708,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
|
||||
"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_add_pack" = "Add 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_default_set" = "Great Minds";
|
||||
"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_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_restore" = "Restore";
|
||||
"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.";
|
||||
|
||||
|
@ -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) {
|
||||
if (channel->amIn()) {
|
||||
channelAmInUpdated(channel);
|
||||
@ -1180,3 +1283,57 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs
|
||||
ApiWrap::~ApiWrap() {
|
||||
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;
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ class ApiWrap : public QObject, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
ApiWrap(QObject *parent);
|
||||
void init();
|
||||
|
||||
@ -51,6 +50,7 @@ public:
|
||||
|
||||
void scheduleStickerSetRequest(uint64 setId, uint64 access);
|
||||
void requestStickerSets();
|
||||
void saveStickerSets(const Stickers::Order &localOrder, const Stickers::Order &localRemoved);
|
||||
|
||||
void joinChannel(ChannelData *channel);
|
||||
void leaveChannel(ChannelData *channel);
|
||||
@ -67,11 +67,9 @@ public:
|
||||
~ApiWrap();
|
||||
|
||||
signals:
|
||||
|
||||
void fullPeerUpdated(PeerData *peer);
|
||||
|
||||
public slots:
|
||||
|
||||
void resolveMessageDatas();
|
||||
void resolveWebPages();
|
||||
|
||||
@ -79,7 +77,6 @@ public slots:
|
||||
void saveDraftsToCloud();
|
||||
|
||||
private:
|
||||
|
||||
void updatesReceived(const MTPUpdates &updates);
|
||||
|
||||
void gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req);
|
||||
@ -158,4 +155,16 @@ private:
|
||||
void saveCloudDraftDone(History *history, const MTPBool &result, 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);
|
||||
|
||||
};
|
||||
|
@ -2093,7 +2093,10 @@ namespace {
|
||||
Global::SetLastStickersUpdate(0);
|
||||
Global::SetLastRecentStickersUpdate(0);
|
||||
Global::SetFeaturedStickerSetsOrder(Stickers::Order());
|
||||
Global::SetFeaturedStickerSetsUnreadCount(0);
|
||||
if (Global::FeaturedStickerSetsUnreadCount() != 0) {
|
||||
Global::SetFeaturedStickerSetsUnreadCount(0);
|
||||
Global::RefFeaturedStickerSetsUnreadCountChanged().notify();
|
||||
}
|
||||
Global::SetLastFeaturedStickersUpdate(0);
|
||||
Global::SetArchivedStickerSetsOrder(Stickers::Order());
|
||||
cSetSavedGifs(SavedGifs());
|
||||
|
@ -60,7 +60,7 @@ void AboutBox::resizeEvent(QResizeEvent *e) {
|
||||
|
||||
void AboutBox::onVersion() {
|
||||
if (cRealBetaVersion()) {
|
||||
QString url = qsl("https://tdesktop.com/");
|
||||
auto url = qsl("https://tdesktop.com/");
|
||||
switch (cPlatform()) {
|
||||
case dbipWindows: url += qsl("win/%1.zip"); break;
|
||||
case dbipMac: url += qsl("mac/%1.zip"); break;
|
||||
|
@ -58,13 +58,17 @@ void AbstractBox::keyPressEvent(QKeyEvent *e) {
|
||||
}
|
||||
|
||||
void AbstractBox::resizeEvent(QResizeEvent *e) {
|
||||
updateBlockTitleGeometry();
|
||||
LayerWidget::resizeEvent(e);
|
||||
}
|
||||
|
||||
void AbstractBox::updateBlockTitleGeometry() {
|
||||
if (_blockClose) {
|
||||
_blockClose->moveToRight(0, 0);
|
||||
}
|
||||
if (_blockShadow) {
|
||||
_blockShadow->setGeometry(0, st::boxBlockTitleHeight, width(), st::boxBlockTitleShadow.height());
|
||||
}
|
||||
LayerWidget::resizeEvent(e);
|
||||
}
|
||||
|
||||
void AbstractBox::parentResized() {
|
||||
@ -143,11 +147,22 @@ void AbstractBox::onClose() {
|
||||
emit closed(this);
|
||||
}
|
||||
|
||||
void AbstractBox::setBlockTitle(bool block) {
|
||||
void AbstractBox::setBlockTitle(bool block, bool withClose, bool withShadow) {
|
||||
_blockTitle = block;
|
||||
_blockShadow.create(this, st::boxBlockTitleShadow);
|
||||
_blockClose.create(this, st::boxBlockTitleClose);
|
||||
_blockClose->setClickedCallback([this] { onClose(); });
|
||||
if (withClose) {
|
||||
_blockClose.create(this, st::boxBlockTitleClose);
|
||||
_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() {
|
||||
|
@ -38,7 +38,7 @@ public:
|
||||
|
||||
void setTitleText(const QString &title);
|
||||
void setAdditionalTitle(const QString &additionalTitle);
|
||||
void setBlockTitle(bool block);
|
||||
void setBlockTitle(bool block, bool withClose = true, bool withShadow = true);
|
||||
void raiseShadow();
|
||||
|
||||
public slots:
|
||||
@ -59,9 +59,11 @@ protected:
|
||||
}
|
||||
|
||||
private:
|
||||
int _maxHeight = 0;
|
||||
void updateBlockTitleGeometry();
|
||||
int countHeight() const;
|
||||
|
||||
int _maxHeight = 0;
|
||||
|
||||
bool _closed = false;
|
||||
|
||||
QString _title;
|
||||
|
@ -470,7 +470,7 @@ confirmCaptionArea: InputArea(defaultInputArea) {
|
||||
textMargins: margins(1px, 6px, 1px, 4px);
|
||||
heightMax: 56px;
|
||||
}
|
||||
confirmBg: #f2f2f2;
|
||||
confirmBg: windowBgOver;
|
||||
confirmMaxHeight: 245px;
|
||||
confirmCompressedSkip: 10px;
|
||||
|
||||
|
@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
|
||||
#include "lang.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_dialogs.h"
|
||||
#include "styles/style_window.h"
|
||||
|
@ -25,7 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
namespace Ui {
|
||||
class RoundButton;
|
||||
class LinkButton;
|
||||
class DiscreteSlider;
|
||||
class SettingsSlider;
|
||||
} // namespace Ui
|
||||
|
||||
class NotificationsBox : public AbstractBox {
|
||||
@ -70,7 +70,7 @@ private:
|
||||
ScreenCorner _downCorner = ScreenCorner::TopLeft;
|
||||
|
||||
int _oldCount;
|
||||
ChildWidget<Ui::DiscreteSlider> _countSlider;
|
||||
ChildWidget<Ui::SettingsSlider> _countSlider;
|
||||
ChildWidget<Ui::RoundButton> _done;
|
||||
|
||||
QVector<SampleWidget*> _cornerSamples[4];
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -24,10 +24,15 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
|
||||
class ConfirmBox;
|
||||
|
||||
namespace style {
|
||||
struct RippleAnimation;
|
||||
} // namespace style
|
||||
|
||||
namespace Ui {
|
||||
class PlainShadow;
|
||||
class RoundButton;
|
||||
class RippleAnimation;
|
||||
class SettingsSlider;
|
||||
} // namespace Ui
|
||||
|
||||
class StickersBox : public ItemListBox, public RPCSender {
|
||||
@ -43,8 +48,6 @@ public:
|
||||
StickersBox(Section section = Section::Installed);
|
||||
StickersBox(const Stickers::Order &archivedIds);
|
||||
|
||||
~StickersBox();
|
||||
|
||||
public slots:
|
||||
void onStickersUpdated();
|
||||
|
||||
@ -52,8 +55,6 @@ public slots:
|
||||
void onNoDraggingScroll();
|
||||
void onScrollTimer();
|
||||
|
||||
void onSave();
|
||||
|
||||
private slots:
|
||||
void onScroll();
|
||||
|
||||
@ -64,31 +65,56 @@ protected:
|
||||
void closePressed() override;
|
||||
|
||||
private:
|
||||
void refreshTabs();
|
||||
void setup();
|
||||
int32 countHeight() const;
|
||||
void rebuildList();
|
||||
void updateTabsGeometry();
|
||||
void switchTab();
|
||||
void installSet(uint64 setId);
|
||||
|
||||
void disenableDone(const MTPmessages_StickerSetInstallResult &result, mtpRequestId req);
|
||||
bool disenableFail(const RPCError &error, mtpRequestId req);
|
||||
void reorderDone(const MTPBool &result);
|
||||
bool reorderFail(const RPCError &result);
|
||||
void saveOrder();
|
||||
QPixmap grabContentCache();
|
||||
|
||||
void installDone(const MTPmessages_StickerSetInstallResult &result);
|
||||
bool installFail(uint64 setId, const RPCError &error);
|
||||
|
||||
void updateVisibleTopBottom();
|
||||
void preloadArchivedSets();
|
||||
void requestArchivedSets();
|
||||
void checkLoadMoreArchived();
|
||||
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;
|
||||
|
||||
class Inner;
|
||||
ChildWidget<Inner> _inner;
|
||||
ChildWidget<Ui::RoundButton> _save = { nullptr };
|
||||
ChildWidget<Ui::RoundButton> _cancel = { nullptr };
|
||||
OrderedSet<mtpRequestId> _disenableRequests;
|
||||
mtpRequestId _reorderRequest = 0;
|
||||
ChildWidget<Ui::PlainShadow> _topShadow = { nullptr };
|
||||
struct Tab {
|
||||
Tab() : widget(nullptr) {
|
||||
}
|
||||
template <typename ...Args>
|
||||
Tab(int index, Args&&... args) : index(index), widget(std_::forward<Args>(args)...) {
|
||||
}
|
||||
|
||||
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 };
|
||||
|
||||
FloatAnimation _a_slide;
|
||||
bool _slideLeft = false;
|
||||
QPixmap _leftCache, _rightCache;
|
||||
|
||||
QTimer _scrollTimer;
|
||||
int32 _scrollDelta = 0;
|
||||
|
||||
@ -97,14 +123,19 @@ private:
|
||||
int _aboutHeight = 0;
|
||||
|
||||
mtpRequestId _archivedRequestId = 0;
|
||||
bool _archivedLoaded = 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.
|
||||
class StickersBox::Inner : public TWidget, public RPCSender, private base::Subscriber {
|
||||
class StickersBox::Inner : public TWidget, private base::Subscriber {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
@ -116,14 +147,17 @@ public:
|
||||
void updateSize();
|
||||
void updateRows(); // refresh only pack cover stickers
|
||||
bool appendSet(const Stickers::Set &set);
|
||||
bool savingStart() {
|
||||
if (_saving) return false;
|
||||
_saving = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
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 setVisibleTopBottom(int visibleTop, int visibleBottom) override;
|
||||
@ -143,37 +177,34 @@ signals:
|
||||
|
||||
public slots:
|
||||
void onUpdateSelected();
|
||||
void onClearRecent();
|
||||
void onClearBoxDestroyed(QObject *box);
|
||||
|
||||
private slots:
|
||||
void onImageLoaded();
|
||||
|
||||
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 setPressed(int newPressed);
|
||||
void setup();
|
||||
QRect relativeAddButtonRect() const;
|
||||
void paintButton(Painter &p, int y, bool selected, std_::unique_ptr<Ui::RippleAnimation> &ripple, const QString &text, int badgeCounter) const;
|
||||
QRect relativeButtonRect(bool removeButton) const;
|
||||
void ensureRipple(const style::RippleAnimation &st, QImage mask, bool removeButton);
|
||||
|
||||
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 setActionSel(int32 actionSel);
|
||||
float64 aboveShadowOpacity() const;
|
||||
|
||||
void readVisibleSets();
|
||||
|
||||
void installSet(uint64 setId);
|
||||
void installDone(const MTPmessages_StickerSetInstallResult &result);
|
||||
bool installFail(uint64 setId, const RPCError &error);
|
||||
|
||||
Section _section;
|
||||
Stickers::Order _archivedIds;
|
||||
|
||||
int32 _rowHeight;
|
||||
struct StickerSetRow {
|
||||
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)
|
||||
struct Row {
|
||||
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)
|
||||
, count(count)
|
||||
, title(title)
|
||||
@ -181,66 +212,66 @@ private:
|
||||
, installed(installed)
|
||||
, official(official)
|
||||
, unread(unread)
|
||||
, disabled(disabled)
|
||||
, recent(recent)
|
||||
, archived(archived)
|
||||
, removed(removed)
|
||||
, pixw(pixw)
|
||||
, pixh(pixh)
|
||||
, yadd(0, 0) {
|
||||
}
|
||||
bool isRecentSet() const {
|
||||
return (id == Stickers::CloudRecentSetId);
|
||||
}
|
||||
uint64 id;
|
||||
DocumentData *sticker;
|
||||
int32 count;
|
||||
QString title;
|
||||
int titleWidth;
|
||||
bool installed, official, unread, disabled, recent;
|
||||
bool installed, official, unread, archived, removed;
|
||||
int32 pixw, pixh;
|
||||
anim::ivalue yadd;
|
||||
QSharedPointer<Ui::RippleAnimation> ripple;
|
||||
};
|
||||
using StickerSetRows = QList<StickerSetRow*>;
|
||||
using Rows = QList<Row*>;
|
||||
|
||||
void rebuildAppendSet(const Stickers::Set &set, int maxNameWidth);
|
||||
void fillSetCover(const Stickers::Set &set, DocumentData **outSticker, int *outWidth, int *outHeight) const;
|
||||
int fillSetCount(const Stickers::Set &set) 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;
|
||||
|
||||
StickerSetRows _rows;
|
||||
Rows _rows;
|
||||
QList<uint64> _animStartTimes;
|
||||
uint64 _aboveShadowFadeStart = 0;
|
||||
anim::fvalue _aboveShadowFadeOpacity = { 0., 0. };
|
||||
Animation _a_shifting;
|
||||
|
||||
base::lambda<void(uint64 setId)> _installSetCallback;
|
||||
|
||||
int _visibleTop = 0;
|
||||
int _visibleBottom = 0;
|
||||
int _itemsTop = 0;
|
||||
|
||||
bool _saving = false;
|
||||
|
||||
int _actionSel = -1;
|
||||
int _actionDown = -1;
|
||||
|
||||
int _clearWidth, _removeWidth, _returnWidth, _restoreWidth;
|
||||
|
||||
ConfirmBox *_clearBox = nullptr;
|
||||
QString _addText;
|
||||
int _addWidth = 0;
|
||||
QString _undoText;
|
||||
int _undoWidth = 0;
|
||||
|
||||
int _buttonHeight = 0;
|
||||
bool _hasFeaturedButton = false;
|
||||
bool _hasArchivedButton = false;
|
||||
|
||||
QPoint _mouse;
|
||||
int _selected = -3; // -2 - featured stickers button, -1 - archived stickers button
|
||||
int _pressed = -2;
|
||||
bool _inDragArea = false;
|
||||
int _selected = -1;
|
||||
int _pressed = -1;
|
||||
QPoint _dragStart;
|
||||
int _started = -1;
|
||||
int _dragging = -1;
|
||||
int _above = -1;
|
||||
|
||||
std_::unique_ptr<Ui::RippleAnimation> _archivedRipple;
|
||||
std_::unique_ptr<Ui::RippleAnimation> _featuredRipple;
|
||||
|
||||
Ui::RectShadow _aboveShadow;
|
||||
|
||||
int _scrollbar = 0;
|
||||
|
@ -100,7 +100,6 @@ dialogsUnlockIconOver: icon {{ "dialogs_unlock", dialogsMenuIconFgOver }};
|
||||
|
||||
dialogsFilter: FlatInput(defaultFlatInput) {
|
||||
font: font(fsize);
|
||||
bgColor: #f2f2f2;
|
||||
phColor: #949494;
|
||||
phFocusColor: #a4a4a4;
|
||||
|
||||
|
@ -214,13 +214,14 @@ UnreadBadgeStyle::UnreadBadgeStyle()
|
||||
, selected(false)
|
||||
, muted(false)
|
||||
, size(st::dialogsUnreadHeight)
|
||||
, padding(st::dialogsUnreadPadding)
|
||||
, sizeId(UnreadBadgeInDialogs)
|
||||
, font(st::dialogsUnreadFont) {
|
||||
}
|
||||
|
||||
void paintUnreadCount(Painter &p, const QString &text, int x, int y, const UnreadBadgeStyle &st, int *outUnreadWidth) {
|
||||
int unreadWidth = st.font->width(text);
|
||||
int unreadRectWidth = unreadWidth + 2 * st::dialogsUnreadPadding;
|
||||
int unreadRectWidth = unreadWidth + 2 * st.padding;
|
||||
int unreadRectHeight = st.size;
|
||||
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);
|
||||
|
||||
auto textTop = st.textTop ? st.textTop : (unreadRectHeight - st.font->height) / 2;
|
||||
p.setFont(st.font);
|
||||
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) {
|
||||
@ -282,7 +284,7 @@ void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool sele
|
||||
st.active = active;
|
||||
st.muted = history->mute();
|
||||
paintUnreadCount(p, counter, unreadRight, unreadTop, st, &unreadWidth);
|
||||
availableWidth -= unreadWidth + st::dialogsUnreadPadding;
|
||||
availableWidth -= unreadWidth + st.padding;
|
||||
}
|
||||
if (history->typing.isEmpty() && history->sendActions.isEmpty()) {
|
||||
item->drawInDialog(p, QRect(nameleft, texttop, availableWidth, st::dialogsTextFont->height), active, selected, history->textCachedFor, history->lastItemTextCache);
|
||||
|
@ -52,7 +52,9 @@ struct UnreadBadgeStyle {
|
||||
bool active;
|
||||
bool selected;
|
||||
bool muted;
|
||||
int textTop = 0;
|
||||
int size;
|
||||
int padding;
|
||||
UnreadBadgeSize sizeId;
|
||||
style::font font;
|
||||
};
|
||||
|
@ -637,6 +637,7 @@ struct Data {
|
||||
uint64 LastRecentStickersUpdate = 0;
|
||||
Stickers::Order FeaturedStickerSetsOrder;
|
||||
int FeaturedStickerSetsUnreadCount = 0;
|
||||
base::Observable<void> FeaturedStickerSetsUnreadCountChanged;
|
||||
uint64 LastFeaturedStickersUpdate = 0;
|
||||
Stickers::Order ArchivedStickerSetsOrder;
|
||||
|
||||
@ -754,6 +755,7 @@ DefineVar(Global, uint64, LastStickersUpdate);
|
||||
DefineVar(Global, uint64, LastRecentStickersUpdate);
|
||||
DefineVar(Global, Stickers::Order, FeaturedStickerSetsOrder);
|
||||
DefineVar(Global, int, FeaturedStickerSetsUnreadCount);
|
||||
DefineRefVar(Global, base::Observable<void>, FeaturedStickerSetsUnreadCountChanged);
|
||||
DefineVar(Global, uint64, LastFeaturedStickersUpdate);
|
||||
DefineVar(Global, Stickers::Order, ArchivedStickerSetsOrder);
|
||||
|
||||
|
@ -317,6 +317,7 @@ DeclareVar(uint64, LastStickersUpdate);
|
||||
DeclareVar(uint64, LastRecentStickersUpdate);
|
||||
DeclareVar(Stickers::Order, FeaturedStickerSetsOrder);
|
||||
DeclareVar(int, FeaturedStickerSetsUnreadCount);
|
||||
DeclareRefVar(base::Observable<void>, FeaturedStickerSetsUnreadCountChanged);
|
||||
DeclareVar(uint64, LastFeaturedStickersUpdate);
|
||||
DeclareVar(Stickers::Order, ArchivedStickerSetsOrder);
|
||||
|
||||
|
@ -701,10 +701,10 @@ void HistoryItem::nextItemChanged() {
|
||||
void HistoryItem::recountAttachToPrevious() {
|
||||
bool attach = false;
|
||||
if (auto previous = previousItem()) {
|
||||
if (!isPost() && !Has<HistoryMessageDate>() && !Has<HistoryMessageUnreadBar>()) {
|
||||
attach = !previous->isPost()
|
||||
&& !previous->serviceMsg()
|
||||
&& !previous->isEmpty()
|
||||
if (!Has<HistoryMessageDate>() && !Has<HistoryMessageUnreadBar>()) {
|
||||
attach = !isPost() && !previous->isPost()
|
||||
&& !serviceMsg() && !previous->serviceMsg()
|
||||
&& !isEmpty() && !previous->isEmpty()
|
||||
&& previous->from() == from()
|
||||
&& (qAbs(previous->date.secsTo(date)) < kAttachMessageToPreviousSecondsDelta);
|
||||
}
|
||||
|
@ -3992,7 +3992,10 @@ void HistoryWidget::featuredStickersGot(const MTPmessages_FeaturedStickers &stic
|
||||
it = sets.erase(it);
|
||||
}
|
||||
}
|
||||
Global::SetFeaturedStickerSetsUnreadCount(unreadCount);
|
||||
if (Global::FeaturedStickerSetsUnreadCount() != unreadCount) {
|
||||
Global::SetFeaturedStickerSetsUnreadCount(unreadCount);
|
||||
Global::RefFeaturedStickerSetsUnreadCountChanged().notify();
|
||||
}
|
||||
|
||||
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()));
|
||||
|
@ -36,7 +36,7 @@ introCountry: countryInput {
|
||||
width: 300px;
|
||||
height: 41px;
|
||||
top: 33px;
|
||||
bgColor: #f2f2f2;
|
||||
bgColor: windowBgOver;
|
||||
ptrSize: size(15px, 8px);
|
||||
textMrg: margins(16px, 5px, 16px, 15px);
|
||||
font: defaultInputFont;
|
||||
|
@ -3224,7 +3224,7 @@ void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr,
|
||||
outOrder->push_front(setId);
|
||||
}
|
||||
} else if (setId == Stickers::CustomSetId) {
|
||||
setTitle = lang(lng_custom_stickers);
|
||||
setTitle = qsl("Custom stickers");
|
||||
setFlags |= qFlags(MTPDstickerSet_ClientFlag::f_special);
|
||||
} else if (setId == Stickers::CloudRecentSetId) {
|
||||
setTitle = lang(lng_recent_stickers);
|
||||
@ -3404,7 +3404,7 @@ void importOldRecentStickers() {
|
||||
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 &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;
|
||||
while (!stickers.stream.atEnd()) {
|
||||
@ -3480,7 +3480,10 @@ void readFeaturedStickers() {
|
||||
++unreadCount;
|
||||
}
|
||||
}
|
||||
Global::SetFeaturedStickerSetsUnreadCount(unreadCount);
|
||||
if (Global::FeaturedStickerSetsUnreadCount() != unreadCount) {
|
||||
Global::SetFeaturedStickerSetsUnreadCount(unreadCount);
|
||||
Global::RefFeaturedStickerSetsUnreadCountChanged().notify();
|
||||
}
|
||||
}
|
||||
|
||||
void readRecentStickers() {
|
||||
|
@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
#include "media/player/media_player_cover.h"
|
||||
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/media_slider.h"
|
||||
#include "ui/widgets/continuous_sliders.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "media/media_audio.h"
|
||||
#include "media/view/media_clip_playback.h"
|
||||
|
@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
|
||||
#include "media/media_audio.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_widgets.h"
|
||||
#include "mainwindow.h"
|
||||
|
@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
#include "media/player/media_player_widget.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/buttons.h"
|
||||
#include "media/media_audio.h"
|
||||
|
@ -25,7 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
#include "media/view/media_clip_volume_controller.h"
|
||||
#include "styles/style_mediaview.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/widgets/buttons.h"
|
||||
#include "media/media_audio.h"
|
||||
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ui/widgets/continuous_slider.h"
|
||||
#include "ui/widgets/continuous_sliders.h"
|
||||
|
||||
struct AudioPlaybackState;
|
||||
|
||||
|
@ -94,7 +94,7 @@ overviewLoader: size(34px, 14px);
|
||||
overviewLoaderPoint: size(4px, 4px);
|
||||
overviewLoaderSkip: 4px;
|
||||
|
||||
playlistHoverBg: #f2f2f2;
|
||||
playlistHoverBg: windowBgOver;
|
||||
playlistPadding: 10px;
|
||||
|
||||
linksSearchMargin: margins(20px, 20px, 20px, 0px);
|
||||
@ -121,7 +121,6 @@ overviewLinksChecked: icon {
|
||||
|
||||
overviewFilter: FlatInput(defaultFlatInput) {
|
||||
font: font(fsize);
|
||||
bgColor: #f2f2f2;
|
||||
phColor: #949494;
|
||||
phFocusColor: #a4a4a4;
|
||||
icon: fieldSearchIcon;
|
||||
|
@ -28,7 +28,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
#include "mainwindow.h"
|
||||
#include "boxes/confirmbox.h"
|
||||
#include "application.h"
|
||||
#include "ui/widgets/discrete_slider.h"
|
||||
#include "ui/widgets/discrete_sliders.h"
|
||||
|
||||
namespace Settings {
|
||||
namespace {
|
||||
@ -52,7 +52,7 @@ ScaleWidget::ScaleWidget(QWidget *parent, UserData *self) : BlockWidget(parent,
|
||||
void ScaleWidget::createControls() {
|
||||
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));
|
||||
|
||||
_scale->addSection(scaleLabel(dbisOne));
|
||||
@ -63,7 +63,7 @@ void ScaleWidget::createControls() {
|
||||
_scale->setSectionActivatedCallback([this] { scaleChanged(); });
|
||||
}
|
||||
|
||||
void ScaleWidget::onAutoChosen() {
|
||||
void ScaleWidget::onAutoChanged() {
|
||||
auto newScale = _auto->checked() ? dbisAuto : cEvalScale(cConfigScale());
|
||||
if (newScale == cScreenScale()) {
|
||||
if (newScale != cScale()) {
|
||||
@ -81,6 +81,11 @@ void ScaleWidget::onAutoChosen() {
|
||||
}
|
||||
|
||||
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()) {
|
||||
_auto->setChecked(true);
|
||||
} else if (newScale != dbisAuto && _auto->checked()) {
|
||||
@ -111,9 +116,6 @@ void ScaleWidget::scaleChanged() {
|
||||
case 2: newScale = dbisOneAndHalf; break;
|
||||
case 3: newScale = dbisTwo; break;
|
||||
}
|
||||
if (newScale == cScreenScale()) {
|
||||
newScale = dbisAuto;
|
||||
}
|
||||
setScale(newScale);
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
|
||||
namespace Ui {
|
||||
class Checkbox;
|
||||
class DiscreteSlider;
|
||||
class SettingsSlider;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Settings {
|
||||
@ -36,7 +36,7 @@ public:
|
||||
ScaleWidget(QWidget *parent, UserData *self);
|
||||
|
||||
private slots:
|
||||
void onAutoChosen();
|
||||
void onAutoChanged();
|
||||
void onRestartNow();
|
||||
void onCancel();
|
||||
|
||||
@ -46,9 +46,10 @@ private:
|
||||
void setScale(DBIScale newScale);
|
||||
|
||||
ChildWidget<Ui::Checkbox> _auto = { nullptr };
|
||||
ChildWidget<Ui::DiscreteSlider> _scale = { nullptr };
|
||||
ChildWidget<Ui::SettingsSlider> _scale = { nullptr };
|
||||
|
||||
DBIScale _newScale = dbisAuto;
|
||||
bool _inSetScale = false;
|
||||
|
||||
};
|
||||
|
||||
|
@ -2530,7 +2530,6 @@ void EmojiPan::SlideAnimation::paintFrame(QPainter &p, float64 dt, float64 opaci
|
||||
t_assert(started());
|
||||
t_assert(dt >= 0.);
|
||||
|
||||
auto &transition = anim::easeOutCirc;
|
||||
_frameAlpha = anim::interpolate(1, 256, opacity);
|
||||
|
||||
auto frameInts = _frameInts + _innerLeft + _innerTop * _frameIntsPerLine;
|
||||
|
@ -83,6 +83,26 @@ void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d) {
|
||||
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) {
|
||||
auto &sets = Global::RefStickerSets();
|
||||
auto it = sets.find(setId);
|
||||
@ -199,7 +219,10 @@ void FeaturedReader::onReadSets() {
|
||||
|
||||
if (!wrappedIds.empty()) {
|
||||
MTP::send(MTPmessages_ReadFeaturedStickers(MTP_vector<MTPlong>(wrappedIds)), rpcDone(&readFeaturedDone));
|
||||
Global::SetFeaturedStickerSetsUnreadCount(count);
|
||||
if (Global::FeaturedStickerSetsUnreadCount() != count) {
|
||||
Global::SetFeaturedStickerSetsUnreadCount(count);
|
||||
Global::RefFeaturedStickerSetsUnreadCountChanged().notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
namespace Stickers {
|
||||
|
||||
void applyArchivedResult(const MTPDmessages_stickerSetInstallResultArchive &d);
|
||||
bool applyArchivedResultFake(); // For testing.
|
||||
void installLocally(uint64 setId);
|
||||
void undoInstallLocally(uint64 setId);
|
||||
void markFeaturedAsRead(uint64 setId);
|
||||
|
@ -41,27 +41,46 @@ stickersTrendingSubheaderTop: 20px;
|
||||
|
||||
stickersTrendingAddTop: 3px;
|
||||
stickersTrendingAdd: RoundButton(defaultActiveButton) {
|
||||
width: -17px;
|
||||
width: -16px;
|
||||
height: 26px;
|
||||
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;
|
||||
|
||||
stickersAddIcon: icon {{ "stickers_add", #ffffff }};
|
||||
stickersAddSize: size(30px, 24px);
|
||||
|
||||
stickersFeaturedHeight: 32px;
|
||||
stickersFeaturedFont: contactsNameFont;
|
||||
stickersFeaturedPosition: point(16px, 6px);
|
||||
stickersFeaturedBadgeFont: semiboldFont;
|
||||
stickersFeaturedBadgeSize: 21px;
|
||||
stickersFeaturedBadgeFont: font(12px bold);
|
||||
stickersFeaturedBadgeSize: 15px;
|
||||
stickersFeaturedBadgeTextTop: -1px;
|
||||
stickersFeaturedBadgePadding: 4px;
|
||||
stickersFeaturedBadgeSkip: 4px;
|
||||
stickersFeaturedBadgeTop: 9px;
|
||||
stickersFeaturedPen: lightButtonFg;
|
||||
stickersFeaturedUnreadBg: msgFileInBg;
|
||||
stickersFeaturedUnreadSize: 5px;
|
||||
stickersFeaturedUnreadSkip: 5px;
|
||||
stickersFeaturedUnreadTop: 7px;
|
||||
stickersFeaturedInstalled: icon {{ "mediaview_save_check", lightButtonFg }};
|
||||
stickersFeaturedInstalled: icon {{ "send_control_save", lightButtonFg }};
|
||||
|
||||
stickersMaxHeight: 440px;
|
||||
stickersPadding: margins(19px, 17px, 19px, 17px);
|
||||
|
@ -744,7 +744,7 @@ public:
|
||||
return flags & MTPDchannel::Flag::f_verified;
|
||||
}
|
||||
bool canAddMembers() const {
|
||||
return amCreator() || amEditor() || (flags & MTPDchannel::Flag::f_democracy);
|
||||
return amCreator() || amEditor() || (amIn() && (flags & MTPDchannel::Flag::f_democracy));
|
||||
}
|
||||
bool canEditPhoto() const {
|
||||
return amCreator() || (amEditor() && isMegagroup());
|
||||
|
@ -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
|
293
Telegram/SourceFiles/ui/widgets/continuous_sliders.cpp
Normal file
293
Telegram/SourceFiles/ui/widgets/continuous_sliders.cpp
Normal 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
|
@ -20,6 +20,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
namespace Ui {
|
||||
|
||||
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
|
@ -19,14 +19,13 @@ 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/discrete_slider.h"
|
||||
#include "ui/widgets/discrete_sliders.h"
|
||||
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
namespace Ui {
|
||||
|
||||
DiscreteSlider::DiscreteSlider(QWidget *parent) : TWidget(parent)
|
||||
, _a_left(animation(this, &DiscreteSlider::step_left)) {
|
||||
DiscreteSlider::DiscreteSlider(QWidget *parent) : TWidget(parent) {
|
||||
setCursor(style::cur_pointer);
|
||||
}
|
||||
|
||||
@ -35,54 +34,70 @@ void DiscreteSlider::setSectionActivatedCallback(SectionActivatedCallback &&call
|
||||
}
|
||||
|
||||
void DiscreteSlider::setActiveSection(int index) {
|
||||
setSelectedSection(index);
|
||||
if (_activeIndex != index) {
|
||||
_activeIndex = index;
|
||||
if (_callback) {
|
||||
_callback();
|
||||
}
|
||||
}
|
||||
setSelectedSection(index);
|
||||
}
|
||||
|
||||
void DiscreteSlider::setActiveSectionFast(int index) {
|
||||
setActiveSection(index);
|
||||
a_left.finish();
|
||||
_a_left.stop();
|
||||
_a_left.finish();
|
||||
update();
|
||||
}
|
||||
|
||||
void DiscreteSlider::addSection(const QString &label) {
|
||||
auto section = Section(label);
|
||||
_sections.push_back(section);
|
||||
void DiscreteSlider::setSelectOnPress(bool selectOnPress) {
|
||||
_selectOnPress = selectOnPress;
|
||||
}
|
||||
|
||||
void DiscreteSlider::resizeSections(int newWidth) {
|
||||
auto count = _sections.size();
|
||||
if (!count) return;
|
||||
void DiscreteSlider::addSection(const QString &label) {
|
||||
_sections.push_back(Section(label, getLabelFont()));
|
||||
resizeToWidth(width());
|
||||
}
|
||||
|
||||
auto skips = count - 1;
|
||||
auto sectionsWidth = newWidth - skips * st::discreteSliderSkip;
|
||||
auto sectionWidth = sectionsWidth / float64(count);
|
||||
auto x = 0.;
|
||||
for (int i = 0; i != count; ++i) {
|
||||
auto §ion = _sections[i];
|
||||
auto skip = i * st::discreteSliderThickness;
|
||||
section.left = qFloor(x) + skip;
|
||||
x += sectionWidth;
|
||||
section.width = qRound(x) - (section.left - skip);
|
||||
void DiscreteSlider::setSections(const QStringList &labels) {
|
||||
t_assert(!labels.isEmpty());
|
||||
|
||||
_sections.clear();
|
||||
for_const (auto &label, labels) {
|
||||
_sections.push_back(Section(label, getLabelFont()));
|
||||
}
|
||||
stopAnimation();
|
||||
if (_activeIndex >= _sections.size()) {
|
||||
_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 §ion : _sections) {
|
||||
callback(section);
|
||||
}
|
||||
a_left = anim::ivalue(_sections[_activeIndex].left, _sections[_activeIndex].left);
|
||||
_a_left.stop();
|
||||
}
|
||||
|
||||
void DiscreteSlider::mousePressEvent(QMouseEvent *e) {
|
||||
setSelectedSection(getIndexFromPosition(e->pos()));
|
||||
if (_selectOnPress) {
|
||||
setSelectedSection(getIndexFromPosition(e->pos()));
|
||||
}
|
||||
_pressed = true;
|
||||
}
|
||||
|
||||
void DiscreteSlider::mouseMoveEvent(QMouseEvent *e) {
|
||||
if (!_pressed) return;
|
||||
setSelectedSection(getIndexFromPosition(e->pos()));
|
||||
if (_selectOnPress) {
|
||||
setSelectedSection(getIndexFromPosition(e->pos()));
|
||||
}
|
||||
}
|
||||
|
||||
void DiscreteSlider::mouseReleaseEvent(QMouseEvent *e) {
|
||||
@ -92,50 +107,16 @@ void DiscreteSlider::mouseReleaseEvent(QMouseEvent *e) {
|
||||
}
|
||||
|
||||
void DiscreteSlider::setSelectedSection(int index) {
|
||||
if (index < 0) return;
|
||||
if (index < 0 || index >= _sections.size()) return;
|
||||
|
||||
if (_selected != index) {
|
||||
auto from = _sections[_selected].left;
|
||||
_selected = index;
|
||||
a_left.start(_sections[_selected].left);
|
||||
_a_left.start();
|
||||
auto to = _sections[_selected].left;
|
||||
_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 §ion = _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 count = _sections.size();
|
||||
for (int i = 0; i != count; ++i) {
|
||||
@ -146,22 +127,73 @@ int DiscreteSlider::getIndexFromPosition(QPoint pos) {
|
||||
return count - 1;
|
||||
}
|
||||
|
||||
void DiscreteSlider::step_left(float64 ms, bool timer) {
|
||||
auto dt = ms / st::discreteSliderDuration;
|
||||
if (dt >= 1) {
|
||||
a_left.finish();
|
||||
_a_left.stop();
|
||||
} else {
|
||||
a_left.update(dt, anim::linear);
|
||||
}
|
||||
if (timer) {
|
||||
update();
|
||||
}
|
||||
DiscreteSlider::Section::Section(const QString &label, const style::font &font)
|
||||
: label(label)
|
||||
, labelWidth(font->width(label)) {
|
||||
}
|
||||
|
||||
DiscreteSlider::Section::Section(const QString &label)
|
||||
: label(label)
|
||||
, labelWidth(st::discreteSliderLabelFont->width(label)) {
|
||||
SettingsSlider::SettingsSlider(QWidget *parent, const style::SettingsSlider &st) : DiscreteSlider(parent)
|
||||
, _st(st) {
|
||||
}
|
||||
|
||||
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 §ion) {
|
||||
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 §ion) {
|
||||
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
|
@ -20,6 +20,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
namespace Ui {
|
||||
|
||||
class DiscreteSlider : public TWidget {
|
||||
@ -27,46 +29,80 @@ public:
|
||||
DiscreteSlider(QWidget *parent);
|
||||
|
||||
void addSection(const QString &label);
|
||||
|
||||
void setSections(const QStringList &labels);
|
||||
int activeSection() const {
|
||||
return _activeIndex;
|
||||
}
|
||||
void setActiveSection(int index);
|
||||
void setActiveSectionFast(int index);
|
||||
void setSelectOnPress(bool selectOnPress);
|
||||
|
||||
using SectionActivatedCallback = base::lambda<void()>;
|
||||
void setSectionActivatedCallback(SectionActivatedCallback &&callback);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
|
||||
private:
|
||||
void resizeSections(int newWidth);
|
||||
int getIndexFromPosition(QPoint pos);
|
||||
void setSelectedSection(int index);
|
||||
void step_left(float64 ms, bool timer);
|
||||
int resizeGetHeight(int newWidth) override = 0;
|
||||
|
||||
struct Section {
|
||||
Section(const QString &label);
|
||||
Section(const QString &label, const style::font &font);
|
||||
|
||||
int left, width;
|
||||
QString label;
|
||||
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;
|
||||
int _activeIndex = 0;
|
||||
bool _selectOnPress = true;
|
||||
|
||||
SectionActivatedCallback _callback;
|
||||
|
||||
bool _pressed = false;
|
||||
int _selected = 0;
|
||||
anim::ivalue a_left = { 0 };
|
||||
Animation _a_left;
|
||||
FloatAnimation _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;
|
||||
|
||||
};
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -566,7 +566,7 @@ defaultSolidScroll: FlatScroll(defaultFlatScroll) {
|
||||
defaultInputFont: font(17px);
|
||||
defaultFlatInput: FlatInput {
|
||||
textColor: #000000;
|
||||
bgColor: #f2f2f2;
|
||||
bgColor: windowBgOver;
|
||||
bgActive: #ffffff;
|
||||
width: 210px;
|
||||
height: 40px;
|
||||
@ -575,7 +575,7 @@ defaultFlatInput: FlatInput {
|
||||
font: defaultInputFont;
|
||||
|
||||
borderWidth: 2px;
|
||||
borderColor: #f2f2f2;
|
||||
borderColor: windowBgOver;
|
||||
borderActive: #54c3f3;
|
||||
borderError: #ed8080;
|
||||
|
||||
@ -724,16 +724,47 @@ widgetFadeDuration: 200;
|
||||
fieldSearchIcon: icon {{ "box_search", #aaaaaa, point(9px, 8px) }};
|
||||
boxFieldSearchIcon: icon {{ "box_search", #aaaaaa, point(10px, 9px) }};
|
||||
|
||||
discreteSliderHeight: 39px;
|
||||
discreteSliderTop: 5px;
|
||||
discreteSliderSkip: 3px;
|
||||
discreteSliderThickness: 3px;
|
||||
discreteSliderActiveFg: #4bb5e7;
|
||||
discreteSliderInactiveFg: #e1eaef;
|
||||
discreteSliderLabelTop: 17px;
|
||||
discreteSliderLabelFont: normalFont;
|
||||
discreteSliderLabelFg: #1485c2;
|
||||
discreteSliderDuration: 200;
|
||||
SettingsSlider {
|
||||
height: pixels;
|
||||
barTop: pixels;
|
||||
barSkip: pixels;
|
||||
barStroke: pixels;
|
||||
barFg: color;
|
||||
barFgActive: color;
|
||||
labelTop: pixels;
|
||||
labelFont: font;
|
||||
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 {
|
||||
left: icon {{ "round_shadow_left", windowShadowFg }};
|
||||
|
@ -496,22 +496,18 @@
|
||||
'<(src_loc)/ui/widgets/buttons.h',
|
||||
'<(src_loc)/ui/widgets/checkbox.cpp',
|
||||
'<(src_loc)/ui/widgets/checkbox.h',
|
||||
'<(src_loc)/ui/widgets/continuous_slider.cpp',
|
||||
'<(src_loc)/ui/widgets/continuous_slider.h',
|
||||
'<(src_loc)/ui/widgets/discrete_slider.cpp',
|
||||
'<(src_loc)/ui/widgets/discrete_slider.h',
|
||||
'<(src_loc)/ui/widgets/continuous_sliders.cpp',
|
||||
'<(src_loc)/ui/widgets/continuous_sliders.h',
|
||||
'<(src_loc)/ui/widgets/discrete_sliders.cpp',
|
||||
'<(src_loc)/ui/widgets/discrete_sliders.h',
|
||||
'<(src_loc)/ui/widgets/dropdown_menu.cpp',
|
||||
'<(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.h',
|
||||
'<(src_loc)/ui/widgets/input_fields.cpp',
|
||||
'<(src_loc)/ui/widgets/input_fields.h',
|
||||
'<(src_loc)/ui/widgets/labels.cpp',
|
||||
'<(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.h',
|
||||
'<(src_loc)/ui/widgets/multi_select.cpp',
|
||||
|
Loading…
Reference in New Issue
Block a user