diff --git a/bin/assets/i18n/en.xml b/bin/assets/i18n/en.xml index 96e71d9ca..d8fd6b169 100644 --- a/bin/assets/i18n/en.xml +++ b/bin/assets/i18n/en.xml @@ -1,5 +1,5 @@ - + About Ecode Add Branch Add Build @@ -194,8 +194,9 @@ is hover a word that represents a color. Failed checking for updates. Error copying file. Error renaming file. - Replace \, , -, and (Unicode characters + Replace \, , +, + and (Unicode characters Exclusive Mode Open directory in terminal Execute in terminal @@ -387,6 +388,8 @@ Restart ecode to see the changes. New Terminal New Terminal Behavior New terminal name: + New language assigned. +Please restart the application to see the complete changes. New UI scale factor assigned. Please restart the application. New Value @@ -615,6 +618,7 @@ file in the directory tree. Type Type to Locate Ui Font Size + UI Language Multisample Anti-Aliasing Level Ui Panel Font Size UI Prefers Color Scheme diff --git a/include/eepp/system/translator.hpp b/include/eepp/system/translator.hpp index 7b48fea7a..15e18adf2 100644 --- a/include/eepp/system/translator.hpp +++ b/include/eepp/system/translator.hpp @@ -61,10 +61,15 @@ class EE_API Translator { StringLocaleDictionary& getDictionary() { return mDictionary; } + void setLanguageName( const std::string& id, const std::string& name ); + + std::unordered_map getLanguageNames() const; + protected: std::string mDefaultLanguage; std::string mCurrentLanguage; StringLocaleDictionary mDictionary; + std::unordered_map mLangNames; bool mSetDefaultValues{ false }; bool loadNodes( pugi::xml_node node, std::string lang = "" ); diff --git a/src/eepp/system/translator.cpp b/src/eepp/system/translator.cpp index 8babd0b55..52be924f7 100644 --- a/src/eepp/system/translator.cpp +++ b/src/eepp/system/translator.cpp @@ -278,6 +278,11 @@ void Translator::saveToStream( IOStream& stream, std::string lang ) { auto r = resources.append_child( "string" ); auto d = r.append_child( pugi::node_pcdata ); r.append_attribute( "name" ).set_value( str.first.c_str() ); + + auto langNameIt = mLangNames.find( lang ); + if ( langNameIt != mLangNames.end() ) + r.append_attribute( "title" ).set_name( langNameIt->second.c_str() ); + d.set_value( str.second.toUtf8().c_str() ); } @@ -285,4 +290,12 @@ void Translator::saveToStream( IOStream& stream, std::string lang ) { doc.save( writer ); } +void Translator::setLanguageName( const std::string& id, const std::string& name ) { + mLangNames[id] = name; +} + +std::unordered_map Translator::getLanguageNames() const { + return mLangNames; +} + }} // namespace EE::System diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index c0a868489..a3645b532 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -732,17 +732,6 @@ App::~App() { mFileSystemListener = nullptr; } mDirTree.reset(); - -#ifdef EE_DEBUG - if ( !mUISceneNode->getTranslator().isSetDefaultValues() ) - return; - std::string langsPath( mConfigPath + "i18n" + FileSystem::getOSSlash() ); - if ( !FileSystem::fileExists( langsPath ) && !FileSystem::makeDir( langsPath ) ) - return; - std::string lang( mUISceneNode->getTranslator().getCurrentLanguage() ); - IOStreamFile file( langsPath + lang + ".xml", "wb" ); - mUISceneNode->getTranslator().saveToStream( file, lang ); -#endif } void App::updateRecentFiles() { @@ -1838,6 +1827,10 @@ const std::string& App::getThemesPath() const { return mThemesPath; } +const std::string& App::geti18nPath() const { + return mi18nPath; +} + std::string App::getThemePath() const { if ( mConfig.ui.theme.empty() || "default_theme" == mConfig.ui.theme ) return getDefaultThemePath(); @@ -3562,8 +3555,8 @@ void App::init( const LogLevel& logLevel, std::string file, const Float& pidelDe if ( !language.empty() ) mUISceneNode->getTranslator().setCurrentLanguage( language ); std::string currentLanguage( mUISceneNode->getTranslator().getCurrentLanguage() ); - std::string langPath( mResPath + "i18n" + FileSystem::getOSSlash() + currentLanguage + - ".xml" ); + mi18nPath = mResPath + "i18n" + FileSystem::getOSSlash(); + std::string langPath( mi18nPath + currentLanguage + ".xml" ); if ( currentLanguage != "en" && FileSystem::fileExists( langPath ) ) mUISceneNode->getTranslator().loadFromFile( langPath ); diff --git a/src/tools/ecode/ecode.hpp b/src/tools/ecode/ecode.hpp index 7ff2c6f48..9cc5015c5 100644 --- a/src/tools/ecode/ecode.hpp +++ b/src/tools/ecode/ecode.hpp @@ -387,6 +387,8 @@ class App : public UICodeEditorSplitter::Client { const std::string& getThemesPath() const; + const std::string& geti18nPath() const; + std::string getThemePath() const; std::string getDefaultThemePath() const; @@ -468,6 +470,7 @@ class App : public UICodeEditorSplitter::Client { std::string mLanguagesPath; std::string mThemesPath; std::string mLogsPath; + std::string mi18nPath; Float mDisplayDPI{ 96 }; std::shared_ptr mThreadPool; std::shared_ptr mDirTree; diff --git a/src/tools/ecode/iconmanager.cpp b/src/tools/ecode/iconmanager.cpp index 413147f92..6db2f631c 100644 --- a/src/tools/ecode/iconmanager.cpp +++ b/src/tools/ecode/iconmanager.cpp @@ -219,7 +219,8 @@ void IconManager::init( UISceneNode* sceneNode, FontTrueType* iconFont, FontTrue { "git-merge", 0xeafe }, { "diff-single", 0xec22 }, { "remove", 0xeb3b }, - { "tag", 0xea66 } }; + { "tag", 0xea66 }, + { "globe", 0xeb01 } }; for ( const auto& icon : codIcons ) iconTheme->add( UIGlyphIcon::New( icon.first, codIconFont, icon.second ) ); diff --git a/src/tools/ecode/plugins/git/git.cpp b/src/tools/ecode/plugins/git/git.cpp index 580e87cc6..8ff89cbf5 100644 --- a/src/tools/ecode/plugins/git/git.cpp +++ b/src/tools/ecode/plugins/git/git.cpp @@ -460,7 +460,8 @@ std::vector Git::getAllBranchesAndTags( RefType ref, std::string_vi if ( ( ref & RefType::Stash ) && EXIT_SUCCESS == git( "stash list", projectDir, buf ) ) { branches.reserve( branches.size() + countLines( buf ) ); - LuaPattern pattern( "(stash@{%d+}):%s(.*)" ); + std::string ptrn( "(stash@{%d+}):%s(.*)" ); + LuaPattern pattern( ptrn ); readAllLines( buf, [&]( const std::string_view& line ) { LuaPattern::Range matches[3]; if ( pattern.matches( line.data(), 0, matches, line.size() ) ) { @@ -484,7 +485,8 @@ std::vector Git::fetchSubModules( const std::string& projectDir ) { std::vector submodules; std::string buf; FileSystem::fileGet( ( !projectDir.empty() ? projectDir : mProjectPath ) + ".gitmodules", buf ); - LuaPattern pattern( "^%s*path%s*=%s*(.+)" ); + std::string ptrn( "^%s*path%s*=%s*(.+)" ); + LuaPattern pattern( ptrn ); readAllLines( buf, [&pattern, &submodules]( const std::string_view& line ) { LuaPattern::Range matches[2]; if ( pattern.matches( line.data(), 0, matches, line.size() ) ) { @@ -549,7 +551,8 @@ Git::Status Git::status( bool recurseSubmodules, const std::string& projectDir ) getSubModules( projectDir ); bool submodules = hasSubmodules( projectDir ); - LuaPattern subModulePattern( "^Entering '(.*)'" ); + std::string enteringPtrn( "^Entering '(.*)'" ); + LuaPattern subModulePattern( enteringPtrn ); bool modifiedSubmodule = false; @@ -567,7 +570,8 @@ Git::Status Git::status( bool recurseSubmodules, const std::string& projectDir ) auto parseStatus = [&s, &buf, &modifiedSubmodule, &projectDir, this, &subModulePattern, submodules, &isSubmodule]() { std::string subModulePath = ""; - LuaPattern pattern( "^([mMARTUD?%s][mMARTUD?%s])%s(.*)" ); + std::string ptrn = "^([mMARTUD?%s][mMARTUD?%s])%s(.*)"; + LuaPattern pattern( ptrn ); size_t changesCount = countLines( buf ); if ( changesCount > 1000 ) @@ -602,7 +606,8 @@ Git::Status Git::status( bool recurseSubmodules, const std::string& projectDir ) status.type == GitStatusType::Staged && statusStr[1] != ' '; if ( status.symbol == GitStatusChar::Renamed ) { - LuaPattern rpattern( ".*%s%-%>%s(.*)" ); + std::string rptrn( ".*%s%-%>%s(.*)" ); + LuaPattern rpattern( rptrn ); LuaPattern::Range rranges[2]; if ( rpattern.matches( file.data(), 0, rranges, file.size() ) ) file = file.substr( rranges[1].start, rranges[1].end - rranges[1].start ); @@ -645,7 +650,8 @@ Git::Status Git::status( bool recurseSubmodules, const std::string& projectDir ) } auto parseNumStat = [&s, &buf, &projectDir, this, &subModulePattern]( bool isStaged ) { - LuaPattern pattern( "(%d+)%s+(%d+)%s+(.+)" ); + std::string ptrn( "(%d+)%s+(%d+)%s+(.+)" ); + LuaPattern pattern( ptrn ); std::string subModulePath = ""; readAllLines( buf, [&]( const std::string_view& line ) { LuaPattern::Range matches[4]; @@ -662,7 +668,8 @@ Git::Status Git::status( bool recurseSubmodules, const std::string& projectDir ) int deletes; if ( String::fromString( inserts, inserted ) && String::fromString( deletes, deleted ) && ( inserts || deletes ) ) { - LuaPattern pattern( "(.*)%{.*%s->%s(.*)%}" ); + std::string rptrn( "(.*)%{.*%s->%s(.*)%}" ); + LuaPattern pattern( rptrn ); if ( pattern.matches( file.data(), 0, matches, file.size() ) ) { file = file.substr( matches[1].start, matches[1].end - matches[1].start ) + file.substr( matches[2].start, matches[2].end - matches[2].start ); diff --git a/src/tools/ecode/settingsmenu.cpp b/src/tools/ecode/settingsmenu.cpp index 5f8e65ce8..2d566540a 100644 --- a/src/tools/ecode/settingsmenu.cpp +++ b/src/tools/ecode/settingsmenu.cpp @@ -75,7 +75,7 @@ void SettingsMenu::createSettingsMenu( App* app ) { mSettingsMenu->addSeparator(); UIMenuSubMenu* fileTypeMenu = mSettingsMenu->addSubMenu( i18n( "file_type", "File Type" ), findIcon( "file-code" ), createFileTypeMenu() ); - fileTypeMenu->addEventListener( Event::OnMenuShow, [&, fileTypeMenu]( const Event* ) { + fileTypeMenu->on( Event::OnMenuShow, [&, fileTypeMenu]( const Event* ) { if ( mFileTypeMenuesCreatedWithHeight != mUISceneNode->getPixelsSize().getHeight() ) { for ( UIPopUpMenu* menu : mFileTypeMenues ) menu->close(); @@ -88,7 +88,7 @@ void SettingsMenu::createSettingsMenu( App* app ) { UIMenuSubMenu* colorSchemeMenu = mSettingsMenu->addSubMenu( i18n( "syntax_color_scheme", "Syntax Color Scheme" ), findIcon( "palette" ), createColorSchemeMenu() ); - colorSchemeMenu->addEventListener( Event::OnMenuShow, [&, colorSchemeMenu]( const Event* ) { + colorSchemeMenu->on( Event::OnMenuShow, [&, colorSchemeMenu]( const Event* ) { if ( mColorSchemeMenuesCreatedWithHeight != mUISceneNode->getPixelsSize().getHeight() ) { for ( UIPopUpMenu* menu : mColorSchemeMenues ) menu->close(); @@ -133,9 +133,8 @@ void SettingsMenu::createSettingsMenu( App* app ) { mSettingsMenu->add( i18n( "quit", "Quit" ), findIcon( "quit" ), getKeybind( "close-app" ) ) ->setId( "close-app" ); mSettingsButton = mUISceneNode->find( "settings" ); - mSettingsButton->addEventListener( Event::MouseClick, - [this]( const Event* ) { toggleSettingsMenu(); } ); - mSettingsMenu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + mSettingsButton->on( Event::MouseClick, [this]( const Event* ) { toggleSettingsMenu(); } ); + mSettingsMenu->on( Event::OnItemClicked, [this]( const Event* event ) { if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) ) return; const String& id = event->getNode()->asType()->getId(); @@ -161,7 +160,7 @@ UIMenu* SettingsMenu::createFileTypeMenu() { }; UIPopUpMenu* menu = UIPopUpMenu::New(); - menu->addEventListener( Event::OnItemClicked, cb ); + menu->on( Event::OnItemClicked, cb ); mFileTypeMenues.push_back( menu ); size_t total = 0; @@ -182,7 +181,7 @@ UIMenu* SettingsMenu::createFileTypeMenu() { if ( menu->getCount() == maxItems && names.size() - total > 1 ) { UIPopUpMenu* newMenu = UIPopUpMenu::New(); menu->addSubMenu( i18n( "more_ellipsis", "More..." ), nullptr, newMenu ); - newMenu->addEventListener( Event::OnItemClicked, cb ); + newMenu->on( Event::OnItemClicked, cb ); mFileTypeMenues.push_back( newMenu ); menu = newMenu; } @@ -201,7 +200,7 @@ UIMenu* SettingsMenu::createColorSchemeMenu() { }; UIPopUpMenu* menu = UIPopUpMenu::New(); - menu->addEventListener( Event::OnItemClicked, cb ); + menu->on( Event::OnItemClicked, cb ); mColorSchemeMenues.push_back( menu ); size_t total = 0; const auto& colorSchemes = mSplitter->getColorSchemes(); @@ -222,7 +221,7 @@ UIMenu* SettingsMenu::createColorSchemeMenu() { if ( menu->getCount() == maxItems && colorSchemes.size() - total > 1 ) { UIPopUpMenu* newMenu = UIPopUpMenu::New(); menu->addSubMenu( i18n( "more_ellipsis", "More..." ), nullptr, newMenu ); - newMenu->addEventListener( Event::OnItemClicked, cb ); + newMenu->on( Event::OnItemClicked, cb ); mColorSchemeMenues.push_back( newMenu ); menu = newMenu; } @@ -251,7 +250,7 @@ UIMenu* SettingsMenu::createDocumentMenu() { tabTypeMenu->addRadioButton( i18n( "spaces", "Spaces" ) )->setId( "spaces" ); mDocMenu->addSubMenu( i18n( "indentation_type", "Indentation Type" ), nullptr, tabTypeMenu ) ->setId( "indent_type_cur" ); - tabTypeMenu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + tabTypeMenu->on( Event::OnItemClicked, [this]( const Event* event ) { const String& text = event->getNode()->asType()->getId(); if ( mSplitter->curEditorExistsAndFocused() ) { TextDocument::IndentType indentType = text == "tabs" @@ -271,7 +270,7 @@ UIMenu* SettingsMenu::createDocumentMenu() { ->setData( w ); mDocMenu->addSubMenu( i18n( "indent_width", "Indent Width" ), nullptr, indentWidthMenu ) ->setId( "indent_width_cur" ); - indentWidthMenu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + indentWidthMenu->on( Event::OnItemClicked, [this]( const Event* event ) { if ( mSplitter->curEditorExistsAndFocused() ) { int width = event->getNode()->getData(); mSplitter->getCurEditor()->getDocument().setIndentWidth( width ); @@ -288,7 +287,7 @@ UIMenu* SettingsMenu::createDocumentMenu() { ->setData( w ); mDocMenu->addSubMenu( i18n( "tab_width", "Tab Width" ), nullptr, tabWidthMenu ) ->setId( "tab_width_cur" ); - tabWidthMenu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + tabWidthMenu->on( Event::OnItemClicked, [this]( const Event* event ) { if ( mSplitter->curEditorExistsAndFocused() ) { int width = event->getNode()->getData(); mSplitter->getCurEditor()->setTabWidth( width ); @@ -310,7 +309,7 @@ UIMenu* SettingsMenu::createDocumentMenu() { ->setId( "CR" ); mDocMenu->addSubMenu( i18n( "line_endings", "Line Endings" ), nullptr, lineEndingsMenu ) ->setId( "line_endings_cur" ); - lineEndingsMenu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + lineEndingsMenu->on( Event::OnItemClicked, [this]( const Event* event ) { auto le = TextDocument::stringToLineEnding( event->getNode()->asType()->getId() ); if ( mSplitter->curEditorExistsAndFocused() ) { @@ -337,7 +336,7 @@ UIMenu* SettingsMenu::createDocumentMenu() { mApp->getConfig().doc.writeUnicodeBOM ) ->setId( "write_bom_cur" ); - mDocMenu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + mDocMenu->on( Event::OnItemClicked, [this]( const Event* event ) { if ( !mSplitter->curEditorExistsAndFocused() || event->getNode()->isType( UI_TYPE_MENU_SEPARATOR ) || event->getNode()->isType( UI_TYPE_MENUSUBMENU ) ) @@ -384,7 +383,7 @@ UIMenu* SettingsMenu::createDocumentMenu() { globalMenu ->addSubMenu( i18n( "indentation_type", "Indentation Type" ), nullptr, tabTypeMenuGlobal ) ->setId( "indent_type" ); - tabTypeMenuGlobal->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + tabTypeMenuGlobal->on( Event::OnItemClicked, [this]( const Event* event ) { const String& text = event->getNode()->asType()->getId(); mApp->getConfig().doc.indentSpaces = text != "tabs"; } ); @@ -397,7 +396,7 @@ UIMenu* SettingsMenu::createDocumentMenu() { ->setData( w ); globalMenu->addSubMenu( i18n( "indent_width", "Indent Width" ), nullptr, indentWidthMenuGlobal ) ->setId( "indent_width" ); - indentWidthMenuGlobal->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + indentWidthMenuGlobal->on( Event::OnItemClicked, [this]( const Event* event ) { int width = event->getNode()->getData(); mApp->getConfig().doc.indentWidth = width; } ); @@ -410,7 +409,7 @@ UIMenu* SettingsMenu::createDocumentMenu() { ->setData( w ); globalMenu->addSubMenu( i18n( "tab_width", "Tab Width" ), nullptr, tabWidthMenuGlobal ) ->setId( "tab_width_cur" ); - tabWidthMenuGlobal->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + tabWidthMenuGlobal->on( Event::OnItemClicked, [this]( const Event* event ) { int width = event->getNode()->getData(); mApp->getConfig().doc.tabWidth = width; } ); @@ -430,7 +429,7 @@ UIMenu* SettingsMenu::createDocumentMenu() { ->setId( "CR" ); globalMenu->addSubMenu( i18n( "line_endings", "Line Endings" ), nullptr, lineEndingsGlobalMenu ) ->setId( "line_endings" ); - lineEndingsGlobalMenu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + lineEndingsGlobalMenu->on( Event::OnItemClicked, [this]( const Event* event ) { mApp->getConfig().doc.lineEndings = TextDocument::stringToLineEnding( event->getNode()->asType()->getId() ); } ); @@ -474,7 +473,7 @@ UIMenu* SettingsMenu::createDocumentMenu() { mApp->getConfig().editor.autoCloseXMLTags ) ->setOnShouldCloseCb( shouldCloseCb ) ->setId( "XML" ); - bracketsMenu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + bracketsMenu->on( Event::OnItemClicked, [this]( const Event* event ) { std::string id = event->getNode()->getId(); if ( event->getNode()->isType( UI_TYPE_MENUCHECKBOX ) ) { UIMenuCheckBox* item = event->getNode()->asType(); @@ -527,7 +526,7 @@ UIMenu* SettingsMenu::createDocumentMenu() { globalMenu->add( i18n( "cursor_blinking_time", "Cursor Blinking Time" ) ) ->setId( "cursor_blinking_time" ); - globalMenu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + globalMenu->on( Event::OnItemClicked, [this]( const Event* event ) { if ( !mSplitter->curEditorExistsAndFocused() || event->getNode()->isType( UI_TYPE_MENU_SEPARATOR ) || event->getNode()->isType( UI_TYPE_MENUSUBMENU ) ) @@ -582,7 +581,7 @@ UIMenu* SettingsMenu::createDocumentMenu() { ->addSubMenu( i18n( "indentation_type", "Indentation Type" ), nullptr, tabTypeMenuProject ) ->setId( "indent_type" ) ->setEnabled( !mApp->getProjectDocConfig().useGlobalSettings ); - tabTypeMenuProject->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + tabTypeMenuProject->on( Event::OnItemClicked, [this]( const Event* event ) { const String& text = event->getNode()->asType()->getId(); mApp->getProjectDocConfig().doc.indentSpaces = text != "tabs"; } ); @@ -598,7 +597,7 @@ UIMenu* SettingsMenu::createDocumentMenu() { ->addSubMenu( i18n( "indent_width", "Indent Width" ), nullptr, indentWidthMenuProject ) ->setId( "indent_width" ) ->setEnabled( !mApp->getProjectDocConfig().useGlobalSettings ); - indentWidthMenuProject->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + indentWidthMenuProject->on( Event::OnItemClicked, [this]( const Event* event ) { int width = event->getNode()->getData(); mApp->getProjectDocConfig().doc.indentWidth = width; } ); @@ -612,7 +611,7 @@ UIMenu* SettingsMenu::createDocumentMenu() { mProjectDocMenu->addSubMenu( i18n( "tab_width", "Tab Width" ), nullptr, tabWidthMenuProject ) ->setId( "tab_width" ) ->setEnabled( !mApp->getProjectDocConfig().useGlobalSettings ); - tabWidthMenuProject->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + tabWidthMenuProject->on( Event::OnItemClicked, [this]( const Event* event ) { int width = event->getNode()->getData(); mApp->getProjectDocConfig().doc.tabWidth = width; } ); @@ -634,7 +633,7 @@ UIMenu* SettingsMenu::createDocumentMenu() { ->addSubMenu( i18n( "line_endings", "Line Endings" ), nullptr, lineEndingsProjectMenu ) ->setId( "line_endings" ) ->setEnabled( !mApp->getProjectDocConfig().useGlobalSettings ); - lineEndingsProjectMenu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + lineEndingsProjectMenu->on( Event::OnItemClicked, [this]( const Event* event ) { mApp->getProjectDocConfig().doc.lineEndings = TextDocument::stringToLineEnding( event->getNode()->asType()->getId() ); } ); @@ -662,7 +661,7 @@ UIMenu* SettingsMenu::createDocumentMenu() { mProjectDocMenu->add( i18n( "line_breaking_column", "Line Breaking Column" ) ) ->setId( "line_breaking_column" ); - mProjectDocMenu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + mProjectDocMenu->on( Event::OnItemClicked, [this]( const Event* event ) { if ( !mSplitter->curEditorExistsAndFocused() || event->getNode()->isType( UI_TYPE_MENU_SEPARATOR ) || event->getNode()->isType( UI_TYPE_MENUSUBMENU ) ) @@ -694,7 +693,7 @@ UIMenu* SettingsMenu::createDocumentMenu() { msgBox->getTextInput()->setText( String::toString( mApp->getProjectDocConfig().doc.lineBreakingColumn ) ); msgBox->showWhenReady(); - msgBox->addEventListener( Event::OnConfirm, [&, msgBox]( const Event* ) { + msgBox->on( Event::OnConfirm, [&, msgBox]( const Event* ) { int val; if ( String::fromString( val, msgBox->getTextInput()->getText() ) && val >= 0 ) { mApp->getProjectDocConfig().doc.lineBreakingColumn = val; @@ -743,10 +742,9 @@ UIMenu* SettingsMenu::createTerminalMenu() { UIMenuSubMenu* termColorSchemeMenu = mTerminalMenu->addSubMenu( i18n( "terminal_color_scheme", "Terminal Color Scheme" ), findIcon( "palette" ), mApp->getTerminalManager()->createColorSchemeMenu() ); - termColorSchemeMenu->addEventListener( - Event::OnMenuShow, [&, termColorSchemeMenu]( const Event* ) { - mApp->getTerminalManager()->updateMenuColorScheme( termColorSchemeMenu ); - } ); + termColorSchemeMenu->on( Event::OnMenuShow, [&, termColorSchemeMenu]( const Event* ) { + mApp->getTerminalManager()->updateMenuColorScheme( termColorSchemeMenu ); + } ); #endif UIPopUpMenu* newTerminalBehaviorSubMenu = UIPopUpMenu::New(); @@ -784,7 +782,7 @@ UIMenu* SettingsMenu::createTerminalMenu() { mApp->getConfig().term.newTerminalOrientation = NewTerminalOrientation::fromString( id ); } ); - mTerminalMenu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + mTerminalMenu->on( Event::OnItemClicked, [this]( const Event* event ) { const std::string& id( event->getNode()->getId() ); if ( mSplitter->getCurWidget() && mSplitter->getCurWidget()->isType( UI_TYPE_TERMINAL ) ) { UITerminal* terminal = mSplitter->getCurWidget()->asType(); @@ -839,12 +837,12 @@ UIMenu* SettingsMenu::createEditMenu() { menu->add( i18n( "key_bindings", "Key Bindings" ), findIcon( "keybindings" ), getKeybind( "keybindings" ) ) ->setId( "keybindings" ); - menu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + menu->on( Event::OnItemClicked, [this]( const Event* event ) { if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) ) return; runCommand( event->getNode()->getId() ); } ); - menu->addEventListener( Event::OnMenuShow, [this, menu, fileSep]( const Event* ) { + menu->on( Event::OnMenuShow, [this, menu, fileSep]( const Event* ) { if ( !mSplitter->curEditorExistsAndFocused() ) { menu->getItemId( "undo" )->setEnabled( false ); menu->getItemId( "redo" )->setEnabled( false ); @@ -882,13 +880,15 @@ UIMenu* SettingsMenu::createWindowMenu() { ->addRadioButton( i18n( "dark", "Dark" ), mApp->getUIColorScheme() == ColorSchemePreference::Dark ) ->setId( "dark" ); - colorsMenu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + colorsMenu->on( Event::OnItemClicked, [this]( const Event* event ) { if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) ) return; UIMenuItem* item = event->getNode()->asType(); mApp->setUIColorScheme( item->getId() == "light" ? ColorSchemePreference::Light : ColorSchemePreference::Dark ); } ); + mWindowMenu->addSubMenu( i18n( "ui_language", "UI Language" ), findIcon( "globe" ), + createLanguagesMenu() ); mWindowMenu->addSubMenu( i18n( "ui_prefes_color_scheme", "UI Prefers Color Scheme" ), findIcon( "color-scheme" ), colorsMenu ); mWindowMenu->addSubMenu( i18n( "ui_thene", "UI Theme" ), findIcon( "palette" ), @@ -999,7 +999,7 @@ UIMenu* SettingsMenu::createWindowMenu() { ->add( i18n( "inspect_widgets", "Inspect Widgets" ), findIcon( "package" ), getKeybind( "debug-widget-tree-view" ) ) ->setId( "debug-widget-tree-view" ); - mWindowMenu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + mWindowMenu->on( Event::OnItemClicked, [this]( const Event* event ) { if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) ) return; UIMenuItem* item = event->getNode()->asType(); @@ -1027,7 +1027,7 @@ UIMenu* SettingsMenu::createRendererMenu() { mRendererMenu->add( i18n( "frame_rate_limit", "Frame Rate Limit" ), findIcon( "fps" ) ) ->setId( "frame_rate_limit" ); - mRendererMenu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + mRendererMenu->on( Event::OnItemClicked, [this]( const Event* event ) { if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) ) return; UIMenuItem* item = event->getNode()->asType(); @@ -1049,7 +1049,7 @@ UIMenu* SettingsMenu::createRendererMenu() { msgBox->getTextInput()->setText( String::toString( mApp->getConfig().context.FrameRateLimit ) ); msgBox->showWhenReady(); - msgBox->addEventListener( Event::OnConfirm, [&, msgBox]( const Event* ) { + msgBox->on( Event::OnConfirm, [&, msgBox]( const Event* ) { int val; if ( String::fromString( val, msgBox->getTextInput()->getText() ) && val >= 0 ) { mApp->getConfig().context.FrameRateLimit = val; @@ -1071,7 +1071,7 @@ UIMenu* SettingsMenu::createRendererMenu() { ->addRadioButton( Renderer::graphicsLibraryVersionToString( ver ), GLi->version() == ver ) ->setData( ver ); - glVersion->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + glVersion->on( Event::OnItemClicked, [this]( const Event* event ) { if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) ) return; UIMenuItem* item = event->getNode()->asType(); @@ -1094,7 +1094,7 @@ UIMenu* SettingsMenu::createRendererMenu() { ->setData( val ); mRendererMenu->addSubMenu( i18n( "ui_multisamples_level", "Multisample Anti-Aliasing Level" ), findIcon( "multisamples" ), multisampleLvl ); - multisampleLvl->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + multisampleLvl->on( Event::OnItemClicked, [this]( const Event* event ) { if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) ) return; UIMenuItem* item = event->getNode()->asType(); @@ -1180,7 +1180,7 @@ UIMenu* SettingsMenu::createViewMenu() { "directory tree." ) ) ->setId( "sync-project-tree" ); - mViewMenu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + mViewMenu->on( Event::OnItemClicked, [this]( const Event* event ) { if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) ) return; UIMenuItem* item = event->getNode()->asType(); @@ -1333,7 +1333,7 @@ UIPopUpMenu* SettingsMenu::createToolsMenu() { ->add( i18n( "load_cur_dir_as_folder", "Load current document directory as folder" ), findIcon( "folder" ), getKeybind( "load-current-dir" ) ) ->setId( "load-current-dir" ); - mToolsMenu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + mToolsMenu->on( Event::OnItemClicked, [this]( const Event* event ) { if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) ) return; runCommand( event->getNode()->getId() ); @@ -1349,9 +1349,8 @@ UIMenu* SettingsMenu::createHelpMenu() { ->setId( "check-for-updates" ); helpMenu->add( i18n( "about_ecode", "About ecode..." ), findIcon( "ecode" ) ) ->setId( "about-ecode" ); - helpMenu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { - runCommand( event->getNode()->getId() ); - } ); + helpMenu->on( Event::OnItemClicked, + [this]( const Event* event ) { runCommand( event->getNode()->getId() ); } ); return helpMenu; } @@ -1373,7 +1372,7 @@ UIMenu* SettingsMenu::createThemesMenu() { menu->addRadioButton( name, curTheme == name )->setId( name ); } - menu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + menu->on( Event::OnItemClicked, [this]( const Event* event ) { auto id = event->getNode()->getId(); mApp->getConfig().ui.theme = "default_theme" != id ? id : ""; std::string path( mApp->getConfig().ui.theme.empty() @@ -1385,6 +1384,58 @@ UIMenu* SettingsMenu::createThemesMenu() { return menu; } +UIMenu* SettingsMenu::createLanguagesMenu() { + UIPopUpMenu* menu = UIPopUpMenu::New(); + + std::string curLang = mApp->getConfig().ui.language; + if ( curLang.empty() ) + curLang = "en"; + + mApp->getThreadPool()->run( [this, menu, curLang] { + auto files = + FileSystem::filesInfoGetInPath( mApp->geti18nPath(), false, true, false, true ); + + std::map languages; + for ( const auto& file : files ) { + if ( file.getExtension() != "xml" ) + continue; + auto name( FileSystem::fileRemoveExtension( file.getFileName() ) ); + std::string data; + FileSystem::fileGet( file.getFilepath(), data ); + std::string lptrn( "title=\"(.-)\"" ); + LuaPattern pattern( lptrn ); + LuaPattern::Range matches[2]; + if ( pattern.matches( data, matches ) ) { + std::string title( + data.substr( matches[1].start, matches[1].end - matches[1].start ) ); + languages[title] = name; + } else { + languages[name] = name; + } + } + if ( languages.empty() ) + return; + + menu->runOnMainThread( [this, menu, curLang, languages] { + for ( const auto& lang : languages ) + menu->addRadioButton( lang.first, curLang == lang.second )->setId( lang.second ); + + menu->on( Event::OnItemClicked, [this]( const Event* event ) { + auto id = event->getNode()->getId(); + mApp->getConfig().ui.language = id; + UIMessageBox* msg = UIMessageBox::New( + UIMessageBox::OK, + i18n( "new_ui_language", "New language assigned.\nPlease restart the " + "application to see the complete changes." ) ); + msg->showWhenReady(); + mApp->setFocusEditorOnClose( msg ); + } ); + } ); + } ); + + return menu; +} + void SettingsMenu::toggleSettingsMenu() { if ( ( !mSettingsMenu->isVisible() || mSettingsMenu->isHiding() ) && mSettingsMenu->getInactiveTime().getElapsedTime().asMilliseconds() > 1 ) { @@ -1599,7 +1650,7 @@ void SettingsMenu::createProjectTreeMenu() { ->setId( "open-folder" ); } - mProjectTreeMenu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + mProjectTreeMenu->on( Event::OnItemClicked, [this]( const Event* event ) { if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) ) return; UIMenuItem* item = event->getNode()->asType(); @@ -1723,7 +1774,7 @@ void SettingsMenu::createProjectTreeMenu( const FileInfo& file ) { ->setId( "configure-ignore-files" ); } - mProjectTreeMenu->addEventListener( Event::OnItemClicked, [&, file]( const Event* event ) { + mProjectTreeMenu->on( Event::OnItemClicked, [&, file]( const Event* event ) { if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) ) return; UIMenuItem* item = event->getNode()->asType(); @@ -1743,7 +1794,7 @@ void SettingsMenu::createProjectTreeMenu( const FileInfo& file ) { i18n( "duplicate_file", "Duplicate file" ).toUtf8().c_str(), file.getFileName().c_str() ), i18n( "enter_duplicate_file_name", "Enter duplicate file name:" ) ); - msgBox->addEventListener( Event::OnConfirm, [&, file, msgBox]( const Event* ) { + msgBox->on( Event::OnConfirm, [&, file, msgBox]( const Event* ) { auto newFilePath( mApp->getNewFilePath( file, msgBox ) ); if ( !FileSystem::fileExists( newFilePath ) ) { if ( !FileSystem::fileCopy( file.getFilepath(), newFilePath ) ) @@ -1832,7 +1883,7 @@ void SettingsMenu::deleteFileDialog( const FileInfo& file ) { String::format( i18n( "confirm_remove_file", "Do you really want to remove \"%s\"?" ).toUtf8().c_str(), file.getFileName().c_str() ) ); - msgBox->addEventListener( Event::OnConfirm, [&, file, msgBox]( const Event* ) { + msgBox->on( Event::OnConfirm, [&, file, msgBox]( const Event* ) { auto errFn = [&, file] { mApp->errorMsgBox( String::format( std::string( i18n( "couldnt_remove", "Couldn't remove" ).toUtf8() + "%s." ).c_str(), @@ -1869,7 +1920,7 @@ void SettingsMenu::createProjectMenu() { mApp->getProjectDocConfig().hAsCPP ) ->setId( "h_as_cpp" ); - mProjectMenu->addEventListener( Event::OnItemClicked, [this]( const Event* event ) { + mProjectMenu->on( Event::OnItemClicked, [this]( const Event* event ) { if ( event->getNode()->isType( UI_TYPE_MENU_SEPARATOR ) || event->getNode()->isType( UI_TYPE_MENUSUBMENU ) ) return; diff --git a/src/tools/ecode/settingsmenu.hpp b/src/tools/ecode/settingsmenu.hpp index d8217e294..9883839ea 100644 --- a/src/tools/ecode/settingsmenu.hpp +++ b/src/tools/ecode/settingsmenu.hpp @@ -40,6 +40,8 @@ class SettingsMenu { UIMenu* createThemesMenu(); + UIMenu* createLanguagesMenu(); + void updateTerminalMenu(); void updateProjectSettingsMenu();