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_languages" = "Languages";
"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_check_now" = "Check 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_clear_failed" = "Clear failed :(";
"lng_settings_section_advanced" = "Advanced";
"lng_settings_section_advanced_settings" = "Advanced Settings";
"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_button" = "Terminate";
"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_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";

View file

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

View file

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

View file

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

View file

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

View file

@ -354,7 +354,6 @@ class BotKeyboard : public TWidget, public AbstractTooltipShower, public ClickHa
Q_OBJECT
public:
BotKeyboard();
void paintEvent(QPaintEvent *e) override;
@ -373,7 +372,10 @@ public:
bool forceReply() const;
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 singleUse() const;
@ -390,6 +392,9 @@ public:
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
protected:
int resizeGetHeight(int newWidth) override;
private:
void updateSelected();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -40,8 +40,6 @@ class FixedBar final : public TWidget, public Notify::Observer {
public:
FixedBar(QWidget *parent, PeerData *peer);
void resizeToWidth(int newWidth);
// When animating mode is enabled the content is hidden and the
// whole fixed bar acts like a back button.
void setAnimatingMode(bool enabled);
@ -51,6 +49,7 @@ public:
protected:
void mousePressEvent(QMouseEvent *e) override;
int resizeGetHeight(int newWidth) override;
public slots:
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) {
_visibleTop = visibleTop;
_visibleBottom = visibleBottom;
@ -225,7 +219,10 @@ int InnerWidget::resizeGetHeight(int newWidth) {
refreshBlocksPositions();
update();
return countHeight();
auto naturalHeight = countHeight();
_addedHeight = qMax(_minHeight - naturalHeight, 0);
return naturalHeight + _addedHeight;
}
int InnerWidget::countHeight() const {

View file

@ -35,8 +35,10 @@ public:
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.
void setVisibleTopBottom(int visibleTop, int visibleBottom);
@ -58,12 +60,12 @@ protected:
void paintEvent(QPaintEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override;
private:
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.
int countHeight() const;
@ -92,6 +94,7 @@ private:
// Height that we added to the natural height so that it is allowed
// to scroll down to the desired position.
int _addedHeight = 0;
int _minHeight = 0;
int _visibleTop = 0;
int _visibleBottom = 0;

View file

@ -86,8 +86,9 @@ settingsSecondaryButton: RoundButton(settingsPrimaryButton) {
settingsBlocksTop: 7px;
settingsBlocksBottom: 20px;
settingsBlockMarginTop: 14px;
settingsBlockMarginBottom: 7px;
settingsBlockTitleHeight: 24px;
settingsBlockMarginRight: 10px;
settingsBlockMarginBottom: 16px;
settingsBlockTitleHeight: 31px;
settingsBlockTitleFont: font(14px semibold);
settingsBlockTitleFg: #333333;
settingsBlockTitleTop: 0px;
@ -99,5 +100,20 @@ settingsBlockOneLineTextPart: flatLabel(labelDefFlat) {
margin: margins(5px, 5px, 5px, 5px);
maxHeight: 20px;
}
settingsBlockOneLineSkip: 9px;
settingsBlockOneLineWidthMax: 240px;
settingsSubSkip: 4px;
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 "lang.h"
#include "boxes/connectionbox.h"
#include "boxes/confirmbox.h"
#include "boxes/aboutbox.h"
#include "mainwindow.h"
namespace Settings {
AdvancedWidget::AdvancedWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_advanced)) {
refreshControls();
AdvancedWidget::AdvancedWidget(QWidget *parent, UserData *self) : BlockWidget(parent, self, lang(lng_settings_section_advanced_settings)) {
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) {
int newHeight = contentTop();
void AdvancedWidget::onManageLocalStorage() {
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

View file

@ -21,19 +21,39 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once
#include "settings/settings_block_widget.h"
#include "settings/settings_chat_settings_widget.h"
namespace Settings {
class AdvancedWidget : public BlockWidget {
class AdvancedWidget : public BlockWidget, public RPCSender {
Q_OBJECT
public:
AdvancedWidget(QWidget *parent, UserData *self);
protected:
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override;
private slots:
void onManageLocalStorage();
#ifndef TDESKTOP_DISABLE_NETWORK_PROXY
void onConnectionType();
#endif // TDESKTOP_DISABLE_NETWORK_PROXY
void onAskQuestion();
void onAskQuestionSure();
void onTelegramFAQ();
void onLogOut();
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 "styles/style_settings.h"
#include "ui/flatcheckbox.h"
namespace Settings {
@ -38,6 +39,23 @@ int BlockWidget::contentTop() const {
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) {
Painter p(this);
@ -54,4 +72,31 @@ void BlockWidget::paintTitle(Painter &p) {
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

View file

@ -22,6 +22,14 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "core/observer.h"
class Checkbox;
class Radiobutton;
namespace Ui {
template <typename Widget>
class WidgetSlideWrap;
} // namespace Ui
namespace Settings {
class BlockWidget : public ScrolledWidget, public Notify::Observer, public base::Subscriber {
@ -44,7 +52,7 @@ protected:
int contentTop() const;
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override = 0;
int resizeGetHeight(int newWidth) override;
void contentSizeUpdated() {
resizeToWidth(width());
@ -59,9 +67,62 @@ protected:
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:
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);
struct ChildRow {
TWidget *child;
style::margins margin;
};
QVector<ChildRow> _rows;
int _contentLeft = 0;
UserData *_self;
QString _title;

View file

@ -23,21 +23,122 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "styles/style_settings.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 {
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) {
int newHeight = contentTop();
LabeledLink::LabeledLink(QWidget *parent, const QString &label, const QString &text) : TWidget(parent)
, _label(this, label, FlatLabel::InitType::Simple)
, _link(this, text) {
}
newHeight += st::settingsBlockMarginBottom;
return newHeight;
void LabeledLink::setLink(const QString &text) {
_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

View file

@ -22,18 +22,58 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "settings/settings_block_widget.h"
class FlatLabel;
namespace Settings {
class ChatSettingsWidget : public BlockWidget {
class LabeledLink : public TWidget {
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:
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override;
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) {
resize(newWidth, st::settingsFixedBarHeight);
int FixedBar::resizeGetHeight(int newWidth) {
return st::settingsFixedBarHeight;
}
void FixedBar::resizeEvent(QResizeEvent *e) {

View file

@ -30,12 +30,12 @@ class FixedBar : public TWidget {
public:
FixedBar(QWidget *parent);
void resizeToWidth(int newWidth);
protected:
void resizeEvent(QResizeEvent *e) override;
void paintEvent(QPaintEvent *e) override;
int resizeGetHeight(int newWidth) override;
private:
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 "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 {
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();
}
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) {
int newHeight = contentTop();
void GeneralWidget::refreshControls() {
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;
return newHeight;
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
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

View file

@ -21,19 +21,62 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#pragma once
#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 {
class GeneralWidget : public BlockWidget {
Q_OBJECT
public:
GeneralWidget(QWidget *parent, UserData *self);
protected:
// Resizes content and counts natural widget height for the desired width.
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:
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 "lang.h"
#include "ui/flatlabel.h"
#include "ui/widgets/widget_slide_wrap.h"
#include "boxes/usernamebox.h"
#include "observer_peer.h"
namespace Settings {
using UpdateFlag = Notify::PeerUpdate::Flag;
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();
}
void InfoWidget::refreshControls() {
refreshMobileNumber();
refreshUsername();
refreshLink();
}
int InfoWidget::resizeGetHeight(int newWidth) {
int newHeight = contentTop();
void InfoWidget::refreshMobileNumber() {
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;
return newHeight;
void InfoWidget::refreshUsername() {
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

View file

@ -34,30 +34,51 @@ class InfoWidget : public BlockWidget {
public:
InfoWidget(QWidget *parent, UserData *self);
protected:
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override;
private:
// Observed notifications.
void notifyPeerUpdated(const Notify::PeerUpdate &update);
bool usernameClickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button);
void createControls();
void refreshControls();
void refreshMobileNumber();
void refreshUsername();
void refreshLink();
// labelWidget may be nullptr.
void setLabeledText(ChildWidget<FlatLabel> *labelWidget, const QString &label,
ChildWidget<FlatLabel> *textWidget, const TextWithEntities &textWithEntities, const QString &copyText);
class LabeledWidget : public TWidget {
public:
LabeledWidget(QWidget *parent);
ChildWidget<FlatLabel> _mobileNumberLabel = { nullptr };
ChildWidget<FlatLabel> _mobileNumber = { nullptr };
ChildWidget<FlatLabel> _usernameLabel = { nullptr };
ChildWidget<FlatLabel> _username = { nullptr };
ChildWidget<FlatLabel> _linkLabel = { nullptr };
ChildWidget<FlatLabel> _link = { nullptr };
ChildWidget<FlatLabel> _linkShort = { nullptr };
void setLabeledText(const QString &label, const TextWithEntities &textWithEntities, const TextWithEntities &shortTextWithEntities, const QString &copyText);
FlatLabel *textLabel() {
return _text;
}
FlatLabel *shortTextLabel() {
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::AdvancedWidget(this, _self));
for_const (auto block, _blocks) {
connect(block, SIGNAL(heightUpdated()), this, SLOT(onBlockHeightUpdated()));
}
}
void InnerWidget::showFinished() {
@ -68,32 +71,40 @@ void InnerWidget::showFinished() {
}
}
void InnerWidget::resizeToWidth(int newWidth, int contentLeft) {
int newHeight = resizeGetHeight(newWidth, contentLeft);
resize(newWidth, newHeight);
int InnerWidget::resizeGetHeight(int newWidth) {
if (_cover) {
_cover->setContentLeft(_contentLeft);
_cover->resizeToWidth(newWidth);
}
for_const (auto block, _blocks) {
block->setContentLeft(_contentLeft);
block->resizeToWidth(newWidth);
}
int InnerWidget::resizeGetHeight(int newWidth, int contentLeft) {
int result = 0;
if (_cover) {
_cover->setContentLeft(contentLeft);
_cover->resizeToWidth(newWidth);
result += _cover->height();
int result = refreshBlocksPositions();
return result;
}
result += st::settingsBlocksTop;
int InnerWidget::refreshBlocksPositions() {
int result = (_cover ? _cover->height() : 0) + st::settingsBlocksTop;
for_const (auto block, _blocks) {
if (block->isHidden()) {
continue;
}
block->moveToLeft(0, result);
block->setContentLeft(contentLeft);
block->resizeToWidth(newWidth);
result += block->height();
}
return result;
}
void InnerWidget::onBlockHeightUpdated() {
int newHeight = refreshBlocksPositions();
if (newHeight != height()) {
resize(width(), newHeight);
}
}
void InnerWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) {
_visibleTop = visibleTop;
_visibleBottom = visibleBottom;

View file

@ -26,28 +26,42 @@ class CoverWidget;
class BlockWidget;
class InnerWidget : public TWidget {
Q_OBJECT
public:
InnerWidget(QWidget *parent);
// 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.
void setVisibleTopBottom(int visibleTop, int visibleBottom);
void showFinished();
private slots:
void onBlockHeightUpdated();
protected:
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override;
private:
void refreshBlocks();
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth, int contentLeft);
// Returns the new height value.
int refreshBlocksPositions();
ChildWidget<CoverWidget> _cover = { nullptr };
QList<BlockWidget*> _blocks;
UserData *_self = nullptr;
int _contentLeft = 0;
int _visibleTop = 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 "lang.h"
#include "localstorage.h"
#include "ui/widgets/widget_slide_wrap.h"
#include "ui/flatcheckbox.h"
#include "mainwindow.h"
namespace Settings {
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) {
int newHeight = contentTop();
void NotificationsWidget::onDesktopNotifications() {
cSetDesktopNotify(_desktopNotifications->checked());
Local::writeUserSettings();
if (App::wnd()) App::wnd()->updateTrayMenu();
newHeight += st::settingsBlockMarginBottom;
return newHeight;
if (_desktopNotifications->checked()) {
_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

View file

@ -25,15 +25,30 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
namespace Settings {
class NotificationsWidget : public BlockWidget {
Q_OBJECT
public:
NotificationsWidget(QWidget *parent, UserData *self);
protected:
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override;
private slots:
void onDesktopNotifications();
void onShowSenderName();
void onShowMessagePreview();
#ifdef Q_OS_WIN
void onWindowsNative();
#endif // Q_OS_WIN
void onPlaySound();
void onIncludeMuted();
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() {
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) {
int newHeight = contentTop();
void PrivacyWidget::onEditPasscode() {
}
void PrivacyWidget::onEditPassword() {
}
void PrivacyWidget::onShowSessions() {
newHeight += st::settingsBlockMarginBottom;
return newHeight;
}
} // namespace Settings

View file

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

View file

@ -23,21 +23,244 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "styles/style_settings.h"
#include "lang.h"
#include "localstorage.h"
#include "mainwindow.h"
#include "boxes/confirmbox.h"
#include "application.h"
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)) {
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) {
int newHeight = contentTop();
void ScaleWidget::onAutoChosen() {
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;
return newHeight;
void ScaleWidget::setScale(DBIScale newScale) {
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

View file

@ -22,18 +22,74 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "settings/settings_block_widget.h"
class Checkbox;
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 {
Q_OBJECT
public:
ScaleWidget(QWidget *parent, UserData *self);
protected:
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override;
private slots:
void onAutoChosen();
void onSectionActivated();
void onRestartNow();
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
, _changeLanguage(this, lang(lng_settings_change_lang))
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
, _autoUpdate(this, lang(lng_settings_auto_update), cAutoUpdate())
, _autoUpdate(this, QString(), cAutoUpdate())
, _checkNow(this, lang(lng_settings_check_now))
, _restartNow(this, lang(lng_settings_update_now))
#endif
@ -672,7 +672,7 @@ void SettingsInner::paintEvent(QPaintEvent *e) {
// advanced
p.setFont(st::setHeaderFont->f);
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;
p.setFont(st::linkFont->f);

View file

@ -42,13 +42,13 @@ void LeftOutlineButton::setText(const QString &text) {
update();
}
void LeftOutlineButton::resizeToWidth(int newWidth) {
int LeftOutlineButton::resizeGetHeight(int newWidth) {
int availableWidth = qMax(newWidth - _st.padding.left() - _st.padding.right(), 1);
if ((availableWidth < _fullTextWidth) || (_textWidth < availableWidth)) {
_text = _st.font->elided(_fullText, availableWidth);
_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) {

View file

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

View file

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

View file

@ -66,23 +66,24 @@ class LinkButton : public Button {
Q_OBJECT
public:
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);
~LinkButton();
public slots:
protected:
void paintEvent(QPaintEvent *e) override;
public slots:
void onStateChange(int oldState, ButtonStateChangeSource source);
private:
QString _text;
style::linkButton _st;
};
class IconedButton : public Button {

View file

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

View file

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

View file

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

View file

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

View file

@ -276,21 +276,10 @@ public:
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.
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:
void heightUpdated();

View file

@ -206,7 +206,19 @@ public:
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:
@ -217,6 +229,11 @@ protected:
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);

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;
textFg: windowTextFg;
}
widgetSlideDuration: 200;

View file

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

View file

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