diff --git a/RedPandaIDE/RedPandaIDE.pro b/RedPandaIDE/RedPandaIDE.pro index 0335fe6a..7bf1a546 100644 --- a/RedPandaIDE/RedPandaIDE.pro +++ b/RedPandaIDE/RedPandaIDE.pro @@ -204,6 +204,7 @@ SOURCES += \ systemconsts.cpp \ utils.cpp \ utils/escape.cpp \ + utils/font.cpp \ utils/parsearg.cpp \ widgets/coloredit.cpp \ widgets/compileargumentswidget.cpp \ @@ -336,6 +337,7 @@ HEADERS += \ systemconsts.h \ utils.h \ utils/escape.h \ + utils/font.h \ utils/parsearg.h \ common.h \ widgets/coloredit.h \ diff --git a/RedPandaIDE/editor.cpp b/RedPandaIDE/editor.cpp index 84e2b062..2cf04d5f 100644 --- a/RedPandaIDE/editor.cpp +++ b/RedPandaIDE/editor.cpp @@ -5258,7 +5258,7 @@ void Editor::applySettings() QFont f=QFont(); f.setFamily(pSettings->editor().fontName()); - f.setFamilies(pSettings->editor().fontFamilies()); + f.setFamilies(pSettings->editor().fontFamiliesWithControlFont()); f.setPixelSize(pointToPixel(pSettings->editor().fontSize())); f.setStyleStrategy(QFont::PreferAntialias); setFont(f); diff --git a/RedPandaIDE/iconsmanager.cpp b/RedPandaIDE/iconsmanager.cpp index 54960286..21c70d03 100644 --- a/RedPandaIDE/iconsmanager.cpp +++ b/RedPandaIDE/iconsmanager.cpp @@ -97,6 +97,9 @@ void IconsManager::updateActionIcons(const QString& iconSet, int size) mIconPixmaps.insert(ACTION_MISC_RENAME, createSVGIcon(iconFolder+"00Misc-11Rename.svg",size,size)); mIconPixmaps.insert(ACTION_MISC_HELP, createSVGIcon(iconFolder+"00Misc-12Help.svg",size,size)); mIconPixmaps.insert(ACTION_MISC_FILTER, createSVGIcon(iconFolder+"00Misc-13Filter.svg",size,size)); + mIconPixmaps.insert(ACTION_MISC_MOVEUP, createSVGIcon(iconFolder+"00Misc-14MoveUp.svg",size,size)); + mIconPixmaps.insert(ACTION_MISC_MOVEDOWN, createSVGIcon(iconFolder+"00Misc-15MoveDown.svg",size,size)); + mIconPixmaps.insert(ACTION_MISC_RESET, createSVGIcon(iconFolder+"00Misc-16Reset.svg",size,size)); mIconPixmaps.insert(ACTION_FILE_NEW, createSVGIcon(iconFolder+"01File-01New.svg",size,size)); mIconPixmaps.insert(ACTION_FILE_OPEN, createSVGIcon(iconFolder+"01File-02Open.svg",size,size)); diff --git a/RedPandaIDE/iconsmanager.h b/RedPandaIDE/iconsmanager.h index 429e7ebb..5991469d 100644 --- a/RedPandaIDE/iconsmanager.h +++ b/RedPandaIDE/iconsmanager.h @@ -113,6 +113,9 @@ public: ACTION_MISC_RENAME, ACTION_MISC_HELP, ACTION_MISC_FILTER, + ACTION_MISC_MOVEUP, + ACTION_MISC_MOVEDOWN, + ACTION_MISC_RESET, ACTION_FILE_NEW, ACTION_FILE_OPEN, diff --git a/RedPandaIDE/resources/iconsets/bluesky/actions/00Misc-14MoveUp.svg b/RedPandaIDE/resources/iconsets/bluesky/actions/00Misc-14MoveUp.svg new file mode 100644 index 00000000..63bc1190 --- /dev/null +++ b/RedPandaIDE/resources/iconsets/bluesky/actions/00Misc-14MoveUp.svg @@ -0,0 +1 @@ + diff --git a/RedPandaIDE/resources/iconsets/bluesky/actions/00Misc-15MoveDown.svg b/RedPandaIDE/resources/iconsets/bluesky/actions/00Misc-15MoveDown.svg new file mode 100644 index 00000000..5f7d8e15 --- /dev/null +++ b/RedPandaIDE/resources/iconsets/bluesky/actions/00Misc-15MoveDown.svg @@ -0,0 +1 @@ + diff --git a/RedPandaIDE/resources/iconsets/bluesky/actions/00Misc-16Reset.svg b/RedPandaIDE/resources/iconsets/bluesky/actions/00Misc-16Reset.svg new file mode 100644 index 00000000..21dbe516 --- /dev/null +++ b/RedPandaIDE/resources/iconsets/bluesky/actions/00Misc-16Reset.svg @@ -0,0 +1 @@ + diff --git a/RedPandaIDE/resources/iconsets/contrast/actions/00Misc-14MoveUp.svg b/RedPandaIDE/resources/iconsets/contrast/actions/00Misc-14MoveUp.svg new file mode 100644 index 00000000..bdc81f23 --- /dev/null +++ b/RedPandaIDE/resources/iconsets/contrast/actions/00Misc-14MoveUp.svg @@ -0,0 +1 @@ + diff --git a/RedPandaIDE/resources/iconsets/contrast/actions/00Misc-15MoveDown.svg b/RedPandaIDE/resources/iconsets/contrast/actions/00Misc-15MoveDown.svg new file mode 100644 index 00000000..c7358952 --- /dev/null +++ b/RedPandaIDE/resources/iconsets/contrast/actions/00Misc-15MoveDown.svg @@ -0,0 +1 @@ + diff --git a/RedPandaIDE/resources/iconsets/contrast/actions/00Misc-16Reset.svg b/RedPandaIDE/resources/iconsets/contrast/actions/00Misc-16Reset.svg new file mode 100644 index 00000000..764f74bb --- /dev/null +++ b/RedPandaIDE/resources/iconsets/contrast/actions/00Misc-16Reset.svg @@ -0,0 +1 @@ + diff --git a/RedPandaIDE/resources/iconsets/newlook/actions/00Misc-14MoveUp.svg b/RedPandaIDE/resources/iconsets/newlook/actions/00Misc-14MoveUp.svg new file mode 100644 index 00000000..6ee957e8 --- /dev/null +++ b/RedPandaIDE/resources/iconsets/newlook/actions/00Misc-14MoveUp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/RedPandaIDE/resources/iconsets/newlook/actions/00Misc-15MoveDown.svg b/RedPandaIDE/resources/iconsets/newlook/actions/00Misc-15MoveDown.svg new file mode 100644 index 00000000..8d101671 --- /dev/null +++ b/RedPandaIDE/resources/iconsets/newlook/actions/00Misc-15MoveDown.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/RedPandaIDE/resources/iconsets/newlook/actions/00Misc-16Reset.svg b/RedPandaIDE/resources/iconsets/newlook/actions/00Misc-16Reset.svg new file mode 100644 index 00000000..ac1510a3 --- /dev/null +++ b/RedPandaIDE/resources/iconsets/newlook/actions/00Misc-16Reset.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/RedPandaIDE/settings.cpp b/RedPandaIDE/settings.cpp index b064f51f..98c34e67 100644 --- a/RedPandaIDE/settings.cpp +++ b/RedPandaIDE/settings.cpp @@ -20,6 +20,7 @@ #include #include "utils.h" #include "utils/escape.h" +#include "utils/font.h" #include "utils/parsearg.h" #include #include "systemconsts.h" @@ -669,65 +670,19 @@ void Settings::Editor::setEnableLigaturesSupport(bool newEnableLigaturesSupport) mEnableLigaturesSupport = newEnableLigaturesSupport; } -const QString &Settings::Editor::fallbackFontName() const -{ - return mFallbackFontName; -} - -void Settings::Editor::setFallbackFontName(const QString &newFontName) -{ - mFallbackFontName = newFontName; -} - -const QString &Settings::Editor::fallbackFontName2() const -{ - return mFallbackFontName2; -} - -void Settings::Editor::setFallbackFontName2(const QString &newFontName) -{ - mFallbackFontName2 = newFontName; -} - -const QString &Settings::Editor::fallbackFontName3() const -{ - return mFallbackFontName3; -} - -void Settings::Editor::setFallbackFontName3(const QString &newFontName) -{ - mFallbackFontName3 = newFontName; -} - -bool Settings::Editor::useFallbackFont2() const { - return mUseFallbackFont2; -} - -void Settings::Editor::setUseFallbackFont2(bool useFont) { - mUseFallbackFont2 = useFont; -} - -bool Settings::Editor::useFallbackFont3() const { - return mUseFallbackFont3; -} - -void Settings::Editor::setUseFallbackFont3(bool useFont) { - mUseFallbackFont3 = useFont; -} - QStringList Settings::Editor::fontFamilies() const { - QStringList result { - //QString("%1 [%2]").arg(mFontName,mFallbackFontName), - mFontName, - mFallbackFontName, - }; - if (mUseFallbackFont2) - result.append(mFallbackFontName2); - if (mUseFallbackFont3) - result.append(mFallbackFontName3); - result.append("Red Panda Control"); - return result; + return mFontFamilies; +} + +void Settings::Editor::setFontFamilies(const QStringList &newFontFamilies) +{ + mFontFamilies = newFontFamilies; +} + +QStringList Settings::Editor::fontFamiliesWithControlFont() const +{ + return mFontFamilies + QStringList{"Red Panda Control"}; } int Settings::Editor::mouseSelectionScrollSpeed() const @@ -1300,16 +1255,6 @@ void Settings::Editor::setGutterVisible(bool gutterVisible) mGutterVisible = gutterVisible; } -bool Settings::Editor::fontOnlyMonospaced() const -{ - return mFontOnlyMonospaced; -} - -void Settings::Editor::setFontOnlyMonospaced(bool fontOnlyMonospaced) -{ - mFontOnlyMonospaced = fontOnlyMonospaced; -} - int Settings::Editor::fontSize() const { return mFontSize; @@ -1322,12 +1267,7 @@ void Settings::Editor::setFontSize(int fontSize) QString Settings::Editor::fontName() const { - return mFontName; -} - -void Settings::Editor::setFontName(const QString &fontName) -{ - mFontName = fontName; + return mFontFamilies.length() > 0 ? mFontFamilies[0] : ""; } bool Settings::Editor::scrollByOneLess() const @@ -1410,15 +1350,8 @@ void Settings::Editor::doSave() //Font //font - saveValue("font_name", mFontName); - saveValue("fallback_font_name", mFallbackFontName); - saveValue("fallback_font_name2", mFallbackFontName2); - saveValue("fallback_font_name3", mFallbackFontName3); - saveValue("use_fallback_font2", mUseFallbackFont2); - saveValue("use_fallback_font3", mUseFallbackFont3); - + saveValue("font_families", mFontFamilies); saveValue("font_size", mFontSize); - saveValue("font_only_monospaced", mFontOnlyMonospaced); saveValue("line_spacing",mLineSpacing); saveValue("enable_ligatures_support", mEnableLigaturesSupport); saveValue("force_fixed_font_width", mForceFixedFontWidth); @@ -1549,32 +1482,22 @@ void Settings::Editor::doLoad() mRightEdgeLineColor = colorValue("right_edge_line_color",Qt::yellow); //Editor font - mFontName = stringValue("font_name",DEFAULT_MONO_FONT); - QString defaultCjkFontName = DEFAULT_MONO_FONT; - QString defaultLocaleName = QLocale::system().name(); - bool isCNJP = - defaultLocaleName.startsWith("zh_") - || defaultLocaleName.startsWith("ja_") - || defaultLocaleName==("zh") - || defaultLocaleName == ("ja"); - - if (defaultLocaleName == "zh_TW") - defaultCjkFontName = CJK_MONO_FONT_TC; - else if (defaultLocaleName == "ja_JP") - defaultCjkFontName = CJK_MONO_FONT_J; - else if (defaultLocaleName == "ko_KR") - defaultCjkFontName = CJK_MONO_FONT_K; - else if (defaultLocaleName == "zh_CN") - defaultCjkFontName = CJK_MONO_FONT_SC; - mFallbackFontName = stringValue("fallback_font_name",defaultCjkFontName); - mFallbackFontName2 = stringValue("fallback_font_name2",DEFAULT_MONO_FONT); - mFallbackFontName3 = stringValue("fallback_font_name3",DEFAULT_MONO_FONT); - mUseFallbackFont2 = boolValue("use_fallback_font2", false); - mUseFallbackFont3 = boolValue("use_fallback_font3", false); + QStringList fontFamilies = stringListValue("font_families", QStringList()); + if (fontFamilies.empty()) { + // backward compatibility: try old font settings + QString fontName = stringValue("font_name", ""); + if (!fontName.isEmpty()) + fontFamilies.append(fontName); + QString nonAsciiFontName = stringValue("non_ascii_font_name", ""); + if (!nonAsciiFontName.isEmpty()) + fontFamilies.append(nonAsciiFontName); + mFontFamilies = fontFamilies.empty() ? defaultEditorFonts() : fontFamilies; + } else { + mFontFamilies = fontFamilies; + } mFontSize = intValue("font_size",12); - mFontOnlyMonospaced = boolValue("font_only_monospaced",true); mLineSpacing = doubleValue("line_spacing",1.1); - mForceFixedFontWidth = boolValue("force_fixed_font_width", isCNJP); + mForceFixedFontWidth = boolValue("force_fixed_font_width", isCjk()); // if (mForceFixedFontWidth) // mEnableLigaturesSupport = false; // else @@ -1598,7 +1521,7 @@ void Settings::Editor::doLoad() mGutterLineNumbersStartZero = boolValue("gutter_line_numbers_start_zero",false); mGutterUseCustomFont = boolValue("gutter_use_custom_font",false); - mGutterFontName = stringValue("gutter_font_name",DEFAULT_MONO_FONT); + mGutterFontName = stringValue("gutter_font_name", defaultMonoFont()); mGutterFontSize = intValue("gutter_font_size",12); mGutterFontOnlyMonospaced = boolValue("gutter_font_only_monospaced",true); @@ -3879,29 +3802,10 @@ void Settings::Environment::doLoad() { //Appearance mTheme = stringValue("theme","dark"); - QString defaultFontName = DEFAULT_UI_FONT; - QString defaultLocaleName = QLocale::system().name(); - { - QString fontName; - if (defaultLocaleName == "zh_CN") - fontName = CJK_UI_FONT_SC; - else if (defaultLocaleName == "zh_TW") - fontName = CJK_UI_FONT_TC; - else if (defaultLocaleName == "ja_JP") - fontName = CJK_UI_FONT_J; - else if (defaultLocaleName == "ko_KR") - fontName = CJK_UI_FONT_K; - else - fontName = DEFAULT_UI_FONT; - QFont font(fontName); - if (font.exactMatch()) { - defaultFontName = fontName; - } - } - mInterfaceFont = stringValue("interface_font",defaultFontName); + mInterfaceFont = stringValue("interface_font", defaultUiFont()); mInterfaceFontSize = intValue("interface_font_size",11); mIconZoomFactor = doubleValue("icon_zoom_factor",1.0); - mLanguage = stringValue("language", defaultLocaleName); + mLanguage = stringValue("language", QLocale::system().name()); mIconSet = stringValue("icon_set","contrast"); mUseCustomIconSet = boolValue("use_custom_icon_set", false); mUseCustomTheme = boolValue("use_custom_theme", false); @@ -4515,7 +4419,7 @@ void Settings::Executor::doLoad() mProblemCaseValidateType =(ProblemCaseValidateType)intValue("problem_case_validate_type", (int)ProblemCaseValidateType::Exact); mRedirectStderrToToolLog = boolValue("redirect_stderr_to_toollog", false); - mCaseEditorFontName = stringValue("case_editor_font_name",DEFAULT_MONO_FONT); + mCaseEditorFontName = stringValue("case_editor_font_name", defaultMonoFont()); mCaseEditorFontSize = intValue("case_editor_font_size",11); mCaseEditorFontOnlyMonospaced = boolValue("case_editor_font_only_monospaced",true); int case_timeout = intValue("case_timeout", -1); @@ -4744,11 +4648,7 @@ void Settings::Debugger::doLoad() { mEnableDebugConsole = boolValue("enable_debug_console",true); mShowDetailLog = boolValue("show_detail_log",false); -#ifdef Q_OS_WIN - mFontName = stringValue("font_name","Consolas"); -#else - mFontName = stringValue("font_name","Dejavu Sans Mono"); -#endif + mFontName = stringValue("font_name", defaultMonoFont()); mOnlyShowMono = boolValue("only_show_mono",true); mFontSize = intValue("font_size",14); mUseIntelStyle = boolValue("use_intel_style",false); diff --git a/RedPandaIDE/settings.h b/RedPandaIDE/settings.h index f520b429..9f351748 100644 --- a/RedPandaIDE/settings.h +++ b/RedPandaIDE/settings.h @@ -26,6 +26,7 @@ #include "qsynedit/qsynedit.h" #include "compiler/compilerinfo.h" #include "utils.h" +#include "utils/font.h" /** * use the following command to get gcc's default bin/library folders: @@ -171,7 +172,6 @@ public: void setHalfPageScroll(bool halfPageScroll); QString fontName() const; - void setFontName(const QString &fontName); int fontSize() const; void setFontSize(int fontSize); @@ -355,22 +355,9 @@ public: bool enableLigaturesSupport() const; void setEnableLigaturesSupport(bool newEnableLigaturesSupport); - const QString &fallbackFontName() const; - void setFallbackFontName(const QString &newFontName); - - const QString &fallbackFontName2() const; - void setFallbackFontName2(const QString &newFontName); - - const QString &fallbackFontName3() const; - void setFallbackFontName3(const QString &newFontName); - - bool useFallbackFont2() const; - void setUseFallbackFont2(bool useFont); - - bool useFallbackFont3() const; - void setUseFallbackFont3(bool useFont); - QStringList fontFamilies() const; + void setFontFamilies(const QStringList &newFontFamilies); + QStringList fontFamiliesWithControlFont() const; int mouseSelectionScrollSpeed() const; void setMouseSelectionScrollSpeed(int newMouseSelectionScrollSpeed); @@ -462,14 +449,8 @@ public: //Font //font - QString mFontName; - QString mFallbackFontName; - QString mFallbackFontName2; - QString mFallbackFontName3; - bool mUseFallbackFont2; - bool mUseFallbackFont3; + QStringList mFontFamilies; int mFontSize; - bool mFontOnlyMonospaced; double mLineSpacing; bool mEnableLigaturesSupport; bool mForceFixedFontWidth; diff --git a/RedPandaIDE/settingsdialog/editorfontwidget.cpp b/RedPandaIDE/settingsdialog/editorfontwidget.cpp index 955d917b..f5abc821 100644 --- a/RedPandaIDE/settingsdialog/editorfontwidget.cpp +++ b/RedPandaIDE/settingsdialog/editorfontwidget.cpp @@ -15,21 +15,114 @@ * along with this program. If not, see . */ #include "editorfontwidget.h" +#include "editor.h" #include "ui_editorfontwidget.h" #include "../settings.h" #include "../mainwindow.h" +#include "../iconsmanager.h" +#include "utils.h" +#include "utils/font.h" + +void EditorFontModel::addFont(const QString& font) +{ + beginInsertRows(QModelIndex(),mFonts.size(),mFonts.size()); + mFonts.append(font); + endInsertRows(); +} + +void EditorFontModel::remove(int index) +{ + beginRemoveRows(QModelIndex(),index,index); + mFonts.removeAt(index); + endRemoveRows(); +} + +void EditorFontModel::clear() +{ + beginResetModel(); + mFonts.clear(); + endResetModel(); +} + +void EditorFontModel::moveUp(int index) +{ + if (index == 0) + return; + beginMoveRows(QModelIndex(),index,index,QModelIndex(),index - 1); + mFonts.move(index,index - 1); + endMoveRows(); +} + +void EditorFontModel::moveDown(int index) +{ + if (index == mFonts.size() - 1) + return; + beginMoveRows(QModelIndex(),index,index,QModelIndex(),index + 2); + mFonts.move(index,index + 1); + endMoveRows(); +} + +QModelIndex EditorFontModel::lastFont() +{ + return index(mFonts.size() - 1,0); +} + +const QStringList &EditorFontModel::fonts() const +{ + return mFonts; +} + +void EditorFontModel::updateFonts(const QStringList& fonts) +{ + beginResetModel(); + mFonts = fonts; + endResetModel(); +} + +int EditorFontModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + return mFonts.size(); +} + +int EditorFontModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + return 1; +} + +QVariant EditorFontModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + if (role == Qt::DisplayRole) + return mFonts.at(index.row()); + return QVariant(); +} + +bool EditorFontModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (!index.isValid()) + return false; + if (role == Qt::EditRole) { + mFonts[index.row()] = value.toString(); + emit dataChanged(index,index); + return true; + } + return false; +} EditorFontWidget::EditorFontWidget(const QString& name, const QString& group, QWidget *parent) : SettingsWidget(name,group,parent), ui(new Ui::EditorFontWidget) { ui->setupUi(this); - ui->cbFallbackFont2->setEnabled(false); - ui->cbFallbackFont3->setEnabled(false); - connect(ui->chkFallbackFont2, &QCheckBox::stateChanged, - this, &EditorFontWidget::onFallbackFontsCheckStateChanged); - connect(ui->chkFallbackFont3, &QCheckBox::stateChanged, - this, &EditorFontWidget::onFallbackFontsCheckStateChanged); + + QItemSelectionModel *m = ui->lstFontList->selectionModel(); + ui->lstFontList->setModel(&mModel); + delete m; } EditorFontWidget::~EditorFontWidget() @@ -37,16 +130,6 @@ EditorFontWidget::~EditorFontWidget() delete ui; } - -void EditorFontWidget::on_chkOnlyMonospacedFonts_stateChanged(int) -{ - if (ui->chkOnlyMonospacedFonts->isChecked()) { - ui->cbFont->setFontFilters(QFontComboBox::FontFilter::MonospacedFonts); - } else { - ui->cbFont->setFontFilters(QFontComboBox::FontFilter::AllFonts); - } -} - void EditorFontWidget::on_chkGutterOnlyMonospacedFonts_stateChanged(int) { if (ui->chkGutterOnlyMonospacedFonts->isChecked()) { @@ -56,17 +139,46 @@ void EditorFontWidget::on_chkGutterOnlyMonospacedFonts_stateChanged(int) } } +void EditorFontWidget::on_btnAddFont_clicked() +{ + mModel.addFont(ui->cbNewFont->currentFont().family()); +} + +void EditorFontWidget::on_btnRemoveFont_clicked() +{ + QModelIndex index = ui->lstFontList->currentIndex(); + if (!index.isValid()) + return; + mModel.remove(index.row()); +} + +void EditorFontWidget::on_btnMoveFontUp_clicked() +{ + QModelIndex index = ui->lstFontList->currentIndex(); + if (!index.isValid()) + return; + mModel.moveUp(index.row()); +} + +void EditorFontWidget::on_btnMoveFontDown_clicked() +{ + QModelIndex index = ui->lstFontList->currentIndex(); + if (!index.isValid()) + return; + mModel.moveDown(index.row()); +} + +void EditorFontWidget::on_btnResetFonts_clicked() +{ + mModel.updateFonts(defaultEditorFonts()); +} + void EditorFontWidget::doLoad() { //pSettings->editor().load(); //font - ui->chkOnlyMonospacedFonts->setChecked(pSettings->editor().fontOnlyMonospaced()); - ui->cbFont->setCurrentFont(QFont(pSettings->editor().fontName())); - ui->cbFallbackFont->setCurrentFont(QFont(pSettings->editor().fallbackFontName())); - ui->cbFallbackFont2->setCurrentFont(QFont(pSettings->editor().fallbackFontName2())); - ui->cbFallbackFont3->setCurrentFont(QFont(pSettings->editor().fallbackFontName3())); - ui->chkFallbackFont2->setChecked(pSettings->editor().useFallbackFont2()); - ui->chkFallbackFont3->setChecked(pSettings->editor().useFallbackFont3()); + ui->cbNewFont->setCurrentFont(QFont(defaultMonoFont())); + mModel.updateFonts(pSettings->editor().fontFamilies()); ui->spinFontSize->setValue(pSettings->editor().fontSize()); ui->spinLineSpacing->setValue(pSettings->editor().lineSpacing()); @@ -94,13 +206,7 @@ void EditorFontWidget::doLoad() void EditorFontWidget::doSave() { //font - pSettings->editor().setFontOnlyMonospaced(ui->chkOnlyMonospacedFonts->isChecked()); - pSettings->editor().setFontName(ui->cbFont->currentFont().family()); - pSettings->editor().setFallbackFontName(ui->cbFallbackFont->currentFont().family()); - pSettings->editor().setFallbackFontName2(ui->cbFallbackFont2->currentFont().family()); - pSettings->editor().setFallbackFontName3(ui->cbFallbackFont3->currentFont().family()); - pSettings->editor().setUseFallbackFont2(ui->chkFallbackFont2->isChecked()); - pSettings->editor().setUseFallbackFont3(ui->chkFallbackFont3->isChecked()); + pSettings->editor().setFontFamilies(mModel.fonts()); pSettings->editor().setFontSize(ui->spinFontSize->value()); pSettings->editor().setLineSpacing(ui->spinLineSpacing->value()); @@ -129,23 +235,10 @@ void EditorFontWidget::doSave() pMainWindow->updateEditorSettings(); } -void EditorFontWidget::onFallbackFontsCheckStateChanged() -{ - ui->cbFallbackFont2->setEnabled(ui->chkFallbackFont2->isChecked()); - ui->cbFallbackFont3->setEnabled(ui->chkFallbackFont3->isChecked()); +void EditorFontWidget::updateIcons(const QSize &/*size*/) { + pIconsManager->setIcon(ui->btnAddFont, IconsManager::ACTION_MISC_ADD); + pIconsManager->setIcon(ui->btnRemoveFont, IconsManager::ACTION_MISC_REMOVE); + pIconsManager->setIcon(ui->btnMoveFontUp, IconsManager::ACTION_MISC_MOVEUP); + pIconsManager->setIcon(ui->btnMoveFontDown, IconsManager::ACTION_MISC_MOVEDOWN); + pIconsManager->setIcon(ui->btnResetFonts, IconsManager::ACTION_MISC_RESET); } - - -// void EditorFontWidget::on_chkLigature_toggled(bool checked) -// { -// if (ui->chkLigature->isChecked()) -// ui->chkForceFixedFontWidth->setChecked(false); -// } - - -// void EditorFontWidget::on_chkForceFixedFontWidth_toggled(bool checked) -// { -// if (ui->chkForceFixedFontWidth->isChecked()) -// ui->chkLigature->setChecked(false); -// } - diff --git a/RedPandaIDE/settingsdialog/editorfontwidget.h b/RedPandaIDE/settingsdialog/editorfontwidget.h index a2545e9b..1464b110 100644 --- a/RedPandaIDE/settingsdialog/editorfontwidget.h +++ b/RedPandaIDE/settingsdialog/editorfontwidget.h @@ -18,12 +18,38 @@ #define EDITORFONTWIDGET_H #include +#include #include "settingswidget.h" +#include "utils/font.h" namespace Ui { class EditorFontWidget; } +class EditorFontModel : public QAbstractListModel +{ + Q_OBJECT +public: + void addFont(const QString& font); + void remove(int index); + void clear(); + void moveUp(int index); + void moveDown(int index); + QModelIndex lastFont(); + const QStringList &fonts() const; + void updateFonts(const QStringList& fonts); + + // QAbstractItemModel interface +public: + int rowCount(const QModelIndex &parent) const override; + int columnCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role) override; + +private: + QStringList mFonts; +}; + class EditorFontWidget : public SettingsWidget { Q_OBJECT @@ -33,9 +59,12 @@ public: private slots: - void onFallbackFontsCheckStateChanged(); - void on_chkOnlyMonospacedFonts_stateChanged(int arg1); void on_chkGutterOnlyMonospacedFonts_stateChanged(int arg1); + void on_btnAddFont_clicked(); + void on_btnRemoveFont_clicked(); + void on_btnMoveFontUp_clicked(); + void on_btnMoveFontDown_clicked(); + void on_btnResetFonts_clicked(); // void on_chkLigature_toggled(bool checked); @@ -43,11 +72,13 @@ private slots: private: Ui::EditorFontWidget *ui; + EditorFontModel mModel; // SettingsWidget interface protected: void doLoad() override; void doSave() override; + void updateIcons(const QSize &size) override; }; #endif // EDITORFONTWIDGET_H diff --git a/RedPandaIDE/settingsdialog/editorfontwidget.ui b/RedPandaIDE/settingsdialog/editorfontwidget.ui index 082b4ebc..28829a9e 100644 --- a/RedPandaIDE/settingsdialog/editorfontwidget.ui +++ b/RedPandaIDE/settingsdialog/editorfontwidget.ui @@ -7,13 +7,80 @@ 0 0 876 - 781 + 850 Form + + + + Font: + + + + + + + + + Add + + + + + + + + + + + + Remove + + + + + + + Move up + + + + + + + Move down + + + + + + + Reset + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + @@ -23,16 +90,9 @@ 11 - - - - Line Spacing: - - - - - - + + + 0 @@ -46,14 +106,21 @@ 0 - - - false + + + Enable ligatures support - + + + Force fixed width + + + + + Qt::Horizontal @@ -68,7 +135,21 @@ - + + + + Line Spacing: + + + + + + + Size: + + + + @@ -107,171 +188,6 @@ - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - false - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - Fallback Font 3: - - - - - - - Fallback Font: - - - - - - - Fallback Font 2: - - - - - - - Size: - - - - - - - Font: - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - false - - - QComboBox::AdjustToContents - - - QFontComboBox::AllFonts - - - - - - - Show only monospaced fonts - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - false - - - QComboBox::AdjustToContents - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - @@ -318,51 +234,6 @@ - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Enable ligatures support - - - - - - - Force fixed width - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - diff --git a/RedPandaIDE/settingsdialog/environmentprogramswidget.cpp b/RedPandaIDE/settingsdialog/environmentprogramswidget.cpp index 9c2980ac..5aa55f9b 100644 --- a/RedPandaIDE/settingsdialog/environmentprogramswidget.cpp +++ b/RedPandaIDE/settingsdialog/environmentprogramswidget.cpp @@ -20,7 +20,9 @@ #include "../iconsmanager.h" #include "../systemconsts.h" #include "../compiler/executablerunner.h" +#include "utils.h" #include "utils/escape.h" +#include "utils/font.h" #include #include @@ -30,7 +32,7 @@ EnvironmentProgramsWidget::EnvironmentProgramsWidget(const QString& name, const ui(new Ui::EnvironmentProgramsWidget) { ui->setupUi(this); - ui->labelCmdPreviewResult->setFont(QFont(DEFAULT_MONO_FONT)); + ui->labelCmdPreviewResult->setFont(defaultMonoFont()); #ifndef Q_OS_WINDOWS ui->grpUseCustomTerminal->setCheckable(false); #endif diff --git a/RedPandaIDE/settingsdialog/executorgeneralwidget.cpp b/RedPandaIDE/settingsdialog/executorgeneralwidget.cpp index 95551fb9..cd7bd9ec 100644 --- a/RedPandaIDE/settingsdialog/executorgeneralwidget.cpp +++ b/RedPandaIDE/settingsdialog/executorgeneralwidget.cpp @@ -19,6 +19,8 @@ #include "../settings.h" #include "../iconsmanager.h" #include "../systemconsts.h" +#include "utils.h" +#include "utils/font.h" #include "utils/parsearg.h" #include @@ -30,7 +32,7 @@ ExecutorGeneralWidget::ExecutorGeneralWidget(const QString& name, const QString& ui(new Ui::ExecutorGeneralWidget) { ui->setupUi(this); - ui->txtParsedArgsInJson->setFont(QFont(DEFAULT_MONO_FONT)); + ui->txtParsedArgsInJson->setFont(defaultMonoFont()); #ifdef Q_OS_WIN ui->chkVTSeq->setVisible(true); #else diff --git a/RedPandaIDE/systemconsts.h b/RedPandaIDE/systemconsts.h index 8f89b1db..63e76e03 100644 --- a/RedPandaIDE/systemconsts.h +++ b/RedPandaIDE/systemconsts.h @@ -125,41 +125,6 @@ #define SDCC_HEX_SUFFIX "hex" #define SDCC_REL_SUFFIX "rel" -#if defined(Q_OS_WIN) -# define DEFAULT_UI_FONT "Segoe UI" -# define CJK_UI_FONT_SC "Microsoft YaHei UI" -# define CJK_UI_FONT_TC "Microsoft JhengHei UI" -# define CJK_UI_FONT_J "Yu Gothic UI" -# define CJK_UI_FONT_K "Malgun Gothic" -# define DEFAULT_MONO_FONT "Consolas" -# define CJK_MONO_FONT_SC "Microsoft YaHei" -# define CJK_MONO_FONT_TC "Microsoft JhengHei" -# define CJK_MONO_FONT_J "Yu Gothic" -# define CJK_MONO_FONT_K "Malgun Gothic" -#elif defined(Q_OS_MACOS) -# define DEFAULT_UI_FONT "Helvetica Neue" -# define CJK_UI_FONT_SC "PingFang SC" -# define CJK_UI_FONT_TC "PingFang TC" -# define CJK_UI_FONT_J "Hiragino Sans" -# define CJK_UI_FONT_K "Apple SD Gothic Neo" -# define DEFAULT_MONO_FONT "Menlo" -# define CJK_MONO_FONT_SC CJK_UI_FONT_SC -# define CJK_MONO_FONT_TC CJK_UI_FONT_TC -# define CJK_MONO_FONT_J CJK_UI_FONT_J -# define CJK_MONO_FONT_K CJK_UI_FONT_K -#else // XDG desktop -# define DEFAULT_UI_FONT "Sans" // use fontconfig default -# define CJK_UI_FONT_SC "Noto Sans CJK SC" -# define CJK_UI_FONT_TC "Noto Sans CJK TC" -# define CJK_UI_FONT_J "Noto Sans CJK JP" -# define CJK_UI_FONT_K "Noto Sans CJK KR" -# define DEFAULT_MONO_FONT "Monospace" // use fontconfig default -# define CJK_MONO_FONT_SC CJK_UI_FONT_SC // intentionally: the "Mono" version is not stricly monospaced either, and has less weights -# define CJK_MONO_FONT_TC CJK_UI_FONT_TC -# define CJK_MONO_FONT_J CJK_UI_FONT_J -# define CJK_MONO_FONT_K CJK_UI_FONT_K -#endif - class SystemConsts { public: diff --git a/RedPandaIDE/utils/font.cpp b/RedPandaIDE/utils/font.cpp new file mode 100644 index 00000000..72c11e74 --- /dev/null +++ b/RedPandaIDE/utils/font.cpp @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "utils/font.h" + +#include +#include +#include + +#if defined(Q_OS_WIN) + +static const QMap uiFontsByLocale = {}; + +static const QMap uiFontsByScript = { + {QLocale::CyrillicScript, {"Segoe UI", "Tahoma"}}, + {QLocale::SimplifiedHanScript, {"Microsoft YaHei UI", "Microsoft YaHei", "SimHei"}}, + {QLocale::TraditionalHanScript, {"Microsoft JhengHei UI", "Microsoft JhengHei", "SimHei"}}, + {QLocale::LatinScript, {"Segoe UI", "Tahoma"}}, + {QLocale::GreekScript, {"Segoe UI", "Tahoma"}}, + {QLocale::JapaneseScript, {"Yu Gothic UI", "Meiryo UI", "MS UI Gothic"}}, + {QLocale::KoreanScript, {"Malgun Gothic", "Dotum"}}, +}; + +#elif defined(Q_OS_MACOS) + +static const QMap uiFontsByLocale = { + {"zh_HK", {"PingFang HK"}}, +}; + +static const QMap uiFontsByScript = { + {QLocale::CyrillicScript, {"Helvetica Neue"}}, + {QLocale::SimplifiedHanScript, {"PingFang SC"}}, + {QLocale::TraditionalHanScript, {"PingFang TC"}}, + {QLocale::LatinScript, {"Helvetica Neue"}}, + {QLocale::GreekScript, {"Helvetica Neue"}}, + {QLocale::JapaneseScript, {"Hiragino Sans"}}, + {QLocale::KoreanScript, {"Apple SD Gothic Neo"}}, +}; + +#else // XDG desktop + +static const QMap uiFontsByLocale = { + {"zh_HK", {"Noto Sans CJK HK"}}, +}; + +static const QMap uiFontsByScript = { + {QLocale::CyrillicScript, {"Noto Sans"}}, + {QLocale::SimplifiedHanScript, {"Noto Sans CJK SC"}}, + {QLocale::TraditionalHanScript, {"Noto Sans CJK TC"}}, + {QLocale::LatinScript, {"Noto Sans"}}, + {QLocale::GreekScript, {"Noto Sans"}}, + {QLocale::JapaneseScript, {"Noto Sans CJK JP"}}, + {QLocale::KoreanScript, {"Noto Sans CJK KR"}}, +}; + +#endif + +QString defaultUiFont() +{ + QString defaultLocaleName = QLocale::system().name(); + QLocale::Script defaultScript = QLocale::system().script(); + if (uiFontsByLocale.contains(defaultLocaleName)) { + QStringList fonts = uiFontsByLocale[defaultLocaleName]; + for (const QString &font : fonts) { + if (QFont(font).exactMatch()) + return font; + } + } + if (uiFontsByScript.contains(defaultScript)) { + QStringList fonts = uiFontsByScript[defaultScript]; + for (const QString &font : fonts) { + if (QFont(font).exactMatch()) + return font; + } + } + + // final fallback +#if defined(Q_OS_WIN) + return "Microsoft Sans Serif"; +#elif defined(Q_OS_MACOS) + return "Helvetica Neue"; +#else // XDG desktop + return "Sans Serif"; +#endif +} + +QString defaultMonoFont() +{ +#if defined(Q_OS_WIN) + QFont font("Consolas"); + if (font.exactMatch()) + return "Consolas"; + else + return "Courier New"; +#elif defined(Q_OS_MACOS) + return "Menlo"; +#else // XDG desktop + QFont font("Noto Sans Mono"); + if (font.exactMatch()) + return "Noto Sans Mono"; + else + return "DejaVu Sans Mono"; +#endif +} + +QString defaultEmojiFont() +{ +#if defined(Q_OS_WIN) + return "Segoe UI Emoji"; +#elif defined(Q_OS_MACOS) + return "Apple Color Emoji"; +#else // XDG desktop + return "Noto Color Emoji"; +#endif +} + +bool isCjk(const QString &locale) +{ + return locale.startsWith("zh_") || locale == "zh" || + locale.startsWith("ja_") || locale == "ja" || + locale.startsWith("ko_") || locale == "ko"; +} + +QStringList defaultCjkEditorFonts(const QString &locale) +{ +#if defined(Q_OS_WIN) + QVersionNumber currentVersion = QVersionNumber::fromString(QSysInfo::kernelVersion()); + const QVersionNumber vista(6, 0); + if (locale == "zh_TW" || locale == "zh_HK"){ + if (currentVersion >= vista) + return {"Microsoft JhengHei"}; + else + return {"SimHei"}; + } else if (locale == "ja_JP") { + if (currentVersion >= vista) + // prefer Meiryo over Yu Gothic, and YaHei over JhengHei + // they are bolder and more readable + return {"Meiryo", "Microsoft YaHei"}; + else + return {"MS Gothic", "SimHei"}; + } else if (locale == "ko_KR") { + if (currentVersion >= vista) + return {"Malgun Gothic", "Microsoft YaHei"}; + else + return {"Dotum", "SimHei"}; + } else { + // finally fallback to zh_CN + // with largest coverage, CJK ideographs have uniform look + if (currentVersion >= vista) + return {"Microsoft YaHei"}; + else + return {"SimHei"}; + } +#elif defined(Q_OS_MACOS) + // TODO: coverage is not verified + if (locale == "zh_TW") + return {"PingFang TC"}; + else if (locale == "zh_HK") + return {"PingFang HK"}; + else if (locale == "ja_JP") + // prefer Hiragino Sans GB for uniform look of CJK ideographs + return {"Hiragino Sans", "Hiragino Sans GB"}; + else if (locale == "ko_KR") + return {"Apple SD Gothic Neo", "PingFang SC"}; + else + return {"PingFang SC"}; +#else // XDG desktop + // Noto Sans CJK have same coverage, add one of them is enough + // intentionally: the "Mono" variant is not strictly monospaced either, and has less weights + if (locale == "zh_TW") + return {"Noto Sans CJK TC"}; + else if (locale == "zh_HK") + return {"Noto Sans CJK HK"}; + else if (locale == "ja_JP") + return {"Noto Sans CJK JP"}; + else if (locale == "ko_KR") + return {"Noto Sans CJK KR"}; + else + return {"Noto Sans CJK SC"}; +#endif +} + +QStringList defaultFallbackEditorFonts() +{ +#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) + // use system fallback fonts + return {}; +#else // XDG desktop + // There is a limit of 256 fallback fonts in Qt: + // https://bugreports.qt.io/browse/QTBUG-80434 + // As a result, on systems with Noto installed (~1000 fonts), fallback will fail. + // Here we recommend use merged Noto fonts to reduce the number of required fonts. + // https://github.com/notofonts/notofonts.github.io/tree/main/megamerge + return { + "Noto Sans Living", + "Noto Sans Historical", + "Noto Serif Living", + "Noto Serif Historical", + }; +#endif +} + +QStringList defaultEditorFonts() +{ + QStringList result = { + defaultMonoFont(), + }; + + // special handling CJK fonts: they share same code points + QString defaultLocaleName = QLocale::system().name(); + if (isCjk(defaultLocaleName)) { + result += defaultCjkEditorFonts(defaultLocaleName); + result += defaultFallbackEditorFonts(); + } else { + result += defaultFallbackEditorFonts(); + result += defaultCjkEditorFonts(defaultLocaleName); + } + + result.append(defaultEmojiFont()); + return result; +} diff --git a/RedPandaIDE/utils/font.h b/RedPandaIDE/utils/font.h new file mode 100644 index 00000000..952ead06 --- /dev/null +++ b/RedPandaIDE/utils/font.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef FONT_H +#define FONT_H + +#include +#include +#include + +enum class UnicodeSupportLevel { + BmpOnly = 0, + FullCodePoint = 1, + Contextual = 2, + Grapheme = 3, + Bidirectional = 4, +}; + +QString defaultUiFont(); +QString defaultMonoFont(); +QString defaultEmojiFont(); +bool isCjk(const QString &locale = QLocale::system().name()); +QStringList defaultCjkEditorFonts(const QString &locale); +QStringList defaultFallbackEditorFonts(); +QStringList defaultEditorFonts(); + +#endif // FONT_H diff --git a/RedPandaIDE/widgets/cpudialog.cpp b/RedPandaIDE/widgets/cpudialog.cpp index 541a6fc2..b397646e 100644 --- a/RedPandaIDE/widgets/cpudialog.cpp +++ b/RedPandaIDE/widgets/cpudialog.cpp @@ -146,7 +146,7 @@ void CPUDialog::resetEditorFont(float dpi) ui->txtCode->setOptions(options); QFont f=QFont(); f.setFamily(pSettings->editor().fontName()); - f.setFamilies(pSettings->editor().fontFamilies()); + f.setFamilies(pSettings->editor().fontFamiliesWithControlFont()); f.setPixelSize(pointToPixel(pSettings->editor().fontSize(),dpi)); f.setStyleStrategy(QFont::PreferAntialias); ui->txtCode->setFont(f); diff --git a/RedPandaIDE/xmake.lua b/RedPandaIDE/xmake.lua index e4649b6c..287f6089 100644 --- a/RedPandaIDE/xmake.lua +++ b/RedPandaIDE/xmake.lua @@ -53,6 +53,7 @@ target("RedPandaIDE") "problems/ojproblemset.cpp", "problems/problemcasevalidator.cpp", "utils/escape.cpp", + "utils/font.cpp", "utils/parsearg.cpp") add_moc_classes( diff --git a/libs/qsynedit/qsynedit/painter.cpp b/libs/qsynedit/qsynedit/painter.cpp index f23644c0..34475d43 100644 --- a/libs/qsynedit/qsynedit/painter.cpp +++ b/libs/qsynedit/qsynedit/painter.cpp @@ -152,7 +152,7 @@ void QSynEditPainter::paintGutter(const QRect& clip) textRect = mPainter->boundingRect(textRect, Qt::AlignLeft,s); mPainter->drawText( (mEdit->mGutterWidth - mEdit->mGutter.rightOffset() - 2) - textRect.width(), - rcLine.bottom() + ((mEdit->mTextHeight - int(textRect.height())) / 2 - mPainter->fontMetrics().descent()), + rcLine.bottom() - (mEdit->mTextHeight - int(textRect.height())) / 2 - mPainter->fontMetrics().descent(), s ); } @@ -351,7 +351,10 @@ void QSynEditPainter::paintToken( if (last >= first && mRcToken.right() > mRcToken.left()) { int nX = fixXValue(first); - int nY = mRcToken.bottom()-mPainter->fontMetrics().descent(); + int lineHeight = mRcToken.height(); + int fontHeight = mPainter->fontMetrics().descent() + mPainter->fontMetrics().ascent(); + int linePadding = (lineHeight - fontHeight) / 2; + int nY = mRcToken.bottom() - linePadding - mPainter->fontMetrics().descent(); first -= tokenLeft; last -= tokenLeft; QRect rcTokenBack = mRcToken;