Most of the new Settings sections filled with widgets.

Some animations added: new scale slider, widget_slide_wrap<TWidget>.
Any TWidget now can resizeToWidth() with overriden resizeGetHeight().
This commit is contained in:
John Preston 2016-08-22 19:16:21 +02:00
parent b9e22f59a1
commit 993b91ac15
50 changed files with 1516 additions and 181 deletions

View file

@ -253,7 +253,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_settings_change_lang" = "Change language"; "lng_settings_change_lang" = "Change language";
"lng_languages" = "Languages"; "lng_languages" = "Languages";
"lng_sure_save_language" = "Telegram will restart in order to change language"; "lng_sure_save_language" = "Telegram will restart in order to change language";
"lng_settings_auto_update" = "Update automatically"; "lng_settings_update_automatically" = "Update automatically (ver. {version})";
"lng_settings_current_version" = "Version {version}"; "lng_settings_current_version" = "Version {version}";
"lng_settings_check_now" = "Check for updates"; "lng_settings_check_now" = "Check for updates";
"lng_settings_update_checking" = "Checking for updates..."; "lng_settings_update_checking" = "Checking for updates...";
@ -314,7 +314,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_local_storage_cleared" = "Cleared!"; "lng_local_storage_cleared" = "Cleared!";
"lng_local_storage_clear_failed" = "Clear failed :("; "lng_local_storage_clear_failed" = "Clear failed :(";
"lng_settings_section_advanced" = "Advanced"; "lng_settings_section_advanced_settings" = "Advanced Settings";
"lng_passcode_remove_button" = "Remove"; "lng_passcode_remove_button" = "Remove";
@ -388,6 +388,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_settings_reset_one_sure" = "Do you want to terminate this session?"; "lng_settings_reset_one_sure" = "Do you want to terminate this session?";
"lng_settings_reset_button" = "Terminate"; "lng_settings_reset_button" = "Terminate";
"lng_settings_reset_done" = "Other sessions terminated"; "lng_settings_reset_done" = "Other sessions terminated";
"lng_settings_manage_local_storage" = "Manage local storage";
"lng_settings_ask_question" = "Ask a Question"; "lng_settings_ask_question" = "Ask a Question";
"lng_settings_ask_sure" = "Please note that Telegram Support is done by volunteers. We try to respond as quickly as possible, but it may take a while.\n\nPlease take a look at the Telegram FAQ: it has important troubleshooting tips and answers to most questions."; "lng_settings_ask_sure" = "Please note that Telegram Support is done by volunteers. We try to respond as quickly as possible, but it may take a while.\n\nPlease take a look at the Telegram FAQ: it has important troubleshooting tips and answers to most questions.";
"lng_settings_faq_button" = "Go to FAQ"; "lng_settings_faq_button" = "Go to FAQ";

View file

@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,10,2,0 FILEVERSION 0,10,2,1
PRODUCTVERSION 0,10,2,0 PRODUCTVERSION 0,10,2,1
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -51,10 +51,10 @@ BEGIN
BLOCK "040904b0" BLOCK "040904b0"
BEGIN BEGIN
VALUE "CompanyName", "Telegram Messenger LLP" VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileVersion", "0.10.2.0" VALUE "FileVersion", "0.10.2.1"
VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "LegalCopyright", "Copyright (C) 2014-2016"
VALUE "ProductName", "Telegram Desktop" VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "0.10.2.0" VALUE "ProductVersion", "0.10.2.1"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,10,2,0 FILEVERSION 0,10,2,1
PRODUCTVERSION 0,10,2,0 PRODUCTVERSION 0,10,2,1
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -43,10 +43,10 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Telegram Messenger LLP" VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileDescription", "Telegram Updater" VALUE "FileDescription", "Telegram Updater"
VALUE "FileVersion", "0.10.2.0" VALUE "FileVersion", "0.10.2.1"
VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "LegalCopyright", "Copyright (C) 2014-2016"
VALUE "ProductName", "Telegram Desktop" VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "0.10.2.0" VALUE "ProductVersion", "0.10.2.1"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -22,9 +22,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "core/basic_types.h" #include "core/basic_types.h"
#define BETA_VERSION_MACRO (0ULL) #define BETA_VERSION_MACRO (10002001ULL)
constexpr int AppVersion = 10002; constexpr int AppVersion = 10002;
constexpr str_const AppVersionStr = "0.10.2"; constexpr str_const AppVersionStr = "0.10.2";
constexpr bool AppAlphaVersion = true; constexpr bool AppAlphaVersion = false;
constexpr uint64 AppBetaVersion = BETA_VERSION_MACRO; constexpr uint64 AppBetaVersion = BETA_VERSION_MACRO;

View file

@ -2557,9 +2557,7 @@ bool BotKeyboard::forceReply() const {
return _forceReply; return _forceReply;
} }
void BotKeyboard::resizeToWidth(int newWidth, int maxOuterHeight) { int BotKeyboard::resizeGetHeight(int newWidth) {
_maxOuterHeight = maxOuterHeight;
updateStyle(newWidth); updateStyle(newWidth);
_height = st::botKbScroll.deltat + st::botKbScroll.deltab + (_impl ? _impl->naturalHeight() : 0); _height = st::botKbScroll.deltat + st::botKbScroll.deltab + (_impl ? _impl->naturalHeight() : 0);
if (_maximizeSize) { if (_maximizeSize) {
@ -2570,10 +2568,7 @@ void BotKeyboard::resizeToWidth(int newWidth, int maxOuterHeight) {
int implHeight = _height - (st::botKbScroll.deltat + st::botKbScroll.deltab); int implHeight = _height - (st::botKbScroll.deltat + st::botKbScroll.deltab);
_impl->resize(implWidth, implHeight); _impl->resize(implWidth, implHeight);
} }
QSize newSize(newWidth, _height); return _height;
if (newSize != size()) {
resize(newSize);
}
} }
bool BotKeyboard::maximizeSize() const { bool BotKeyboard::maximizeSize() const {

View file

@ -354,7 +354,6 @@ class BotKeyboard : public TWidget, public AbstractTooltipShower, public ClickHa
Q_OBJECT Q_OBJECT
public: public:
BotKeyboard(); BotKeyboard();
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
@ -373,7 +372,10 @@ public:
bool forceReply() const; bool forceReply() const;
void step_selected(uint64 ms, bool timer); void step_selected(uint64 ms, bool timer);
void resizeToWidth(int newWidth, int maxOuterHeight); void resizeToWidth(int newWidth, int maxOuterHeight) {
_maxOuterHeight = maxOuterHeight;
return TWidget::resizeToWidth(newWidth);
}
bool maximizeSize() const; bool maximizeSize() const;
bool singleUse() const; bool singleUse() const;
@ -390,6 +392,9 @@ public:
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override; void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override; void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
protected:
int resizeGetHeight(int newWidth) override;
private: private:
void updateSelected(); void updateSelected();

View file

@ -107,11 +107,15 @@ void LayerStackWidget::paintEvent(QPaintEvent *e) {
void LayerStackWidget::keyPressEvent(QKeyEvent *e) { void LayerStackWidget::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Escape) { if (e->key() == Qt::Key_Escape) {
onClose(); onCloseCurrent();
} }
} }
void LayerStackWidget::mousePressEvent(QMouseEvent *e) { void LayerStackWidget::mousePressEvent(QMouseEvent *e) {
onCloseCurrent();
}
void LayerStackWidget::onCloseCurrent() {
if (layer()) { if (layer()) {
onCloseLayers(); onCloseLayers();
} else { } else {

View file

@ -73,6 +73,7 @@ public:
bool contentOverlapped(const QRect &globalRect); bool contentOverlapped(const QRect &globalRect);
void onCloseCurrent();
void onCloseLayers(); void onCloseLayers();
void onClose(); void onClose();

View file

@ -111,7 +111,7 @@ int CoverWidget::countPhotoLeft(int newWidth) const {
return qMin(result, st::profilePhotoLeftMax); return qMin(result, st::profilePhotoLeftMax);
} }
void CoverWidget::resizeToWidth(int newWidth) { int CoverWidget::resizeGetHeight(int newWidth) {
int newHeight = 0; int newHeight = 0;
newHeight += st::profileMarginTop; newHeight += st::profileMarginTop;
@ -137,9 +137,8 @@ void CoverWidget::resizeToWidth(int newWidth) {
newHeight += st::profileBlocksTop; newHeight += st::profileBlocksTop;
resizeDropArea(); resizeDropArea(newWidth);
resize(newWidth, newHeight); return newHeight;
update();
} }
void CoverWidget::refreshNameGeometry(int newWidth) { void CoverWidget::refreshNameGeometry(int newWidth) {
@ -210,9 +209,9 @@ void CoverWidget::paintEvent(QPaintEvent *e) {
paintDivider(p); paintDivider(p);
} }
void CoverWidget::resizeDropArea() { void CoverWidget::resizeDropArea(int newWidth) {
if (_dropArea) { if (_dropArea) {
_dropArea->setGeometry(0, 0, width(), _dividerTop); _dropArea->setGeometry(0, 0, newWidth, _dividerTop);
} }
} }
@ -277,7 +276,7 @@ void CoverWidget::dragEnterEvent(QDragEnterEvent *e) {
subtitle = lang(lng_profile_drop_area_subtitle_channel); subtitle = lang(lng_profile_drop_area_subtitle_channel);
} }
_dropArea = new CoverDropArea(this, title, subtitle); _dropArea = new CoverDropArea(this, title, subtitle);
resizeDropArea(); resizeDropArea(width());
} }
_dropArea->showAnimated(); _dropArea->showAnimated();
e->setDropAction(Qt::CopyAction); e->setDropAction(Qt::CopyAction);

View file

@ -46,9 +46,6 @@ class CoverWidget final : public TWidget, public Notify::Observer {
public: public:
CoverWidget(QWidget *parent, PeerData *peer); CoverWidget(QWidget *parent, PeerData *peer);
// Count new height for width=newWidth and resize to it.
void resizeToWidth(int newWidth);
void showFinished(); void showFinished();
// Profile fixed top bar should use this flag to decide // Profile fixed top bar should use this flag to decide
@ -78,6 +75,8 @@ protected:
void dragLeaveEvent(QDragLeaveEvent *e) override; void dragLeaveEvent(QDragLeaveEvent *e) override;
void dropEvent(QDropEvent *e) override; void dropEvent(QDropEvent *e) override;
int resizeGetHeight(int newWidth) override;
private: private:
// Observed notifications. // Observed notifications.
void notifyPeerUpdated(const Notify::PeerUpdate &update); void notifyPeerUpdated(const Notify::PeerUpdate &update);
@ -105,7 +104,7 @@ private:
bool canEditPhoto() const; bool canEditPhoto() const;
void showSetPhotoBox(const QImage &img); void showSetPhotoBox(const QImage &img);
void resizeDropArea(); void resizeDropArea(int newWidth);
void dropAreaHidden(CoverDropArea *dropArea); void dropAreaHidden(CoverDropArea *dropArea);
bool mimeDataHasImage(const QMimeData *mimeData) const; bool mimeDataHasImage(const QMimeData *mimeData) const;

View file

@ -37,11 +37,10 @@ public:
setCursor(style::cur_pointer); setCursor(style::cur_pointer);
} }
void resizeToWidth(int newWidth) {
resize(newWidth, st::profileTopBarHeight);
}
protected: protected:
int resizeGetHeight(int newWidth) override {
return st::profileTopBarHeight;
}
void paintEvent(QPaintEvent *e) override { void paintEvent(QPaintEvent *e) override {
Painter p(this); Painter p(this);
@ -224,7 +223,7 @@ void FixedBar::onLeaveGroupSure() {
App::main()->deleteAndExit(_peerChat); App::main()->deleteAndExit(_peerChat);
} }
void FixedBar::resizeToWidth(int newWidth) { int FixedBar::resizeGetHeight(int newWidth) {
int newHeight = 0; int newHeight = 0;
int buttonLeft = newWidth; int buttonLeft = newWidth;
@ -238,7 +237,7 @@ void FixedBar::resizeToWidth(int newWidth) {
_backButton->moveToLeft(0, 0); _backButton->moveToLeft(0, 0);
newHeight += _backButton->height(); newHeight += _backButton->height();
resize(newWidth, newHeight); return newHeight;
} }
void FixedBar::setAnimatingMode(bool enabled) { void FixedBar::setAnimatingMode(bool enabled) {

View file

@ -40,8 +40,6 @@ class FixedBar final : public TWidget, public Notify::Observer {
public: public:
FixedBar(QWidget *parent, PeerData *peer); FixedBar(QWidget *parent, PeerData *peer);
void resizeToWidth(int newWidth);
// When animating mode is enabled the content is hidden and the // When animating mode is enabled the content is hidden and the
// whole fixed bar acts like a back button. // whole fixed bar acts like a back button.
void setAnimatingMode(bool enabled); void setAnimatingMode(bool enabled);
@ -51,6 +49,7 @@ public:
protected: protected:
void mousePressEvent(QMouseEvent *e) override; void mousePressEvent(QMouseEvent *e) override;
int resizeGetHeight(int newWidth) override;
public slots: public slots:
void onBack(); void onBack();

View file

@ -69,12 +69,6 @@ void InnerWidget::createBlocks() {
} }
} }
void InnerWidget::resizeToWidth(int newWidth, int minHeight) {
int naturalHeight = resizeGetHeight(newWidth);
_addedHeight = qMax(minHeight - naturalHeight, 0);
resize(newWidth, naturalHeight + _addedHeight);
}
void InnerWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) { void InnerWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) {
_visibleTop = visibleTop; _visibleTop = visibleTop;
_visibleBottom = visibleBottom; _visibleBottom = visibleBottom;
@ -225,7 +219,10 @@ int InnerWidget::resizeGetHeight(int newWidth) {
refreshBlocksPositions(); refreshBlocksPositions();
update(); update();
return countHeight(); auto naturalHeight = countHeight();
_addedHeight = qMax(_minHeight - naturalHeight, 0);
return naturalHeight + _addedHeight;
} }
int InnerWidget::countHeight() const { int InnerWidget::countHeight() const {

View file

@ -35,8 +35,10 @@ public:
return _peer; return _peer;
} }
// Count new height for width=newWidth and resize to it. void resizeToWidth(int newWidth, int minHeight) {
void resizeToWidth(int newWidth, int minHeight); _minHeight = minHeight;
return TWidget::resizeToWidth(newWidth);
}
// Updates the area that is visible inside the scroll container. // Updates the area that is visible inside the scroll container.
void setVisibleTopBottom(int visibleTop, int visibleBottom); void setVisibleTopBottom(int visibleTop, int visibleBottom);
@ -58,12 +60,12 @@ protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
void keyPressEvent(QKeyEvent *e) override; void keyPressEvent(QKeyEvent *e) override;
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override;
private: private:
void createBlocks(); void createBlocks();
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth);
// Counts the natural widget height after resizing of child widgets. // Counts the natural widget height after resizing of child widgets.
int countHeight() const; int countHeight() const;
@ -92,6 +94,7 @@ private:
// Height that we added to the natural height so that it is allowed // Height that we added to the natural height so that it is allowed
// to scroll down to the desired position. // to scroll down to the desired position.
int _addedHeight = 0; int _addedHeight = 0;
int _minHeight = 0;
int _visibleTop = 0; int _visibleTop = 0;
int _visibleBottom = 0; int _visibleBottom = 0;

View file

@ -86,8 +86,9 @@ settingsSecondaryButton: RoundButton(settingsPrimaryButton) {
settingsBlocksTop: 7px; settingsBlocksTop: 7px;
settingsBlocksBottom: 20px; settingsBlocksBottom: 20px;
settingsBlockMarginTop: 14px; settingsBlockMarginTop: 14px;
settingsBlockMarginBottom: 7px; settingsBlockMarginRight: 10px;
settingsBlockTitleHeight: 24px; settingsBlockMarginBottom: 16px;
settingsBlockTitleHeight: 31px;
settingsBlockTitleFont: font(14px semibold); settingsBlockTitleFont: font(14px semibold);
settingsBlockTitleFg: #333333; settingsBlockTitleFg: #333333;
settingsBlockTitleTop: 0px; settingsBlockTitleTop: 0px;
@ -99,5 +100,20 @@ settingsBlockOneLineTextPart: flatLabel(labelDefFlat) {
margin: margins(5px, 5px, 5px, 5px); margin: margins(5px, 5px, 5px, 5px);
maxHeight: 20px; maxHeight: 20px;
} }
settingsBlockOneLineSkip: 9px; settingsSubSkip: 4px;
settingsBlockOneLineWidthMax: 240px; settingsSmallSkip: 10px;
settingsSkip: 15px;
settingsLargeSkip: 23px;
settingsActionPadding: margins(0px, 4px, 0px, 5px);
settingsSliderHeight: 39px;
settingsSliderTop: 5px;
settingsSliderSkip: 3px;
settingsSliderThickness: 3px;
settingsSliderActiveFg: #4bb5e7;
settingsSliderInactiveFg: #e1eaef;
settingsSliderLabelTop: 17px;
settingsSliderLabelFont: normalFont;
settingsSliderLabelFg: #1485c2;
settingsSliderDuration: 200;

View file

@ -23,21 +23,76 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "styles/style_settings.h" #include "styles/style_settings.h"
#include "lang.h" #include "lang.h"
#include "boxes/connectionbox.h"
#include "boxes/confirmbox.h"
#include "boxes/aboutbox.h"
#include "mainwindow.h"
namespace Settings { namespace Settings {
AdvancedWidget::AdvancedWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_advanced)) { AdvancedWidget::AdvancedWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_advanced_settings)) {
refreshControls(); createControls();
} }
void AdvancedWidget::refreshControls() { void AdvancedWidget::createControls() {
style::margins marginSmall(0, 0, 0, st::settingsSmallSkip);
style::margins marginLarge(0, 0, 0, st::settingsLargeSkip);
if (self()) {
addChildRow(_manageLocalStorage, marginSmall, lang(lng_settings_manage_local_storage), SLOT(onManageLocalStorage()));
}
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
addChildRow(_connectionType, marginLarge, lang(lng_connection_type), lang(lng_connection_auto_connecting));
connect(_connectionType->link(), SIGNAL(clicked()), this, SLOT(onConnectionType()));
#endif // TDESKTOP_DISABLE_NETWORK_PROXY
if (self()) {
addChildRow(_askQuestion, marginSmall, lang(lng_settings_ask_question), SLOT(onAskQuestion()));
}
addChildRow(_telegramFAQ, marginLarge, lang(lng_settings_faq), SLOT(onTelegramFAQ()));
if (self()) {
addChildRow(_logOut, marginSmall, lang(lng_settings_logout), SLOT(onLogOut()));
}
} }
int AdvancedWidget::resizeGetHeight(int newWidth) { void AdvancedWidget::onManageLocalStorage() {
int newHeight = contentTop();
newHeight += st::settingsBlockMarginBottom;
return newHeight;
} }
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
void AdvancedWidget::onConnectionType() {
Ui::showLayer(new ConnectionBox());
}
#endif // TDESKTOP_DISABLE_NETWORK_PROXY
void AdvancedWidget::onAskQuestion() {
ConfirmBox *box = new ConfirmBox(lang(lng_settings_ask_sure), lang(lng_settings_ask_ok), st::defaultBoxButton, lang(lng_settings_faq_button));
connect(box, SIGNAL(confirmed()), this, SLOT(onAskQuestionSure()));
connect(box, SIGNAL(cancelPressed()), this, SLOT(onTelegramFAQ()));
Ui::showLayer(box);
}
void AdvancedWidget::onAskQuestionSure() {
if (_supportGetRequest) return;
_supportGetRequest = MTP::send(MTPhelp_GetSupport(), rpcDone(&AdvancedWidget::supportGot));
}
void AdvancedWidget::supportGot(const MTPhelp_Support &support) {
if (!App::main()) return;
if (support.type() == mtpc_help_support) {
if (auto user = App::feedUsers(MTP_vector<MTPUser>(1, support.c_help_support().vuser))) {
Ui::showPeerHistory(user, ShowAtUnreadMsgId);
}
}
}
void AdvancedWidget::onTelegramFAQ() {
QDesktopServices::openUrl(telegramFaqLink());
}
void AdvancedWidget::onLogOut() {
App::wnd()->onLogout();
}
} // namespace Settings } // namespace Settings

View file

@ -21,19 +21,39 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once #pragma once
#include "settings/settings_block_widget.h" #include "settings/settings_block_widget.h"
#include "settings/settings_chat_settings_widget.h"
namespace Settings { namespace Settings {
class AdvancedWidget : public BlockWidget { class AdvancedWidget : public BlockWidget, public RPCSender {
Q_OBJECT
public: public:
AdvancedWidget(QWidget *parent, UserData *self); AdvancedWidget(QWidget *parent, UserData *self);
protected: private slots:
// Resizes content and counts natural widget height for the desired width. void onManageLocalStorage();
int resizeGetHeight(int newWidth) override; #ifndef TDESKTOP_DISABLE_NETWORK_PROXY
void onConnectionType();
#endif // TDESKTOP_DISABLE_NETWORK_PROXY
void onAskQuestion();
void onAskQuestionSure();
void onTelegramFAQ();
void onLogOut();
private: private:
void refreshControls(); void createControls();
void supportGot(const MTPhelp_Support &support);
ChildWidget<LinkButton> _manageLocalStorage = { nullptr };
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
ChildWidget<LabeledLink> _connectionType = { nullptr };
#endif // TDESKTOP_DISABLE_NETWORK_PROXY
ChildWidget<LinkButton> _askQuestion = { nullptr };
ChildWidget<LinkButton> _telegramFAQ = { nullptr };
ChildWidget<LinkButton> _logOut = { nullptr };
mtpRequestId _supportGetRequest = 0;
}; };

View file

@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "settings/settings_block_widget.h" #include "settings/settings_block_widget.h"
#include "styles/style_settings.h" #include "styles/style_settings.h"
#include "ui/flatcheckbox.h"
namespace Settings { namespace Settings {
@ -38,6 +39,23 @@ int BlockWidget::contentTop() const {
return emptyTitle() ? 0 : (st::settingsBlockMarginTop + st::settingsBlockTitleHeight); return emptyTitle() ? 0 : (st::settingsBlockMarginTop + st::settingsBlockTitleHeight);
} }
int BlockWidget::resizeGetHeight(int newWidth) {
int x = contentLeft(), result = contentTop();
int availw = newWidth - x;
for_const (auto &row, _rows) {
row.child->moveToLeft(x + row.margin.left(), result + row.margin.top());
auto availRowWidth = availw - row.margin.left() - row.margin.right();
auto natural = row.child->naturalWidth();
auto rowWidth = (natural < 0) ? (availRowWidth - x) : qMin(natural, availRowWidth);
if (row.child->width() != rowWidth) {
row.child->resizeToWidth(rowWidth);
}
result += row.child->height() + row.margin.top() + row.margin.bottom();
}
result += st::settingsBlockMarginBottom;
return result;
}
void BlockWidget::paintEvent(QPaintEvent *e) { void BlockWidget::paintEvent(QPaintEvent *e) {
Painter p(this); Painter p(this);
@ -54,4 +72,31 @@ void BlockWidget::paintTitle(Painter &p) {
p.drawTextLeft(contentLeft(), titleTop, width(), _title); p.drawTextLeft(contentLeft(), titleTop, width(), _title);
} }
void BlockWidget::addCreatedRow(TWidget *child, const style::margins &margin) {
_rows.push_back({ child, margin });
}
void BlockWidget::rowHeightUpdated() {
auto newHeight = resizeGetHeight(width());
if (newHeight != height()) {
resize(width(), newHeight);
emit heightUpdated();
}
}
void BlockWidget::createChildRow(ChildWidget<Checkbox> &child, style::margins &margin, const QString &text, const char *slot, bool checked) {
child = new Checkbox(this, text, checked);
connect(child, SIGNAL(changed()), this, slot);
}
void BlockWidget::createChildRow(ChildWidget<Radiobutton> &child, style::margins &margin, const QString &group, int value, const QString &text, const char *slot, bool checked) {
child = new Radiobutton(this, group, value, text, checked);
connect(child, SIGNAL(changed()), this, slot);
}
void BlockWidget::createChildRow(ChildWidget<LinkButton> &child, style::margins &margin, const QString &text, const char *slot) {
child = new LinkButton(this, text);
connect(child, SIGNAL(changed()), this, slot);
}
} // namespace Settings } // namespace Settings

View file

@ -22,6 +22,14 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "core/observer.h" #include "core/observer.h"
class Checkbox;
class Radiobutton;
namespace Ui {
template <typename Widget>
class WidgetSlideWrap;
} // namespace Ui
namespace Settings { namespace Settings {
class BlockWidget : public ScrolledWidget, public Notify::Observer, public base::Subscriber { class BlockWidget : public ScrolledWidget, public Notify::Observer, public base::Subscriber {
@ -44,7 +52,7 @@ protected:
int contentTop() const; int contentTop() const;
// Resizes content and counts natural widget height for the desired width. // Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override = 0; int resizeGetHeight(int newWidth) override;
void contentSizeUpdated() { void contentSizeUpdated() {
resizeToWidth(width()); resizeToWidth(width());
@ -59,9 +67,62 @@ protected:
return _title.isEmpty(); return _title.isEmpty();
} }
template <typename Widget, typename ...Args>
Widget *addChildRow(ChildWidget<Widget> &child, style::margins margin, Args&&... args) {
createChildRow(child, margin, std_::forward<Args>(args)...);
addCreatedRow(child, margin);
return child;
}
private: private:
template <typename Widget, typename ...Args>
void createChildRow(ChildWidget<Ui::WidgetSlideWrap<Widget>> &child, style::margins &margin, const style::margins &padding, Args&&... args) {
ChildWidget<Widget> plainChild = { nullptr };
createChildRow(plainChild, margin, std_::forward<Args>(args)...);
child = new Ui::WidgetSlideWrap<Widget>(this, plainChild, padding, [this]() {
rowHeightUpdated();
});
margin.setLeft(margin.left() - padding.left());
margin.setTop(margin.top() - padding.top());
margin.setRight(margin.right() - padding.right());
margin.setBottom(margin.bottom() - padding.bottom());
}
void createChildRow(ChildWidget<Checkbox> &child, style::margins &margin, const QString &text, const char *slot, bool checked);
void createChildRow(ChildWidget<Radiobutton> &child, style::margins &margin, const QString &group, int value, const QString &text, const char *slot, bool checked);
void createChildRow(ChildWidget<LinkButton> &child, style::margins &margin, const QString &text, const char *slot);
void addCreatedRow(TWidget *child, const style::margins &margin);
void rowHeightUpdated();
template <typename Widget>
struct IsWidgetSlideWrap {
static constexpr bool value = false;
};
template <typename Widget>
struct IsWidgetSlideWrap<Ui::WidgetSlideWrap<Widget>> {
static constexpr bool value = true;
};
template <typename Widget>
using NotImplementedYet = std_::enable_if_t<
!IsWidgetSlideWrap<Widget>::value &&
!std_::is_same<Widget, Checkbox>::value &&
!std_::is_same<Widget, Radiobutton>::value &&
!std_::is_same<Widget, LinkButton>::value>;
template <typename Widget, typename... Args, typename = NotImplementedYet<Widget>>
void createChildRow(ChildWidget<Widget> &child, style::margins &margin, Args&&... args) {
child = new Widget(this, std_::forward<Args>(args)...);
}
void paintTitle(Painter &p); void paintTitle(Painter &p);
struct ChildRow {
TWidget *child;
style::margins margin;
};
QVector<ChildRow> _rows;
int _contentLeft = 0; int _contentLeft = 0;
UserData *_self; UserData *_self;
QString _title; QString _title;

View file

@ -23,21 +23,122 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "styles/style_settings.h" #include "styles/style_settings.h"
#include "lang.h" #include "lang.h"
#include "ui/widgets/widget_slide_wrap.h"
#include "ui/flatlabel.h"
#include "localstorage.h"
#include "mainwidget.h"
#include "boxes/emojibox.h"
#include "boxes/stickersetbox.h"
#include "boxes/downloadpathbox.h"
#include "boxes/connectionbox.h"
namespace Settings { namespace Settings {
ChatSettingsWidget::ChatSettingsWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_chat_settings)) { ChatSettingsWidget::ChatSettingsWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_chat_settings)) {
refreshControls(); createControls();
} }
void ChatSettingsWidget::refreshControls() { void ChatSettingsWidget::createControls() {
style::margins marginSmall(0, 0, 0, st::settingsSmallSkip);
style::margins marginSkip(0, 0, 0, st::settingsSkip);
style::margins marginSub(0, 0, 0, st::settingsSubSkip);
style::margins slidedPadding(0, marginSub.bottom() / 2, 0, marginSub.bottom() - (marginSub.bottom() / 2));
addChildRow(_replaceEmoji, marginSub, lang(lng_settings_replace_emojis), SLOT(onReplaceEmoji()), cReplaceEmojis());
style::margins marginList(st::defaultCheckbox.textPosition.x(), 0, 0, st::settingsSkip);
addChildRow(_viewList, marginList, slidedPadding, lang(lng_settings_view_emojis), SLOT(onViewList()));
addChildRow(_dontAskDownloadPath, marginSub, lang(lng_download_path_dont_ask), SLOT(onDontAskDownloadPath()), !cAskDownloadPath());
auto downloadPathText = []() -> QString {
if (cDownloadPath().isEmpty()) {
return lang(lng_download_path_default);
} else if (cDownloadPath() == qsl("tmp")) {
return lang(lng_download_path_temp);
}
return QDir::toNativeSeparators(cDownloadPath());
};
style::margins marginPath(st::defaultCheckbox.textPosition.x(), 0, 0, st::settingsSkip);
addChildRow(_downloadPath, marginPath, slidedPadding, lang(lng_download_path_label), downloadPathText());
connect(_downloadPath->entity()->link(), SIGNAL(clicked()), this, SLOT(onDownloadPath()));
addChildRow(_sendByEnter, marginSmall, qsl("send_key"), 0, lang(lng_settings_send_enter), SLOT(onSendByEnter()), !cCtrlEnter());
addChildRow(_sendByCtrlEnter, marginSkip, qsl("send_key"), 1, lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_settings_send_cmdenter : lng_settings_send_ctrlenter), SLOT(onSendByCtrlEnter()), cCtrlEnter());
addChildRow(_automaticMediaDownloadSettings, marginSmall, lang(lng_media_auto_settings), SLOT(onAutomaticMediaDownloadSettings()));
addChildRow(_manageStickerSets, marginSmall, lang(lng_stickers_you_have), SLOT(onManageStickerSets()));
} }
int ChatSettingsWidget::resizeGetHeight(int newWidth) { LabeledLink::LabeledLink(QWidget *parent, const QString &label, const QString &text) : TWidget(parent)
int newHeight = contentTop(); , _label(this, label, FlatLabel::InitType::Simple)
, _link(this, text) {
}
newHeight += st::settingsBlockMarginBottom; void LabeledLink::setLink(const QString &text) {
return newHeight; _link.destroy();
_link = new LinkButton(this, text);
}
int LabeledLink::naturalWidth() const {
return _label->naturalWidth() + st::normalFont->spacew + _link->naturalWidth();
}
int LabeledLink::resizeGetHeight(int newWidth) {
_label->moveToLeft(0, 0);
_link->resizeToWidth(newWidth - st::normalFont->spacew - _label->width());
_link->moveToLeft(_label->width() + st::normalFont->spacew, 0);
return _label->height();
}
void ChatSettingsWidget::onReplaceEmoji() {
cSetReplaceEmojis(_replaceEmoji->checked());
Local::writeUserSettings();
if (_replaceEmoji->checked()) {
_viewList->slideDown();
} else {
_viewList->slideUp();
}
}
void ChatSettingsWidget::onViewList() {
Ui::showLayer(new EmojiBox());
}
void ChatSettingsWidget::onDontAskDownloadPath() {
cSetAskDownloadPath(!_dontAskDownloadPath->checked());
Local::writeUserSettings();
if (_dontAskDownloadPath->checked()) {
_downloadPath->slideDown();
} else {
_downloadPath->slideUp();
}
}
void ChatSettingsWidget::onDownloadPath() {
Ui::showLayer(new DownloadPathBox());
}
void ChatSettingsWidget::onSendByEnter() {
if (_sendByEnter->checked()) {
cSetCtrlEnter(false);
if (App::main()) App::main()->ctrlEnterSubmitUpdated();
Local::writeUserSettings();
}
}
void ChatSettingsWidget::onSendByCtrlEnter() {
if (_sendByCtrlEnter->checked()) {
cSetCtrlEnter(true);
if (App::main()) App::main()->ctrlEnterSubmitUpdated();
Local::writeUserSettings();
}
}
void ChatSettingsWidget::onAutomaticMediaDownloadSettings() {
Ui::showLayer(new AutoDownloadBox());
}
void ChatSettingsWidget::onManageStickerSets() {
Ui::showLayer(new StickersBox());
} }
} // namespace Settings } // namespace Settings

View file

@ -22,18 +22,58 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "settings/settings_block_widget.h" #include "settings/settings_block_widget.h"
class FlatLabel;
namespace Settings { namespace Settings {
class ChatSettingsWidget : public BlockWidget { class LabeledLink : public TWidget {
public: public:
ChatSettingsWidget(QWidget *parent, UserData *self); LabeledLink(QWidget *parent, const QString &label, const QString &text);
void setLink(const QString &text);
LinkButton *link() {
return _link;
}
int naturalWidth() const override;
protected: protected:
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override; int resizeGetHeight(int newWidth) override;
private: private:
void refreshControls(); ChildWidget<FlatLabel> _label;
ChildWidget<LinkButton> _link;
};
class ChatSettingsWidget : public BlockWidget {
Q_OBJECT
public:
ChatSettingsWidget(QWidget *parent, UserData *self);
private slots:
void onReplaceEmoji();
void onViewList();
void onDontAskDownloadPath();
void onDownloadPath();
void onSendByEnter();
void onSendByCtrlEnter();
void onAutomaticMediaDownloadSettings();
void onManageStickerSets();
private:
void createControls();
ChildWidget<Checkbox> _replaceEmoji = { nullptr };
ChildWidget<Ui::WidgetSlideWrap<LinkButton>> _viewList = { nullptr };
ChildWidget<Checkbox> _dontAskDownloadPath = { nullptr };
ChildWidget<Ui::WidgetSlideWrap<LabeledLink>> _downloadPath = { nullptr };
ChildWidget<Radiobutton> _sendByEnter = { nullptr };
ChildWidget<Radiobutton> _sendByCtrlEnter = { nullptr };
ChildWidget<LinkButton> _automaticMediaDownloadSettings = { nullptr };
ChildWidget<LinkButton> _manageStickerSets = { nullptr };
}; };

View file

@ -35,8 +35,8 @@ FixedBar::FixedBar(QWidget *parent) : TWidget(parent)
}); });
} }
void FixedBar::resizeToWidth(int newWidth) { int FixedBar::resizeGetHeight(int newWidth) {
resize(newWidth, st::settingsFixedBarHeight); return st::settingsFixedBarHeight;
} }
void FixedBar::resizeEvent(QResizeEvent *e) { void FixedBar::resizeEvent(QResizeEvent *e) {

View file

@ -30,12 +30,12 @@ class FixedBar : public TWidget {
public: public:
FixedBar(QWidget *parent); FixedBar(QWidget *parent);
void resizeToWidth(int newWidth);
protected: protected:
void resizeEvent(QResizeEvent *e) override; void resizeEvent(QResizeEvent *e) override;
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
int resizeGetHeight(int newWidth) override;
private: private:
ChildWidget<Ui::IconButton> _close; ChildWidget<Ui::IconButton> _close;

View file

@ -23,21 +23,180 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "styles/style_settings.h" #include "styles/style_settings.h"
#include "lang.h" #include "lang.h"
#include "ui/widgets/widget_slide_wrap.h"
#include "ui/flatbutton.h"
#include "ui/flatcheckbox.h"
#include "localstorage.h"
#include "pspecific.h"
#include "mainwindow.h"
#include "boxes/languagebox.h"
#include "boxes/confirmbox.h"
#include "ui/filedialog.h"
#include "langloaderplain.h"
namespace Settings { namespace Settings {
namespace {
GeneralWidget::GeneralWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_general)) { QString currentVersion() {
auto result = QString::fromLatin1(AppVersionStr.c_str());
if (cAlphaVersion()) {
result += " alpha";
}
if (cBetaVersion()) {
result += qsl(" beta %1").arg(cBetaVersion());
}
return result;
}
} // namespace
GeneralWidget::GeneralWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_general))
, _changeLanguage(this, lang(lng_settings_change_lang)) {
refreshControls(); refreshControls();
} }
void GeneralWidget::refreshControls() { int GeneralWidget::resizeGetHeight(int newWidth) {
_changeLanguage->moveToRight(contentLeft(), st::settingsBlockMarginTop + st::settingsBlockTitleTop + st::settingsBlockTitleFont->ascent - st::btnDefLink.font->ascent);
return BlockWidget::resizeGetHeight(newWidth);
} }
int GeneralWidget::resizeGetHeight(int newWidth) { void GeneralWidget::refreshControls() {
int newHeight = contentTop(); style::margins marginSub(0, 0, 0, st::settingsSubSkip);
style::margins marginLarge(0, 0, 0, st::settingsLargeSkip);
style::margins marginSmall(0, 0, 0, st::settingsSmallSkip);
style::margins slidedPadding(0, marginSmall.bottom() / 2, 0, marginSmall.bottom() - (marginSmall.bottom() / 2));
newHeight += st::settingsBlockMarginBottom; #ifndef TDESKTOP_DISABLE_AUTOUPDATE
return newHeight; addChildRow(_updateAutomatically, marginSub, lng_settings_update_automatically(lt_version, currentVersion()), SLOT(onUpdateAutomatically()), cAutoUpdate());
style::margins marginLink(st::defaultCheckbox.textPosition.x(), 0, 0, st::settingsSkip);
addChildRow(_checkForUpdates, marginLink, lang(lng_settings_check_now), SLOT(onCheckForUpdates()));
#endif // TDESKTOP_DISABLE_AUTOUPDATE
if (cPlatform() == dbipWindows || cSupportTray()) {
addChildRow(_enableTrayIcon, marginSmall, lang(lng_settings_workmode_tray), SLOT(onWorkmodeChange()), (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray));
if (cPlatform() == dbipWindows) {
addChildRow(_enableTaskbarIcon, marginLarge, lang(lng_settings_workmode_window), SLOT(onWorkmodeChange()), (cWorkMode() == dbiwmWindowOnly || cWorkMode() == dbiwmWindowAndTray));
addChildRow(_autoStart, marginSmall, lang(lng_settings_auto_start), SLOT(onAutoStart()), cAutoStart());
addChildRow(_startMinimized, marginLarge, slidedPadding, lang(lng_settings_start_min), SLOT(onStartMinimized()), cStartMinimized());
if (!cAutoStart()) {
_startMinimized->hideFast();
}
addChildRow(_addInSendTo, marginSmall, lang(lng_settings_add_sendto), SLOT(onAddInSendTo()), cSendToMenu());
}
}
}
void GeneralWidget::chooseCustomLang() {
auto filter = qsl("Language files (*.strings)");
auto title = qsl("Choose language .strings file");
_chooseLangFileQueryId = FileDialog::queryReadFile(title, filter);
}
void GeneralWidget::notifyFileQueryUpdated(const FileDialog::QueryUpdate &update) {
if (_chooseLangFileQueryId != update.queryId) {
return;
}
_chooseLangFileQueryId = 0;
if (update.filePaths.isEmpty()) {
return;
}
_testLanguage = QFileInfo(update.filePaths.front()).absoluteFilePath();
LangLoaderPlain loader(_testLanguage, LangLoaderRequest(lng_sure_save_language, lng_cancel, lng_box_ok));
if (loader.errors().isEmpty()) {
LangLoaderResult result = loader.found();
QString text = result.value(lng_sure_save_language, langOriginal(lng_sure_save_language)),
save = result.value(lng_box_ok, langOriginal(lng_box_ok)),
cancel = result.value(lng_cancel, langOriginal(lng_cancel));
auto box = new ConfirmBox(text, save, st::defaultBoxButton, cancel);
connect(box, SIGNAL(confirmed()), this, SLOT(onSaveTestLanguage()));
Ui::showLayer(box);
} else {
Ui::showLayer(new InformBox("Custom lang failed :(\n\nError: " + loader.errors()));
}
}
void GeneralWidget::onChangeLanguage() {
if ((_changeLanguage->clickModifiers() & Qt::ShiftModifier) && (_changeLanguage->clickModifiers() & Qt::AltModifier)) {
chooseCustomLang();
} else {
Ui::showLayer(new LanguageBox());
}
}
void GeneralWidget::onSaveTestLanguage() {
cSetLangFile(_testLanguage);
cSetLang(languageTest);
Local::writeSettings();
cSetRestarting(true);
App::quit();
}
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
void GeneralWidget::onUpdateAutomatically() {
}
void GeneralWidget::onCheckForUpdates() {
}
#endif // TDESKTOP_DISABLE_AUTOUPDATE
void GeneralWidget::onEnableTrayIcon() {
if ((!_enableTrayIcon->checked() || cPlatform() != dbipWindows) && !_enableTaskbarIcon->checked()) {
_enableTaskbarIcon->setChecked(true);
} else {
updateWorkmode();
}
}
void GeneralWidget::onEnableTaskbarIcon() {
if (!_enableTrayIcon->checked() && !_enableTaskbarIcon->checked()) {
_enableTrayIcon->setChecked(true);
} else {
updateWorkmode();
}
}
void GeneralWidget::updateWorkmode() {
DBIWorkMode newMode = (_enableTrayIcon->checked() && _enableTaskbarIcon->checked()) ? dbiwmWindowAndTray : (_enableTrayIcon->checked() ? dbiwmTrayOnly : dbiwmWindowOnly);
if (cWorkMode() != newMode && (newMode == dbiwmWindowAndTray || newMode == dbiwmTrayOnly)) {
cSetSeenTrayTooltip(false);
}
cSetWorkMode(newMode);
App::wnd()->psUpdateWorkmode();
Local::writeSettings();
}
void GeneralWidget::onAutoStart() {
cSetAutoStart(_autoStart->checked());
if (cAutoStart()) {
psAutoStart(true);
_startMinimized->slideDown();
Local::writeSettings();
} else {
psAutoStart(false);
if (_startMinimized->entity()->checked()) {
_startMinimized->entity()->setChecked(false);
} else {
Local::writeSettings();
}
_startMinimized->slideUp();
}
}
void GeneralWidget::onStartMinimized() {
cSetStartMinimized(_startMinimized->entity()->checked());
Local::writeSettings();
}
void GeneralWidget::onAddInSendTo() {
cSetSendToMenu(_addInSendTo->checked());
psSendToMenu(_addInSendTo->checked());
Local::writeSettings();
} }
} // namespace Settings } // namespace Settings

View file

@ -21,19 +21,62 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once #pragma once
#include "settings/settings_block_widget.h" #include "settings/settings_block_widget.h"
#include "ui/filedialog.h"
class Checkbox;
class LinkButton;
namespace Ui {
template <typename Widget>
class WidgetSlideWrap;
} // namespace Ui
namespace Settings { namespace Settings {
class GeneralWidget : public BlockWidget { class GeneralWidget : public BlockWidget {
Q_OBJECT
public: public:
GeneralWidget(QWidget *parent, UserData *self); GeneralWidget(QWidget *parent, UserData *self);
protected: protected:
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override; int resizeGetHeight(int newWidth) override;
private slots:
void onChangeLanguage();
void onSaveTestLanguage();
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
void onUpdateAutomatically();
void onCheckForUpdates();
#endif // TDESKTOP_DISABLE_AUTOUPDATE
void onEnableTrayIcon();
void onEnableTaskbarIcon();
void onAutoStart();
void onStartMinimized();
void onAddInSendTo();
private: private:
void refreshControls(); void refreshControls();
void updateWorkmode();
void chooseCustomLang();
void notifyFileQueryUpdated(const FileDialog::QueryUpdate &update);
ChildWidget<LinkButton> _changeLanguage;
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
ChildWidget<Checkbox> _updateAutomatically = { nullptr };
ChildWidget<LinkButton> _checkForUpdates = { nullptr };
#endif // TDESKTOP_DISABLE_AUTOUPDATE
ChildWidget<Checkbox> _enableTrayIcon = { nullptr };
ChildWidget<Checkbox> _enableTaskbarIcon = { nullptr };
ChildWidget<Checkbox> _autoStart = { nullptr };
ChildWidget<Ui::WidgetSlideWrap<Checkbox>> _startMinimized = { nullptr };
ChildWidget<Checkbox> _addInSendTo = { nullptr };
FileDialog::QueryId _chooseLangFileQueryId = 0;
QString _testLanguage;
}; };

View file

@ -23,21 +23,182 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "styles/style_settings.h" #include "styles/style_settings.h"
#include "lang.h" #include "lang.h"
#include "ui/flatlabel.h"
#include "ui/widgets/widget_slide_wrap.h"
#include "boxes/usernamebox.h"
#include "observer_peer.h"
namespace Settings { namespace Settings {
using UpdateFlag = Notify::PeerUpdate::Flag;
InfoWidget::InfoWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_info)) { InfoWidget::InfoWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_info)) {
auto observeEvents = UpdateFlag::UsernameChanged | UpdateFlag::UserPhoneChanged;
Notify::registerPeerObserver(observeEvents, this, &InfoWidget::notifyPeerUpdated);
createControls();
}
void InfoWidget::createControls() {
style::margins margin(0, -st::settingsBlockOneLineTextPart.margin.top(), 0, st::settingsSmallSkip - st::settingsBlockOneLineTextPart.margin.bottom());
style::margins slidedPadding(0, st::settingsSmallSkip / 2, 0, st::settingsSmallSkip - (st::settingsSmallSkip / 2));
addChildRow(_mobileNumber, margin, slidedPadding);
addChildRow(_username, margin, slidedPadding);
addChildRow(_link, margin, slidedPadding);
refreshControls(); refreshControls();
} }
void InfoWidget::refreshControls() { void InfoWidget::refreshControls() {
refreshMobileNumber();
refreshUsername();
refreshLink();
} }
int InfoWidget::resizeGetHeight(int newWidth) { void InfoWidget::refreshMobileNumber() {
int newHeight = contentTop(); TextWithEntities phoneText;
if (auto user = self()->asUser()) {
if (!user->phone().isEmpty()) {
phoneText.text = App::formatPhone(user->phone());
} else {
phoneText.text = App::phoneFromSharedContact(peerToUser(user->id));
}
}
setLabeledText(_mobileNumber, lang(lng_profile_mobile_number), phoneText, TextWithEntities(), lang(lng_profile_copy_phone));
}
newHeight += st::settingsBlockMarginBottom; void InfoWidget::refreshUsername() {
return newHeight; TextWithEntities usernameText;
QString copyText;
if (self()->username.isEmpty()) {
usernameText.text = lang(lng_settings_choose_username);
} else {
usernameText.text = '@' + self()->username;
copyText = lang(lng_context_copy_mention);
}
usernameText.entities.push_back(EntityInText(EntityInTextCustomUrl, 0, usernameText.text.size()));
setLabeledText(_username, lang(lng_profile_username), usernameText, TextWithEntities(), copyText);
if (auto text = _username->entity()->textLabel()) {
text->setClickHandlerHook(func(this, &InfoWidget::usernameClickHandlerHook));
}
}
void InfoWidget::refreshLink() {
TextWithEntities linkText;
TextWithEntities linkTextShort;
if (!self()->username.isEmpty()) {
linkText.text = qsl("https://telegram.me/") + self()->username;
linkText.entities.push_back(EntityInText(EntityInTextUrl, 0, linkText.text.size()));
linkTextShort.text = qsl("telegram.me/") + self()->username;
linkTextShort.entities.push_back(EntityInText(EntityInTextCustomUrl, 0, linkTextShort.text.size(), qsl("https://telegram.me/") + self()->username));
}
setLabeledText(_link, lang(lng_profile_link), linkText, linkTextShort, QString());
if (auto text = _link->entity()->textLabel()) {
text->setClickHandlerHook(func(this, &InfoWidget::usernameClickHandlerHook));
}
if (auto shortText = _link->entity()->shortTextLabel()) {
shortText->setExpandLinksMode(ExpandLinksUrlOnly);
shortText->setClickHandlerHook(func(this, &InfoWidget::usernameClickHandlerHook));
}
}
bool InfoWidget::usernameClickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button) {
Ui::showLayer(new UsernameBox());
return false;
}
InfoWidget::LabeledWidget::LabeledWidget(QWidget *parent) : TWidget(parent) {
resize(width(), st::labelDefFlat.font->height);
}
void InfoWidget::setLabeledText(ChildWidget<LabeledWrap> &row, const QString &label, const TextWithEntities &textWithEntities, const TextWithEntities &shortTextWithEntities, const QString &copyText) {
if (textWithEntities.text.isEmpty()) {
row->slideUp();
} else {
row->entity()->setLabeledText(label, textWithEntities, shortTextWithEntities, copyText);
row->slideDown();
}
}
void InfoWidget::LabeledWidget::setLabeledText(const QString &label, const TextWithEntities &textWithEntities, const TextWithEntities &shortTextWithEntities, const QString &copyText) {
_label.destroy();
_text.destroy();
_shortText.destroy();
if (textWithEntities.text.isEmpty()) return;
_label = new FlatLabel(this, label, FlatLabel::InitType::Simple, st::settingsBlockLabel);
_label->show();
setLabelText(_text, textWithEntities, copyText);
setLabelText(_shortText, shortTextWithEntities, copyText);
}
void InfoWidget::LabeledWidget::setLabelText(ChildWidget<FlatLabel> &text, const TextWithEntities &textWithEntities, const QString &copyText) {
text.destroy();
if (textWithEntities.text.isEmpty()) return;
text = new FlatLabel(this, QString(), FlatLabel::InitType::Simple, st::settingsBlockOneLineTextPart);
text->show();
text->setMarkedText(textWithEntities);
text->setContextCopyText(copyText);
text->setSelectable(true);
text->setDoubleClickSelectsParagraph(true);
}
void InfoWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) {
if (update.peer != self()) {
return;
}
if (update.flags & UpdateFlag::UsernameChanged) {
refreshUsername();
refreshLink();
}
if (update.flags & (UpdateFlag::UserPhoneChanged)) {
refreshMobileNumber();
}
contentSizeUpdated();
}
int InfoWidget::LabeledWidget::naturalWidth() const {
if (!_text) return -1;
return _label->naturalWidth() + st::normalFont->spacew + (_shortText ? _shortText : _text)->naturalWidth();
}
int InfoWidget::LabeledWidget::resizeGetHeight(int newWidth) {
int marginLeft = st::settingsBlockOneLineTextPart.margin.left();
int marginRight = st::settingsBlockOneLineTextPart.margin.right();
if (!_label) return 0;
_label->moveToLeft(0, st::settingsBlockOneLineTextPart.margin.top());
auto labelNatural = _label->naturalWidth();
t_assert(labelNatural >= 0);
_label->resize(qMin(newWidth, labelNatural), _label->height());
int textLeft = _label->width() + st::normalFont->spacew;
int textWidth = _text->naturalWidth();
int availableWidth = newWidth - textLeft;
bool doesNotFit = (textWidth > availableWidth);
accumulate_min(textWidth, availableWidth);
accumulate_min(textWidth, st::msgMaxWidth);
if (textWidth + marginLeft + marginRight < 0) {
textWidth = -(marginLeft + marginRight);
}
_text->resizeToWidth(textWidth + marginLeft + marginRight);
_text->moveToLeft(textLeft - marginLeft, 0);
if (_shortText) {
_shortText->resizeToWidth(textWidth + marginLeft + marginRight);
_shortText->moveToLeft(textLeft - marginLeft, 0);
if (doesNotFit) {
_shortText->show();
_text->hide();
} else {
_shortText->hide();
_text->show();
}
}
return st::settingsBlockOneLineTextPart.margin.top() + _label->height() + st::settingsBlockOneLineTextPart.margin.bottom();
} }
} // namespace Settings } // namespace Settings

View file

@ -34,30 +34,51 @@ class InfoWidget : public BlockWidget {
public: public:
InfoWidget(QWidget *parent, UserData *self); InfoWidget(QWidget *parent, UserData *self);
protected:
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override;
private: private:
// Observed notifications. // Observed notifications.
void notifyPeerUpdated(const Notify::PeerUpdate &update); void notifyPeerUpdated(const Notify::PeerUpdate &update);
bool usernameClickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button);
void createControls();
void refreshControls(); void refreshControls();
void refreshMobileNumber(); void refreshMobileNumber();
void refreshUsername(); void refreshUsername();
void refreshLink(); void refreshLink();
// labelWidget may be nullptr. class LabeledWidget : public TWidget {
void setLabeledText(ChildWidget<FlatLabel> *labelWidget, const QString &label, public:
ChildWidget<FlatLabel> *textWidget, const TextWithEntities &textWithEntities, const QString &copyText); LabeledWidget(QWidget *parent);
ChildWidget<FlatLabel> _mobileNumberLabel = { nullptr }; void setLabeledText(const QString &label, const TextWithEntities &textWithEntities, const TextWithEntities &shortTextWithEntities, const QString &copyText);
ChildWidget<FlatLabel> _mobileNumber = { nullptr };
ChildWidget<FlatLabel> _usernameLabel = { nullptr }; FlatLabel *textLabel() {
ChildWidget<FlatLabel> _username = { nullptr }; return _text;
ChildWidget<FlatLabel> _linkLabel = { nullptr }; }
ChildWidget<FlatLabel> _link = { nullptr }; FlatLabel *shortTextLabel() {
ChildWidget<FlatLabel> _linkShort = { nullptr }; return _shortText;
}
int naturalWidth() const override;
protected:
int resizeGetHeight(int newWidth) override;
private:
void setLabelText(ChildWidget<FlatLabel> &text, const TextWithEntities &textWithEntities, const QString &copyText);
ChildWidget<FlatLabel> _label = { nullptr };
ChildWidget<FlatLabel> _text = { nullptr };
ChildWidget<FlatLabel> _shortText = { nullptr };
};
using LabeledWrap = Ui::WidgetSlideWrap<LabeledWidget>;
void setLabeledText(ChildWidget<LabeledWrap> &row, const QString &label, const TextWithEntities &textWithEntities, const TextWithEntities &shortTextWithEntities, const QString &copyText);
ChildWidget<LabeledWrap> _mobileNumber = { nullptr };
ChildWidget<LabeledWrap> _username = { nullptr };
ChildWidget<LabeledWrap> _link = { nullptr };
}; };

View file

@ -60,6 +60,9 @@ void InnerWidget::refreshBlocks() {
_blocks.push_back(new Settings::PrivacyWidget(this, _self)); _blocks.push_back(new Settings::PrivacyWidget(this, _self));
} }
_blocks.push_back(new Settings::AdvancedWidget(this, _self)); _blocks.push_back(new Settings::AdvancedWidget(this, _self));
for_const (auto block, _blocks) {
connect(block, SIGNAL(heightUpdated()), this, SLOT(onBlockHeightUpdated()));
}
} }
void InnerWidget::showFinished() { void InnerWidget::showFinished() {
@ -68,32 +71,40 @@ void InnerWidget::showFinished() {
} }
} }
void InnerWidget::resizeToWidth(int newWidth, int contentLeft) { int InnerWidget::resizeGetHeight(int newWidth) {
int newHeight = resizeGetHeight(newWidth, contentLeft); if (_cover) {
resize(newWidth, newHeight); _cover->setContentLeft(_contentLeft);
_cover->resizeToWidth(newWidth);
}
for_const (auto block, _blocks) {
block->setContentLeft(_contentLeft);
block->resizeToWidth(newWidth);
}
int result = refreshBlocksPositions();
return result;
} }
int InnerWidget::resizeGetHeight(int newWidth, int contentLeft) { int InnerWidget::refreshBlocksPositions() {
int result = 0; int result = (_cover ? _cover->height() : 0) + st::settingsBlocksTop;
if (_cover) {
_cover->setContentLeft(contentLeft);
_cover->resizeToWidth(newWidth);
result += _cover->height();
}
result += st::settingsBlocksTop;
for_const (auto block, _blocks) { for_const (auto block, _blocks) {
if (block->isHidden()) { if (block->isHidden()) {
continue; continue;
} }
block->moveToLeft(0, result); block->moveToLeft(0, result);
block->setContentLeft(contentLeft);
block->resizeToWidth(newWidth);
result += block->height(); result += block->height();
} }
return result; return result;
} }
void InnerWidget::onBlockHeightUpdated() {
int newHeight = refreshBlocksPositions();
if (newHeight != height()) {
resize(width(), newHeight);
}
}
void InnerWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) { void InnerWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) {
_visibleTop = visibleTop; _visibleTop = visibleTop;
_visibleBottom = visibleBottom; _visibleBottom = visibleBottom;

View file

@ -26,28 +26,42 @@ class CoverWidget;
class BlockWidget; class BlockWidget;
class InnerWidget : public TWidget { class InnerWidget : public TWidget {
Q_OBJECT
public: public:
InnerWidget(QWidget *parent); InnerWidget(QWidget *parent);
// Count new height for width=newWidth and resize to it. // Count new height for width=newWidth and resize to it.
void resizeToWidth(int newWidth, int contentLeft); void resizeToWidth(int newWidth, int contentLeft) {
_contentLeft = contentLeft;
return TWidget::resizeToWidth(newWidth);
}
// Updates the area that is visible inside the scroll container. // Updates the area that is visible inside the scroll container.
void setVisibleTopBottom(int visibleTop, int visibleBottom); void setVisibleTopBottom(int visibleTop, int visibleBottom);
void showFinished(); void showFinished();
private slots:
void onBlockHeightUpdated();
protected:
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override;
private: private:
void refreshBlocks(); void refreshBlocks();
// Resizes content and counts natural widget height for the desired width. // Returns the new height value.
int resizeGetHeight(int newWidth, int contentLeft); int refreshBlocksPositions();
ChildWidget<CoverWidget> _cover = { nullptr }; ChildWidget<CoverWidget> _cover = { nullptr };
QList<BlockWidget*> _blocks; QList<BlockWidget*> _blocks;
UserData *_self = nullptr; UserData *_self = nullptr;
int _contentLeft = 0;
int _visibleTop = 0; int _visibleTop = 0;
int _visibleBottom = 0; int _visibleBottom = 0;

View file

@ -23,21 +23,105 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "styles/style_settings.h" #include "styles/style_settings.h"
#include "lang.h" #include "lang.h"
#include "localstorage.h"
#include "ui/widgets/widget_slide_wrap.h"
#include "ui/flatcheckbox.h"
#include "mainwindow.h"
namespace Settings { namespace Settings {
NotificationsWidget::NotificationsWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_notify)) { NotificationsWidget::NotificationsWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_notify)) {
refreshControls(); createControls();
} }
void NotificationsWidget::refreshControls() { void NotificationsWidget::createControls() {
style::margins margin(0, 0, 0, st::settingsSmallSkip);
style::margins slidedPadding(0, margin.bottom() / 2, 0, margin.bottom() - (margin.bottom() / 2));
addChildRow(_desktopNotifications, margin, lang(lng_settings_desktop_notify), SLOT(onDesktopNotifications()), cDesktopNotify());
addChildRow(_showSenderName, margin, slidedPadding, lang(lng_settings_show_name), SLOT(onShowSenderName()), cNotifyView() <= dbinvShowName);
addChildRow(_showMessagePreview, margin, slidedPadding, lang(lng_settings_show_preview), SLOT(onShowMessagePreview()), cNotifyView() <= dbinvShowPreview);
if (!_showSenderName->entity()->checked()) {
_showMessagePreview->hideFast();
}
if (!_desktopNotifications->checked()) {
_showSenderName->hideFast();
_showMessagePreview->hideFast();
}
#ifdef Q_OS_WIN
if (App::wnd()->psHasNativeNotifications()) {
addChildRow(_windowsNative, margin, lang(lng_settings_use_windows), SLOT(onWindowsNative()), cWindowsNotifications());
}
#endif // Q_OS_WIN
addChildRow(_playSound, margin, lang(lng_settings_sound_notify), SLOT(onPlaySound()), cSoundNotify());
addChildRow(_includeMuted, margin, lang(lng_settings_include_muted), SLOT(onIncludeMuted()), cIncludeMuted());
} }
int NotificationsWidget::resizeGetHeight(int newWidth) { void NotificationsWidget::onDesktopNotifications() {
int newHeight = contentTop(); cSetDesktopNotify(_desktopNotifications->checked());
Local::writeUserSettings();
if (App::wnd()) App::wnd()->updateTrayMenu();
newHeight += st::settingsBlockMarginBottom; if (_desktopNotifications->checked()) {
return newHeight; _showSenderName->slideDown();
if (_showSenderName->entity()->checked()) {
_showMessagePreview->slideDown();
}
} else {
App::wnd()->notifyClear();
_showSenderName->slideUp();
_showMessagePreview->slideUp();
}
}
void NotificationsWidget::onShowSenderName() {
if (_showSenderName->entity()->checked()) {
_showMessagePreview->slideDown();
} else {
_showMessagePreview->slideUp();
}
if (!_showSenderName->entity()->checked()) {
cSetNotifyView(dbinvShowNothing);
} else if (!_showMessagePreview->entity()->checked()) {
cSetNotifyView(dbinvShowName);
} else {
cSetNotifyView(dbinvShowPreview);
}
Local::writeUserSettings();
App::wnd()->notifyUpdateAll();
}
void NotificationsWidget::onShowMessagePreview() {
if (_showMessagePreview->entity()->checked()) {
cSetNotifyView(dbinvShowPreview);
} else if (_showSenderName->entity()->checked()) {
cSetNotifyView(dbinvShowName);
} else {
cSetNotifyView(dbinvShowNothing);
}
Local::writeUserSettings();
App::wnd()->notifyUpdateAll();
}
#ifdef Q_OS_WIN
void NotificationsWidget::onWindowsNative() {
if (cPlatform() != dbipWindows) return;
cSetWindowsNotifications(!cWindowsNotifications());
App::wnd()->notifyClearFast();
cSetCustomNotifies(!cWindowsNotifications());
Local::writeUserSettings();
}
#endif // Q_OS_WIN
void NotificationsWidget::onPlaySound() {
cSetSoundNotify(_playSound->checked());
Local::writeUserSettings();
}
void NotificationsWidget::onIncludeMuted() {
cSetIncludeMuted(_includeMuted->checked());
Notify::unreadCounterUpdated();
Local::writeUserSettings();
} }
} // namespace Settings } // namespace Settings

View file

@ -25,15 +25,30 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
namespace Settings { namespace Settings {
class NotificationsWidget : public BlockWidget { class NotificationsWidget : public BlockWidget {
Q_OBJECT
public: public:
NotificationsWidget(QWidget *parent, UserData *self); NotificationsWidget(QWidget *parent, UserData *self);
protected: private slots:
// Resizes content and counts natural widget height for the desired width. void onDesktopNotifications();
int resizeGetHeight(int newWidth) override; void onShowSenderName();
void onShowMessagePreview();
#ifdef Q_OS_WIN
void onWindowsNative();
#endif // Q_OS_WIN
void onPlaySound();
void onIncludeMuted();
private: private:
void refreshControls(); void createControls();
ChildWidget<Checkbox> _desktopNotifications = { nullptr };
ChildWidget<Ui::WidgetSlideWrap<Checkbox>> _showSenderName = { nullptr };
ChildWidget<Ui::WidgetSlideWrap<Checkbox>> _showMessagePreview = { nullptr };
ChildWidget<Checkbox> _windowsNative = { nullptr };
ChildWidget<Checkbox> _playSound = { nullptr };
ChildWidget<Checkbox> _includeMuted = { nullptr };
}; };

View file

@ -31,13 +31,25 @@ PrivacyWidget::PrivacyWidget(QWidget *parent, UserData *self) : BlockWidget(pare
} }
void PrivacyWidget::refreshControls() { void PrivacyWidget::refreshControls() {
style::margins marginSmall(0, 0, 0, st::settingsSmallSkip);
style::margins marginSkip(0, 0, 0, st::settingsSkip);
style::margins slidedPadding(0, marginSmall.bottom() / 2, 0, marginSmall.bottom() - (marginSmall.bottom() / 2));
addChildRow(_editPasscode, marginSmall, lang(lng_passcode_turn_on), SLOT(onEditPasscode()));
addChildRow(_editPassword, marginSmall, lang(lng_cloud_password_set), SLOT(onEditPassword()));
addChildRow(_showAllSessions, marginSmall, lang(lng_settings_show_sessions), SLOT(onShowSessions()));
} }
int PrivacyWidget::resizeGetHeight(int newWidth) { void PrivacyWidget::onEditPasscode() {
int newHeight = contentTop();
}
void PrivacyWidget::onEditPassword() {
}
void PrivacyWidget::onShowSessions() {
newHeight += st::settingsBlockMarginBottom;
return newHeight;
} }
} // namespace Settings } // namespace Settings

View file

@ -25,16 +25,23 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
namespace Settings { namespace Settings {
class PrivacyWidget : public BlockWidget { class PrivacyWidget : public BlockWidget {
Q_OBJECT
public: public:
PrivacyWidget(QWidget *parent, UserData *self); PrivacyWidget(QWidget *parent, UserData *self);
protected: private slots:
// Resizes content and counts natural widget height for the desired width. void onEditPasscode();
int resizeGetHeight(int newWidth) override; void onEditPassword();
void onShowSessions();
private: private:
void refreshControls(); void refreshControls();
ChildWidget<LinkButton> _editPasscode = { nullptr };
ChildWidget<LinkButton> _editPassword = { nullptr };
ChildWidget<LinkButton> _showAllSessions = { nullptr };
}; };
} // namespace Settings } // namespace Settings

View file

@ -23,21 +23,244 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "styles/style_settings.h" #include "styles/style_settings.h"
#include "lang.h" #include "lang.h"
#include "localstorage.h"
#include "mainwindow.h"
#include "boxes/confirmbox.h"
#include "application.h"
namespace Settings { namespace Settings {
namespace {
QString scaleLabel(DBIScale scale) {
switch (scale) {
case dbisOne: return qsl("100%");
case dbisOneAndQuarter: return qsl("125%");
case dbisOneAndHalf: return qsl("150%");
case dbisTwo: return qsl("200%");
}
return QString();
}
} // namespace
Slider::Slider(QWidget *parent) : TWidget(parent)
, _a_left(animation(this, &Slider::step_left)) {
setCursor(style::cur_pointer);
}
void Slider::setActiveSection(int index) {
setSelectedSection(index);
if (_activeIndex != index) {
_activeIndex = index;
emit sectionActivated();
}
}
void Slider::setActiveSectionFast(int index) {
setActiveSection(index);
a_left.finish();
_a_left.stop();
update();
}
void Slider::addSection(const QString &label) {
auto section = Section(label);
_sections.push_back(section);
}
void Slider::resizeSections(int newWidth) {
auto count = _sections.size();
if (!count) return;
auto skips = count - 1;
auto sectionsWidth = newWidth - skips * st::settingsSliderSkip;
auto sectionWidth = sectionsWidth / float64(count);
auto x = 0.;
for (int i = 0; i != count; ++i) {
auto &section = _sections[i];
auto skip = i * st::settingsSliderThickness;
section.left = qFloor(x) + skip;
x += sectionWidth;
section.width = qRound(x) - (section.left - skip);
}
a_left = anim::ivalue(_sections[_activeIndex].left, _sections[_activeIndex].left);
_a_left.stop();
}
void Slider::mousePressEvent(QMouseEvent *e) {
setSelectedSection(getIndexFromPosition(e->pos()));
_pressed = true;
}
void Slider::mouseMoveEvent(QMouseEvent *e) {
if (!_pressed) return;
setSelectedSection(getIndexFromPosition(e->pos()));
}
void Slider::mouseReleaseEvent(QMouseEvent *e) {
if (!_pressed) return;
_pressed = false;
setActiveSection(getIndexFromPosition(e->pos()));
}
void Slider::setSelectedSection(int index) {
if (index < 0) return;
if (_selected != index) {
_selected = index;
a_left.start(_sections[_selected].left);
_a_left.start();
}
}
void Slider::paintEvent(QPaintEvent *e) {
Painter p(this);
int activeLeft = a_left.current();
p.setFont(st::settingsSliderLabelFont);
p.setPen(st::settingsSliderLabelFg);
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::settingsSliderTop, fill, st::settingsSliderThickness), st::settingsSliderInactiveFg);
from += fill;
tofill -= fill;
}
if (activeLeft + section.width > from) {
if (auto fill = qMin(tofill, activeLeft + section.width - from)) {
p.fillRect(myrtlrect(from, st::settingsSliderTop, fill, st::settingsSliderThickness), st::settingsSliderActiveFg);
from += fill;
tofill -= fill;
}
}
if (tofill) {
p.fillRect(myrtlrect(from, st::settingsSliderTop, tofill, st::settingsSliderThickness), st::settingsSliderInactiveFg);
}
p.drawTextLeft(section.left + (section.width - section.labelWidth) / 2, st::settingsSliderLabelTop, width(), section.label, section.labelWidth);
}
}
int Slider::resizeGetHeight(int newWidth) {
resizeSections(newWidth);
return st::settingsSliderHeight;
}
int Slider::getIndexFromPosition(QPoint pos) {
int count = _sections.size();
for (int i = 0; i != count; ++i) {
if (_sections[i].left + _sections[i].width > pos.x()) {
return i;
}
}
return count - 1;
}
void Slider::step_left(float64 ms, bool timer) {
auto dt = ms / st::settingsSliderDuration;
if (dt >= 1) {
a_left.finish();
_a_left.stop();
} else {
a_left.update(dt, anim::linear);
}
if (timer) {
update();
}
}
Slider::Section::Section(const QString &label)
: label(label)
, labelWidth(st::settingsSliderLabelFont->width(label)) {
}
ScaleWidget::ScaleWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_scale)) { ScaleWidget::ScaleWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_scale)) {
refreshControls(); createControls();
} }
void ScaleWidget::refreshControls() { 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(_scale, style::margins(0, 0, 0, 0));
_scale->addSection(scaleLabel(dbisOne));
_scale->addSection(scaleLabel(dbisOneAndQuarter));
_scale->addSection(scaleLabel(dbisOneAndHalf));
_scale->addSection(scaleLabel(dbisTwo));
_scale->setActiveSectionFast(cEvalScale(cConfigScale()) - 1);
connect(_scale, SIGNAL(sectionActivated()), this, SLOT(onSectionActivated()));
} }
int ScaleWidget::resizeGetHeight(int newWidth) { void ScaleWidget::onAutoChosen() {
int newHeight = contentTop(); auto newScale = _auto->checked() ? dbisAuto : cEvalScale(cConfigScale());
if (newScale == cScreenScale()) {
if (newScale != cScale()) {
newScale = cScale();
} else {
switch (newScale) {
case dbisOne: newScale = dbisOneAndQuarter; break;
case dbisOneAndQuarter: newScale = dbisOne; break;
case dbisOneAndHalf: newScale = dbisOneAndQuarter; break;
case dbisTwo: newScale = dbisOneAndHalf; break;
}
}
}
setScale(newScale);
}
newHeight += st::settingsBlockMarginBottom; void ScaleWidget::setScale(DBIScale newScale) {
return newHeight; if (cConfigScale() == newScale) return;
cSetConfigScale(newScale);
Local::writeSettings();
App::wnd()->getTitle()->showUpdateBtn();
if (newScale == dbisAuto && !_auto->checked()) {
_auto->setChecked(true);
} else if (newScale != dbisAuto && _auto->checked()) {
_auto->setChecked(false);
}
if (newScale == dbisAuto) newScale = cScreenScale();
if (_scale->activeSection() != newScale - 1) {
_scale->setActiveSection(newScale - 1);
}
if (cEvalScale(cConfigScale()) != cEvalScale(cRealScale())) {
auto box = new ConfirmBox(lang(lng_settings_need_restart), lang(lng_settings_restart_now), st::defaultBoxButton, lang(lng_settings_restart_later));
connect(box, SIGNAL(confirmed()), this, SLOT(onRestartNow()));
Ui::showLayer(box);
}
}
void ScaleWidget::onSectionActivated() {
auto newScale = dbisAuto;
switch (_scale->activeSection()) {
case 0: newScale = dbisOne; break;
case 1: newScale = dbisOneAndQuarter; break;
case 2: newScale = dbisOneAndHalf; break;
case 3: newScale = dbisTwo; break;
}
if (newScale == cScreenScale()) {
newScale = dbisAuto;
}
setScale(newScale);
}
void ScaleWidget::onRestartNow() {
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
bool updateReady = (Sandbox::updatingState() == Application::UpdatingReady);
#else
bool updateReady = false;
#endif
if (updateReady) {
cSetRestartingUpdate(true);
} else {
cSetRestarting(true);
cSetRestartingToSettings(true);
}
App::quit();
} }
} // namespace Settings } // namespace Settings

View file

@ -22,18 +22,74 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "settings/settings_block_widget.h" #include "settings/settings_block_widget.h"
class Checkbox;
namespace Settings { namespace Settings {
class Slider : public TWidget {
Q_OBJECT
public:
Slider(QWidget *parent);
int activeSection() const {
return _activeIndex;
}
void setActiveSection(int index);
void setActiveSectionFast(int index);
void addSection(const QString &label);
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;
signals:
void sectionActivated();
private:
void resizeSections(int newWidth);
int getIndexFromPosition(QPoint pos);
void setSelectedSection(int index);
void step_left(float64 ms, bool timer);
struct Section {
Section(const QString &label);
int left, width;
QString label;
int labelWidth;
};
QList<Section> _sections;
int _activeIndex = 0;
bool _pressed = false;
int _selected = 0;
anim::ivalue a_left = { 0 };
Animation _a_left;
};
class ScaleWidget : public BlockWidget { class ScaleWidget : public BlockWidget {
Q_OBJECT
public: public:
ScaleWidget(QWidget *parent, UserData *self); ScaleWidget(QWidget *parent, UserData *self);
protected: private slots:
// Resizes content and counts natural widget height for the desired width. void onAutoChosen();
int resizeGetHeight(int newWidth) override; void onSectionActivated();
void onRestartNow();
private: private:
void refreshControls(); void createControls();
void setScale(DBIScale newScale);
ChildWidget<Checkbox> _auto = { nullptr };
ChildWidget<Slider> _scale = { nullptr };
}; };

View file

@ -137,7 +137,7 @@ SettingsInner::SettingsInner(SettingsWidget *parent) : TWidget(parent)
// general // general
, _changeLanguage(this, lang(lng_settings_change_lang)) , _changeLanguage(this, lang(lng_settings_change_lang))
#ifndef TDESKTOP_DISABLE_AUTOUPDATE #ifndef TDESKTOP_DISABLE_AUTOUPDATE
, _autoUpdate(this, lang(lng_settings_auto_update), cAutoUpdate()) , _autoUpdate(this, QString(), cAutoUpdate())
, _checkNow(this, lang(lng_settings_check_now)) , _checkNow(this, lang(lng_settings_check_now))
, _restartNow(this, lang(lng_settings_update_now)) , _restartNow(this, lang(lng_settings_update_now))
#endif #endif
@ -672,7 +672,7 @@ void SettingsInner::paintEvent(QPaintEvent *e) {
// advanced // advanced
p.setFont(st::setHeaderFont->f); p.setFont(st::setHeaderFont->f);
p.setPen(st::setHeaderColor->p); p.setPen(st::setHeaderColor->p);
p.drawText(_left + st::setHeaderLeft, top + st::setHeaderTop + st::setHeaderFont->ascent, lang(lng_settings_section_advanced)); p.drawText(_left + st::setHeaderLeft, top + st::setHeaderTop + st::setHeaderFont->ascent, lang(lng_settings_section_advanced_settings));
top += st::setHeaderSkip; top += st::setHeaderSkip;
p.setFont(st::linkFont->f); p.setFont(st::linkFont->f);

View file

@ -42,13 +42,13 @@ void LeftOutlineButton::setText(const QString &text) {
update(); update();
} }
void LeftOutlineButton::resizeToWidth(int newWidth) { int LeftOutlineButton::resizeGetHeight(int newWidth) {
int availableWidth = qMax(newWidth - _st.padding.left() - _st.padding.right(), 1); int availableWidth = qMax(newWidth - _st.padding.left() - _st.padding.right(), 1);
if ((availableWidth < _fullTextWidth) || (_textWidth < availableWidth)) { if ((availableWidth < _fullTextWidth) || (_textWidth < availableWidth)) {
_text = _st.font->elided(_fullText, availableWidth); _text = _st.font->elided(_fullText, availableWidth);
_textWidth = _st.font->width(_text); _textWidth = _st.font->width(_text);
} }
resize(newWidth, _st.padding.top() + _st.font->height + _st.padding.bottom()); return _st.padding.top() + _st.font->height + _st.padding.bottom();
} }
void LeftOutlineButton::paintEvent(QPaintEvent *e) { void LeftOutlineButton::paintEvent(QPaintEvent *e) {

View file

@ -28,7 +28,6 @@ class LeftOutlineButton : public Button {
public: public:
LeftOutlineButton(QWidget *parent, const QString &text, const style::OutlineButton &st = st::defaultLeftOutlineButton); LeftOutlineButton(QWidget *parent, const QString &text, const style::OutlineButton &st = st::defaultLeftOutlineButton);
void resizeToWidth(int newWidth);
void setText(const QString &text); void setText(const QString &text);
protected: protected:
@ -36,6 +35,8 @@ protected:
void onStateChanged(int oldState, ButtonStateChangeSource source) override; void onStateChanged(int oldState, ButtonStateChangeSource source) override;
int resizeGetHeight(int newWidth) override;
private: private:
QString _text, _fullText; QString _text, _fullText;
int _textWidth, _fullTextWidth; int _textWidth, _fullTextWidth;

View file

@ -127,6 +127,10 @@ LinkButton::LinkButton(QWidget *parent, const QString &text, const style::linkBu
setCursor(style::cur_pointer); setCursor(style::cur_pointer);
} }
int LinkButton::naturalWidth() const {
return _st.font->width(_text);
}
void LinkButton::paintEvent(QPaintEvent *e) { void LinkButton::paintEvent(QPaintEvent *e) {
QPainter p(this); QPainter p(this);
p.setFont(((_state & StateOver) ? _st.overFont : _st.font)->f); p.setFont(((_state & StateOver) ? _st.overFont : _st.font)->f);

View file

@ -66,23 +66,24 @@ class LinkButton : public Button {
Q_OBJECT Q_OBJECT
public: public:
LinkButton(QWidget *parent, const QString &text, const style::linkButton &st = st::btnDefLink); LinkButton(QWidget *parent, const QString &text, const style::linkButton &st = st::btnDefLink);
void paintEvent(QPaintEvent *e); int naturalWidth() const override;
void setText(const QString &text); void setText(const QString &text);
~LinkButton(); ~LinkButton();
public slots: protected:
void paintEvent(QPaintEvent *e) override;
public slots:
void onStateChange(int oldState, ButtonStateChangeSource source); void onStateChange(int oldState, ButtonStateChangeSource source);
private: private:
QString _text; QString _text;
style::linkButton _st; style::linkButton _st;
}; };
class IconedButton : public Button { class IconedButton : public Button {

View file

@ -310,6 +310,10 @@ void Checkbox::step_checked(float64 ms, bool timer) {
if (timer) update(_checkRect); if (timer) update(_checkRect);
} }
int Checkbox::naturalWidth() const {
return _st.textPosition.x() + _st.font->width(_fullText);
}
void Checkbox::paintEvent(QPaintEvent *e) { void Checkbox::paintEvent(QPaintEvent *e) {
Painter p(this); Painter p(this);

View file

@ -98,7 +98,10 @@ public:
void finishAnimations(); void finishAnimations();
void paintEvent(QPaintEvent *e); int naturalWidth() const override;
protected:
void paintEvent(QPaintEvent *e) override;
public slots: public slots:
void onClicked(); void onClicked();

View file

@ -112,11 +112,13 @@ void FlatLabel::setBreakEverywhere(bool breakEverywhere) {
_breakEverywhere = breakEverywhere; _breakEverywhere = breakEverywhere;
} }
void FlatLabel::resizeToWidth(int32 width) { int FlatLabel::resizeGetHeight(int newWidth) {
_allowedWidth = newWidth;
textstyleSet(&_tst); textstyleSet(&_tst);
_allowedWidth = width; int textWidth = countTextWidth();
refreshSize(); int textHeight = countTextHeight(textWidth);
textstyleRestore(); textstyleRestore();
return _st.margin.top() + textHeight + _st.margin.bottom();
} }
int FlatLabel::naturalWidth() const { int FlatLabel::naturalWidth() const {

View file

@ -43,8 +43,7 @@ public:
void setExpandLinksMode(ExpandLinksMode mode); void setExpandLinksMode(ExpandLinksMode mode);
void setBreakEverywhere(bool breakEverywhere); void setBreakEverywhere(bool breakEverywhere);
void resizeToWidth(int32 width); int naturalWidth() const override;
int naturalWidth() const;
void setLink(uint16 lnkIndex, const ClickHandlerPtr &lnk); void setLink(uint16 lnkIndex, const ClickHandlerPtr &lnk);
@ -70,6 +69,8 @@ protected:
bool event(QEvent *e) override; // calls touchEvent when necessary bool event(QEvent *e) override; // calls touchEvent when necessary
void touchEvent(QTouchEvent *e); void touchEvent(QTouchEvent *e);
int resizeGetHeight(int newWidth) override;
private slots: private slots:
void onCopySelectedText(); void onCopySelectedText();
void onCopyContextText(); void onCopyContextText();

View file

@ -276,21 +276,10 @@ public:
ScrolledWidget(QWidget *parent = nullptr) : TWidget(parent) { ScrolledWidget(QWidget *parent = nullptr) : TWidget(parent) {
} }
// Count new height for width=newWidth and resize to it.
void resizeToWidth(int newWidth) {
resize(newWidth, resizeGetHeight(newWidth));
}
// Updates the area that is visible inside the scroll container. // Updates the area that is visible inside the scroll container.
virtual void setVisibleTopBottom(int visibleTop, int visibleBottom) { virtual void setVisibleTopBottom(int visibleTop, int visibleBottom) {
} }
protected:
// Resizes content and counts natural widget height for the desired width.
virtual int resizeGetHeight(int newWidth) {
return height();
}
signals: signals:
void heightUpdated(); void heightUpdated();

View file

@ -206,7 +206,19 @@ public:
return QPointer<const TWidget>(this); return QPointer<const TWidget>(this);
} }
virtual ~TWidget() { // Get the size of the widget as it should be.
// Negative return value means no default width.
virtual int naturalWidth() const {
return -1;
}
// Count new height for width=newWidth and resize to it.
void resizeToWidth(int newWidth) {
auto newSize = QSize(newWidth, resizeGetHeight(newWidth));
if (newSize != size()) {
resize(newSize);
update();
}
} }
protected: protected:
@ -217,6 +229,11 @@ protected:
return QWidget::leaveEvent(e); return QWidget::leaveEvent(e);
} }
// Resizes content and counts natural widget height for the desired width.
virtual int resizeGetHeight(int newWidth) {
return height();
}
}; };
void myEnsureResized(QWidget *target); void myEnsureResized(QWidget *target);

View file

@ -0,0 +1,164 @@
/*
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 "styles/style_widgets.h"
namespace Ui {
template <typename Widget>
class WidgetSlideWrap : public TWidget {
public:
WidgetSlideWrap(QWidget *parent, Widget *entity
, style::margins entityPadding
, base::lambda_unique<void()> &&updateCallback
, int duration = st::widgetSlideDuration) : TWidget(parent)
, _entity(entity)
, _padding(entityPadding)
, _duration(duration)
, _updateCallback(std_::move(updateCallback))
, _a_height(animation(this, &WidgetSlideWrap<Widget>::step_height)) {
entity->setParent(this);
entity->moveToLeft(_padding.left(), _padding.top());
_realSize = entity->rect().marginsAdded(_padding).size();
entity->installEventFilter(this);
resize(_realSize);
}
bool eventFilter(QObject *object, QEvent *event) {
if (object == _entity && event->type() == QEvent::Resize) {
_realSize = _entity->rect().marginsAdded(_padding).size();
if (!_inResizeToWidth) {
resize(_realSize.width(), (_forceHeight >= 0) ? _forceHeight : _realSize.height());
if (_updateCallback) {
_updateCallback();
}
}
}
return TWidget::eventFilter(object, event);
}
void slideUp() {
if (isHidden()) {
_forceHeight = 0;
resize(_realSize.width(), _forceHeight);
if (_updateCallback) _updateCallback();
return;
}
if (_a_height.animating()) {
if (_hiding) return;
} else {
a_height = anim::ivalue(_realSize.height());
}
a_height.start(0);
_hiding = true;
_a_height.start();
}
void slideDown() {
if (isHidden()) {
show();
}
if (_forceHeight < 0) {
return;
}
if (_a_height.animating()) {
if (!_hiding) return;
}
a_height.start(_realSize.height());
_forceHeight = a_height.current();
_hiding = false;
_a_height.start();
}
void showFast() {
_a_height.stop();
resize(_realSize);
if (_updateCallback) {
_updateCallback();
}
}
void hideFast() {
_a_height.stop();
a_height = anim::ivalue(0);
_forceHeight = 0;
resize(_realSize.width(), 0);
hide();
if (_updateCallback) {
_updateCallback();
}
}
Widget *entity() {
return _entity;
}
const Widget *entity() const {
return _entity;
}
int naturalWidth() const override {
return _padding.top() + _entity->naturalWidth() + _padding.bottom();
}
protected:
int resizeGetHeight(int newWidth) override {
_inResizeToWidth = true;
_entity->resizeToWidth(newWidth - _padding.left() - _padding.right());
_inResizeToWidth = false;
return (_forceHeight >= 0) ? _forceHeight : _realSize.height();
}
private:
void step_height(float64 ms, bool timer) {
auto dt = ms / _duration;
if (dt >= 1) {
a_height.finish();
_a_height.stop();
_forceHeight = _hiding ? 0 : -1;
if (_hiding) hide();
} else {
a_height.update(dt, anim::linear);
_forceHeight = a_height.current();
}
resize(_realSize.width(), (_forceHeight >= 0) ? _forceHeight : _realSize.height());
if (_updateCallback) {
_updateCallback();
}
}
Widget *_entity;
bool _inResizeToWidth = false;
style::margins _padding;
int _duration;
base::lambda_unique<void()> _updateCallback;
style::size _realSize;
int _forceHeight = -1;
anim::ivalue a_height;
Animation _a_height;
bool _hiding = false;
};
} // namespace Ui

View file

@ -32,3 +32,5 @@ defaultLabelSimple: LabelSimple {
maxWidth: 0px; maxWidth: 0px;
textFg: windowTextFg; textFg: windowTextFg;
} }
widgetSlideDuration: 200;

View file

@ -2,5 +2,5 @@ AppVersion 10002
AppVersionStrMajor 0.10 AppVersionStrMajor 0.10
AppVersionStrSmall 0.10.2 AppVersionStrSmall 0.10.2
AppVersionStr 0.10.2 AppVersionStr 0.10.2
AlphaChannel 1 AlphaChannel 0
BetaVersion 0 BetaVersion 10002001

View file

@ -394,6 +394,7 @@
'<(src_loc)/ui/toast/toast_widget.h', '<(src_loc)/ui/toast/toast_widget.h',
'<(src_loc)/ui/widgets/label_simple.cpp', '<(src_loc)/ui/widgets/label_simple.cpp',
'<(src_loc)/ui/widgets/label_simple.h', '<(src_loc)/ui/widgets/label_simple.h',
'<(src_loc)/ui/widgets/widget_slide_wrap.h',
'<(src_loc)/ui/animation.cpp', '<(src_loc)/ui/animation.cpp',
'<(src_loc)/ui/animation.h', '<(src_loc)/ui/animation.h',
'<(src_loc)/ui/boxshadow.cpp', '<(src_loc)/ui/boxshadow.cpp',