diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 4c19f0506..ac50254df 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -987,6 +987,8 @@ PRIVATE intro/intro_step.h intro/intro_widget.cpp intro/intro_widget.h + kotato/boxes/kotato_fonts_box.cpp + kotato/boxes/kotato_fonts_box.h kotato/boxes/kotato_radio_box.cpp kotato/boxes/kotato_radio_box.h kotato/kotato_lang.cpp diff --git a/Telegram/Resources/langs/rewrites/en.json b/Telegram/Resources/langs/rewrites/en.json index b2fa173d9..b72e24466 100644 --- a/Telegram/Resources/langs/rewrites/en.json +++ b/Telegram/Resources/langs/rewrites/en.json @@ -28,6 +28,17 @@ "ktg_mac_menu_show": "Show Kotatogram", "ktg_settings_kotato": "Kotatogram Settings", "ktg_settings_chats": "Chats", + "ktg_fonts_title": "Fonts", + "ktg_settings_fonts": "Change application fonts", + "ktg_fonts_reset": "Reset", + "ktg_fonts_about": "You will need to restart app to apply and see changes.", + "ktg_fonts_main": "Main font", + "ktg_fonts_semibold": "Semibold font", + "ktg_fonts_semibold_is_bold": "Bold font face", + "ktg_fonts_monospaced": "Monospaced font", + "ktg_fonts_size": "Font size: {pixels}px", + "ktg_fonts_use_system_font": "Use system font", + "ktg_fonts_use_original_metrics": "Use Open Sans height", "ktg_settings_network": "Network", "ktg_settings_system": "System", "ktg_settings_other": "Other", diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index f43708f48..506a4529c 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -1017,3 +1017,7 @@ shortInfoBox: ShortInfoBox { labeled: infoLabeled; labeledOneLine: infoLabeledOneLine; } + +fontsBoxTextStyle: TextStyle(defaultTextStyle) { + font: font(13px); +} diff --git a/Telegram/SourceFiles/core/crash_report_window.cpp b/Telegram/SourceFiles/core/crash_report_window.cpp index c66f8f7db..4f561518d 100644 --- a/Telegram/SourceFiles/core/crash_report_window.cpp +++ b/Telegram/SourceFiles/core/crash_report_window.cpp @@ -27,12 +27,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace { constexpr auto kDefaultProxyPort = 80; +Core::UiIntegration UiIntegrationInstance; } // namespace PreLaunchWindow *PreLaunchWindowInstance = nullptr; PreLaunchWindow::PreLaunchWindow(QString title) { + Ui::Integration::Set(&UiIntegrationInstance); style::internal::StartFonts(); setWindowIcon(Window::CreateIcon()); diff --git a/Telegram/SourceFiles/core/ui_integration.cpp b/Telegram/SourceFiles/core/ui_integration.cpp index ba2593e7b..7e15614da 100644 --- a/Telegram/SourceFiles/core/ui_integration.cpp +++ b/Telegram/SourceFiles/core/ui_integration.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/ui_integration.h" #include "api/api_text_entities.h" +#include "kotato/kotato_settings.h" #include "core/local_url_handlers.h" #include "core/file_utilities.h" #include "core/application.h" @@ -19,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/text/text_custom_emoji.h" #include "ui/basic_click_handlers.h" #include "ui/emoji_config.h" +#include "ui/style/style_core_custom_font.h" #include "lang/lang_keys.h" #include "platform/platform_specific.h" #include "boxes/url_auth_box.h" @@ -136,6 +138,18 @@ void UiIntegration::activationFromTopPanel() { Platform::IgnoreApplicationActivationRightNow(); } +style::CustomFontSettings UiIntegration::fontSettings() { + return { + ::Kotato::JsonSettings::GetString("fonts/main"), + ::Kotato::JsonSettings::GetString("fonts/semibold"), + ::Kotato::JsonSettings::GetString("fonts/monospaced"), + ::Kotato::JsonSettings::GetInt("fonts/size"), + ::Kotato::JsonSettings::GetBool("fonts/semibold_is_bold"), + ::Kotato::JsonSettings::GetBool("fonts/use_system_font"), + ::Kotato::JsonSettings::GetBool("fonts/use_original_metrics"), + }; +} + bool UiIntegration::screenIsLocked() { return Core::App().screenIsLocked(); } diff --git a/Telegram/SourceFiles/core/ui_integration.h b/Telegram/SourceFiles/core/ui_integration.h index 36ee45777..2a872987d 100644 --- a/Telegram/SourceFiles/core/ui_integration.h +++ b/Telegram/SourceFiles/core/ui_integration.h @@ -46,6 +46,7 @@ public: void activationFromTopPanel() override; bool screenIsLocked() override; + style::CustomFontSettings fontSettings() override; std::shared_ptr createLinkHandler( const EntityLinkData &data, diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 4921e6307..186fe72fd 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -8264,7 +8264,7 @@ void HistoryWidget::paintEvent(QPaintEvent *e) { HistoryView::ServiceMessagePainter::PaintBubble(p, st, tr); p.setPen(st->msgServiceFg()); - p.setFont(st::msgServiceFont->f); + p.setFont(st::msgServiceFont); p.drawTextLeft(tr.left() + st::msgPadding.left(), tr.top() + st::msgServicePadding.top(), width(), tr::lng_willbe_history(tr::now)); //AssertIsDebug(); diff --git a/Telegram/SourceFiles/kotato/boxes/kotato_fonts_box.cpp b/Telegram/SourceFiles/kotato/boxes/kotato_fonts_box.cpp new file mode 100644 index 000000000..460d93712 --- /dev/null +++ b/Telegram/SourceFiles/kotato/boxes/kotato_fonts_box.cpp @@ -0,0 +1,303 @@ +/* +This file is part of Kotatogram Desktop, +the unofficial app based on Telegram Desktop. + +For license and copyright information please follow this link: +https://github.com/kotatogram/kotatogram-desktop/blob/dev/LEGAL +*/ +#include "kotato/boxes/kotato_fonts_box.h" + +#include "kotato/kotato_lang.h" +#include "kotato/kotato_settings.h" +#include "base/platform/base_platform_info.h" +#include "ui/wrap/vertical_layout.h" +#include "ui/wrap/padding_wrap.h" +#include "ui/wrap/wrap.h" +#include "ui/widgets/checkbox.h" +#include "ui/widgets/buttons.h" +#include "ui/widgets/fields/input_field.h" +#include "ui/widgets/labels.h" +#include "ui/widgets/continuous_sliders.h" +#include "styles/style_layers.h" +#include "styles/style_boxes.h" +#include "styles/style_calls.h" +#include "styles/style_settings.h" +#include "ui/boxes/confirm_box.h" +#include "lang/lang_keys.h" +#include "core/application.h" + +#include +#include +#include +#include + +class FontListView : public QListView { +public: + FontListView(QWidget *parent) + : QListView(parent) { + setModel(new QStringListModel(parent)); + setEditTriggers(NoEditTriggers); + setFont(st::normalFont); + } + + inline QStringListModel *model() const { + return static_cast(QListView::model()); + } + inline void setCurrentItem(int item) { + QListView::setCurrentIndex(static_cast(model())->index(item)); + } + inline int currentItem() const { + return QListView::currentIndex().row(); + } + inline int count() const { + return model()->rowCount(); + } + inline QString currentText() const { + int row = QListView::currentIndex().row(); + return row < 0 ? QString() : model()->stringList().at(row); + } + void currentChanged(const QModelIndex ¤t, const QModelIndex &previous) override { + QListView::currentChanged(current, previous); + if (current.isValid()) + _highlighted.fire_copy(model()->stringList().at(current.row())); + } + QString text(int i) const { + return model()->stringList().at(i); + } + rpl::producer highlighted() { + return _highlighted.events(); + } + rpl::lifetime &lifetime() { + return _lifetime; + } + +private: + rpl::event_stream _highlighted; + rpl::lifetime _lifetime; +}; + +class RpFontListView : public Ui::RpWidget { +public: + RpFontListView(QWidget *parent) + : Ui::RpWidget(parent) + , _layout(this) + , _view(this) { + _layout->addWidget(_view); + } + + void prepare( + Ui::InputField *field, + const QStringList &fontList) { + _view->model()->setStringList(fontList); + resize(0, _view->sizeHintForRow(0) * 10); + _view->highlighted( + ) | rpl::start_with_next([=](QString fontName) { + if (!field->hasFocus()) { + field->setText(fontName); + } + }, _view->lifetime()); + field->changes( + ) | rpl::start_with_next([=] { + if (field->getLastText().isEmpty()) { + _view->setCurrentItem(-1); + return; + } + _view->setCurrentItem( + std::distance(fontList.begin(), ranges::find_if( + fontList, + [&](const auto &fontName) { + return fontName.startsWith(field->getLastText()); + }))); + }, field->lifetime()); + const auto defaultValue = field->getLastText().trimmed(); + if (!defaultValue.isEmpty()) { + _view->setCurrentItem(fontList.indexOf(defaultValue)); + } + } + +private: + object_ptr _layout; + object_ptr _view; +}; + +FontsBox::FontsBox(QWidget* parent) +: _owned(this) +, _content(_owned.data()) +, _fontSize(::Kotato::JsonSettings::GetIntWithPending("fonts/size")) +{ +} + +void FontsBox::prepare() { + setTitle(rktr("ktg_fonts_title")); + + addButton(tr::lng_settings_save(), [=] { save(); }); + addButton(tr::lng_cancel(), [=] { closeBox(); }); + + addLeftButton(rktr("ktg_fonts_reset"), [=] { resetToDefault(); }); + + _useSystemFont = _content->add( + object_ptr(_content, + ktr("ktg_fonts_use_system_font"), + ::Kotato::JsonSettings::GetBoolWithPending("fonts/use_system_font")), + QMargins( + st::boxPadding.left(), + 0, + st::boxPadding.right(), + st::boxPadding.bottom())); + _useOriginalMetrics = _content->add( + object_ptr(_content, + ktr("ktg_fonts_use_original_metrics"), + ::Kotato::JsonSettings::GetBoolWithPending("fonts/use_original_metrics")), + QMargins( + st::boxPadding.left(), + st::boxPadding.bottom(), + st::boxPadding.right(), + st::boxPadding.bottom())); + _mainFontName = _content->add( + object_ptr(_content, st::defaultInputField, rktr("ktg_fonts_main")), + QMargins( + st::boxPadding.left(), + 0, + st::boxPadding.right(), + st::boxPadding.bottom())); + _mainFontList = _content->add( + object_ptr(_content), + QMargins( + st::boxPadding.left(), + st::boxPadding.bottom(), + st::boxPadding.right(), + st::boxPadding.bottom())); + _semiboldFontName = _content->add( + object_ptr(_content, st::defaultInputField, rktr("ktg_fonts_semibold")), + QMargins( + st::boxPadding.left(), + 0, + st::boxPadding.right(), + st::boxPadding.bottom())); + _semiboldFontList = _content->add( + object_ptr(_content), + QMargins( + st::boxPadding.left(), + st::boxPadding.bottom(), + st::boxPadding.right(), + st::boxPadding.bottom())); + _semiboldIsBold = _content->add( + object_ptr(_content, + ktr("ktg_fonts_semibold_is_bold"), + ::Kotato::JsonSettings::GetBoolWithPending("fonts/semibold_is_bold")), + QMargins( + st::boxPadding.left(), + 0, + st::boxPadding.right(), + st::boxPadding.bottom())); + _monospacedFontName = _content->add( + object_ptr(_content, st::defaultInputField, rktr("ktg_fonts_monospaced")), + QMargins( + st::boxPadding.left(), + 0, + st::boxPadding.right(), + st::boxPadding.bottom())); + _monospacedFontList = _content->add( + object_ptr(_content), + QMargins( + st::boxPadding.left(), + st::boxPadding.bottom(), + st::boxPadding.right(), + st::boxPadding.bottom())); + _fontSizeLabel = _content->add( + object_ptr( + _content, + st::ktgSettingsSliderLabel), + st::groupCallDelayLabelMargin); + _fontSizeSlider = _content->add( + object_ptr( + _content, + st::defaultContinuousSlider), + st::localStorageLimitMargin); + const auto updateFontSizeLabel = [=](int value) { + const auto prefix = (value >= 0) ? qsl("+") : QString(); + const auto pixels = prefix + QString::number(value); + _fontSizeLabel->setText( + ktr("ktg_fonts_size", { "pixels", pixels })); + }; + const auto updateFontSize = [=](int value) { + updateFontSizeLabel(value); + _fontSize = value; + }; + _fontSizeSlider->resize(st::defaultContinuousSlider.seekSize); + _fontSizeSlider->setPseudoDiscrete( + 21, + [](int val) { return val - 10; }, + _fontSize, + updateFontSize); + updateFontSizeLabel(_fontSize); + _content->add( + object_ptr(_content, rktr("ktg_fonts_about"), st::boxDividerLabel), + QMargins( + st::boxPadding.left(), + 0, + st::boxPadding.right(), + st::boxPadding.bottom())); + + _mainFontName->setText(::Kotato::JsonSettings::GetStringWithPending("fonts/main")); + _semiboldFontName->setText(::Kotato::JsonSettings::GetStringWithPending("fonts/semibold")); + _monospacedFontName->setText(::Kotato::JsonSettings::GetStringWithPending("fonts/monospaced")); + + const auto fontNames = QFontDatabase().families(); + _mainFontList->prepare(_mainFontName, fontNames); + _semiboldFontList->prepare(_semiboldFontName, fontNames); + _monospacedFontList->prepare(_monospacedFontName, fontNames); + + auto wrap = object_ptr(this, std::move(_owned)); + setDimensionsToContent(st::boxWidth, wrap.data()); + setInnerWidget(std::move(wrap)); +} + + +void FontsBox::setInnerFocus() { + _mainFontName->setFocusFast(); +} + +void FontsBox::save() { + ::Kotato::JsonSettings::SetAfterRestart("fonts/main", _mainFontName->getLastText().trimmed()); + ::Kotato::JsonSettings::SetAfterRestart("fonts/semibold", _semiboldFontName->getLastText().trimmed()); + ::Kotato::JsonSettings::SetAfterRestart("fonts/monospaced", _monospacedFontName->getLastText().trimmed()); + ::Kotato::JsonSettings::SetAfterRestart("fonts/semibold_is_bold", _semiboldIsBold->checked()); + ::Kotato::JsonSettings::SetAfterRestart("fonts/use_system_font", _useSystemFont->checked()); + ::Kotato::JsonSettings::SetAfterRestart("fonts/use_original_metrics", _useOriginalMetrics->checked()); + ::Kotato::JsonSettings::SetAfterRestart("fonts/size", _fontSize); + ::Kotato::JsonSettings::Write(); + + const auto box = std::make_shared>(); + + *box = getDelegate()->show( + Ui::MakeConfirmBox({ + .text = tr::lng_settings_need_restart(), + .confirmed = [] { Core::Restart(); }, + .cancelled = crl::guard(this, [=] { closeBox(); box->data()->closeBox(); }), + .confirmText = tr::lng_settings_restart_now(), + .cancelText = tr::lng_settings_restart_later(), + })); +} + +void FontsBox::resetToDefault() { + ::Kotato::JsonSettings::ResetAfterRestart("fonts/main"); + ::Kotato::JsonSettings::ResetAfterRestart("fonts/semibold"); + ::Kotato::JsonSettings::ResetAfterRestart("fonts/monospaced"); + ::Kotato::JsonSettings::ResetAfterRestart("fonts/semibold_is_bold"); + ::Kotato::JsonSettings::ResetAfterRestart("fonts/size"); + ::Kotato::JsonSettings::ResetAfterRestart("fonts/use_system_font"); + ::Kotato::JsonSettings::ResetAfterRestart("fonts/use_original_metrics"); + ::Kotato::JsonSettings::Write(); + + const auto box = std::make_shared>(); + + *box = getDelegate()->show( + Ui::MakeConfirmBox({ + .text = tr::lng_settings_need_restart(), + .confirmed = [] { Core::Restart(); }, + .cancelled = crl::guard(this, [=] { closeBox(); box->data()->closeBox(); }), + .confirmText = tr::lng_settings_restart_now(), + .cancelText = tr::lng_settings_restart_later(), + })); +} diff --git a/Telegram/SourceFiles/kotato/boxes/kotato_fonts_box.h b/Telegram/SourceFiles/kotato/boxes/kotato_fonts_box.h new file mode 100644 index 000000000..07e97c48d --- /dev/null +++ b/Telegram/SourceFiles/kotato/boxes/kotato_fonts_box.h @@ -0,0 +1,50 @@ +/* +This file is part of Kotatogram Desktop, +the unofficial app based on Telegram Desktop. + +For license and copyright information please follow this link: +https://github.com/kotatogram/kotatogram-desktop/blob/dev/LEGAL +*/ +#pragma once + +#include "ui/layers/box_content.h" + +namespace Ui { +class VerticalLayout; +class Checkbox; +class InputField; +class LabelSimple; +class MediaSlider; +} // namespace Ui + +class RpFontListView; + +class FontsBox : public Ui::BoxContent { +public: + FontsBox(QWidget* parent); + +protected: + void prepare() override; + void setInnerFocus() override; + +private: + void save(); + void resetToDefault(); + + object_ptr _owned; + not_null _content; + + QPointer _useSystemFont; + QPointer _useOriginalMetrics; + QPointer _mainFontName; + QPointer _mainFontList; + QPointer _semiboldFontName; + QPointer _semiboldFontList; + QPointer _semiboldIsBold; + QPointer _monospacedFontName; + QPointer _monospacedFontList; + QPointer _fontSizeLabel; + QPointer _fontSizeSlider; + + int _fontSize; +}; diff --git a/Telegram/SourceFiles/kotato/kotato_settings.cpp b/Telegram/SourceFiles/kotato/kotato_settings.cpp index ec354ea85..32fb8f3eb 100644 --- a/Telegram/SourceFiles/kotato/kotato_settings.cpp +++ b/Telegram/SourceFiles/kotato/kotato_settings.cpp @@ -217,6 +217,32 @@ const std::map> DefinitionMap { .defaultValue = false, }}, // Stored settings + { "fonts/main", { + .type = SettingType::QStringSetting, + .fillerValue = qsl("Open Sans"), }}, + { "fonts/semibold", { + .type = SettingType::QStringSetting, + .fillerValue = qsl("Open Sans Semibold"), }}, + { "fonts/semibold_is_bold", { + .type = SettingType::BoolSetting, + .defaultValue = false, }}, + { "fonts/monospaced", { + .type = SettingType::QStringSetting, + .fillerValue = qsl("Consolas"), }}, + { "fonts/size", { + .type = SettingType::IntSetting, + .defaultValue = 0, }}, + { "fonts/use_system_font", { + .type = SettingType::BoolSetting, +#ifdef DESKTOP_APP_USE_PACKAGED_FONTS + .defaultValue = true, +#else + .defaultValue = Platform::IsLinux(), +#endif + }}, + { "fonts/use_original_metrics", { + .type = SettingType::BoolSetting, + .defaultValue = false, }}, }; using OldOptionKey = QString; diff --git a/Telegram/SourceFiles/kotato/kotato_settings_menu.cpp b/Telegram/SourceFiles/kotato/kotato_settings_menu.cpp index ae32660a9..fde6ffc30 100644 --- a/Telegram/SourceFiles/kotato/kotato_settings_menu.cpp +++ b/Telegram/SourceFiles/kotato/kotato_settings_menu.cpp @@ -71,6 +71,14 @@ void SetupKotatoChats( Ui::AddSkip(container); Ui::AddSubsectionTitle(container, rktr("ktg_settings_chats")); + container->add(object_ptr