diff --git a/bin/assets/i18n/de.xml b/bin/assets/i18n/de.xml index dafd7c4e7..37f12229a 100644 --- a/bin/assets/i18n/de.xml +++ b/bin/assets/i18n/de.xml @@ -265,6 +265,7 @@ Soll es jetzt heruntergeladen werden? Bearbeiten Build bearbeiten Angewählten individuellen Output-Parser bearbeiten + Editor-Schriftart und -größe... Editor-Schriftgröße Editor: Schritt zurück Editor: Schritt nach vorn @@ -807,7 +808,7 @@ Datei im Verzeichnisbaum. Konsolenfarbschema: %s Konsole: Kopieren Konsolenschriftart - Konsolenschriftart... + Konsolenschriftart und -größe... Konsole: Schriftgröße Konsole: Schriftgröße erhöhen Konsole: Schriftgröße verringern @@ -853,6 +854,7 @@ in der Baumansicht und in Öffen-/Schließdialogen aktivieren. Leerzeichen nach den Enden beschneiden Typ Zu findender Typ + Schriftart und -größe der Oberfläche... Schriftgröße der Oberfläche Sprache der Oberfläche Multisample-Antialiasing-Stufe diff --git a/bin/assets/i18n/en.xml b/bin/assets/i18n/en.xml index 367908aad..63704b28e 100644 --- a/bin/assets/i18n/en.xml +++ b/bin/assets/i18n/en.xml @@ -249,6 +249,7 @@ Do you want to download it now? Edit Edit Build Edit Selected Custom Output Parser + Editor Font & Size... Editor Font Size Editor Go Back Editor Go Forward @@ -791,7 +792,7 @@ file in the directory tree. Terminal color scheme: %s Terminal Copy Terminal Font - Terminal Font... + Terminal Font & Size... Terminal Font Size Terminal Font Size Grow Terminal Font Size Shrink @@ -837,6 +838,7 @@ the directory tree and in file dialogs to open a folder or file. Trim Trailing Whitespaces Type Type to Locate + UI Font & Size... Ui Font Size UI Language Multisample Anti-Aliasing Level diff --git a/bin/assets/i18n/fr.xml b/bin/assets/i18n/fr.xml index d27b72aef..fab4e7f9f 100644 --- a/bin/assets/i18n/fr.xml +++ b/bin/assets/i18n/fr.xml @@ -250,6 +250,7 @@ Voulez-vous le télécharger maintenant ? Modifier Modifier la construction Modifier l'analyseur de sortie personnalisé sélectionné + Police et taille de l'éditeur... Taille de la police de l'éditeur Éditeur : retour en arrière Éditeur : avancer @@ -782,7 +783,7 @@ dans l'arborescence du répertoire. Schéma de couleurs du terminal : %s Terminal : copie Police du terminal - Police du terminal... + Police et taille du terminal... Terminal : taille de la police Terminal : agrandir la taille de la police Terminal : réduire la taille de la police @@ -828,6 +829,7 @@ dans l'arborescence de répertoires ainsi que dans les boites de dialogues de s Retirer les espaces en fin de ligne Type Type à localiser + Police et taille de l'interface utilisateur... Interface utilisateur : taille de la police Interface utilisateur : langue Interface utilisateur : niveau d'anti-aliasing multiéchantillon diff --git a/bin/assets/i18n/zh.xml b/bin/assets/i18n/zh.xml index 15f247b24..7e61a50a8 100644 --- a/bin/assets/i18n/zh.xml +++ b/bin/assets/i18n/zh.xml @@ -184,6 +184,7 @@ 编辑 编辑构建 编辑已选的自定义输出解析器 + 编辑器字体和大小... 编辑器字体大小 编辑器撤销 编辑器重做 @@ -593,7 +594,7 @@ file in the directory tree. 终端配色方案:%s 终端复制 终端字体 - 终端字体... + 终端字体和大小... 终端字体大小 终端字体+ 终端字体- @@ -626,6 +627,7 @@ file in the directory tree. Trim Trailing Whitespaces Type Type to Locate + 界面字体和大小... Ui字体大小 界面语言 多重采样抗锯齿级别 diff --git a/include/eepp/ui/tools/uifontpickerdialog.hpp b/include/eepp/ui/tools/uifontpickerdialog.hpp index 1c70dd623..a7f24a8e8 100644 --- a/include/eepp/ui/tools/uifontpickerdialog.hpp +++ b/include/eepp/ui/tools/uifontpickerdialog.hpp @@ -28,6 +28,7 @@ class UIColorPicker; struct UIFontSelection { FontDesc font; + /** Font size in density-independent pixels. */ Uint32 size{ 12 }; bool underline{ false }; bool strikeThrough{ false }; @@ -54,7 +55,8 @@ class EE_API UIFontPickerDialog : public UIWindow { ShowEffects = 1 << 2, ShowColor = 1 << 3, ShowApplyButton = 1 << 4, - DefaultFlags = ShowSize | ShowEffects | ShowColor, + ShowStyle = 1 << 5, + DefaultFlags = ShowSize | ShowEffects | ShowColor | ShowStyle, }; struct FontStyleEntry { @@ -62,6 +64,12 @@ class EE_API UIFontPickerDialog : public UIWindow { FontDesc desc; }; + struct FontFamilyEntry { + std::string label; + std::string family; + std::string externalFontKey; + }; + static UIFontPickerDialog* New( Uint32 flags = DefaultFlags ); virtual ~UIFontPickerDialog(); @@ -113,10 +121,11 @@ class EE_API UIFontPickerDialog : public UIWindow { FontPickedCb mFontPickedCb; FontSelectionChangedCb mFontSelectionChangedCb; std::vector mFonts; - std::vector mFamilies; + std::vector mFamilies; std::vector mStyles; std::vector mSizes; UnorderedSet mLoadedFontKeys; + UnorderedSet mExternalFontKeys; UnorderedMap mFontTags; Graphics::FontTrueTypePtr mPreviewFont; Graphics::Font* mPreviewTextDefaultFont{ nullptr }; @@ -196,7 +205,7 @@ class EE_API UIFontPickerDialog : public UIWindow { void selectInitialRows(); - void selectFamily( const std::string& family ); + void selectFamily( const FontDesc& font ); void selectRegularStyle(); diff --git a/include/eepp/ui/uilinearlayout.hpp b/include/eepp/ui/uilinearlayout.hpp index 7d9956763..ea8a245bd 100644 --- a/include/eepp/ui/uilinearlayout.hpp +++ b/include/eepp/ui/uilinearlayout.hpp @@ -2,6 +2,7 @@ #define UI_UILINEARLAYOUT_HPP #include +#include namespace EE { namespace UI { @@ -52,7 +53,11 @@ class EE_API UILinearLayout : public UILayout { void packHorizontal(); - Sizei getTotalUsedSize(); + /** + * @return A pair containing the space used by visible fixed-size children and margins, followed + * by the sum of the visible children's positive layout weights. + */ + std::pair getTotalUsedSize(); void applyWidthPolicyOnChildren(); diff --git a/src/eepp/ui/tools/uifontpickerdialog.cpp b/src/eepp/ui/tools/uifontpickerdialog.cpp index 73dbefd2c..e0ec8fe7b 100644 --- a/src/eepp/ui/tools/uifontpickerdialog.cpp +++ b/src/eepp/ui/tools/uifontpickerdialog.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include using namespace EE::UI::Abstract; @@ -89,7 +88,7 @@ static const char* FONT_PICKER_LAYOUT = R"xml( - + @@ -100,7 +99,7 @@ static const char* FONT_PICKER_LAYOUT = R"xml( - + @@ -151,6 +150,33 @@ class StyleListModel final : public Model { const std::vector* mData{ nullptr }; }; +class FamilyListModel final : public Model { + public: + explicit FamilyListModel( const std::vector* data ) : + mData( data ) {} + + size_t rowCount( const ModelIndex& ) const override { return mData ? mData->size() : 0; } + + size_t columnCount( const ModelIndex& ) const override { return 1; } + + ModelIndex index( int row, int column, + const ModelIndex& parent = ModelIndex() ) const override { + if ( row >= static_cast( rowCount( parent ) ) || column >= 1 ) + return {}; + return Model::index( row, column, parent ); + } + + Variant data( const ModelIndex& index, ModelRole role = ModelRole::Display ) const override { + if ( role == ModelRole::Display && mData && + index.row() < static_cast( mData->size() ) ) + return Variant( ( *mData )[index.row()].label ); + return {}; + } + + private: + const std::vector* mData{ nullptr }; +}; + static Uint64 loadFontsTaskTag( const UIFontPickerDialog* dialog ) { return reinterpret_cast( dialog ); } @@ -231,7 +257,9 @@ UIFontPickerDialog::UIFontPickerDialog( Uint32 flags ) : UIWindow(), mFlags( fla mStyleConfig.WinFlags = UI_WIN_DEFAULT_FLAGS | UI_WIN_MAXIMIZE_BUTTON | UI_WIN_MODAL; updateWinFlags(); - mSizes = { 8, 9, 10, 11, 12, 14, 16, 18, 20, 24, 32, 48, 64, 72 }; + mSizes.reserve( 67 ); + for ( Uint32 size = 6; size <= 72; size++ ) + mSizes.emplace_back( size ); mSelection.size = 12; setTitle( i18n( "font_picker_select_font", "Select Font" ) ); @@ -343,6 +371,11 @@ void UIFontPickerDialog::loadWidgets() { sizeColumn->setVisible( false )->setEnabled( false ); } + if ( ( mFlags & ShowStyle ) == 0 ) { + if ( auto styleColumn = root->find( "style_column" ) ) + styleColumn->setVisible( false )->setEnabled( false ); + } + if ( ( mFlags & ShowEffects ) == 0 ) { mAntialiasing->setVisible( false )->setEnabled( false ); mUnderline->setVisible( false )->setEnabled( false ); @@ -441,10 +474,13 @@ void UIFontPickerDialog::setFonts( std::vector fonts ) { FontDesc selectedFont = mSelection.font; mergeLoadedFonts( fonts ); for ( const auto& font : mFonts ) { - if ( std::find_if( fonts.begin(), fonts.end(), [&]( const FontDesc& desc ) { - return desc.sameFile( font ); - } ) == fonts.end() ) + auto found = std::find_if( fonts.begin(), fonts.end(), + [&]( const FontDesc& desc ) { return desc.sameFile( font ); } ); + if ( found == fonts.end() ) { fonts.push_back( font ); + } else if ( mExternalFontKeys.find( font.getFileKey() ) != mExternalFontKeys.end() ) { + *found = font; + } } mFonts = std::move( fonts ); @@ -536,29 +572,33 @@ bool UIFontPickerDialog::wantsMonospaceOnly() const { } void UIFontPickerDialog::updateFamilies() { - std::string previousFamily = mSelection.font.family; - if ( !mFamilyList->getSelection().isEmpty() && - mFamilyList->getSelection().first().row() < static_cast( mFamilies.size() ) ) - previousFamily = mFamilies[mFamilyList->getSelection().first().row()]; + FontDesc previousFont = mSelection.font; const std::string query = String::toLower( mSearchInput->getText().toUtf8() ); - std::set families; + UnorderedSet familyKeys; + mFamilies.clear(); for ( const auto& font : mFonts ) { - if ( wantsMonospaceOnly() && !font.monospace ) + const bool external = + mExternalFontKeys.find( font.getFileKey() ) != mExternalFontKeys.end(); + if ( wantsMonospaceOnly() && !font.monospace && !external ) continue; - if ( !query.empty() && String::toLower( font.family ).find( query ) == std::string::npos ) + const std::string label = font.family + ( external ? " [External]" : "" ); + if ( !query.empty() && String::toLower( label ).find( query ) == std::string::npos ) continue; - families.insert( font.family ); + const std::string familyKey = + font.family + ( external ? "\n" + font.getFileKey() : std::string{} ); + if ( familyKeys.insert( familyKey ).second ) + mFamilies.push_back( + { label, font.family, external ? font.getFileKey() : std::string{} } ); } - mFamilies.assign( families.begin(), families.end() ); - mFamilyModel = ItemListModel::create( mFamilies ); + mFamilyModel = std::make_shared( &mFamilies ); mUpdating = true; mFamilyList->setModel( mFamilyModel ); mUpdating = false; - if ( !previousFamily.empty() ) - selectFamily( previousFamily ); + if ( !previousFont.family.empty() ) + selectFamily( previousFont ); if ( mFamilyList->getSelection().isEmpty() && !mFamilies.empty() ) mFamilyList->setSelection( mFamilyModel->index( 0 ) ); @@ -572,9 +612,15 @@ void UIFontPickerDialog::updateStyles() { if ( !mFamilyList->getSelection().isEmpty() ) { const Int64 row = mFamilyList->getSelection().first().row(); if ( row >= 0 && row < static_cast( mFamilies.size() ) ) { - const std::string& family = mFamilies[row]; + const FontFamilyEntry& family = mFamilies[row]; for ( const auto& font : mFonts ) { - if ( font.family == family && ( !wantsMonospaceOnly() || font.monospace ) ) { + const bool external = + mExternalFontKeys.find( font.getFileKey() ) != mExternalFontKeys.end(); + const bool matchesSource = family.externalFontKey.empty() + ? !external + : family.externalFontKey == font.getFileKey(); + if ( font.family == family.family && matchesSource && + ( !wantsMonospaceOnly() || font.monospace || external ) ) { std::string label( styleLabel( font ) ); auto tagIt = mFontTags.find( font.getFileKey() ); if ( tagIt != mFontTags.end() ) @@ -651,8 +697,9 @@ void UIFontPickerDialog::updatePreview() { } } - mPreviewText->setFontSize( PixelDensity::dpToPxI( mSelection.size * 2 ) ); - mPreviewInput->setFontSize( PixelDensity::dpToPxI( 12 ) ); + const Uint32 previewSize = PixelDensity::dpToPxI( mSelection.size ); + mPreviewText->setFontSize( previewSize ); + mPreviewInput->setFontSize( previewSize ); mPreviewText->setFontStyle( styleFlags( mSelection ) ); mPreviewInput->setFontStyle( styleFlags( mSelection ) ); mPreviewText->setFontColor( mSelection.color ); @@ -668,8 +715,8 @@ void UIFontPickerDialog::updatePreview() { if ( mSelection.font.faceIndex != 0 ) faceIndexSuffix = " #" + String::toString( mSelection.font.faceIndex ); mDetailsText->setText( - String::format( "%s %s - %u pt - %s%s", mSelection.font.family.c_str(), - styleLabel( mSelection.font ).c_str(), mSelection.size, + String::format( "%s %s - %u dp (%u px) - %s%s", mSelection.font.family.c_str(), + styleLabel( mSelection.font ).c_str(), mSelection.size, previewSize, mSelection.font.path.c_str(), faceIndexSuffix.c_str() ) ); } } @@ -677,6 +724,10 @@ void UIFontPickerDialog::updatePreview() { void UIFontPickerDialog::clearPreviewFont() { if ( !mPreviewFont ) return; + if ( SceneManager::isShuttingDown() ) { + mPreviewFont.reset(); + return; + } if ( mPreviewText && mPreviewTextDefaultFont && mPreviewText->getFont() == mPreviewFont.get() ) mPreviewText->setFont( mPreviewTextDefaultFont ); if ( mPreviewInput && mPreviewInputDefaultFont && @@ -693,11 +744,15 @@ void UIFontPickerDialog::selectInitialRows() { mSizeList->setSelection( mSizeModel->index( 4 ) ); } -void UIFontPickerDialog::selectFamily( const std::string& family ) { - if ( family.empty() || !mFamilyModel ) +void UIFontPickerDialog::selectFamily( const FontDesc& font ) { + if ( font.family.empty() || !mFamilyModel ) return; + const bool external = mExternalFontKeys.find( font.getFileKey() ) != mExternalFontKeys.end(); for ( size_t i = 0; i < mFamilies.size(); i++ ) { - if ( mFamilies[i] == family ) { + const FontFamilyEntry& family = mFamilies[i]; + if ( family.family == font.family && + ( external ? family.externalFontKey == font.getFileKey() + : family.externalFontKey.empty() ) ) { mFamilyList->setSelection( mFamilyModel->index( i ) ); return; } @@ -738,6 +793,13 @@ void UIFontPickerDialog::selectSize( Uint32 size ) { return; } } + + auto position = std::lower_bound( mSizes.begin(), mSizes.end(), size ); + const size_t index = position - mSizes.begin(); + mSizes.insert( position, size ); + mSizeModel = ItemListModel::create( mSizes ); + mSizeList->setModel( mSizeModel ); + mSizeList->setSelection( mSizeModel->index( index ) ); } void UIFontPickerDialog::emitPicked() { @@ -808,25 +870,24 @@ bool UIFontPickerDialog::addExternalFont( const std::string& path, Uint32 faceIn return true; } - const std::string fontName( - FileSystem::fileRemoveExtension( FileSystem::fileNameFromPath( path ) ) ); if ( !getUISceneNode() ) return false; ResourceScope& resourceScope = *getUISceneNode()->getResourceScope(); - FontTrueTypePtr font = FontTrueType::New( fontName, resourceScope ); - if ( !font || !font->loadFromFile( path, faceIndex ) ) { - resourceScope.eraseLocalFont( font.get() ); + FontDesc requestedFont; + requestedFont.path = path; + requestedFont.faceIndex = faceIndex; + FontTrueTypePtr font = resourceScope.getFontService().loadSystemFont( requestedFont ); + if ( !font ) return false; - } FontDesc desc; - if ( !font->getFontDesc( desc ) ) { - resourceScope.eraseLocalFont( font.get() ); + if ( !font->getFontDesc( desc ) ) return false; - } - resourceScope.eraseLocalFont( font.get() ); + if ( desc.family.empty() ) + desc.family = FileSystem::fileRemoveExtension( FileSystem::fileNameFromPath( path ) ); mLoadedFontKeys.insert( desc.getFileKey() ); + mExternalFontKeys.insert( desc.getFileKey() ); mFonts.push_back( desc ); sortFonts(); updateFontTags(); @@ -867,7 +928,7 @@ void UIFontPickerDialog::setSelectedFont( const FontDesc& desc ) { mSelection.font = selection; if ( selection.monospace && mMonospaceOnly ) mMonospaceOnly->setChecked( true ); - selectFamily( selection.family ); + selectFamily( selection ); updateStyles(); selectStyle( selection ); updateSelectionFromLists( false ); diff --git a/src/eepp/ui/uilinearlayout.cpp b/src/eepp/ui/uilinearlayout.cpp index 31b18bb96..46beeeeed 100644 --- a/src/eepp/ui/uilinearlayout.cpp +++ b/src/eepp/ui/uilinearlayout.cpp @@ -180,7 +180,7 @@ void UILinearLayout::packVertical() { Float curY = mPaddingPx.Top; Float maxX = 0; - Sizei freeSize = getTotalUsedSize(); + auto [freeSize, totalWeight] = getTotalUsedSize(); Node* child = mChild; @@ -193,15 +193,16 @@ void UILinearLayout::packVertical() { Vector2f pos( mPaddingPx.Left, curY ); - if ( widget->getLayoutWeight() != 0 ) { + if ( widget->getLayoutWeight() > 0 && totalWeight > 0 ) { Float totSize = ( getLayoutHeightPolicy() == SizePolicy::MatchParent || getLayoutHeightPolicy() == SizePolicy::Fixed ) ? getPixelsSize().getHeight() - mPaddingPx.Top - mPaddingPx.Bottom : getParent()->getPixelsSize().getHeight() - mLayoutMarginPx.Bottom - mLayoutMarginPx.Top - mPaddingPx.Top - mPaddingPx.Bottom; - Float newSize = eemax( - eeceil( totSize - freeSize.getHeight() ) * widget->getLayoutWeight(), 0.f ); + Float newSize = eemax( eeceil( totSize - freeSize.getHeight() ) * + widget->getLayoutWeight() / totalWeight, + 0.f ); widget->setPixelsSize( widget->getPixelsSize().getWidth(), newSize ); } @@ -315,7 +316,7 @@ void UILinearLayout::packHorizontal() { Float curX = mPaddingPx.Left; Float maxY = 0; - Sizei freeSize = getTotalUsedSize(); + auto [freeSize, totalWeight] = getTotalUsedSize(); Node* child = mChild; @@ -328,15 +329,16 @@ void UILinearLayout::packHorizontal() { Vector2f pos( curX, mPaddingPx.Top ); - if ( widget->getLayoutWeight() != 0 ) { + if ( widget->getLayoutWeight() > 0 && totalWeight > 0 ) { Float totSize = ( getLayoutWidthPolicy() == SizePolicy::MatchParent || getLayoutWidthPolicy() == SizePolicy::Fixed ) ? getPixelsSize().getWidth() - mPaddingPx.Left - mPaddingPx.Right : getParent()->getPixelsSize().getWidth() - mLayoutMarginPx.Right - mLayoutMarginPx.Left - mPaddingPx.Left - mPaddingPx.Right; - Float newSize = eemax( - eeceil( totSize - freeSize.getWidth() ) * widget->getLayoutWeight(), 0.f ); + Float newSize = eemax( eeceil( totSize - freeSize.getWidth() ) * + widget->getLayoutWeight() / totalWeight, + 0.f ); widget->setPixelsSize( newSize, widget->getPixelsSize().getHeight() ); } @@ -412,13 +414,15 @@ void UILinearLayout::packHorizontal() { mPacking = false; } -Sizei UILinearLayout::getTotalUsedSize() { +std::pair UILinearLayout::getTotalUsedSize() { Node* child = mChild; Sizei size( 0, 0 ); + Float totalWeight = 0; while ( NULL != child ) { if ( child->isWidget() && child->isVisible() ) { UIWidget* widget = static_cast( child ); + totalWeight += eemax( widget->getLayoutWeight(), 0.f ); Rectf margin = widget->getLayoutPixelsMargin(); size.x += margin.Left + margin.Right; @@ -443,7 +447,7 @@ Sizei UILinearLayout::getTotalUsedSize() { child = child->getNextNode(); } - return size; + return { size, totalWeight }; } std::string UILinearLayout::getPropertyString( const PropertyDefinition* propertyDef, diff --git a/src/tests/unit_tests/uifontpickerdialog_tests.cpp b/src/tests/unit_tests/uifontpickerdialog_tests.cpp index c90ae6504..d27063b51 100644 --- a/src/tests/unit_tests/uifontpickerdialog_tests.cpp +++ b/src/tests/unit_tests/uifontpickerdialog_tests.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -9,9 +10,12 @@ #include #include #include +#include #include #include #include +#include +#include using namespace EE; using namespace EE::UI; @@ -51,12 +55,19 @@ template static void pumpUntil( UISceneNode* sceneNode, Pre class TestFontPickerDialog : public UIFontPickerDialog { public: - static TestFontPickerDialog* New() { return eeNew( TestFontPickerDialog, () ); } + static TestFontPickerDialog* New( Uint32 flags = DefaultFlags ) { + return eeNew( TestFontPickerDialog, ( flags ) ); + } FontTrueTypeWeakPtr getPreviewFontHandle() const { return mPreviewFont; } + void selectCustomSize( Uint32 size ) { selectSize( size ); } + void releasePreviewFont() { clearPreviewFont(); } + Uint32 getPreviewTextSize() const { return mPreviewText->getFontSize(); } + Uint32 getPreviewInputSize() const { return mPreviewInput->getFontSize(); } + String getDetails() const { return mDetailsText->getText(); } protected: - TestFontPickerDialog() : UIFontPickerDialog() {} + TestFontPickerDialog( Uint32 flags ) : UIFontPickerDialog( flags ) {} }; UTEST( UIFontPickerDialog, PreselectsExternalFontPath ) { @@ -74,6 +85,8 @@ UTEST( UIFontPickerDialog, PreselectsExternalFontPath ) { EXPECT_FALSE( dialog->getSelection().font.family.empty() ); EXPECT_FALSE( dialog->getFamilyList()->getSelection().isEmpty() ); EXPECT_FALSE( dialog->getStyleList()->getSelection().isEmpty() ); + EXPECT_TRUE( dialog->getFamilyList()->getSelection().first().data().toString().find( + "[External]" ) != std::string::npos ); UIFontPickerDialog* selectionDialog = UIFontPickerDialog::New(); UIFontSelection selection; @@ -84,6 +97,58 @@ UTEST( UIFontPickerDialog, PreselectsExternalFontPath ) { EXPECT_FALSE( selectionDialog->getSelection().font.family.empty() ); } +UTEST( UIFontPickerDialog, ExternalFontKeepsSeparateFamilyEntryOnNameCollision ) { + std::vector fonts = SystemFontResolver::instance()->enumerate(); + auto fontIt = std::find_if( fonts.begin(), fonts.end(), []( const FontDesc& font ) { + return !font.family.empty() && !font.path.empty() && FileSystem::fileExists( font.path ); + } ); + if ( fontIt == fonts.end() ) + UTEST_SKIP( "no system font available" ); + + const std::string externalPath = Sys::getTempPath() + "UIFontPickerDialogExternal-" + + String::toString( Sys::getProcessID() ) + "." + + FileSystem::fileExtension( fontIt->path ); + ASSERT_TRUE( FileSystem::fileCopy( fontIt->path, externalPath ) ); + + UIApplication app( + WindowSettings( 320, 240, "eepp - UIFontPickerDialog Test", WindowStyle::Default, + WindowBackend::Default, 32 ), + UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) ); + + ResourceScope& resourceScope = *app.getUI()->getResourceScope(); + const std::string externalName( + FileSystem::fileRemoveExtension( FileSystem::fileNameFromPath( externalPath ) ) ); + const std::string managedFontPath = + Sys::getProcessPath() + "assets/fonts/NotoSansKR-Regular.ttf"; + FontTrueTypePtr managedFont = FontTrueType::New( externalName, managedFontPath, resourceScope ); + ASSERT_TRUE( managedFont && managedFont->loaded() ); + + TestFontPickerDialog* dialog = TestFontPickerDialog::New(); + dialog->setSelectedFont( externalPath ); + pumpUntil( app.getUI(), [dialog] { return dialog->getButtonOK()->isEnabled(); } ); + + EXPECT_STDSTREQ( externalPath, dialog->getSelection().font.path ); + EXPECT_FALSE( dialog->getFamilyList()->getSelection().isEmpty() ); + EXPECT_STDSTREQ( fontIt->family + " [External]", + dialog->getFamilyList()->getSelection().first().data().toString() ); + + bool foundSystemFamily = false; + bool foundExternalFamily = false; + Model* familyModel = dialog->getFamilyList()->getModel(); + ASSERT_TRUE( familyModel != nullptr ); + for ( size_t row = 0; row < familyModel->rowCount(); row++ ) { + const std::string label = familyModel->index( row ).data().toString(); + foundSystemFamily |= label == fontIt->family; + foundExternalFamily |= label == fontIt->family + " [External]"; + } + EXPECT_TRUE( foundSystemFamily ); + EXPECT_TRUE( foundExternalFamily ); + EXPECT_EQ( managedFont.get(), resourceScope.findFont( externalName ).get() ); + + dialog->releasePreviewFont(); + FileSystem::fileRemove( externalPath ); +} + UTEST( UIFontPickerDialog, PreviewFontsDoNotPopulateSceneFontCatalog ) { UIApplication app( WindowSettings( 320, 240, "eepp - UIFontPickerDialog Test", WindowStyle::Default, @@ -130,6 +195,18 @@ UTEST( UIFontPickerDialog, SelectingFontDoesNotCreateMetricOnlyPage ) { EXPECT_TRUE( foundPreviewPage ); } +UTEST( UIFontPickerDialog, TeardownWithActivePreviewDoesNotInvalidateDestroyedLayouts ) { + UIApplication app( + WindowSettings( 320, 240, "eepp - UIFontPickerDialog Test", WindowStyle::Default, + WindowBackend::Default, 32 ), + UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) ); + + UILinearLayout::New()->setParent( app.getUI()->getRoot() ); + const std::string fontPath = Sys::getProcessPath() + "assets/fonts/NotoSansKR-Regular.ttf"; + ASSERT_TRUE( FileSystem::fileExists( fontPath ) ); + UIFontPickerDialog::New()->setSelectedFont( fontPath ); +} + UTEST( UIFontPickerDialog, ReleasesPreviewFontTexturesOnClose ) { UIApplication app( WindowSettings( 320, 240, "eepp - UIFontPickerDialog Test", WindowStyle::Default, @@ -238,7 +315,7 @@ UTEST( UIFontPickerDialog, AsyncLoadPreservesExternalFontPreselection ) { const std::string fontPath = Sys::getProcessPath() + "assets/fonts/NotoSansKR-Regular.ttf"; ASSERT_TRUE( FileSystem::fileExists( fontPath ) ); - UIFontPickerDialog* dialog = UIFontPickerDialog::New(); + UIFontPickerDialog* dialog = UIFontPickerDialog::New( UIFontPickerDialog::MonospaceOnly ); EXPECT_FALSE( dialog->getButtonOK()->isEnabled() ); dialog->setSelectedFont( fontPath ); @@ -249,6 +326,8 @@ UTEST( UIFontPickerDialog, AsyncLoadPreservesExternalFontPreselection ) { EXPECT_FALSE( dialog->getSelection().font.family.empty() ); EXPECT_FALSE( dialog->getFamilyList()->getSelection().isEmpty() ); EXPECT_FALSE( dialog->getStyleList()->getSelection().isEmpty() ); + EXPECT_TRUE( dialog->getFamilyList()->getSelection().first().data().toString().find( + "[External]" ) != std::string::npos ); } UTEST( UIFontPickerDialog, DefaultColorComesFromTheme ) { @@ -360,3 +439,23 @@ UTEST( UIFontPickerDialog, ApplyButtonEmitsOnApply ) { EXPECT_TRUE( picked ); EXPECT_FALSE( confirmed ); } + +UTEST( UIFontPickerDialog, HidesStyleAndSupportsEveryIntegerSize ) { + UIApplication app( + WindowSettings( 320, 240, "eepp - UIFontPickerDialog Test", WindowStyle::Default, + WindowBackend::Default, 32 ), + UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) ); + + TestFontPickerDialog* dialog = TestFontPickerDialog::New( UIFontPickerDialog::ShowSize ); + dialog->selectCustomSize( 15 ); + + EXPECT_FALSE( dialog->getStyleList()->getParent()->isVisible() ); + EXPECT_EQ( 67u, dialog->getSizeList()->getModel()->rowCount() ); + EXPECT_EQ( 15u, dialog->getSelection().size ); + EXPECT_FALSE( dialog->getSizeList()->getSelection().isEmpty() ); + EXPECT_EQ( 15u, dialog->getSizeList()->getSelection().first().data().asUint() ); + EXPECT_EQ( static_cast( PixelDensity::dpToPxI( 15 ) ), dialog->getPreviewTextSize() ); + EXPECT_EQ( dialog->getPreviewTextSize(), dialog->getPreviewInputSize() ); + EXPECT_TRUE( dialog->getDetails().contains( "15 dp" ) ); + dialog->releasePreviewFont(); +} diff --git a/src/tests/unit_tests/uilayout_tests.cpp b/src/tests/unit_tests/uilayout_tests.cpp index 54eb87017..55b798227 100644 --- a/src/tests/unit_tests/uilayout_tests.cpp +++ b/src/tests/unit_tests/uilayout_tests.cpp @@ -80,3 +80,65 @@ UTEST( UILinearLayout, CrossAxisAlignmentUsesOwnPadding ) { EXPECT_NEAR( 40.f, middle->getPixelsPosition().y, 0.1f ); EXPECT_NEAR( 60.f, bottom->getPixelsPosition().y, 0.1f ); } + +UTEST( UILinearLayout, HorizontalWeightsNormalizeAcrossVisibleChildren ) { + UIApplication app( + WindowSettings( 320, 240, "eepp - UILinearLayout Test", WindowStyle::Default, + WindowBackend::Default, 32 ), + UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) ); + + UILinearLayout* layout = UILinearLayout::NewHorizontal(); + layout->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed ); + layout->setPixelsSize( 300, 100 ); + layout->setParent( app.getUI()->getRoot() ); + + const auto addChild = [layout]( Float weight ) { + UIWidget* child = UIWidget::New(); + child->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed ); + child->setPixelsSize( 0, 20 ); + child->setLayoutWeight( weight ); + child->setParent( layout ); + return child; + }; + UIWidget* first = addChild( 1 ); + UIWidget* middle = addChild( 2 ); + UIWidget* last = addChild( 1 ); + + app.getUI()->updateDirtyLayouts(); + EXPECT_NEAR( 75.f, first->getPixelsSize().getWidth(), 0.1f ); + EXPECT_NEAR( 150.f, middle->getPixelsSize().getWidth(), 0.1f ); + EXPECT_NEAR( 75.f, last->getPixelsSize().getWidth(), 0.1f ); + + middle->setVisible( false ); + app.getUI()->updateDirtyLayouts(); + EXPECT_NEAR( 150.f, first->getPixelsSize().getWidth(), 0.1f ); + EXPECT_NEAR( 150.f, last->getPixelsSize().getWidth(), 0.1f ); +} + +UTEST( UILinearLayout, VerticalWeightsNormalize ) { + UIApplication app( + WindowSettings( 320, 240, "eepp - UILinearLayout Test", WindowStyle::Default, + WindowBackend::Default, 32 ), + UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) ); + + UILinearLayout* layout = UILinearLayout::NewVertical(); + layout->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed ); + layout->setPixelsSize( 100, 200 ); + layout->setParent( app.getUI()->getRoot() ); + + UIWidget* first = UIWidget::New(); + first->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed ); + first->setPixelsSize( 20, 0 ); + first->setLayoutWeight( 1 ); + first->setParent( layout ); + + UIWidget* second = UIWidget::New(); + second->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed ); + second->setPixelsSize( 20, 0 ); + second->setLayoutWeight( 3 ); + second->setParent( layout ); + + app.getUI()->updateDirtyLayouts(); + EXPECT_NEAR( 50.f, first->getPixelsSize().getHeight(), 0.1f ); + EXPECT_NEAR( 150.f, second->getPixelsSize().getHeight(), 0.1f ); +} diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index f48f033b6..2964a5cd3 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -442,9 +442,9 @@ void App::openFolderDialog() { } void App::openFontDialog( std::string& fontPath, bool loadingMonoFont, bool terminalFont, - std::function onFinish ) { + std::function onFinish, bool pickFontSize ) { mFontPickerController->openFontDialog( fontPath, loadingMonoFont, terminalFont, - std::move( onFinish ) ); + std::move( onFinish ), pickFontSize ); } void App::updateInputFonts() { diff --git a/src/tools/ecode/ecode.hpp b/src/tools/ecode/ecode.hpp index 7ff7b6352..7659266ed 100644 --- a/src/tools/ecode/ecode.hpp +++ b/src/tools/ecode/ecode.hpp @@ -80,7 +80,7 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider { void openFolderDialog(); void openFontDialog( std::string& fontPath, bool loadingMonoFont, bool terminalFont = false, - std::function onFinish = {} ); + std::function onFinish = {}, bool pickFontSize = true ); void updateInputFonts(); @@ -356,13 +356,16 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider { t.setCommand( "terminal-font", [this] { openFontDialog( mConfig.ui.terminalFont, true, true ); } ); t.setCommand( "fallback-font", [this] { - openFontDialog( mConfig.ui.fallbackFont, false, false, [this] { - UIMessageBox::New( UIMessageBox::OK, - i18n( "new_fallback_font_requires_restart", - "New fallback font has been set. Application must be " - "restarted in order to see the changes." ) ) - ->showWhenReady(); - } ); + openFontDialog( + mConfig.ui.fallbackFont, false, false, + [this] { + UIMessageBox::New( UIMessageBox::OK, + i18n( "new_fallback_font_requires_restart", + "New fallback font has been set. Application must be " + "restarted in order to see the changes." ) ) + ->showWhenReady(); + }, + false ); } ); t.setCommand( "tree-view-configure-ignore-files", [this] { treeViewConfigureIgnoreFiles(); } ); diff --git a/src/tools/ecode/fontpickercontroller.cpp b/src/tools/ecode/fontpickercontroller.cpp index 8c17414c3..be8745f23 100644 --- a/src/tools/ecode/fontpickercontroller.cpp +++ b/src/tools/ecode/fontpickercontroller.cpp @@ -1,5 +1,6 @@ #include "fontpickercontroller.hpp" #include "ecode.hpp" +#include "settingsactions.hpp" #include #include #include @@ -18,7 +19,8 @@ struct MonospaceFontPreview { }; void FontPickerController::openFontDialog( std::string& fontPath, bool loadingMonoFont, - bool terminalFont, std::function onFinish ) { + bool terminalFont, std::function onFinish, + bool pickFontSize ) { std::string absoluteFontPath( fontPath ); if ( FileSystem::isRelativePath( absoluteFontPath ) ) absoluteFontPath = mApp->resPath() + fontPath; @@ -103,19 +105,20 @@ void FontPickerController::openFontDialog( std::string& fontPath, bool loadingMo defaultResourceScope().publishLocalFont( std::move( fontName ), font ); }; - const Uint32 flags = UIFontPickerDialog::DefaultFlags | + const Uint32 flags = ( pickFontSize ? UIFontPickerDialog::ShowSize : 0 ) | ( loadingMonoFont ? UIFontPickerDialog::MonospaceOnly : 0 ); UIFontPickerDialog* dialog = UIFontPickerDialog::New( flags ); dialog->setTitle( mApp->i18n( "select_font", "Select Font" ) ); dialog->setCloseShortcut( KEY_ESCAPE ); dialog->on( Event::OnWindowClose, [this, preview, applyMonospaceFont]( const Event* ) { + if ( !App::instance() || SceneManager::isShuttingDown() ) + return; + if ( preview && !preview->confirmed ) applyMonospaceFont( preview->originalFont, false ); - if ( App::instance() && mApp->getSplitter() && mApp->getSplitter()->getCurWidget() && - !SceneManager::instance()->isShuttingDown() ) { + if ( mApp->getSplitter() && mApp->getSplitter()->getCurWidget() ) mApp->getSplitter()->getCurWidget()->setFocus(); - } } ); if ( loadingMonoFont ) { dialog->setOnFontSelectionChanged( @@ -138,9 +141,18 @@ void FontPickerController::openFontDialog( std::string& fontPath, bool loadingMo } } ); } - dialog->setOnFontPicked( [&fontPath, loadingMonoFont, onFinish, preview, normalizedFontPath, - loadPreviewFont, publishPreviewFont, + dialog->setOnFontPicked( [this, &fontPath, loadingMonoFont, terminalFont, onFinish, preview, + normalizedFontPath, pickFontSize, loadPreviewFont, publishPreviewFont, applyMonospaceFont]( const UIFontSelection& selection ) { + if ( pickFontSize ) { + const StyleSheetLength size( selection.size, StyleSheetLength::Dp ); + if ( terminalFont ) + mApp->getSettingsActions()->setTerminalFontSize( size ); + else if ( loadingMonoFont ) + mApp->getSettingsActions()->setEditorFontSize( size ); + else + mApp->getSettingsActions()->setUIFontSize( size ); + } auto newPath = normalizedFontPath( selection.font.path ); if ( newPath.empty() ) return; @@ -168,6 +180,16 @@ void FontPickerController::openFontDialog( std::string& fontPath, bool loadingMo applyMonospaceFont( preview->originalFont, false ); } } ); + if ( pickFontSize ) { + UIFontSelection selection = dialog->getSelection(); + const Float currentSize = + terminalFont ? mApp->getConfig().term.fontSize.asDp( 0, Sizef(), mApp->getDisplayDPI() ) + : loadingMonoFont + ? mApp->getConfig().editor.fontSize.asDp( 0, Sizef(), mApp->getDisplayDPI() ) + : mApp->getConfig().ui.fontSize.asDp( 0, Sizef(), mApp->getDisplayDPI() ); + selection.size = static_cast( currentSize ); + dialog->setSelection( selection ); + } dialog->setSelectedFont( absoluteFontPath ); dialog->center(); dialog->show(); diff --git a/src/tools/ecode/fontpickercontroller.hpp b/src/tools/ecode/fontpickercontroller.hpp index e8533cb1d..cbed59fe5 100644 --- a/src/tools/ecode/fontpickercontroller.hpp +++ b/src/tools/ecode/fontpickercontroller.hpp @@ -13,7 +13,7 @@ class FontPickerController { explicit FontPickerController( App* app ) : mApp( app ) {} void openFontDialog( std::string& fontPath, bool loadingMonoFont, bool terminalFont = false, - std::function onFinish = {} ); + std::function onFinish = {}, bool pickFontSize = true ); private: App* mApp{ nullptr }; diff --git a/src/tools/ecode/settingsactions.cpp b/src/tools/ecode/settingsactions.cpp index 959977147..743fe260f 100644 --- a/src/tools/ecode/settingsactions.cpp +++ b/src/tools/ecode/settingsactions.cpp @@ -316,15 +316,18 @@ void SettingsActions::setEditorFontSize() { msgBox->setCloseShortcut( { KEY_ESCAPE, 0 } ); msgBox->showWhenReady(); msgBox->on( Event::OnConfirm, [this, msgBox]( const Event* ) { - mApp->getConfig().editor.fontSize = StyleSheetLength( msgBox->getTextInput()->getText() ); - mApp->getSplitter()->forEachEditor( [this]( UICodeEditor* editor ) { - editor->setFontSize( - mApp->getConfig().editor.fontSize.asPixels( 0, Sizef(), mApp->getDisplayDPI() ) ); - } ); + setEditorFontSize( StyleSheetLength( msgBox->getTextInput()->getText() ) ); } ); mApp->setFocusEditorOnClose( msgBox ); } +void SettingsActions::setEditorFontSize( const StyleSheetLength& size ) { + mApp->getConfig().editor.fontSize = size; + const Float fontSize = size.asPixels( 0, Sizef(), mApp->getDisplayDPI() ); + mApp->getSplitter()->forEachEditor( + [fontSize]( UICodeEditor* editor ) { editor->setFontSize( fontSize ); } ); +} + void SettingsActions::setTerminalFontSize() { UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::INPUT, i18n( "set_terminal_font_size", "Set the terminal font size:" ) ); @@ -333,16 +336,20 @@ void SettingsActions::setTerminalFontSize() { msgBox->setCloseShortcut( { KEY_ESCAPE, 0 } ); msgBox->showWhenReady(); msgBox->on( Event::OnConfirm, [this, msgBox]( const Event* ) { - mApp->getConfig().term.fontSize = StyleSheetLength( msgBox->getTextInput()->getText() ); - mApp->getSplitter()->forEachWidget( [this]( UIWidget* widget ) { - if ( widget && widget->isType( UI_TYPE_TERMINAL ) ) - widget->asType()->setFontSize( - mApp->getConfig().term.fontSize.asPixels( 0, Sizef(), mApp->getDisplayDPI() ) ); - } ); + setTerminalFontSize( StyleSheetLength( msgBox->getTextInput()->getText() ) ); } ); mApp->setFocusEditorOnClose( msgBox ); } +void SettingsActions::setTerminalFontSize( const StyleSheetLength& size ) { + mApp->getConfig().term.fontSize = size; + const Float fontSize = size.asPixels( 0, Sizef(), mApp->getDisplayDPI() ); + mApp->getSplitter()->forEachWidget( [fontSize]( UIWidget* widget ) { + if ( widget && widget->isType( UI_TYPE_TERMINAL ) ) + widget->asType()->setFontSize( fontSize ); + } ); +} + void SettingsActions::setUIFontSize() { UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::INPUT, i18n( "set_ui_font_size", "Set the UI font size:" ) ); @@ -351,27 +358,30 @@ void SettingsActions::setUIFontSize() { msgBox->setCloseShortcut( { KEY_ESCAPE, 0 } ); msgBox->showWhenReady(); msgBox->on( Event::OnConfirm, [this, msgBox]( const Event* ) { - mApp->getConfig().ui.fontSize = StyleSheetLength( msgBox->getTextInput()->getText() ); - Float fontSize = - mApp->getConfig().ui.fontSize.asPixels( 0, Sizef(), mApp->getDisplayDPI() ); - UIThemeManager* manager = mApp->getUISceneNode()->getUIThemeManager(); - manager->setDefaultFontSize( fontSize ); - manager->getDefaultTheme()->setDefaultFontSize( fontSize ); - mApp->getUISceneNode()->forEachNode( [this]( Node* node ) { - if ( node->isType( UI_TYPE_TEXTVIEW ) ) { - UITextView* textView = node->asType(); - if ( !textView->getUIStyle()->hasProperty( PropertyId::FontSize ) ) { - textView->setFontSize( mApp->getConfig().ui.fontSize.asPixels( - node->getParent()->getPixelsSize().getWidth(), Sizef(), - mApp->getUISceneNode()->getDPI() ) ); - } - } - } ); + setUIFontSize( StyleSheetLength( msgBox->getTextInput()->getText() ) ); msgBox->closeWindow(); } ); mApp->setFocusEditorOnClose( msgBox ); } +void SettingsActions::setUIFontSize( const StyleSheetLength& size ) { + mApp->getConfig().ui.fontSize = size; + const Float fontSize = size.asPixels( 0, Sizef(), mApp->getDisplayDPI() ); + UIThemeManager* manager = mApp->getUISceneNode()->getUIThemeManager(); + manager->setDefaultFontSize( fontSize ); + manager->getDefaultTheme()->setDefaultFontSize( fontSize ); + mApp->getUISceneNode()->forEachNode( [this]( Node* node ) { + if ( node->isType( UI_TYPE_TEXTVIEW ) ) { + UITextView* textView = node->asType(); + if ( !textView->getUIStyle()->hasProperty( PropertyId::FontSize ) ) { + textView->setFontSize( mApp->getConfig().ui.fontSize.asPixels( + node->getParent()->getPixelsSize().getWidth(), Sizef(), + mApp->getUISceneNode()->getDPI() ) ); + } + } + } ); +} + void SettingsActions::setUIPanelFontSize() { UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::INPUT, i18n( "set_side_panel_font_size", "Set side panel font size:" ) ); diff --git a/src/tools/ecode/settingsactions.hpp b/src/tools/ecode/settingsactions.hpp index 68a080b4d..9353b24fb 100644 --- a/src/tools/ecode/settingsactions.hpp +++ b/src/tools/ecode/settingsactions.hpp @@ -30,10 +30,13 @@ class SettingsActions { void setUIScaleFactor(); void setUIFontSize(); + void setUIFontSize( const StyleSheetLength& size ); void setEditorFontSize(); + void setEditorFontSize( const StyleSheetLength& size ); void setTerminalFontSize(); + void setTerminalFontSize( const StyleSheetLength& size ); void setUIPanelFontSize(); @@ -43,7 +46,6 @@ class SettingsActions { String i18n( const std::string& key, const String& def ); void checkForUpdatesResponse( Http::Response&& response, bool fromStartup ); - }; } // namespace ecode diff --git a/src/tools/ecode/settingsmenu.cpp b/src/tools/ecode/settingsmenu.cpp index 3fafa19a9..e42296bbc 100644 --- a/src/tools/ecode/settingsmenu.cpp +++ b/src/tools/ecode/settingsmenu.cpp @@ -3300,21 +3300,18 @@ UIMenu* SettingsMenu::createFontsMenu() { createFontHintMenu() ); mFontsMenu->addSubMenu( i18n( "ui_font_antialiasing", "Font Anti-Aliasing" ), findIcon( "font-size" ), createFontAntiAliasingMenu() ); - mFontsMenu->add( i18n( "ui_font_size", "UI Font Size" ), findIcon( "font-size" ) ) - ->setId( "ui-font-size" ); mFontsMenu->add( i18n( "ui_panel_font_size", "UI Panel Font Size" ), findIcon( "font-size" ) ) ->setId( "ui-panel-font-size" ); - mFontsMenu->add( i18n( "editor_font_size", "Editor Font Size" ), findIcon( "font-size" ) ) - ->setId( "editor-font-size" ); - mFontsMenu->add( i18n( "terminal_font_size", "Terminal Font Size" ), findIcon( "font-size" ) ) - ->setId( "terminal-font-size" ); mFontsMenu - ->add( i18n( "sans-serif_font_ellipsis", "Sans-Serif Font..." ), findIcon( "font-size" ) ) + ->add( i18n( "ui_font_and_size_ellipsis", "UI Font & Size..." ), findIcon( "font-size" ) ) ->setId( "sans-serif-font" ); mFontsMenu - ->add( i18n( "monospace_font_ellipsis", "Monospace Font..." ), findIcon( "font-size" ) ) + ->add( i18n( "editor_font_and_size_ellipsis", "Editor Font & Size..." ), + findIcon( "font-size" ) ) ->setId( "monospace-font" ); - mFontsMenu->add( i18n( "terminal_font_ellipsis", "Terminal Font..." ), findIcon( "font-size" ) ) + mFontsMenu + ->add( i18n( "terminal_font_and_size_ellipsis", "Terminal Font & Size..." ), + findIcon( "font-size" ) ) ->setId( "terminal-font" ); mFontsMenu->add( i18n( "fallback_font_ellipsis", "Fallback Font..." ), findIcon( "font-size" ) ) ->setId( "fallback-font" );