diff --git a/Telegram/SourceFiles/boxes/addcontactbox.cpp b/Telegram/SourceFiles/boxes/addcontactbox.cpp index 6abd3c3b5..78d9c1274 100644 --- a/Telegram/SourceFiles/boxes/addcontactbox.cpp +++ b/Telegram/SourceFiles/boxes/addcontactbox.cpp @@ -197,7 +197,7 @@ void AddContactBox::onImportDone(const MTPcontacts_ImportedContacts &res) { auto &v = d.vimported.v; UserData *user = nullptr; if (!v.isEmpty()) { - const auto &c(v.front().c_importedContact()); + auto &c = v.front().c_importedContact(); if (c.vclient_id.v != _contactId) return; user = App::userLoaded(c.vuser_id.v); @@ -419,8 +419,9 @@ void GroupInfoBox::onPhotoReady(const QImage &img) { SetupChannelBox::SetupChannelBox(QWidget*, ChannelData *channel, bool existing) : _channel(channel) , _existing(existing) -, _public(this, qsl("channel_privacy"), 0, lang(channel->isMegagroup() ? lng_create_public_group_title : lng_create_public_channel_title), true, st::defaultBoxCheckbox) -, _private(this, qsl("channel_privacy"), 1, lang(channel->isMegagroup() ? lng_create_private_group_title : lng_create_private_channel_title), false, st::defaultBoxCheckbox) +, _privacyGroup(std::make_shared<Ui::RadioenumGroup<Privacy>>(Privacy::Public)) +, _public(this, _privacyGroup, Privacy::Public, lang(channel->isMegagroup() ? lng_create_public_group_title : lng_create_public_channel_title), st::defaultBoxCheckbox) +, _private(this, _privacyGroup, Privacy::Private, lang(channel->isMegagroup() ? lng_create_private_group_title : lng_create_private_channel_title), st::defaultBoxCheckbox) , _aboutPublicWidth(st::boxWideWidth - st::boxPadding.left() - st::boxButtonPadding.right() - st::newGroupPadding.left() - st::defaultBoxCheckbox.textPosition.x()) , _aboutPublic(st::defaultTextStyle, lang(channel->isMegagroup() ? lng_create_public_group_about : lng_create_public_channel_about), _defaultOptions, _aboutPublicWidth) , _aboutPrivate(st::defaultTextStyle, lang(channel->isMegagroup() ? lng_create_private_group_about : lng_create_private_channel_about), _defaultOptions, _aboutPublicWidth) @@ -438,13 +439,12 @@ void SetupChannelBox::prepare() { addButton(lang(_existing ? lng_cancel : lng_create_group_skip), [this] { closeBox(); }); connect(_link, SIGNAL(changed()), this, SLOT(onChange())); - _link->setVisible(_public->checked()); + _link->setVisible(_privacyGroup->value() == Privacy::Public); _checkTimer.setSingleShot(true); connect(&_checkTimer, SIGNAL(timeout()), this, SLOT(onCheck())); - connect(_public, SIGNAL(changed()), this, SLOT(onPrivacyChange())); - connect(_private, SIGNAL(changed()), this, SLOT(onPrivacyChange())); + _privacyGroup->setChangedCallback([this](Privacy value) { privacyChanged(value); }); updateMaxHeight(); } @@ -459,7 +459,7 @@ void SetupChannelBox::setInnerFocus() { void SetupChannelBox::updateMaxHeight() { auto newHeight = st::boxPadding.top() + st::newGroupPadding.top() + _public->heightNoMargins() + _aboutPublicHeight + st::newGroupSkip + _private->heightNoMargins() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupSkip + st::newGroupPadding.bottom(); - if (!_channel->isMegagroup() || _public->checked()) { + if (!_channel->isMegagroup() || _privacyGroup->value() == Privacy::Public) { newHeight += st::newGroupLinkPadding.top() + _link->height() + st::newGroupLinkPadding.bottom(); } setDimensions(st::boxWideWidth, newHeight); @@ -563,7 +563,7 @@ void SetupChannelBox::closeHook() { } void SetupChannelBox::onSave() { - if (!_public->checked()) { + if (_privacyGroup->value() == Privacy::Private) { if (_existing) { _sentUsername = QString(); _saveRequestId = MTP::send(MTPchannels_UpdateUsername(_channel->inputChannel, MTP_string(_sentUsername)), rpcDone(&SetupChannelBox::onUpdateDone), rpcFail(&SetupChannelBox::onUpdateFail)); @@ -633,13 +633,13 @@ void SetupChannelBox::onCheck() { } } -void SetupChannelBox::onPrivacyChange() { - if (_public->checked()) { +void SetupChannelBox::privacyChanged(Privacy value) { + if (value == Privacy::Public) { if (_tooMuchUsernames) { - _private->setChecked(true); + _privacyGroup->setValue(Privacy::Private); Ui::show(Box<RevokePublicLinkBox>(base::lambda_guarded(this, [this] { _tooMuchUsernames = false; - _public->setChecked(true); + _privacyGroup->setValue(Privacy::Public); onCheck(); })), KeepOtherLayers); return; @@ -712,8 +712,7 @@ bool SetupChannelBox::onCheckFail(const RPCError &error) { showRevokePublicLinkBoxForEdit(); } else { _tooMuchUsernames = true; - _private->setChecked(true); - onPrivacyChange(); + _privacyGroup->setValue(Privacy::Private); } return true; } else if (err == qstr("USERNAME_INVALID")) { @@ -750,8 +749,7 @@ bool SetupChannelBox::onFirstCheckFail(const RPCError &error) { showRevokePublicLinkBoxForEdit(); } else { _tooMuchUsernames = true; - _private->setChecked(true); - onPrivacyChange(); + _privacyGroup->setValue(Privacy::Private); } return true; } diff --git a/Telegram/SourceFiles/boxes/addcontactbox.h b/Telegram/SourceFiles/boxes/addcontactbox.h index d002e4084..0fa4976c8 100644 --- a/Telegram/SourceFiles/boxes/addcontactbox.h +++ b/Telegram/SourceFiles/boxes/addcontactbox.h @@ -31,7 +31,10 @@ class PhoneInput; class InputArea; class UsernameInput; class Checkbox; -class Radiobutton; +template <typename Enum> +class RadioenumGroup; +template <typename Enum> +class Radioenum; class LinkButton; class NewAvatarButton; } // namespace Ui @@ -150,9 +153,12 @@ private slots: void onChange(); void onCheck(); - void onPrivacyChange(); - private: + enum class Privacy { + Public, + Private, + }; + void privacyChanged(Privacy value); void updateSelected(const QPoint &cursorGlobalPosition); void onUpdateDone(const MTPBool &result); @@ -169,8 +175,9 @@ private: ChannelData *_channel = nullptr; bool _existing = false; - object_ptr<Ui::Radiobutton> _public; - object_ptr<Ui::Radiobutton> _private; + std::shared_ptr<Ui::RadioenumGroup<Privacy>> _privacyGroup; + object_ptr<Ui::Radioenum<Privacy>> _public; + object_ptr<Ui::Radioenum<Privacy>> _private; int32 _aboutPublicWidth, _aboutPublicHeight; Text _aboutPublic, _aboutPrivate; diff --git a/Telegram/SourceFiles/boxes/autolockbox.cpp b/Telegram/SourceFiles/boxes/autolockbox.cpp index be7b1c558..615fa537d 100644 --- a/Telegram/SourceFiles/boxes/autolockbox.cpp +++ b/Telegram/SourceFiles/boxes/autolockbox.cpp @@ -34,31 +34,27 @@ void AutoLockBox::prepare() { addButton(lang(lng_box_ok), [this] { closeBox(); }); - int opts[] = { 60, 300, 3600, 18000 }, cnt = sizeof(opts) / sizeof(opts[0]); + auto options = { 60, 300, 3600, 18000 }; + + auto group = std::make_shared<Ui::RadiobuttonGroup>(Global::AutoLock()); auto y = st::boxOptionListPadding.top(); - _options.reserve(cnt); - for (auto i = 0; i != cnt; ++i) { - auto v = opts[i]; - _options.push_back(new Ui::Radiobutton(this, qsl("autolock"), v, (v % 3600) ? lng_passcode_autolock_minutes(lt_count, v / 60) : lng_passcode_autolock_hours(lt_count, v / 3600), (Global::AutoLock() == v), st::langsButton)); + auto count = int(options.size()); + _options.reserve(count); + for (auto seconds : options) { + _options.emplace_back(this, group, seconds, (seconds % 3600) ? lng_passcode_autolock_minutes(lt_count, seconds / 60) : lng_passcode_autolock_hours(lt_count, seconds / 3600), st::langsButton); _options.back()->move(st::boxPadding.left() + st::boxOptionListPadding.left(), y); y += _options.back()->heightNoMargins() + st::boxOptionListSkip; - connect(_options.back(), SIGNAL(changed()), this, SLOT(onChange())); } + group->setChangedCallback([this](int value) { durationChanged(value); }); - setDimensions(st::langsWidth, st::boxOptionListPadding.top() + cnt * st::langsButton.height + (cnt - 1) * st::boxOptionListSkip + st::boxOptionListPadding.bottom() + st::boxPadding.bottom()); + setDimensions(st::langsWidth, st::boxOptionListPadding.top() + count * st::langsButton.height + (count - 1) * st::boxOptionListSkip + st::boxOptionListPadding.bottom() + st::boxPadding.bottom()); } -void AutoLockBox::onChange() { - if (!isBoxShown()) return; +void AutoLockBox::durationChanged(int seconds) { + Global::SetAutoLock(seconds); + Local::writeUserSettings(); + Global::RefLocalPasscodeChanged().notify(); - for (int32 i = 0, l = _options.size(); i < l; ++i) { - int32 v = _options[i]->val(); - if (_options[i]->checked()) { - Global::SetAutoLock(v); - Local::writeUserSettings(); - Global::RefLocalPasscodeChanged().notify(); - } - } App::wnd()->checkAutoLock(); closeBox(); } diff --git a/Telegram/SourceFiles/boxes/autolockbox.h b/Telegram/SourceFiles/boxes/autolockbox.h index 23831274d..a772d30d5 100644 --- a/Telegram/SourceFiles/boxes/autolockbox.h +++ b/Telegram/SourceFiles/boxes/autolockbox.h @@ -36,10 +36,9 @@ public: protected: void prepare() override; -private slots: - void onChange(); - private: - QVector<Ui::Radiobutton*> _options; + void durationChanged(int seconds); + + std::vector<object_ptr<Ui::Radiobutton>> _options; }; diff --git a/Telegram/SourceFiles/boxes/connectionbox.cpp b/Telegram/SourceFiles/boxes/connectionbox.cpp index bc86d62c2..8f37c45dd 100644 --- a/Telegram/SourceFiles/boxes/connectionbox.cpp +++ b/Telegram/SourceFiles/boxes/connectionbox.cpp @@ -35,9 +35,10 @@ ConnectionBox::ConnectionBox(QWidget *parent) , _portInput(this, st::connectionPortInputField, lang(lng_connection_port_ph), QString::number(Global::ConnectionProxy().port)) , _userInput(this, st::connectionUserInputField, lang(lng_connection_user_ph), Global::ConnectionProxy().user) , _passwordInput(this, st::connectionPasswordInputField, lang(lng_connection_password_ph), Global::ConnectionProxy().password) -, _autoRadio(this, qsl("conn_type"), dbictAuto, lang(lng_connection_auto_rb), (Global::ConnectionType() == dbictAuto), st::defaultBoxCheckbox) -, _httpProxyRadio(this, qsl("conn_type"), dbictHttpProxy, lang(lng_connection_http_proxy_rb), (Global::ConnectionType() == dbictHttpProxy), st::defaultBoxCheckbox) -, _tcpProxyRadio(this, qsl("conn_type"), dbictTcpProxy, lang(lng_connection_tcp_proxy_rb), (Global::ConnectionType() == dbictTcpProxy), st::defaultBoxCheckbox) +, _typeGroup(std::make_shared<Ui::RadioenumGroup<DBIConnectionType>>(Global::ConnectionType())) +, _autoRadio(this, _typeGroup, dbictAuto, lang(lng_connection_auto_rb), st::defaultBoxCheckbox) +, _httpProxyRadio(this, _typeGroup, dbictHttpProxy, lang(lng_connection_http_proxy_rb), st::defaultBoxCheckbox) +, _tcpProxyRadio(this, _typeGroup, dbictTcpProxy, lang(lng_connection_tcp_proxy_rb), st::defaultBoxCheckbox) , _tryIPv6(this, lang(lng_connection_try_ipv6), Global::TryIPv6(), st::defaultBoxCheckbox) { } @@ -47,9 +48,7 @@ void ConnectionBox::prepare() { addButton(lang(lng_connection_save), [this] { onSave(); }); addButton(lang(lng_cancel), [this] { closeBox(); }); - connect(_autoRadio, SIGNAL(changed()), this, SLOT(onChange())); - connect(_httpProxyRadio, SIGNAL(changed()), this, SLOT(onChange())); - connect(_tcpProxyRadio, SIGNAL(changed()), this, SLOT(onChange())); + _typeGroup->setChangedCallback([this](DBIConnectionType value) { typeChanged(value); }); connect(_hostInput, SIGNAL(submitted(bool)), this, SLOT(onSubmit())); connect(_portInput, SIGNAL(submitted(bool)), this, SLOT(onSubmit())); @@ -61,17 +60,17 @@ void ConnectionBox::prepare() { void ConnectionBox::updateControlsVisibility() { auto newHeight = st::boxOptionListPadding.top() + _autoRadio->heightNoMargins() + st::boxOptionListSkip + _httpProxyRadio->heightNoMargins() + st::boxOptionListSkip + _tcpProxyRadio->heightNoMargins() + st::boxOptionListSkip + st::connectionIPv6Skip + _tryIPv6->heightNoMargins() + st::boxOptionListPadding.bottom() + st::boxPadding.bottom(); - if (_httpProxyRadio->checked() || _tcpProxyRadio->checked()) { + if (_typeGroup->value() == dbictAuto) { + _hostInput->hide(); + _portInput->hide(); + _userInput->hide(); + _passwordInput->hide(); + } else { newHeight += 2 * st::boxOptionInputSkip + 2 * _hostInput->height(); _hostInput->show(); _portInput->show(); _userInput->show(); _passwordInput->show(); - } else { - _hostInput->hide(); - _portInput->hide(); - _userInput->hide(); - _passwordInput->hide(); } setDimensions(st::boxWidth, newHeight); @@ -93,16 +92,17 @@ void ConnectionBox::resizeEvent(QResizeEvent *e) { } void ConnectionBox::updateControlsPosition() { + auto type = _typeGroup->value(); _autoRadio->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), st::boxOptionListPadding.top()); _httpProxyRadio->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), _autoRadio->bottomNoMargins() + st::boxOptionListSkip); - int32 inputy = 0; - if (_httpProxyRadio->checked()) { + auto inputy = 0; + if (type == dbictHttpProxy) { inputy = _httpProxyRadio->bottomNoMargins() + st::boxOptionInputSkip; _tcpProxyRadio->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), inputy + st::boxOptionInputSkip + 2 * _hostInput->height() + st::boxOptionListSkip); } else { _tcpProxyRadio->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), _httpProxyRadio->bottomNoMargins() + st::boxOptionListSkip); - if (_tcpProxyRadio->checked()) { + if (type == dbictTcpProxy) { inputy = _tcpProxyRadio->bottomNoMargins() + st::boxOptionInputSkip; } } @@ -114,17 +114,17 @@ void ConnectionBox::updateControlsPosition() { _passwordInput->moveToRight(st::boxPadding.right(), _userInput->y()); } - auto tryipv6y = (_tcpProxyRadio->checked() ? _userInput->bottomNoMargins() : _tcpProxyRadio->bottomNoMargins()) + st::boxOptionListSkip + st::connectionIPv6Skip; + auto tryipv6y = ((type == dbictTcpProxy) ? _userInput->bottomNoMargins() : _tcpProxyRadio->bottomNoMargins()) + st::boxOptionListSkip + st::connectionIPv6Skip; _tryIPv6->moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), tryipv6y); } -void ConnectionBox::onChange() { +void ConnectionBox::typeChanged(DBIConnectionType type) { updateControlsVisibility(); - if (_httpProxyRadio->checked() || _tcpProxyRadio->checked()) { + if (type != dbictAuto) { if (!_hostInput->hasFocus() && !_portInput->hasFocus() && !_userInput->hasFocus() && !_passwordInput->hasFocus()) { _hostInput->setFocusFast(); } - if (_httpProxyRadio->checked() && !_portInput->getLastText().toInt()) { + if ((type == dbictHttpProxy) && !_portInput->getLastText().toInt()) { _portInput->setText(qsl("80")); _portInput->finishAnimations(); } @@ -161,7 +161,15 @@ void ConnectionBox::onSubmit() { } void ConnectionBox::onSave() { - if (_httpProxyRadio->checked() || _tcpProxyRadio->checked()) { + auto type = _typeGroup->value(); + if (type == dbictAuto) { + Global::SetConnectionType(type); + Global::SetConnectionProxy(ProxyData()); +#ifndef TDESKTOP_DISABLE_NETWORK_PROXY + QNetworkProxyFactory::setUseSystemConfiguration(false); + QNetworkProxyFactory::setUseSystemConfiguration(true); +#endif // !TDESKTOP_DISABLE_NETWORK_PROXY + } else { ProxyData p; p.host = _hostInput->getLastText().trimmed(); p.user = _userInput->getLastText().trimmed(); @@ -174,19 +182,8 @@ void ConnectionBox::onSave() { _portInput->setFocus(); return; } - if (_httpProxyRadio->checked()) { - Global::SetConnectionType(dbictHttpProxy); - } else { - Global::SetConnectionType(dbictTcpProxy); - } + Global::SetConnectionType(type); Global::SetConnectionProxy(p); - } else { - Global::SetConnectionType(dbictAuto); - Global::SetConnectionProxy(ProxyData()); -#ifndef TDESKTOP_DISABLE_NETWORK_PROXY - QNetworkProxyFactory::setUseSystemConfiguration(false); - QNetworkProxyFactory::setUseSystemConfiguration(true); -#endif // !TDESKTOP_DISABLE_NETWORK_PROXY } if (cPlatform() == dbipWindows && Global::TryIPv6() != _tryIPv6->checked()) { Global::SetTryIPv6(_tryIPv6->checked()); diff --git a/Telegram/SourceFiles/boxes/connectionbox.h b/Telegram/SourceFiles/boxes/connectionbox.h index 4d486ed02..5ef85ded3 100644 --- a/Telegram/SourceFiles/boxes/connectionbox.h +++ b/Telegram/SourceFiles/boxes/connectionbox.h @@ -27,7 +27,10 @@ class InputField; class PortInput; class PasswordInput; class Checkbox; -class Radiobutton; +template <typename Enum> +class RadioenumGroup; +template <typename Enum> +class Radioenum; } // namespace Ui class ConnectionBox : public BoxContent { @@ -43,11 +46,11 @@ protected: void resizeEvent(QResizeEvent *e) override; private slots: - void onChange(); void onSubmit(); void onSave(); private: + void typeChanged(DBIConnectionType type); void updateControlsVisibility(); void updateControlsPosition(); @@ -55,9 +58,10 @@ private: object_ptr<Ui::PortInput> _portInput; object_ptr<Ui::InputField> _userInput; object_ptr<Ui::PasswordInput> _passwordInput; - object_ptr<Ui::Radiobutton> _autoRadio; - object_ptr<Ui::Radiobutton> _httpProxyRadio; - object_ptr<Ui::Radiobutton> _tcpProxyRadio; + std::shared_ptr<Ui::RadioenumGroup<DBIConnectionType>> _typeGroup; + object_ptr<Ui::Radioenum<DBIConnectionType>> _autoRadio; + object_ptr<Ui::Radioenum<DBIConnectionType>> _httpProxyRadio; + object_ptr<Ui::Radioenum<DBIConnectionType>> _tcpProxyRadio; object_ptr<Ui::Checkbox> _tryIPv6; }; diff --git a/Telegram/SourceFiles/boxes/downloadpathbox.cpp b/Telegram/SourceFiles/boxes/downloadpathbox.cpp index 6aa99f5c0..157a50c51 100644 --- a/Telegram/SourceFiles/boxes/downloadpathbox.cpp +++ b/Telegram/SourceFiles/boxes/downloadpathbox.cpp @@ -31,9 +31,10 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org DownloadPathBox::DownloadPathBox(QWidget *parent) : _path(Global::DownloadPath()) , _pathBookmark(Global::DownloadPathBookmark()) -, _default(this, qsl("dir_type"), 0, lang(lng_download_path_default_radio), _path.isEmpty(), st::defaultBoxCheckbox) -, _temp(this, qsl("dir_type"), 1, lang(lng_download_path_temp_radio), (_path == qsl("tmp")), st::defaultBoxCheckbox) -, _dir(this, qsl("dir_type"), 2, lang(lng_download_path_dir_radio), (!_path.isEmpty() && _path != qsl("tmp")), st::defaultBoxCheckbox) +, _group(std::make_shared<Ui::RadioenumGroup<Directory>>(typeFromPath(_path))) +, _default(this, _group, Directory::Downloads, lang(lng_download_path_default_radio), st::defaultBoxCheckbox) +, _temp(this, _group, Directory::Temp, lang(lng_download_path_temp_radio), st::defaultBoxCheckbox) +, _dir(this, _group, Directory::Custom, lang(lng_download_path_dir_radio), st::defaultBoxCheckbox) , _pathLink(this, QString(), st::boxLinkButton) { } @@ -43,9 +44,7 @@ void DownloadPathBox::prepare() { setTitle(lang(lng_download_path_header)); - connect(_default, SIGNAL(changed()), this, SLOT(onChange())); - connect(_temp, SIGNAL(changed()), this, SLOT(onChange())); - connect(_dir, SIGNAL(changed()), this, SLOT(onChange())); + _group->setChangedCallback([this](Directory value) { radioChanged(value); }); connect(_pathLink, SIGNAL(clicked()), this, SLOT(onEditPath())); if (!_path.isEmpty() && _path != qsl("tmp")) { @@ -55,10 +54,11 @@ void DownloadPathBox::prepare() { } void DownloadPathBox::updateControlsVisibility() { - _pathLink->setVisible(_dir->checked()); + auto custom = (_group->value() == Directory::Custom); + _pathLink->setVisible(custom); auto newHeight = st::boxOptionListPadding.top() + _default->heightNoMargins() + st::boxOptionListSkip + _temp->heightNoMargins() + st::boxOptionListSkip + _dir->heightNoMargins(); - if (_dir->checked()) { + if (custom) { newHeight += st::downloadPathSkip + _pathLink->height(); } newHeight += st::boxOptionListPadding.bottom(); @@ -78,18 +78,15 @@ void DownloadPathBox::resizeEvent(QResizeEvent *e) { _pathLink->moveToLeft(inputx, inputy); } -void DownloadPathBox::onChange() { - if (_dir->checked()) { +void DownloadPathBox::radioChanged(Directory value) { + if (value == Directory::Custom) { if (_path.isEmpty() || _path == qsl("tmp")) { - (_path.isEmpty() ? _default : _temp)->setChecked(true); + _group->setValue(_path.isEmpty() ? Directory::Downloads : Directory::Temp); onEditPath(); - if (!_path.isEmpty() && _path != qsl("tmp")) { - _dir->setChecked(true); - } } else { setPathText(QDir::toNativeSeparators(_path)); } - } else if (_temp->checked()) { + } else if (value == Directory::Temp) { _path = qsl("tmp"); } else { _path = QString(); @@ -110,14 +107,24 @@ void DownloadPathBox::onEditPath() { _path = result + '/'; _pathBookmark = psDownloadPathBookmark(_path); setPathText(QDir::toNativeSeparators(_path)); + _group->setValue(Directory::Custom); } })); } void DownloadPathBox::save() { #ifndef OS_WIN_STORE - Global::SetDownloadPath(_default->checked() ? QString() : (_temp->checked() ? qsl("tmp") : _path)); - Global::SetDownloadPathBookmark((_default->checked() || _temp->checked()) ? QByteArray() : _pathBookmark); + auto value = _group->value(); + auto computePath = [this, value] { + if (value == Directory::Custom) { + return _path; + } else if (value == Directory::Temp) { + return qsl("tmp"); + } + return QString(); + }; + Global::SetDownloadPath(computePath()); + Global::SetDownloadPathBookmark((value == Directory::Custom) ? _pathBookmark : QByteArray()); Local::writeUserSettings(); Global::RefDownloadPathChanged().notify(); closeBox(); diff --git a/Telegram/SourceFiles/boxes/downloadpathbox.h b/Telegram/SourceFiles/boxes/downloadpathbox.h index 7fc954d6b..98b3b1cfa 100644 --- a/Telegram/SourceFiles/boxes/downloadpathbox.h +++ b/Telegram/SourceFiles/boxes/downloadpathbox.h @@ -24,7 +24,10 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "core/observer.h" namespace Ui { -class Radiobutton; +template <typename Enum> +class RadioenumGroup; +template <typename Enum> +class Radioenum; class LinkButton; } // namespace Ui @@ -40,10 +43,24 @@ protected: void resizeEvent(QResizeEvent *e) override; private slots: - void onChange(); void onEditPath(); private: + enum class Directory { + Downloads, + Temp, + Custom, + }; + void radioChanged(Directory value); + Directory typeFromPath(const QString &path) { + if (path.isEmpty()) { + return Directory::Downloads; + } else if (path == qsl("tmp")) { + return Directory::Temp; + } + return Directory::Custom; + } + void save(); void updateControlsVisibility(); void setPathText(const QString &text); @@ -51,9 +68,10 @@ private: QString _path; QByteArray _pathBookmark; - object_ptr<Ui::Radiobutton> _default; - object_ptr<Ui::Radiobutton> _temp; - object_ptr<Ui::Radiobutton> _dir; + std::shared_ptr<Ui::RadioenumGroup<Directory>> _group; + object_ptr<Ui::Radioenum<Directory>> _default; + object_ptr<Ui::Radioenum<Directory>> _temp; + object_ptr<Ui::Radioenum<Directory>> _dir; object_ptr<Ui::LinkButton> _pathLink; }; diff --git a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp index 8a25c347d..63aa3007e 100644 --- a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp @@ -90,7 +90,7 @@ std::unique_ptr<PrivacyExceptionsBoxController::Row> PrivacyExceptionsBoxControl class EditPrivacyBox::OptionWidget : public TWidget { public: - OptionWidget(QWidget *parent, const std::shared_ptr<Ui::RadiobuttonGroup> &group, int value, const QString &text, const QString &description); + OptionWidget(QWidget *parent, const std::shared_ptr<Ui::RadioenumGroup<Option>> &group, Option value, const QString &text, const QString &description); QMargins getMargins() const override { return _option->getMargins(); @@ -100,12 +100,12 @@ protected: int resizeGetHeight(int newWidth) override; private: - object_ptr<Ui::Radiobutton> _option; + object_ptr<Ui::Radioenum<Option>> _option; object_ptr<Ui::FlatLabel> _description; }; -EditPrivacyBox::OptionWidget::OptionWidget(QWidget *parent, const std::shared_ptr<Ui::RadiobuttonGroup> &group, int value, const QString &text, const QString &description) : TWidget(parent) +EditPrivacyBox::OptionWidget::OptionWidget(QWidget *parent, const std::shared_ptr<Ui::RadioenumGroup<Option>> &group, Option value, const QString &text, const QString &description) : TWidget(parent) , _option(this, group, value, text, st::defaultBoxCheckbox) , _description(this, description, Ui::FlatLabel::InitType::Simple, st::editPrivacyLabel) { } @@ -178,15 +178,14 @@ int EditPrivacyBox::resizeGetHeight(int newWidth) { int EditPrivacyBox::countDefaultHeight(int newWidth) { auto height = 0; - auto fakeGroup = std::make_shared<Ui::RadiobuttonGroup>(0); + auto fakeGroup = std::make_shared<Ui::RadioenumGroup<Option>>(Option::Everyone); auto optionHeight = [this, newWidth, &fakeGroup](Option option, const QString &label) { auto description = _controller->optionDescription(option); if (description.isEmpty()) { return 0; } - auto value = static_cast<int>(Option::Everyone); - auto fake = object_ptr<OptionWidget>(nullptr, fakeGroup, value, label, description); + auto fake = object_ptr<OptionWidget>(nullptr, fakeGroup, Option::Everyone, label, description); fake->resizeToNaturalWidth(newWidth - st::editPrivacyOptionMargin.left() - st::editPrivacyOptionMargin.right()); return st::editPrivacyOptionMargin.top() + fake->heightNoMargins() + st::editPrivacyOptionMargin.bottom(); }; @@ -296,20 +295,19 @@ void EditPrivacyBox::createOption(Option option, object_ptr<OptionWidget> &widge auto description = _controller->optionDescription(option); auto selected = (_option == option); if (!description.isEmpty() || selected) { - auto value = static_cast<int>(option); - widget.create(this, _optionGroup, value, label, description); + widget.create(this, _optionGroup, option, label, description); } } void EditPrivacyBox::createWidgets() { _loading.destroy(); - _optionGroup = std::make_shared<Ui::RadiobuttonGroup>(static_cast<int>(_option)); + _optionGroup = std::make_shared<Ui::RadioenumGroup<Option>>(_option); createOption(Option::Everyone, _everyone, lang(lng_edit_privacy_everyone)); createOption(Option::Contacts, _contacts, lang(lng_edit_privacy_contacts)); createOption(Option::Nobody, _nobody, lang(lng_edit_privacy_nobody)); - _optionGroup->setChangedCallback([this](int value) { - _option = static_cast<Option>(value); + _optionGroup->setChangedCallback([this](Option value) { + _option = value; _alwaysLink->toggleAnimated(showExceptionLink(Exception::Always)); _neverLink->toggleAnimated(showExceptionLink(Exception::Never)); }); diff --git a/Telegram/SourceFiles/boxes/edit_privacy_box.h b/Telegram/SourceFiles/boxes/edit_privacy_box.h index 5325e1051..a193053c9 100644 --- a/Telegram/SourceFiles/boxes/edit_privacy_box.h +++ b/Telegram/SourceFiles/boxes/edit_privacy_box.h @@ -25,7 +25,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org namespace Ui { class FlatLabel; class LinkButton; -class RadiobuttonGroup; +template <typename Enum> +class RadioenumGroup; template <typename Widget> class WidgetSlideWrap; } // namespace Ui @@ -104,7 +105,7 @@ private: std::unique_ptr<Controller> _controller; Option _option = Option::Everyone; - std::shared_ptr<Ui::RadiobuttonGroup> _optionGroup; + std::shared_ptr<Ui::RadioenumGroup<Option>> _optionGroup; object_ptr<Ui::FlatLabel> _loading; object_ptr<OptionWidget> _everyone = { nullptr }; object_ptr<OptionWidget> _contacts = { nullptr }; diff --git a/Telegram/SourceFiles/boxes/report_box.cpp b/Telegram/SourceFiles/boxes/report_box.cpp index 048565e79..0733e443c 100644 --- a/Telegram/SourceFiles/boxes/report_box.cpp +++ b/Telegram/SourceFiles/boxes/report_box.cpp @@ -30,11 +30,11 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "mainwindow.h" ReportBox::ReportBox(QWidget*, PeerData *peer) : _peer(peer) -, _reasonGroup(std::make_shared<Ui::RadiobuttonGroup>(ReasonSpam)) -, _reasonSpam(this, _reasonGroup, ReasonSpam, lang(lng_report_reason_spam), st::defaultBoxCheckbox) -, _reasonViolence(this, _reasonGroup, ReasonViolence, lang(lng_report_reason_violence), st::defaultBoxCheckbox) -, _reasonPornography(this, _reasonGroup, ReasonPornography, lang(lng_report_reason_pornography), st::defaultBoxCheckbox) -, _reasonOther(this, _reasonGroup, ReasonOther, lang(lng_report_reason_other), st::defaultBoxCheckbox) { +, _reasonGroup(std::make_shared<Ui::RadioenumGroup<Reason>>(Reason::Spam)) +, _reasonSpam(this, _reasonGroup, Reason::Spam, lang(lng_report_reason_spam), st::defaultBoxCheckbox) +, _reasonViolence(this, _reasonGroup, Reason::Violence, lang(lng_report_reason_violence), st::defaultBoxCheckbox) +, _reasonPornography(this, _reasonGroup, Reason::Pornography, lang(lng_report_reason_pornography), st::defaultBoxCheckbox) +, _reasonOther(this, _reasonGroup, Reason::Other, lang(lng_report_reason_other), st::defaultBoxCheckbox) { } void ReportBox::prepare() { @@ -43,7 +43,7 @@ void ReportBox::prepare() { addButton(lang(lng_report_button), [this] { onReport(); }); addButton(lang(lng_cancel), [this] { closeBox(); }); - _reasonGroup->setChangedCallback([this](int value) { reasonChanged(value); }); + _reasonGroup->setChangedCallback([this](Reason value) { reasonChanged(value); }); updateMaxHeight(); } @@ -61,8 +61,8 @@ void ReportBox::resizeEvent(QResizeEvent *e) { } } -void ReportBox::reasonChanged(int reason) { - if (reason == ReasonOther) { +void ReportBox::reasonChanged(Reason reason) { + if (reason == Reason::Other) { if (!_reasonOtherText) { _reasonOtherText.create(this, st::profileReportReasonOther, lang(lng_report_reason_description)); _reasonOtherText->show(); @@ -105,10 +105,10 @@ void ReportBox::onReport() { auto getReason = [this]() { switch (_reasonGroup->value()) { - case ReasonSpam: return MTP_inputReportReasonSpam(); - case ReasonViolence: return MTP_inputReportReasonViolence(); - case ReasonPornography: return MTP_inputReportReasonPornography(); - case ReasonOther: return MTP_inputReportReasonOther(MTP_string(_reasonOtherText->getLastText())); + case Reason::Spam: return MTP_inputReportReasonSpam(); + case Reason::Violence: return MTP_inputReportReasonViolence(); + case Reason::Pornography: return MTP_inputReportReasonPornography(); + case Reason::Other: return MTP_inputReportReasonOther(MTP_string(_reasonOtherText->getLastText())); } Unexpected("Bad reason group value."); }; diff --git a/Telegram/SourceFiles/boxes/report_box.h b/Telegram/SourceFiles/boxes/report_box.h index 4296af821..701590613 100644 --- a/Telegram/SourceFiles/boxes/report_box.h +++ b/Telegram/SourceFiles/boxes/report_box.h @@ -23,8 +23,10 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "boxes/abstractbox.h" namespace Ui { -class RadiobuttonGroup; -class Radiobutton; +template <typename Enum> +class RadioenumGroup; +template <typename Enum> +class Radioenum; class InputArea; } // namespace Ui @@ -48,7 +50,13 @@ protected: void resizeEvent(QResizeEvent *e) override; private: - void reasonChanged(int reason); + enum class Reason { + Spam, + Violence, + Pornography, + Other, + }; + void reasonChanged(Reason reason); void updateMaxHeight(); void reportDone(const MTPBool &result); @@ -56,19 +64,13 @@ private: PeerData *_peer; - std::shared_ptr<Ui::RadiobuttonGroup> _reasonGroup; - object_ptr<Ui::Radiobutton> _reasonSpam; - object_ptr<Ui::Radiobutton> _reasonViolence; - object_ptr<Ui::Radiobutton> _reasonPornography; - object_ptr<Ui::Radiobutton> _reasonOther; + std::shared_ptr<Ui::RadioenumGroup<Reason>> _reasonGroup; + object_ptr<Ui::Radioenum<Reason>> _reasonSpam; + object_ptr<Ui::Radioenum<Reason>> _reasonViolence; + object_ptr<Ui::Radioenum<Reason>> _reasonPornography; + object_ptr<Ui::Radioenum<Reason>> _reasonOther; object_ptr<Ui::InputArea> _reasonOtherText = { nullptr }; - enum Reason { - ReasonSpam, - ReasonViolence, - ReasonPornography, - ReasonOther, - }; mtpRequestId _requestId = 0; }; diff --git a/Telegram/SourceFiles/settings/settings_block_widget.cpp b/Telegram/SourceFiles/settings/settings_block_widget.cpp index 62f3c9e27..7bc950126 100644 --- a/Telegram/SourceFiles/settings/settings_block_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_block_widget.cpp @@ -90,12 +90,8 @@ void BlockWidget::createChildRow(object_ptr<Ui::Checkbox> &child, style::margins connect(child, SIGNAL(changed()), this, slot); } -void BlockWidget::createChildRow(object_ptr<Ui::Radiobutton> &child, style::margins &margin, const std::shared_ptr<Ui::RadiobuttonGroup> &group, int value, const QString &text) { - child.create(this, group, value, text, st::defaultBoxCheckbox); -} - void BlockWidget::createChildRow(object_ptr<Ui::LinkButton> &child, style::margins &margin, const QString &text, const char *slot, const style::LinkButton &st) { - child .create(this, text, st); + child.create(this, text, st); connect(child, SIGNAL(clicked()), this, slot); } diff --git a/Telegram/SourceFiles/settings/settings_block_widget.h b/Telegram/SourceFiles/settings/settings_block_widget.h index 25c0ef33d..79b6abeab 100644 --- a/Telegram/SourceFiles/settings/settings_block_widget.h +++ b/Telegram/SourceFiles/settings/settings_block_widget.h @@ -28,6 +28,10 @@ class Checkbox; class RadiobuttonGroup; class Radiobutton; class LinkButton; +template <typename Enum> +class RadioenumGroup; +template <typename Enum> +class Radioenum; template <typename Widget> class WidgetSlideWrap; } // namespace Ui @@ -88,27 +92,35 @@ private: margin.setBottom(margin.bottom() - padding.bottom()); } void createChildRow(object_ptr<Ui::Checkbox> &child, style::margins &margin, const QString &text, const char *slot, bool checked); - void createChildRow(object_ptr<Ui::Radiobutton> &child, style::margins &margin, const Ui::RadiobuttonGroup &group, int value, const QString &text); void createChildRow(object_ptr<Ui::LinkButton> &child, style::margins &margin, const QString &text, const char *slot, const style::LinkButton &st = st::boxLinkButton); + template <typename Enum> + void createChildRow(object_ptr<Ui::Radioenum<Enum>> &child, style::margins &margin, const std::shared_ptr<Ui::RadioenumGroup<Enum>> &group, Enum value, const QString &text) { + child.create(this, group, value, text, st::defaultBoxCheckbox); + } + void addCreatedRow(TWidget *child, const style::margins &margin); void rowHeightUpdated(); template <typename Widget> - struct IsWidgetSlideWrap { - static constexpr bool value = false; + struct IsWidgetSlideWrap : std::false_type { }; template <typename Widget> - struct IsWidgetSlideWrap<Ui::WidgetSlideWrap<Widget>> { - static constexpr bool value = true; + struct IsWidgetSlideWrap<Ui::WidgetSlideWrap<Widget>> : std::true_type { + }; + template <typename Widget> + struct IsRadioenum : std::false_type { + }; + template <typename Enum> + struct IsRadioenum<Ui::Radioenum<Enum>> : std::true_type { }; template <typename Widget> using NotImplementedYet = std::enable_if_t< !IsWidgetSlideWrap<Widget>::value && - !std::is_same<Widget, Ui::Checkbox>::value && - !std::is_same<Widget, Ui::Radiobutton>::value && - !std::is_same<Widget, Ui::LinkButton>::value>; + !IsRadioenum<Widget>::value && + !std::is_same<Ui::Checkbox, Widget>::value && + !std::is_same<Ui::LinkButton, Widget>::value>; template <typename Widget, typename... Args, typename = NotImplementedYet<Widget>> void createChildRow(object_ptr<Widget> &child, style::margins &margin, Args&&... args) { diff --git a/Telegram/SourceFiles/settings/settings_chat_settings_widget.cpp b/Telegram/SourceFiles/settings/settings_chat_settings_widget.cpp index 7a3a46463..c02dcef49 100644 --- a/Telegram/SourceFiles/settings/settings_chat_settings_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_chat_settings_widget.cpp @@ -180,10 +180,10 @@ void ChatSettingsWidget::createControls() { } #endif // OS_WIN_STORE - auto group = std::make_shared<Ui::RadiobuttonGroup>(cCtrlEnter() ? 1 : 0); - addChildRow(_sendByEnter, marginSmall, group, 0, lang(lng_settings_send_enter)); - addChildRow(_sendByCtrlEnter, marginSkip, group, 1, lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_settings_send_cmdenter : lng_settings_send_ctrlenter), SLOT(onSendByCtrlEnter()), cCtrlEnter()); - group->setChangedCallback([this](int value) { + auto group = std::make_shared<Ui::RadioenumGroup<SendByType>>(cCtrlEnter() ? SendByType::CtrlEnter : SendByType::Enter); + addChildRow(_sendByEnter, marginSmall, group, SendByType::Enter, lang(lng_settings_send_enter)); + addChildRow(_sendByCtrlEnter, marginSkip, group, SendByType::CtrlEnter, lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_settings_send_cmdenter : lng_settings_send_ctrlenter)); + group->setChangedCallback([this](SendByType value) { sendByChanged(value); }); @@ -210,8 +210,8 @@ void ChatSettingsWidget::onDontAskDownloadPath() { #endif // OS_WIN_STORE } -void ChatSettingsWidget::sendByChanged(int value) { - cSetCtrlEnter(value == 1); +void ChatSettingsWidget::sendByChanged(SendByType value) { + cSetCtrlEnter(value == SendByType::CtrlEnter); if (App::main()) App::main()->ctrlEnterSubmitUpdated(); Local::writeUserSettings(); } diff --git a/Telegram/SourceFiles/settings/settings_chat_settings_widget.h b/Telegram/SourceFiles/settings/settings_chat_settings_widget.h index d5def43dd..33a71a63b 100644 --- a/Telegram/SourceFiles/settings/settings_chat_settings_widget.h +++ b/Telegram/SourceFiles/settings/settings_chat_settings_widget.h @@ -102,7 +102,11 @@ private slots: void onManageStickerSets(); private: - void sendByChanged(int value); + enum class SendByType { + Enter, + CtrlEnter, + }; + void sendByChanged(SendByType value); void createControls(); object_ptr<Ui::Checkbox> _replaceEmoji = { nullptr }; @@ -113,8 +117,8 @@ private: object_ptr<Ui::WidgetSlideWrap<DownloadPathState>> _downloadPath = { nullptr }; #endif // OS_WIN_STORE - object_ptr<Ui::Radiobutton> _sendByEnter = { nullptr }; - object_ptr<Ui::Radiobutton> _sendByCtrlEnter = { nullptr }; + object_ptr<Ui::Radioenum<SendByType>> _sendByEnter = { nullptr }; + object_ptr<Ui::Radioenum<SendByType>> _sendByCtrlEnter = { nullptr }; object_ptr<Ui::LinkButton> _automaticMediaDownloadSettings = { nullptr }; object_ptr<Ui::LinkButton> _manageStickerSets = { nullptr }; diff --git a/Telegram/SourceFiles/ui/widgets/checkbox.h b/Telegram/SourceFiles/ui/widgets/checkbox.h index a4ca803d9..0d90a5fb0 100644 --- a/Telegram/SourceFiles/ui/widgets/checkbox.h +++ b/Telegram/SourceFiles/ui/widgets/checkbox.h @@ -91,6 +91,8 @@ public: } void setValue(int value); +private: + friend class Radiobutton; void registerButton(Radiobutton *button) { if (!base::contains(_buttons, button)) { _buttons.push_back(button); @@ -100,11 +102,6 @@ public: _buttons.erase(std::remove(_buttons.begin(), _buttons.end(), button), _buttons.end()); } -private: - friend class Radiobutton; - void registerButton(Radiobutton *button); - void unregisterButton(Radiobutton *button); - int _value = 0; bool _hasValue = false; base::lambda<void(int value)> _changedCallback; @@ -116,9 +113,6 @@ class Radiobutton : public RippleButton { public: Radiobutton(QWidget *parent, const std::shared_ptr<RadiobuttonGroup> &group, int value, const QString &text, const style::Checkbox &st = st::defaultCheckbox); - RadiobuttonGroup *group() const { - return _group.get(); - } QMargins getMargins() const override { return _st.margin; } @@ -152,4 +146,48 @@ private: }; +template <typename Enum> +class Radioenum; + +template <typename Enum> +class RadioenumGroup { +public: + RadioenumGroup() = default; + RadioenumGroup(Enum value) : _group(static_cast<int>(value)) { + } + + template <typename Callback> + void setChangedCallback(Callback &&callback) { + _group.setChangedCallback([callback](int value) { + callback(static_cast<Enum>(value)); + }); + } + + bool hasValue() const { + return _group.hasValue(); + } + Enum value() const { + return static_cast<Enum>(_group.value()); + } + void setValue(Enum value) { + _group.setValue(static_cast<int>(value)); + } + +private: + template <typename OtherEnum> + friend class Radioenum; + + RadiobuttonGroup _group; + +}; + +template <typename Enum> +class Radioenum : public Radiobutton { +public: + Radioenum(QWidget *parent, const std::shared_ptr<RadioenumGroup<Enum>> &group, Enum value, const QString &text, const style::Checkbox &st = st::defaultCheckbox) + : Radiobutton(parent, std::shared_ptr<RadiobuttonGroup>(group, &group->_group), static_cast<int>(value), text, st) { + } + +}; + } // namespace Ui