diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 130d096c1..153ff4040 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -324,7 +324,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_settings_bg_use_default" = "Use default color theme"; "lng_settings_bg_from_gallery" = "Choose from gallery"; "lng_settings_bg_from_file" = "Choose from file"; -"lng_settings_bg_edit_theme" = "Edit theme"; +"lng_settings_bg_edit_theme" = "Launch theme editor"; "lng_settings_bg_tile" = "Tile background"; "lng_settings_adaptive_wide" = "Adaptive layout for wide screens"; @@ -334,6 +334,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_settings_local_storage" = "Local storage"; "lng_settings_connection_type" = "Connection type"; "lng_settings_downloading_update" = "Downloading update {progress}..."; +"lng_settings_use_night_mode" = "Use night mode"; "lng_backgrounds_header" = "Choose your new chat background"; "lng_theme_sure_keep" = "Keep this theme?"; diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp index 2d756f898..9962d5bbf 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp @@ -1440,7 +1440,7 @@ void EditPeerInfoBox::prepare() { ) | rpl::start_with_next([this](int height) { setDimensions(st::boxWideWidth, height); }, content->lifetime()); - setInnerWidget(object_ptr<Ui::IgnoreMargins>( + setInnerWidget(object_ptr<Ui::OverrideMargins>( this, std::move(content))); Ui::AttachAsChild(this, std::move(controller)); diff --git a/Telegram/SourceFiles/export/view/export_view_settings.cpp b/Telegram/SourceFiles/export/view/export_view_settings.cpp index 8cc6aa7aa..7a3c8da68 100644 --- a/Telegram/SourceFiles/export/view/export_view_settings.cpp +++ b/Telegram/SourceFiles/export/view/export_view_settings.cpp @@ -93,9 +93,10 @@ void SettingsWidget::setupContent() { const auto scroll = Ui::CreateChild<Ui::ScrollArea>( this, st::boxLayerScroll); - const auto wrap = scroll->setOwnedWidget(object_ptr<Ui::IgnoreMargins>( - scroll, - object_ptr<Ui::VerticalLayout>(scroll))); + const auto wrap = scroll->setOwnedWidget( + object_ptr<Ui::OverrideMargins>( + scroll, + object_ptr<Ui::VerticalLayout>(scroll))); const auto content = static_cast<Ui::VerticalLayout*>(wrap->entity()); const auto buttons = setupButtons(scroll, wrap); diff --git a/Telegram/SourceFiles/settings/settings.style b/Telegram/SourceFiles/settings/settings.style index 2f51ec746..4a27468c3 100644 --- a/Telegram/SourceFiles/settings/settings.style +++ b/Telegram/SourceFiles/settings/settings.style @@ -16,6 +16,9 @@ settingsSectionButton: InfoProfileButton(infoProfileButton) { settingsButton: InfoProfileButton(settingsSectionButton) { padding: margins(28px, 10px, 8px, 8px); } +settingsChatButton: InfoProfileButton(settingsSectionButton) { + padding: margins(22px, 10px, 8px, 8px); +} settingsSectionSkip: infoProfileSkip; settingsButtonRightPosition: point(28px, 10px); settingsButtonRight: FlatLabel(defaultFlatLabel) { @@ -37,7 +40,30 @@ settingsUpdate: InfoProfileButton(infoMainButton, settingsButton) { } settingsUpdateStatePosition: point(28px, 30px); -settingsNotificationsCheckbox: defaultBoxCheckbox; -settingsNotificationsCheckboxPadding: margins(22px, 10px, 10px, 10px); +settingsSendType: defaultBoxCheckbox; +settingsSendTypePadding: margins(22px, 5px, 10px, 5px); +settingsSendTypeSkip: 5px; + +settingsCheckbox: defaultBoxCheckbox; +settingsCheckboxPadding: margins(22px, 10px, 10px, 10px); settingsLink: boxLinkButton; settingsAdvancedNotificationsPadding: margins(22px, 20px, 10px, 10px); +settingsLinkLabel: defaultFlatLabel; + +settingsAskPathPadding: margins(22px, 10px, 10px, 0px); +settingsDownloadPathPadding: margins(22px, 1px, 10px, 0px); + +settingsBackgroundThumb: 76px; +settingsThumbSkip: 16px; +settingsBackgroundTitle: FlatLabel(defaultFlatLabel) { + style: TextStyle(semiboldTextStyle) { + font: font(boxFontSize semibold); + linkFont: font(boxFontSize semibold); + linkFontOver: font(boxFontSize semibold underline); + } + textFg: windowActiveTextFg; +} +settingsBackgroundTitlePadding: margins(22px, 7px, 10px, 9px); +settingsBackgroundPadding: margins(22px, 8px, 10px, 8px); +settingsFromGalleryTop: 2px; +settingsFromFileTop: 14px; diff --git a/Telegram/SourceFiles/settings/settings_chat.cpp b/Telegram/SourceFiles/settings/settings_chat.cpp index 8eddbff24..e98bf379f 100644 --- a/Telegram/SourceFiles/settings/settings_chat.cpp +++ b/Telegram/SourceFiles/settings/settings_chat.cpp @@ -8,12 +8,686 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "settings/settings_chat.h" #include "settings/settings_common.h" -#include "boxes/abstract_box.h" +#include "boxes/connection_box.h" +#include "boxes/stickers_box.h" +#include "boxes/background_box.h" +#include "boxes/download_path_box.h" #include "ui/wrap/vertical_layout.h" +#include "ui/wrap/slide_wrap.h" +#include "ui/widgets/checkbox.h" +#include "ui/widgets/labels.h" +#include "ui/effects/radial_animation.h" #include "lang/lang_keys.h" +#include "window/themes/window_theme_editor.h" +#include "window/themes/window_theme.h" +#include "info/profile/info_profile_button.h" +#include "storage/localstorage.h" +#include "core/file_utilities.h" +#include "mainwidget.h" #include "styles/style_settings.h" namespace Settings { +namespace { + +class BackgroundRow : public Ui::RpWidget { +public: + BackgroundRow(QWidget *parent); + +protected: + void paintEvent(QPaintEvent *e) override; + + int resizeGetHeight(int newWidth) override; + +private: + void updateImage(); + + float64 radialProgress() const; + bool radialLoading() const; + QRect radialRect() const; + void radialStart(); + TimeMs radialTimeShift() const; + void step_radial(TimeMs ms, bool timer); + + QPixmap _background; + object_ptr<Ui::LinkButton> _chooseFromGallery; + object_ptr<Ui::LinkButton> _chooseFromFile; + + Ui::RadialAnimation _radial; + +}; + +#ifndef OS_WIN_STORE +class DownloadPathRow : public Ui::RpWidget { +public: + DownloadPathRow(QWidget *parent); + +private: + void setupControls(); + +}; +#endif // OS_WIN_STORE + +void ChooseFromFile(not_null<QWidget*> parent); + +BackgroundRow::BackgroundRow(QWidget *parent) : RpWidget(parent) +, _chooseFromGallery( + this, + lang(lng_settings_bg_from_gallery), + st::settingsLink) +, _chooseFromFile(this, lang(lng_settings_bg_from_file), st::settingsLink) +, _radial(animation(this, &BackgroundRow::step_radial)) { + updateImage(); + + _chooseFromGallery->addClickHandler([] { + Ui::show(Box<BackgroundBox>()); + }); + _chooseFromFile->addClickHandler([=] { + ChooseFromFile(this); + }); + + using Update = const Window::Theme::BackgroundUpdate; + base::ObservableViewer( + *Window::Theme::Background() + ) | rpl::filter([](const Update &update) { + return (update.type == Update::Type::New + || update.type == Update::Type::Start + || update.type == Update::Type::Changed); + }) | rpl::start_with_next([=] { + updateImage(); + }, lifetime()); +} + +void BackgroundRow::paintEvent(QPaintEvent *e) { + Painter p(this); + + bool radial = false; + float64 radialOpacity = 0; + if (_radial.animating()) { + _radial.step(getms()); + radial = _radial.animating(); + radialOpacity = _radial.opacity(); + } + if (radial) { + const auto backThumb = App::main()->newBackgroundThumb(); + if (backThumb->isNull()) { + p.drawPixmap(0, 0, _background); + } else { + const auto &pix = backThumb->pixBlurred( + Data::FileOrigin(), + st::settingsBackgroundThumb); + const auto factor = cIntRetinaFactor(); + p.drawPixmap( + 0, + 0, + st::settingsBackgroundThumb, + st::settingsBackgroundThumb, + pix, + 0, + (pix.height() - st::settingsBackgroundThumb * factor) / 2, + st::settingsBackgroundThumb * factor, + st::settingsBackgroundThumb * factor); + } + + const auto outer = radialRect(); + const auto inner = QRect( + QPoint( + outer.x() + (outer.width() - st::radialSize.width()) / 2, + outer.y() + (outer.height() - st::radialSize.height()) / 2), + st::radialSize); + p.setPen(Qt::NoPen); + p.setOpacity(radialOpacity); + p.setBrush(st::radialBg); + + { + PainterHighQualityEnabler hq(p); + p.drawEllipse(inner); + } + + p.setOpacity(1); + const auto arc = inner.marginsRemoved(QMargins( + st::radialLine, + st::radialLine, + st::radialLine, + st::radialLine)); + _radial.draw(p, arc, st::radialLine, st::radialFg); + } else { + p.drawPixmap(0, 0, _background); + } +} + +int BackgroundRow::resizeGetHeight(int newWidth) { + auto linkTop = st::settingsFromGalleryTop; + auto linkLeft = st::settingsBackgroundThumb + st::settingsThumbSkip; + auto linkWidth = newWidth - linkLeft; + _chooseFromGallery->resizeToWidth( + qMin(linkWidth, _chooseFromGallery->naturalWidth())); + _chooseFromFile->resizeToWidth( + qMin(linkWidth, _chooseFromFile->naturalWidth())); + _chooseFromGallery->moveToLeft(linkLeft, linkTop, newWidth); + linkTop += _chooseFromGallery->height() + st::settingsFromFileTop; + _chooseFromFile->moveToLeft(linkLeft, linkTop, newWidth); + return st::settingsBackgroundThumb; +} + +float64 BackgroundRow::radialProgress() const { + return App::main()->chatBackgroundProgress(); +} + +bool BackgroundRow::radialLoading() const { + const auto main = App::main(); + if (main->chatBackgroundLoading()) { + main->checkChatBackground(); + if (main->chatBackgroundLoading()) { + return true; + } else { + const_cast<BackgroundRow*>(this)->updateImage(); + } + } + return false; +} + +QRect BackgroundRow::radialRect() const { + return QRect( + 0, + 0, + st::settingsBackgroundThumb, + st::settingsBackgroundThumb); +} + +void BackgroundRow::radialStart() { + if (radialLoading() && !_radial.animating()) { + _radial.start(radialProgress()); + if (const auto shift = radialTimeShift()) { + _radial.update( + radialProgress(), + !radialLoading(), + getms() + shift); + } + } +} + +TimeMs BackgroundRow::radialTimeShift() const { + return st::radialDuration; +} + +void BackgroundRow::step_radial(TimeMs ms, bool timer) { + _radial.update( + radialProgress(), + !radialLoading(), + ms + radialTimeShift()); + if (timer && _radial.animating()) { + rtlupdate(radialRect()); + } +} + +void BackgroundRow::updateImage() { + int32 size = st::settingsBackgroundThumb * cIntRetinaFactor(); + QImage back(size, size, QImage::Format_ARGB32_Premultiplied); + back.setDevicePixelRatio(cRetinaFactor()); + { + Painter p(&back); + PainterHighQualityEnabler hq(p); + + const auto &pix = Window::Theme::Background()->pixmap(); + const auto sx = (pix.width() > pix.height()) + ? ((pix.width() - pix.height()) / 2) + : 0; + const auto sy = (pix.height() > pix.width()) + ? ((pix.height() - pix.width()) / 2) + : 0; + const auto s = (pix.width() > pix.height()) + ? pix.height() + : pix.width(); + p.drawPixmap( + 0, + 0, + st::settingsBackgroundThumb, + st::settingsBackgroundThumb, + pix, + sx, + sy, + s, + s); + } + Images::prepareRound(back, ImageRoundRadius::Small); + _background = App::pixmapFromImageInPlace(std::move(back)); + _background.setDevicePixelRatio(cRetinaFactor()); + + rtlupdate(radialRect()); + + if (radialLoading()) { + radialStart(); + } +} + +void ChooseFromFile(not_null<QWidget*> parent) { + const auto imgExtensions = cImgExtensions(); + auto filters = QStringList( + qsl("Theme files (*.tdesktop-theme *.tdesktop-palette *") + + imgExtensions.join(qsl(" *")) + + qsl(")")); + filters.push_back(FileDialog::AllFilesFilter()); + const auto callback = [=](const FileDialog::OpenResult &result) { + if (result.paths.isEmpty() && result.remoteContent.isEmpty()) { + return; + } + + if (!result.paths.isEmpty()) { + const auto filePath = result.paths.front(); + const auto hasExtension = [&](QLatin1String extension) { + return filePath.endsWith(extension, Qt::CaseInsensitive); + }; + if (hasExtension(qstr(".tdesktop-theme")) + || hasExtension(qstr(".tdesktop-palette"))) { + Window::Theme::Apply(filePath); + return; + } + } + + auto image = result.remoteContent.isEmpty() + ? App::readImage(result.paths.front()) + : App::readImage(result.remoteContent); + if (image.isNull() || image.width() <= 0 || image.height() <= 0) { + return; + } else if (image.width() > 4096 * image.height()) { + image = image.copy( + (image.width() - 4096 * image.height()) / 2, + 0, + 4096 * image.height(), + image.height()); + } else if (image.height() > 4096 * image.width()) { + image = image.copy( + 0, + (image.height() - 4096 * image.width()) / 2, + image.width(), + 4096 * image.width()); + } + + Window::Theme::Background()->setImage( + Window::Theme::kCustomBackground, + std::move(image)); + Window::Theme::Background()->setTile(false); + }; + FileDialog::GetOpenPath( + parent.get(), + lang(lng_choose_image), + filters.join(qsl(";;")), + crl::guard(parent, callback)); + +} + +#ifndef OS_WIN_STORE + +QString DownloadPathText() { + if (Global::DownloadPath().isEmpty()) { + return lang(lng_download_path_default); + } else if (Global::DownloadPath() == qsl("tmp")) { + return lang(lng_download_path_temp); + } + return QDir::toNativeSeparators(Global::DownloadPath()); +} + +DownloadPathRow::DownloadPathRow(QWidget *parent) : RpWidget(parent) { + setupControls(); +} + +void DownloadPathRow::setupControls() { + const auto label = Ui::CreateChild<Ui::FlatLabel>( + this, + Lang::Viewer(lng_download_path_label), + st::settingsLinkLabel); + const auto link = Ui::CreateChild<Ui::LinkButton>( + this, + DownloadPathText(), + st::settingsLink); + + base::ObservableViewer( + Global::RefDownloadPathChanged() + ) | rpl::map([] { + return DownloadPathText(); + }) | rpl::start_with_next([=](const QString &text) { + link->setText(text); + }, link->lifetime()); + + link->addClickHandler([] { + Ui::show(Box<DownloadPathBox>()); + }); + + rpl::combine( + widthValue(), + label->sizeValue(), + link->widthValue() + ) | rpl::start_with_next([=](int width, QSize labelSize, int possible) { + const auto space = st::settingsLinkLabel.style.font->spacew; + link->resizeToNaturalWidth(width - labelSize.width() - space); + if (link->width() == possible) { + label->moveToLeft(0, 0); + link->moveToLeft(labelSize.width() + space, 0); + resize(width, labelSize.height()); + } + }, link->lifetime()); +} + +#endif // OS_WIN_STORE + +void SetupChatOptions(not_null<Ui::VerticalLayout*> container) { + AddDivider(container); + AddSkip(container); + + auto wrap = object_ptr<Ui::VerticalLayout>(container); + const auto inner = wrap.data(); + container->add(object_ptr<Ui::OverrideMargins>( + container, + std::move(wrap), + QMargins(0, 0, 0, st::settingsCheckbox.margin.bottom()))); + + const auto checkbox = [&](LangKey label, bool checked) { + return object_ptr<Ui::Checkbox>( + container, + lang(label), + checked, + st::settingsCheckbox); + }; + const auto add = [&](LangKey label, bool checked, auto &&handle) { + base::ObservableViewer( + inner->add( + checkbox(label, checked), + st::settingsCheckboxPadding + )->checkedChanged + ) | rpl::start_with_next( + std::move(handle), + inner->lifetime()); + }; + add( + lng_settings_replace_emojis, + Global::ReplaceEmoji(), + [](bool checked) { + Global::SetReplaceEmoji(checked); + Global::RefReplaceEmojiChanged().notify(); + Local::writeUserSettings(); + }); + + add( + lng_settings_suggest_emoji, + Global::SuggestEmoji(), + [](bool checked) { + Global::SetSuggestEmoji(checked); + Local::writeUserSettings(); + }); + + add( + lng_settings_suggest_by_emoji, + Global::SuggestStickersByEmoji(), + [](bool checked) { + Global::SetSuggestStickersByEmoji(checked); + Local::writeUserSettings(); + }); + + const auto dontask = inner->add( + checkbox( + lng_download_path_dont_ask, + !Global::AskDownloadPath()), +#ifndef OS_WIN_STORE + st::settingsAskPathPadding); +#else // OS_WIN_STORE + st::settingsCheckboxPadding); +#endif // OS_WIN_STORE + +#ifndef OS_WIN_STORE + const auto showpath = Ui::AttachAsChild( + dontask, + rpl::event_stream<bool>()); + const auto padding = st::settingsDownloadPathPadding; + const auto path = container->add( + object_ptr<Ui::SlideWrap<DownloadPathRow>>( + container, + object_ptr<DownloadPathRow>(container), + QMargins( + (padding.left() + + st::settingsCheckbox.checkPosition.x() + + st::defaultCheck.diameter + + st::settingsCheckbox.textPosition.x() + - st::settingsCheckbox.margin.left()), + padding.top(), + padding.right(), + padding.bottom()))); + AddSkip(container, st::settingsCheckboxPadding.bottom()); + path->toggleOn( + showpath->events_starting_with(!Global::AskDownloadPath())); +#endif // OS_WIN_STORE + + base::ObservableViewer( + dontask->checkedChanged + ) | rpl::start_with_next([=](bool checked) { + Global::SetAskDownloadPath(!checked); + Local::writeUserSettings(); + +#ifndef OS_WIN_STORE + showpath->fire_copy(checked); +#endif // OS_WIN_STORE + + }, inner->lifetime()); + + AddSkip(container); +} + +void SetupSendKey(not_null<Ui::VerticalLayout*> container) { + AddDivider(container); + const auto skip = st::settingsSendTypeSkip; + const auto full = st::settingsSectionSkip + skip; + AddSkip(container, full); + + enum class SendByType { + Enter, + CtrlEnter, + }; + + const auto group = std::make_shared<Ui::RadioenumGroup<SendByType>>( + cCtrlEnter() ? SendByType::CtrlEnter : SendByType::Enter); + auto wrap = object_ptr<Ui::VerticalLayout>(container); + const auto inner = wrap.data(); + container->add( + object_ptr<Ui::OverrideMargins>( + container, + std::move(wrap), + QMargins(0, skip, 0, skip))); + + AddSkip(container, full); + + const auto add = [&]( + SendByType value, + LangKey key, + style::margins padding) { + inner->add( + object_ptr<Ui::Radioenum<SendByType>>( + inner, + group, + value, + lang(key), + st::settingsSendType), + st::settingsSendTypePadding); + }; + const auto small = st::settingsSendTypePadding; + const auto top = skip; + add( + SendByType::Enter, + lng_settings_send_enter, + { small.left(), small.top() + top, small.right(), small.bottom() }); + add( + SendByType::CtrlEnter, + ((cPlatform() == dbipMac || cPlatform() == dbipMacOld) + ? lng_settings_send_cmdenter + : lng_settings_send_ctrlenter), + { small.left(), small.top(), small.right(), small.bottom() + top }); + group->setChangedCallback([](SendByType value) { + cSetCtrlEnter(value == SendByType::CtrlEnter); + if (App::main()) { + App::main()->ctrlEnterSubmitUpdated(); + } + Local::writeUserSettings(); + }); +} + +void SetupMediaOptions(not_null<Ui::VerticalLayout*> container) { + AddDivider(container); + AddSkip(container); + + AddButton( + container, + lng_media_auto_settings, + st::settingsChatButton + )->addClickHandler([] { + Ui::show(Box<AutoDownloadBox>()); + }); + + AddButton( + container, + lng_stickers_you_have, + st::settingsChatButton + )->addClickHandler([] { + Ui::show(Box<StickersBox>(StickersBox::Section::Installed)); + }); + + AddSkip(container); +} + +void SetupChatBackground(not_null<Ui::VerticalLayout*> container) { + AddDivider(container); + AddSkip(container); + + container->add( + object_ptr<Ui::FlatLabel>( + container, + Lang::Viewer(lng_settings_section_background), + st::settingsBackgroundTitle), + st::settingsBackgroundTitlePadding); + + container->add( + object_ptr<BackgroundRow>(container), + st::settingsBackgroundPadding); + + const auto skipTop = st::settingsCheckbox.margin.top(); + const auto skipBottom = st::settingsCheckbox.margin.bottom(); + auto wrap = object_ptr<Ui::VerticalLayout>(container); + const auto inner = wrap.data(); + container->add( + object_ptr<Ui::OverrideMargins>( + container, + std::move(wrap), + QMargins(0, skipTop, 0, skipBottom))); + + AddSkip(container); + + const auto tile = inner->add( + object_ptr<Ui::Checkbox>( + inner, + lang(lng_settings_bg_tile), + Window::Theme::Background()->tile(), + st::settingsCheckbox), + st::settingsSendTypePadding); + const auto adaptive = inner->add( + object_ptr<Ui::SlideWrap<Ui::Checkbox>>( + inner, + object_ptr<Ui::Checkbox>( + inner, + lang(lng_settings_adaptive_wide), + Global::AdaptiveForWide(), + st::settingsCheckbox), + st::settingsSendTypePadding)); + + base::ObservableViewer( + tile->checkedChanged + ) | rpl::start_with_next([](bool checked) { + Window::Theme::Background()->setTile(checked); + }, tile->lifetime()); + + using Update = const Window::Theme::BackgroundUpdate; + base::ObservableViewer( + *Window::Theme::Background() + ) | rpl::filter([](const Update &update) { + return (update.type == Update::Type::Changed); + }) | rpl::map([] { + return Window::Theme::Background()->tile(); + }) | rpl::start_with_next([=](bool tiled) { + tile->setChecked(tiled); + }, tile->lifetime()); + + adaptive->toggleOn(rpl::single( + rpl::empty_value() + ) | rpl::then(base::ObservableViewer( + Adaptive::Changed() + )) | rpl::map([] { + return (Global::AdaptiveChatLayout() == Adaptive::ChatLayout::Wide); + })); + + base::ObservableViewer( + adaptive->entity()->checkedChanged + ) | rpl::start_with_next([](bool checked) { + Global::SetAdaptiveForWide(checked); + Adaptive::Changed().notify(); + Local::writeUserSettings(); + }, adaptive->lifetime()); +} + +void SetupThemeOptions(not_null<Ui::VerticalLayout*> container) { + AddDivider(container); + AddSkip(container); + + const auto calling = Ui::AttachAsChild(container, 0); + AddButton( + container, + lng_settings_use_night_mode, + st::settingsChatButton + )->toggleOn( + rpl::single(Window::Theme::IsNightMode()) + )->toggledValue( + ) | rpl::start_with_next([=](bool toggled) { + ++*calling; + const auto change = [=] { + if (!--*calling && toggled != Window::Theme::IsNightMode()) { + Window::Theme::ToggleNightMode(); + } + }; + App::CallDelayed( + st::settingsButton.toggle.duration, + container, + change); + }, container->lifetime()); + + AddButton( + container, + lng_settings_bg_edit_theme, + st::settingsChatButton + )->addClickHandler(App::LambdaDelayed( + st::settingsChatButton.ripple.hideDuration, + container, + [] { Window::Theme::Editor::Start(); })); + + using Update = const Window::Theme::BackgroundUpdate; + container->add( + object_ptr<Ui::SlideWrap<Button>>( + container, + object_ptr<Button>( + container, + Lang::Viewer(lng_settings_bg_use_default), + st::settingsChatButton)) + )->toggleOn(rpl::single( + Window::Theme::SuggestThemeReset() + ) | rpl::then(base::ObservableViewer( + *Window::Theme::Background() + ) | rpl::filter([](const Update &update) { + return (update.type == Update::Type::ApplyingTheme + || update.type == Update::Type::New); + }) | rpl::map([] { + return Window::Theme::SuggestThemeReset(); + })))->entity()->addClickHandler([] { + Window::Theme::ApplyDefault(); + }); + + AddSkip(container); +} + +} // namespace Chat::Chat(QWidget *parent, not_null<UserData*> self) : Section(parent) @@ -24,7 +698,11 @@ Chat::Chat(QWidget *parent, not_null<UserData*> self) void Chat::setupContent() { const auto content = Ui::CreateChild<Ui::VerticalLayout>(this); - content->add(object_ptr<BoxContentDivider>(content)); + SetupChatOptions(content); + SetupSendKey(content); + SetupMediaOptions(content); + SetupChatBackground(content); + SetupThemeOptions(content); Ui::ResizeFitChild(this, content); } diff --git a/Telegram/SourceFiles/settings/settings_common.cpp b/Telegram/SourceFiles/settings/settings_common.cpp index 0f28a69d3..c3b0e8600 100644 --- a/Telegram/SourceFiles/settings/settings_common.cpp +++ b/Telegram/SourceFiles/settings/settings_common.cpp @@ -47,9 +47,13 @@ object_ptr<Section> CreateSection( } void AddSkip(not_null<Ui::VerticalLayout*> container) { + AddSkip(container, st::settingsSectionSkip); +} + +void AddSkip(not_null<Ui::VerticalLayout*> container, int skip) { container->add(object_ptr<Ui::FixedHeightWidget>( container, - st::settingsSectionSkip)); + skip)); } void AddDivider(not_null<Ui::VerticalLayout*> container) { diff --git a/Telegram/SourceFiles/settings/settings_common.h b/Telegram/SourceFiles/settings/settings_common.h index 92e272560..0f2426c25 100644 --- a/Telegram/SourceFiles/settings/settings_common.h +++ b/Telegram/SourceFiles/settings/settings_common.h @@ -59,6 +59,7 @@ object_ptr<Section> CreateSection( UserData *self = nullptr); void AddSkip(not_null<Ui::VerticalLayout*> container); +void AddSkip(not_null<Ui::VerticalLayout*> container, int skip); void AddDivider(not_null<Ui::VerticalLayout*> container); not_null<Button*> AddButton( not_null<Ui::VerticalLayout*> container, diff --git a/Telegram/SourceFiles/settings/settings_general.cpp b/Telegram/SourceFiles/settings/settings_general.cpp index ef4a3bc66..0f180990e 100644 --- a/Telegram/SourceFiles/settings/settings_general.cpp +++ b/Telegram/SourceFiles/settings/settings_general.cpp @@ -82,7 +82,6 @@ void SetupUpdate(not_null<Ui::VerticalLayout*> container) { AddDivider(container); AddSkip(container); - const auto lifetime = Ui::AttachAsChild(container, rpl::lifetime()); const auto texts = Ui::AttachAsChild( container, rpl::event_stream<QString>()); @@ -115,7 +114,7 @@ void SetupUpdate(not_null<Ui::VerticalLayout*> container) { check->entity()->widthValue() | rpl::start_with_next([=](int width) { update->resizeToWidth(width); update->moveToLeft(0, 0); - }, *lifetime); + }, update->lifetime()); AddSkip(container); @@ -167,7 +166,7 @@ void SetupUpdate(not_null<Ui::VerticalLayout*> container) { checker.stop(); } setDefaultStatus(checker); - }, *lifetime); + }, toggle->lifetime()); Core::UpdateChecker checker; check->toggleOn(rpl::combine( @@ -182,26 +181,26 @@ void SetupUpdate(not_null<Ui::VerticalLayout*> container) { check->setAttribute(Qt::WA_TransparentForMouseEvents); texts->fire(lang(lng_settings_update_checking)); downloading->fire(false); - }, *lifetime); + }, check->lifetime()); checker.isLatest() | rpl::start_with_next([=] { check->setAttribute(Qt::WA_TransparentForMouseEvents, false); texts->fire(lang(lng_settings_latest_installed)); downloading->fire(false); - }, *lifetime); + }, check->lifetime()); checker.progress( ) | rpl::start_with_next([=](Core::UpdateChecker::Progress progress) { showDownloadProgress(progress.already, progress.size); - }, *lifetime); + }, check->lifetime()); checker.failed() | rpl::start_with_next([=] { check->setAttribute(Qt::WA_TransparentForMouseEvents, false); texts->fire(lang(lng_settings_update_fail)); downloading->fire(false); - }, *lifetime); + }, check->lifetime()); checker.ready() | rpl::start_with_next([=] { texts->fire(lang(lng_settings_update_ready)); update->show(); downloading->fire(false); - }, *lifetime); + }, check->lifetime()); setDefaultStatus(checker); @@ -227,7 +226,6 @@ void SetupTray(not_null<Ui::VerticalLayout*> container) { AddDivider(container); AddSkip(container); - const auto lifetime = Ui::AttachAsChild(container, rpl::lifetime()); const auto trayEnabler = Ui::AttachAsChild( container, rpl::event_stream<bool>()); @@ -281,7 +279,7 @@ void SetupTray(not_null<Ui::VerticalLayout*> container) { } else { updateWorkmode(); } - }, *lifetime); + }, tray->lifetime()); if (taskbar) { taskbar->toggledValue( @@ -293,7 +291,7 @@ void SetupTray(not_null<Ui::VerticalLayout*> container) { } else { updateWorkmode(); } - }, *lifetime); + }, taskbar->lifetime()); } #ifndef OS_WIN_STORE @@ -336,7 +334,7 @@ void SetupTray(not_null<Ui::VerticalLayout*> container) { } else { Local::writeSettings(); } - }, *lifetime); + }, autostart->lifetime()); minimized->entity()->toggleOn( minimizedToggler->events_starting_with(minimizedToggled())); @@ -353,13 +351,13 @@ void SetupTray(not_null<Ui::VerticalLayout*> container) { cSetStartMinimized(checked); Local::writeSettings(); } - }, *lifetime); + }, minimized->lifetime()); base::ObservableViewer( Global::RefLocalPasscodeChanged() ) | rpl::start_with_next([=] { minimizedToggler->fire(minimizedToggled()); - }, *lifetime); + }, minimized->lifetime()); sendto->toggledValue( ) | rpl::filter([](bool checked) { @@ -368,7 +366,7 @@ void SetupTray(not_null<Ui::VerticalLayout*> container) { cSetSendToMenu(checked); psSendToMenu(checked); Local::writeSettings(); - }, *lifetime); + }, sendto->lifetime()); } #endif // OS_WIN_STORE diff --git a/Telegram/SourceFiles/settings/settings_notifications.cpp b/Telegram/SourceFiles/settings/settings_notifications.cpp index c6eeb6fa6..62b929559 100644 --- a/Telegram/SourceFiles/settings/settings_notifications.cpp +++ b/Telegram/SourceFiles/settings/settings_notifications.cpp @@ -30,19 +30,19 @@ void SetupNotificationsContent(not_null<Ui::VerticalLayout*> container) { container, lang(label), checked, - st::settingsNotificationsCheckbox); + st::settingsCheckbox); }; const auto addCheckbox = [&](LangKey label, bool checked) { return container->add( checkbox(label, checked), - st::settingsNotificationsCheckboxPadding); + st::settingsCheckboxPadding); }; const auto addSlidingCheckbox = [&](LangKey label, bool checked) { return container->add( object_ptr<Ui::SlideWrap<Ui::Checkbox>>( container, checkbox(label, checked), - st::settingsNotificationsCheckboxPadding)); + st::settingsCheckboxPadding)); }; const auto desktop = addCheckbox( lng_settings_desktop_notify, @@ -96,8 +96,6 @@ void SetupNotificationsContent(not_null<Ui::VerticalLayout*> container) { advanced->hide(anim::type::instant); } - const auto lifetime = Ui::AttachAsChild(container, rpl::lifetime()); - using Change = Window::Notifications::ChangeType; const auto changed = [](Change change) { Local::writeUserSettings(); @@ -110,7 +108,7 @@ void SetupNotificationsContent(not_null<Ui::VerticalLayout*> container) { }) | rpl::start_with_next([=](bool checked) { Global::SetDesktopNotify(checked); changed(Change::DesktopEnabled); - }, *lifetime); + }, desktop->lifetime()); base::ObservableViewer( name->entity()->checkedChanged @@ -126,7 +124,7 @@ void SetupNotificationsContent(not_null<Ui::VerticalLayout*> container) { }) | rpl::start_with_next([=](DBINotifyView value) { Global::SetNotifyView(value); changed(Change::ViewParams); - }, *lifetime); + }, name->lifetime()); base::ObservableViewer( preview->entity()->checkedChanged @@ -142,7 +140,7 @@ void SetupNotificationsContent(not_null<Ui::VerticalLayout*> container) { }) | rpl::start_with_next([=](DBINotifyView value) { Global::SetNotifyView(value); changed(Change::ViewParams); - }, *lifetime); + }, preview->lifetime()); base::ObservableViewer( sound->checkedChanged @@ -151,7 +149,7 @@ void SetupNotificationsContent(not_null<Ui::VerticalLayout*> container) { }) | rpl::start_with_next([=](bool checked) { Global::SetSoundNotify(checked); changed(Change::SoundEnabled); - }, *lifetime); + }, sound->lifetime()); base::ObservableViewer( muted->checkedChanged @@ -160,7 +158,7 @@ void SetupNotificationsContent(not_null<Ui::VerticalLayout*> container) { }) | rpl::start_with_next([=](bool checked) { Global::SetIncludeMuted(checked); changed(Change::IncludeMuted); - }, *lifetime); + }, muted->lifetime()); base::ObservableViewer( Auth().notifications().settingsChanged() @@ -176,7 +174,7 @@ void SetupNotificationsContent(not_null<Ui::VerticalLayout*> container) { } else if (change == Change::SoundEnabled) { sound->setChecked(Global::SoundNotify()); } - }, *lifetime); + }, desktop->lifetime()); if (native) { base::ObservableViewer( @@ -194,7 +192,7 @@ void SetupNotificationsContent(not_null<Ui::VerticalLayout*> container) { !Global::NativeNotifications(), anim::type::normal); } - }, *lifetime); + }, native->lifetime()); } if (advanced) { advanced->entity()->addClickHandler([=] { @@ -210,7 +208,7 @@ void SetupNotifications(not_null<Ui::VerticalLayout*> container) { auto wrap = object_ptr<Ui::VerticalLayout>(container); SetupNotificationsContent(wrap.data()); - container->add(object_ptr<Ui::IgnoreMargins>( + container->add(object_ptr<Ui::OverrideMargins>( container, std::move(wrap))); diff --git a/Telegram/SourceFiles/ui/widgets/buttons.cpp b/Telegram/SourceFiles/ui/widgets/buttons.cpp index 136d269d9..52792a4a3 100644 --- a/Telegram/SourceFiles/ui/widgets/buttons.cpp +++ b/Telegram/SourceFiles/ui/widgets/buttons.cpp @@ -45,7 +45,7 @@ void LinkButton::paintEvent(QPaintEvent *e) { p.setPen(pen); const auto left = _st.padding.left(); const auto top = _st.padding.top() + font->ascent; - if (width() > naturalWidth()) { + if (width() < naturalWidth()) { const auto available = width() - left - _st.padding.right(); p.drawText(left, top, font->elided(_text, available)); } else { diff --git a/Telegram/SourceFiles/ui/wrap/vertical_layout.cpp b/Telegram/SourceFiles/ui/wrap/vertical_layout.cpp index 602a52a1f..c44786cca 100644 --- a/Telegram/SourceFiles/ui/wrap/vertical_layout.cpp +++ b/Telegram/SourceFiles/ui/wrap/vertical_layout.cpp @@ -62,7 +62,7 @@ int VerticalLayout::resizeGetHeight(int newWidth) { + row.widget->heightNoMargins() + row.margin.bottom(); } - return result - margins.bottom(); + return result; } void VerticalLayout::visibleTopBottomUpdated( diff --git a/Telegram/SourceFiles/ui/wrap/wrap.h b/Telegram/SourceFiles/ui/wrap/wrap.h index 221dae1a3..cb18d6929 100644 --- a/Telegram/SourceFiles/ui/wrap/wrap.h +++ b/Telegram/SourceFiles/ui/wrap/wrap.h @@ -145,12 +145,15 @@ public: }; -class IgnoreMargins : public Wrap<RpWidget> { +class OverrideMargins : public Wrap<RpWidget> { using Parent = Wrap<RpWidget>; public: - IgnoreMargins(QWidget *parent, object_ptr<RpWidget> &&child) - : Parent(parent, std::move(child)) { + OverrideMargins( + QWidget *parent, + object_ptr<RpWidget> &&child, + QMargins margins = QMargins()) + : Parent(parent, std::move(child)), _margins(margins) { if (auto weak = wrapped()) { auto margins = weak->getMargins(); resizeToWidth(weak->width() @@ -160,14 +163,14 @@ public: } QMargins getMargins() const override { - return QMargins(); + return _margins; } protected: int resizeGetHeight(int newWidth) override { if (auto weak = wrapped()) { weak->resizeToWidth(newWidth); - weak->moveToLeft(0, 0); + weak->moveToLeft(_margins.left(), _margins.top()); return weak->heightNoMargins(); } return height(); @@ -177,10 +180,20 @@ private: void wrappedSizeUpdated(QSize size) override { auto margins = wrapped()->getMargins(); resize( - size.width() - margins.left() - margins.right(), - size.height() - margins.top() - margins.bottom()); + (size.width() + - margins.left() + - margins.right() + + _margins.left() + + _margins.right()), + (size.height() + - margins.top() + - margins.bottom() + + _margins.top() + + _margins.bottom())); } + QMargins _margins; + }; } // namespace Ui