From d10ead9bba94379d130cdf78e88eb31f63e94f7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Fri, 26 Jun 2020 18:46:56 -0300 Subject: [PATCH] Improved key bindings support in the Code Editor, and some mino fixes. Renamed LuaPatternMatcher to LuaPattern. --- include/eepp/scene/event.hpp | 1 + .../{luapatternmatcher.hpp => luapattern.hpp} | 10 +- include/eepp/ui/doc/textdocument.hpp | 16 +- .../eepp/ui/tools/uicodeeditorsplitter.hpp | 4 + include/eepp/ui/uicodeeditor.hpp | 8 + include/eepp/ui/uitextinput.hpp | 4 + projects/linux/ee.files | 4 +- src/eepp/system/inifile.cpp | 6 +- .../{luapatternmatcher.cpp => luapattern.cpp} | 28 +-- src/eepp/ui/doc/syntaxdefinitionmanager.cpp | 6 +- src/eepp/ui/doc/syntaxtokenizer.cpp | 11 +- src/eepp/ui/doc/textdocument.cpp | 22 ++- src/eepp/ui/tools/uicodeeditorsplitter.cpp | 75 +++++--- src/eepp/ui/uicodeeditor.cpp | 136 ++++++++------- src/eepp/ui/uitextinput.cpp | 6 + src/tools/codeeditor/codeeditor.cpp | 160 ++++++++++++------ src/tools/codeeditor/codeeditor.hpp | 12 +- src/tools/uieditor/uieditor.cpp | 3 +- 18 files changed, 341 insertions(+), 171 deletions(-) rename include/eepp/system/{luapatternmatcher.hpp => luapattern.hpp} (81%) rename src/eepp/system/{luapatternmatcher.cpp => luapattern.cpp} (65%) diff --git a/include/eepp/scene/event.hpp b/include/eepp/scene/event.hpp index b739f2435..86ea73842 100644 --- a/include/eepp/scene/event.hpp +++ b/include/eepp/scene/event.hpp @@ -69,6 +69,7 @@ class EE_API Event { OnLayoutUpdate, OnSelectionChanged, OnNodeDropped, + OnSave, UserEvent, NoEvent = eeINDEX_NOT_FOUND }; diff --git a/include/eepp/system/luapatternmatcher.hpp b/include/eepp/system/luapattern.hpp similarity index 81% rename from include/eepp/system/luapatternmatcher.hpp rename to include/eepp/system/luapattern.hpp index 485c41032..1b4534e4a 100644 --- a/include/eepp/system/luapatternmatcher.hpp +++ b/include/eepp/system/luapattern.hpp @@ -6,7 +6,7 @@ namespace EE { namespace System { -class EE_API LuaPatternMatcher { +class EE_API LuaPattern { public: struct Match { int start{-1}; @@ -18,12 +18,12 @@ class EE_API LuaPatternMatcher { static Match find( const std::string& string, const std::string& pattern ); - LuaPatternMatcher( const std::string& pattern ); + LuaPattern( const std::string& pattern ); bool matches( const char* stringSearch, int stringStartOffset, - LuaPatternMatcher::Match* matchList, size_t stringLength ); + LuaPattern::Match* matchList, size_t stringLength ); - bool matches( const std::string& str, LuaPatternMatcher::Match* matchList, + bool matches( const std::string& str, LuaPattern::Match* matchList, int stringStartOffset = 0 ) { return matches( str.c_str(), stringStartOffset, matchList, str.size() ); } @@ -39,7 +39,7 @@ class EE_API LuaPatternMatcher { int getNumMatches(); bool range( int indexGet, int& startMatch, int& endMatch, - LuaPatternMatcher::Match* returnedMatched ); + LuaPattern::Match* returnedMatched ); protected: std::string mErr; diff --git a/include/eepp/ui/doc/textdocument.hpp b/include/eepp/ui/doc/textdocument.hpp index cfc4f2fde..62ea386ec 100644 --- a/include/eepp/ui/doc/textdocument.hpp +++ b/include/eepp/ui/doc/textdocument.hpp @@ -24,21 +24,25 @@ class EE_API TextDocument { public: typedef std::function DocumentCommand; + enum class UndoRedo { Undo, Redo }; + + enum class IndentType { IndentSpaces, IndentTabs }; + + enum class LineEnding { LF, CRLF }; + class EE_API Client { public: virtual ~Client(); virtual void onDocumentTextChanged() = 0; + virtual void onDocumentUndoRedo( const UndoRedo& eventType ) = 0; virtual void onDocumentCursorChange( const TextPosition& ) = 0; virtual void onDocumentSelectionChange( const TextRange& ) = 0; virtual void onDocumentLineCountChange( const size_t& lastCount, const size_t& newCount ) = 0; virtual void onDocumentLineChanged( const Int64& lineIndex ) = 0; + virtual void onDocumentSaved() = 0; }; - enum class IndentType { IndentSpaces, IndentTabs }; - - enum class LineEnding { LF, CRLF }; - TextDocument(); bool isNonWord( String::StringBaseType ch ) const; @@ -351,10 +355,14 @@ class EE_API TextDocument { void notifySelectionChanged(); + void notifyDocumentSaved(); + void notifyLineCountChanged( const size_t& lastCount, const size_t& newCount ); void notifyLineChanged( const Int64& lineIndex ); + void notifyUndoRedo( const UndoRedo& eventType ); + void insertAtStartOfSelectedLines( const String& text, bool skipEmpty ); void removeFromStartOfSelectedLines( const String& text, bool skipEmpty ); diff --git a/include/eepp/ui/tools/uicodeeditorsplitter.hpp b/include/eepp/ui/tools/uicodeeditorsplitter.hpp index e1f5e931c..87d94fa27 100644 --- a/include/eepp/ui/tools/uicodeeditorsplitter.hpp +++ b/include/eepp/ui/tools/uicodeeditorsplitter.hpp @@ -12,6 +12,10 @@ namespace EE { namespace UI { namespace Tools { class EE_API UICodeEditorSplitter { public: + static const std::map getDefaultKeybindings(); + + static const std::map getLocalDefaultKeybindings(); + struct CodeEditorConfig { std::string colorScheme{"lite"}; Float fontSize{11}; diff --git a/include/eepp/ui/uicodeeditor.hpp b/include/eepp/ui/uicodeeditor.hpp index f5ad3b8cb..0e9bf88c2 100644 --- a/include/eepp/ui/uicodeeditor.hpp +++ b/include/eepp/ui/uicodeeditor.hpp @@ -26,6 +26,8 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client { static UICodeEditor* NewOpt( const bool& autoRegisterBaseCommands, const bool& autoRegisterBaseKeybindings ); + static const std::map getDefaultKeybindings(); + UICodeEditor( const bool& autoRegisterBaseCommands = true, const bool& autoRegisterBaseKeybindings = true ); @@ -198,6 +200,8 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client { void addUnlockedCommand( const std::string& command ); + void addUnlockedCommands( const std::vector& commands ); + virtual bool applyProperty( const StyleSheetProperty& attribute ); virtual std::string getPropertyString( const PropertyDefinition* propertyDef, @@ -391,6 +395,10 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client { virtual void onDocumentLineChanged( const Int64& lineIndex ); + virtual void onDocumentUndoRedo( const TextDocument::UndoRedo& ); + + virtual void onDocumentSaved(); + std::pair getVisibleLineRange(); int getVisibleLinesCount(); diff --git a/include/eepp/ui/uitextinput.hpp b/include/eepp/ui/uitextinput.hpp index 917d8dfa9..99adf410f 100644 --- a/include/eepp/ui/uitextinput.hpp +++ b/include/eepp/ui/uitextinput.hpp @@ -173,6 +173,10 @@ class EE_API UITextInput : public UITextView, public TextDocument::Client { virtual void onDocumentLineChanged( const Int64& lineIndex ); + virtual void onDocumentUndoRedo( const TextDocument::UndoRedo& ); + + virtual void onDocumentSaved(); + void registerKeybindings(); void registerCommands(); diff --git a/projects/linux/ee.files b/projects/linux/ee.files index 04846f253..93e03e1fc 100644 --- a/projects/linux/ee.files +++ b/projects/linux/ee.files @@ -248,7 +248,7 @@ ../../include/eepp/system/iostreamzip.hpp ../../include/eepp/system/lock.hpp ../../include/eepp/system/log.hpp -../../include/eepp/system/luapatternmatcher.hpp +../../include/eepp/system/luapattern.hpp ../../include/eepp/system/md5.hpp ../../include/eepp/system/mutex.hpp ../../include/eepp/system/pack.hpp @@ -716,7 +716,7 @@ ../../src/eepp/system/log.cpp ../../src/eepp/system/lua-str.cpp ../../src/eepp/system/lua-str.hpp -../../src/eepp/system/luapatternmatcher.cpp +../../src/eepp/system/luapattern.cpp ../../src/eepp/system/md5.cpp ../../src/eepp/system/mutex.cpp ../../src/eepp/system/objectloader.cpp diff --git a/src/eepp/system/inifile.cpp b/src/eepp/system/inifile.cpp index c9d69948d..98e5d3f44 100644 --- a/src/eepp/system/inifile.cpp +++ b/src/eepp/system/inifile.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -47,7 +48,7 @@ bool IniFile::loadFromPack( Pack* Pack, std::string iniPackPath ) { bool IniFile::loadFromStream( IOStream& stream ) { if ( !stream.isOpen() ) return false; - + Clock clock; std::string myfile( (size_t)stream.getSize(), '\0' ); stream.read( (char*)&myfile[0], stream.getSize() ); @@ -56,6 +57,8 @@ bool IniFile::loadFromStream( IOStream& stream ) { mLines.clear(); mLines = String::split( myfile ); readFile(); + if ( !mPath.empty() ) + eePRINTL( "%s loaded in %.2fms", mPath.c_str(), clock.getElapsedTime().asMilliseconds() ); return true; } @@ -79,7 +82,6 @@ bool IniFile::loadFromFile( const std::string& iniPath ) { return loadFromPack( tPack, tPath ); } } - return false; } diff --git a/src/eepp/system/luapatternmatcher.cpp b/src/eepp/system/luapattern.cpp similarity index 65% rename from src/eepp/system/luapatternmatcher.cpp rename to src/eepp/system/luapattern.cpp index 367ab4514..921006faf 100644 --- a/src/eepp/system/luapatternmatcher.cpp +++ b/src/eepp/system/luapattern.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include namespace EE { namespace System { @@ -13,33 +13,33 @@ static void failHandler( const char* msg ) { throw std::string( msg ); } -std::string LuaPatternMatcher::match( const std::string& string, const std::string& pattern ) { - LuaPatternMatcher matcher( pattern ); +std::string LuaPattern::match( const std::string& string, const std::string& pattern ) { + LuaPattern matcher( pattern ); int start = 0, end = 0; if ( matcher.find( string, start, end ) ) return string.substr( start, end - start ); return ""; } -LuaPatternMatcher::Match LuaPatternMatcher::find( const std::string& string, +LuaPattern::Match LuaPattern::find( const std::string& string, const std::string& pattern ) { - LuaPatternMatcher matcher( pattern ); + LuaPattern matcher( pattern ); int start = 0, end = 0; if ( matcher.find( string, start, end ) ) return {start, end}; return {-1, -1}; } -LuaPatternMatcher::LuaPatternMatcher( const std::string& pattern ) : mPattern( pattern ) { +LuaPattern::LuaPattern( const std::string& pattern ) : mPattern( pattern ) { if ( !sFailHandlerInitialized ) { sFailHandlerInitialized = true; lua_str_fail_func( failHandler ); } } -bool LuaPatternMatcher::matches( const char* stringSearch, int stringStartOffset, - LuaPatternMatcher::Match* matchList, size_t stringLength ) { - LuaPatternMatcher::Match matchesBuffer[MAX_DEFAULT_MATCHES]; +bool LuaPattern::matches( const char* stringSearch, int stringStartOffset, + LuaPattern::Match* matchList, size_t stringLength ) { + LuaPattern::Match matchesBuffer[MAX_DEFAULT_MATCHES]; if ( matchList == NULL ) matchList = matchesBuffer; if ( stringLength == 0 ) @@ -54,9 +54,9 @@ bool LuaPatternMatcher::matches( const char* stringSearch, int stringStartOffset return mMatchNum == 0 ? false : true; } -bool LuaPatternMatcher::find( const char* stringSearch, int& startMatch, int& endMatch, +bool LuaPattern::find( const char* stringSearch, int& startMatch, int& endMatch, int stringStartOffset, int stringLength, int returnMatchIndex ) { - LuaPatternMatcher::Match matchesBuffer[MAX_DEFAULT_MATCHES]; + LuaPattern::Match matchesBuffer[MAX_DEFAULT_MATCHES]; if ( matches( stringSearch, stringStartOffset, matchesBuffer, stringLength ) ) { range( returnMatchIndex, startMatch, endMatch, matchesBuffer ); return true; @@ -67,8 +67,8 @@ bool LuaPatternMatcher::find( const char* stringSearch, int& startMatch, int& en } } -bool LuaPatternMatcher::range( int indexGet, int& startMatch, int& endMatch, - LuaPatternMatcher::Match* returnedMatched ) { +bool LuaPattern::range( int indexGet, int& startMatch, int& endMatch, + LuaPattern::Match* returnedMatched ) { if ( indexGet == -1 ) { indexGet = getNumMatches() > 1 ? 1 : 0; } @@ -80,7 +80,7 @@ bool LuaPatternMatcher::range( int indexGet, int& startMatch, int& endMatch, return false; } -int LuaPatternMatcher::getNumMatches() { +int LuaPattern::getNumMatches() { return mMatchNum; } diff --git a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp index 88561a68a..2e984991d 100644 --- a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp +++ b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include @@ -1800,7 +1800,7 @@ SyntaxDefinitionManager::getStyleByExtension( const std::string& filePath ) cons for ( auto style = mStyles.rbegin(); style != mStyles.rend(); ++style ) { for ( auto ext : style->getFiles() ) { if ( String::startsWith( ext, "%." ) || String::endsWith( ext, "$" ) ) { - LuaPatternMatcher words( ext ); + LuaPattern words( ext ); int start, end; if ( words.find( filePath, start, end ) ) { return *style; @@ -1819,7 +1819,7 @@ SyntaxDefinitionManager::getStyleByHeader( const std::string& header ) const { if ( !header.empty() ) { for ( auto style = mStyles.rbegin(); style != mStyles.rend(); ++style ) { for ( auto hdr : style->getHeaders() ) { - LuaPatternMatcher words( hdr ); + LuaPattern words( hdr ); int start, end; if ( words.find( header, start, end ) ) { return *style; diff --git a/src/eepp/ui/doc/syntaxtokenizer.cpp b/src/eepp/ui/doc/syntaxtokenizer.cpp index 78b7477e5..828875bb2 100644 --- a/src/eepp/ui/doc/syntaxtokenizer.cpp +++ b/src/eepp/ui/doc/syntaxtokenizer.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -31,7 +31,7 @@ static void pushToken( std::vector& tokens, const std::string& type bool isScaped( const std::string& text, const size_t& startIndex, const std::string& escapeStr ) { char escapeByte = escapeStr.empty() ? '\\' : escapeStr[0]; int count = 0; - for ( int i = startIndex < 1 ? 0 : startIndex - 1; i >= 0; i-- ) { + for ( int i = startIndex - 1; i >= 0; i-- ) { if ( text[i] != escapeByte ) break; count++; @@ -42,7 +42,7 @@ bool isScaped( const std::string& text, const size_t& startIndex, const std::str std::pair findNonEscaped( const std::string& text, const std::string& pattern, int offset, const std::string& escapeStr ) { while ( true ) { - LuaPatternMatcher words( pattern ); + LuaPattern words( pattern ); int start, end; if ( words.find( text, start, end, offset ) ) { if ( !escapeStr.empty() && isScaped( text, start, escapeStr ) ) { @@ -93,10 +93,9 @@ std::pair, int> SyntaxTokenizer::tokenize( const Syntax continue; const std::string& patternStr( pattern.patterns[0][0] == '^' ? pattern.patterns[0] : "^" + pattern.patterns[0] ); - LuaPatternMatcher words( patternStr ); + LuaPattern words( patternStr ); int start, end = 0; if ( words.find( text, start, end, i ) && start != end ) { - eeASSERT( start != end ); std::string patternText( text.substr( start, end - start ) ); std::string type = syntax.getSymbol( patternText ); pushToken( tokens, type.empty() ? pattern.type : type, patternText ); @@ -109,7 +108,7 @@ std::pair, int> SyntaxTokenizer::tokenize( const Syntax } } - if ( !matched ) { + if ( !matched && i < text.size() ) { pushToken( tokens, "normal", text.substr( i, 1 ) ); i += 1; } diff --git a/src/eepp/ui/doc/textdocument.cpp b/src/eepp/ui/doc/textdocument.cpp index b652407e0..e4a27bf00 100644 --- a/src/eepp/ui/doc/textdocument.cpp +++ b/src/eepp/ui/doc/textdocument.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include @@ -155,13 +155,13 @@ void TextDocument::guessIndentType() { for ( size_t i = 0; i < linesCount; i++ ) { const String& text = mLines[i].getText(); std::string match = - LuaPatternMatcher::match( text.size() > 128 ? text.substr( 0, 12 ) : text, "^ +" ); + LuaPattern::match( text.size() > 128 ? text.substr( 0, 12 ) : text, "^ +" ); if ( !match.empty() ) { guessSpaces++; guessWidth[match.size()]++; guessCoundown--; } else { - match = LuaPatternMatcher::match( mLines[i].getText(), "^\t+" ); + match = LuaPattern::match( mLines[i].getText(), "^\t+" ); if ( !match.empty() ) { guessTabs++; guessCoundown--; @@ -275,6 +275,8 @@ bool TextDocument::save( const std::string& path ) { IOStreamFile file( path, "wb" ); mFilePath = path; if ( save( file ) ) { + file.close(); + notifyDocumentSaved(); return true; } else { mFilePath.clear(); @@ -1072,10 +1074,12 @@ void TextDocument::setIndentType( const IndentType& indentType ) { void TextDocument::undo() { mUndoStack.undo(); + notifyUndoRedo( UndoRedo::Undo ); } void TextDocument::redo() { mUndoStack.redo(); + notifyUndoRedo( UndoRedo::Redo ); } const SyntaxDefinition& TextDocument::getSyntaxDefinition() const { @@ -1329,6 +1333,12 @@ void TextDocument::notifySelectionChanged() { } } +void TextDocument::notifyDocumentSaved() { + for ( auto& client : mClients ) { + client->onDocumentSaved(); + } +} + void TextDocument::notifyLineCountChanged( const size_t& lastCount, const size_t& newCount ) { for ( auto& client : mClients ) { client->onDocumentLineCountChange( lastCount, newCount ); @@ -1341,6 +1351,12 @@ void TextDocument::notifyLineChanged( const Int64& lineIndex ) { } } +void TextDocument::notifyUndoRedo( const TextDocument::UndoRedo& eventType ) { + for ( auto& client : mClients ) { + client->onDocumentUndoRedo( eventType ); + } +} + void TextDocument::initializeCommands() { mCommands["reset"] = [&] { reset(); }; mCommands["save"] = [&] { save(); }; diff --git a/src/eepp/ui/tools/uicodeeditorsplitter.cpp b/src/eepp/ui/tools/uicodeeditorsplitter.cpp index 066b4eec6..887b1eaeb 100644 --- a/src/eepp/ui/tools/uicodeeditorsplitter.cpp +++ b/src/eepp/ui/tools/uicodeeditorsplitter.cpp @@ -7,6 +7,54 @@ using namespace EE::System; namespace EE { namespace UI { namespace Tools { +const std::map UICodeEditorSplitter::getDefaultKeybindings() { + auto keybindings = UICodeEditor::getDefaultKeybindings(); + auto localKeybindings = getLocalDefaultKeybindings(); + keybindings.insert( localKeybindings.begin(), localKeybindings.end() ); + return keybindings; +} + +const std::map +UICodeEditorSplitter::getLocalDefaultKeybindings() { + return { + {{KEY_S, KEYMOD_CTRL}, "save-doc"}, + {{KEY_L, KEYMOD_CTRL}, "lock-toggle"}, + {{KEY_T, KEYMOD_CTRL}, "create-new"}, + {{KEY_W, KEYMOD_CTRL}, "close-doc"}, + {{KEY_TAB, KEYMOD_CTRL}, "next-doc"}, + {{KEY_TAB, KEYMOD_CTRL | KEYMOD_SHIFT}, "previous-doc"}, + {{KEY_J, KEYMOD_LALT | KEYMOD_SHIFT}, "split-left"}, + {{KEY_L, KEYMOD_LALT | KEYMOD_SHIFT}, "split-right"}, + {{KEY_I, KEYMOD_LALT | KEYMOD_SHIFT}, "split-top"}, + {{KEY_K, KEYMOD_LALT | KEYMOD_SHIFT}, "split-bottom"}, + {{KEY_S, KEYMOD_LALT | KEYMOD_SHIFT}, "split-swap"}, + {{KEY_J, KEYMOD_CTRL | KEYMOD_LALT}, "switch-to-previous-split"}, + {{KEY_L, KEYMOD_CTRL | KEYMOD_LALT}, "switch-to-next-split"}, + {{KEY_N, KEYMOD_CTRL | KEYMOD_LALT}, "switch-to-previous-colorscheme"}, + {{KEY_M, KEYMOD_CTRL | KEYMOD_LALT}, "switch-to-next-colorscheme"}, + {{KEY_1, KEYMOD_CTRL}, "switch-to-tab-1"}, + {{KEY_2, KEYMOD_CTRL}, "switch-to-tab-2"}, + {{KEY_3, KEYMOD_CTRL}, "switch-to-tab-3"}, + {{KEY_4, KEYMOD_CTRL}, "switch-to-tab-4"}, + {{KEY_5, KEYMOD_CTRL}, "switch-to-tab-5"}, + {{KEY_6, KEYMOD_CTRL}, "switch-to-tab-6"}, + {{KEY_7, KEYMOD_CTRL}, "switch-to-tab-7"}, + {{KEY_8, KEYMOD_CTRL}, "switch-to-tab-8"}, + {{KEY_9, KEYMOD_CTRL}, "switch-to-tab-9"}, + {{KEY_0, KEYMOD_CTRL}, "switch-to-last-tab"}, + {{KEY_1, KEYMOD_LALT}, "switch-to-tab-1"}, + {{KEY_2, KEYMOD_LALT}, "switch-to-tab-2"}, + {{KEY_3, KEYMOD_LALT}, "switch-to-tab-3"}, + {{KEY_4, KEYMOD_LALT}, "switch-to-tab-4"}, + {{KEY_5, KEYMOD_LALT}, "switch-to-tab-5"}, + {{KEY_6, KEYMOD_LALT}, "switch-to-tab-6"}, + {{KEY_7, KEYMOD_LALT}, "switch-to-tab-7"}, + {{KEY_8, KEYMOD_LALT}, "switch-to-tab-8"}, + {{KEY_9, KEYMOD_LALT}, "switch-to-tab-9"}, + {{KEY_0, KEYMOD_LALT}, "switch-to-last-tab"}, + }; +} + UICodeEditorSplitter* UICodeEditorSplitter::New( UICodeEditorSplitter::Client* client, UISceneNode* sceneNode, const std::vector& colorSchemes, @@ -215,27 +263,12 @@ UICodeEditor* UICodeEditorSplitter::createCodeEditor() { event->getNode()->asType(), event->getNode()->asType()->getDocument() ); } ); - codeEditor->addKeyBindingString( "ctrl+s", "save-doc", false ); - codeEditor->addKeyBindingString( "ctrl+l", "lock-toggle", true ); - codeEditor->addKeyBindingString( "ctrl+t", "create-new", true ); - codeEditor->addKeyBindingString( "ctrl+w", "close-doc", true ); - codeEditor->addKeyBindingString( "ctrl+tab", "next-doc", true ); - codeEditor->addKeyBindingString( "ctrl+shift+tab", "previous-doc", true ); - codeEditor->addKeyBindingString( "alt+shift+j", "split-left", true ); - codeEditor->addKeyBindingString( "alt+shift+l", "split-right", true ); - codeEditor->addKeyBindingString( "alt+shift+i", "split-top", true ); - codeEditor->addKeyBindingString( "alt+shift+k", "split-bottom", true ); - codeEditor->addKeyBindingString( "alt+shift+s", "split-swap", true ); - codeEditor->addKeyBindingString( "ctrl+alt+j", "switch-to-previous-split", true ); - codeEditor->addKeyBindingString( "ctrl+alt+l", "switch-to-next-split", true ); - codeEditor->addKeyBindingString( "ctrl+alt+n", "switch-to-previous-colorscheme", true ); - codeEditor->addKeyBindingString( "ctrl+alt+m", "switch-to-next-colorscheme", true ); - for ( int i = 1; i <= 10; i++ ) { - codeEditor->addKeyBindingString( String::format( "ctrl+%d", i ), - String::format( "switch-to-tab-%d", i ), true ); - codeEditor->addKeyBindingString( String::format( "alt+%d", i ), - String::format( "switch-to-tab-%d", i ), true ); - } + + codeEditor->addKeyBinds( getLocalDefaultKeybindings() ); + codeEditor->addUnlockedCommands( + {"lock-toggle", "create-new", "close-doc", "next-doc", "previous-doc", "split-left", + "split-right", "split-top", "split-bottom", "split-swap", "switch-to-previous-split", + "switch-to-next-split", "switch-to-previous-colorscheme", "switch-to-next-colorscheme"} ); if ( nullptr == mCurEditor ) setCurrentEditor( codeEditor ); diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index 2065c99c3..32a163957 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -28,6 +28,69 @@ UICodeEditor* UICodeEditor::NewOpt( const bool& autoRegisterBaseCommands, return eeNew( UICodeEditor, ( autoRegisterBaseCommands, autoRegisterBaseKeybindings ) ); } +const std::map UICodeEditor::getDefaultKeybindings() { + return { + {{KEY_BACKSPACE, KEYMOD_CTRL}, "delete-to-previous-word"}, + {{KEY_BACKSPACE, KEYMOD_SHIFT}, "delete-to-previous-char"}, + {{KEY_BACKSPACE, 0}, "delete-to-previous-char"}, + {{KEY_DELETE, KEYMOD_CTRL}, "delete-to-next-word"}, + {{KEY_DELETE, 0}, "delete-to-next-char"}, + {{KEY_KP_ENTER, KEYMOD_CTRL | KEYMOD_SHIFT}, "new-line-above"}, + {{KEY_RETURN, KEYMOD_CTRL | KEYMOD_SHIFT}, "new-line-above"}, + {{KEY_KP_ENTER, KEYMOD_CTRL}, "new-line"}, + {{KEY_RETURN, KEYMOD_CTRL}, "new-line"}, + {{KEY_KP_ENTER, KEYMOD_SHIFT}, "new-line"}, + {{KEY_RETURN, KEYMOD_SHIFT}, "new-line"}, + {{KEY_KP_ENTER, 0}, "new-line"}, + {{KEY_RETURN, 0}, "new-line"}, + {{KEY_UP, KEYMOD_CTRL | KEYMOD_SHIFT}, "move-lines-up"}, + {{KEY_UP, KEYMOD_CTRL}, "move-scroll-up"}, + {{KEY_UP, KEYMOD_SHIFT}, "select-to-previous-line"}, + {{KEY_UP, 0}, "move-to-previous-line"}, + {{KEY_DOWN, KEYMOD_CTRL | KEYMOD_SHIFT}, "move-lines-down"}, + {{KEY_DOWN, KEYMOD_CTRL}, "move-scroll-down"}, + {{KEY_DOWN, KEYMOD_SHIFT}, "select-to-next-line"}, + {{KEY_DOWN, 0}, "move-to-next-line"}, + {{KEY_LEFT, KEYMOD_CTRL | KEYMOD_SHIFT}, "select-to-previous-word"}, + {{KEY_LEFT, KEYMOD_CTRL}, "move-to-previous-word"}, + {{KEY_LEFT, KEYMOD_SHIFT}, "select-to-previous-char"}, + {{KEY_LEFT, 0}, "move-to-previous-char"}, + {{KEY_RIGHT, KEYMOD_CTRL | KEYMOD_SHIFT}, "select-to-next-word"}, + {{KEY_RIGHT, KEYMOD_CTRL}, "move-to-next-word"}, + {{KEY_RIGHT, KEYMOD_SHIFT}, "select-to-next-char"}, + {{KEY_RIGHT, 0}, "move-to-next-char"}, + {{KEY_Z, KEYMOD_CTRL | KEYMOD_SHIFT}, "redo"}, + {{KEY_HOME, KEYMOD_CTRL | KEYMOD_SHIFT}, "select-to-start-of-doc"}, + {{KEY_HOME, KEYMOD_SHIFT}, "select-to-start-of-content"}, + {{KEY_HOME, KEYMOD_CTRL}, "move-to-start-of-doc"}, + {{KEY_HOME, 0}, "move-to-start-of-content"}, + {{KEY_END, KEYMOD_CTRL | KEYMOD_SHIFT}, "select-to-end-of-doc"}, + {{KEY_END, KEYMOD_SHIFT}, "select-to-end-of-line"}, + {{KEY_END, KEYMOD_CTRL}, "move-to-end-of-doc"}, + {{KEY_END, 0}, "move-to-end-of-line"}, + {{KEY_PAGEUP, KEYMOD_CTRL}, "move-to-previous-page"}, + {{KEY_PAGEUP, KEYMOD_SHIFT}, "select-to-previous-page"}, + {{KEY_PAGEUP, 0}, "move-to-previous-page"}, + {{KEY_PAGEDOWN, KEYMOD_CTRL}, "move-to-next-page"}, + {{KEY_PAGEDOWN, KEYMOD_SHIFT}, "select-to-next-page"}, + {{KEY_PAGEDOWN, 0}, "move-to-next-page"}, + {{KEY_Y, KEYMOD_CTRL}, "redo"}, + {{KEY_Z, KEYMOD_CTRL}, "undo"}, + {{KEY_TAB, KEYMOD_SHIFT}, "unindent"}, + {{KEY_TAB, 0}, "indent"}, + {{KEY_C, KEYMOD_CTRL}, "copy"}, + {{KEY_X, KEYMOD_CTRL}, "cut"}, + {{KEY_V, KEYMOD_CTRL}, "paste"}, + {{KEY_A, KEYMOD_CTRL}, "select-all"}, + {{KEY_PLUS, KEYMOD_CTRL}, "font-size-grow"}, + {{KEY_KP_PLUS, KEYMOD_CTRL}, "font-size-grow"}, + {{KEY_MINUS, KEYMOD_CTRL}, "font-size-shrink"}, + {{KEY_KP_MINUS, KEYMOD_CTRL}, "font-size-shrink"}, + {{KEY_0, KEYMOD_CTRL}, "font-size-reset"}, + {{KEY_KP_DIVIDE, KEYMOD_CTRL}, "toggle-line-comments"}, + }; +} + UICodeEditor::UICodeEditor( const std::string& elementTag, const bool& autoRegisterBaseCommands, const bool& autoRegisterBaseKeybindings ) : UIWidget( elementTag ), @@ -830,6 +893,14 @@ void UICodeEditor::onDocumentLineChanged( const Int64& lineIndex ) { mHighlighter.invalidate( lineIndex ); } +void UICodeEditor::onDocumentUndoRedo( const TextDocument::UndoRedo& ) { + onDocumentSelectionChange( {} ); +} + +void UICodeEditor::onDocumentSaved() { + sendCommonEvent( Event::OnSave ); +} + std::pair UICodeEditor::getVisibleLineRange() { Float lineHeight = getLineHeight(); Float minLine = eemax( 0.f, eefloor( mScroll.y / lineHeight ) ); @@ -1037,6 +1108,10 @@ void UICodeEditor::addUnlockedCommand( const std::string& command ) { mUnlockedCmd.insert( command ); } +void UICodeEditor::addUnlockedCommands( const std::vector& commands ) { + mUnlockedCmd.insert( commands.begin(), commands.end() ); +} + UICodeEditor* UICodeEditor::setFontShadowColor( const Color& color ) { if ( mFontStyleConfig.ShadowColor != color ) { mFontStyleConfig.ShadowColor = color; @@ -1671,66 +1746,7 @@ void UICodeEditor::registerCommands() { } void UICodeEditor::registerKeybindings() { - mKeyBindings.addKeybinds( { - {{KEY_BACKSPACE, KEYMOD_CTRL}, "delete-to-previous-word"}, - {{KEY_BACKSPACE, KEYMOD_SHIFT}, "delete-to-previous-char"}, - {{KEY_BACKSPACE, 0}, "delete-to-previous-char"}, - {{KEY_DELETE, KEYMOD_CTRL}, "delete-to-next-word"}, - {{KEY_DELETE, 0}, "delete-to-next-char"}, - {{KEY_KP_ENTER, KEYMOD_CTRL | KEYMOD_SHIFT}, "new-line-above"}, - {{KEY_RETURN, KEYMOD_CTRL | KEYMOD_SHIFT}, "new-line-above"}, - {{KEY_KP_ENTER, KEYMOD_CTRL}, "new-line"}, - {{KEY_RETURN, KEYMOD_CTRL}, "new-line"}, - {{KEY_KP_ENTER, KEYMOD_SHIFT}, "new-line"}, - {{KEY_RETURN, KEYMOD_SHIFT}, "new-line"}, - {{KEY_KP_ENTER, 0}, "new-line"}, - {{KEY_RETURN, 0}, "new-line"}, - {{KEY_UP, KEYMOD_CTRL | KEYMOD_SHIFT}, "move-lines-up"}, - {{KEY_UP, KEYMOD_CTRL}, "move-scroll-up"}, - {{KEY_UP, KEYMOD_SHIFT}, "select-to-previous-line"}, - {{KEY_UP, 0}, "move-to-previous-line"}, - {{KEY_DOWN, KEYMOD_CTRL | KEYMOD_SHIFT}, "move-lines-down"}, - {{KEY_DOWN, KEYMOD_CTRL}, "move-scroll-down"}, - {{KEY_DOWN, KEYMOD_SHIFT}, "select-to-next-line"}, - {{KEY_DOWN, 0}, "move-to-next-line"}, - {{KEY_LEFT, KEYMOD_CTRL | KEYMOD_SHIFT}, "select-to-previous-word"}, - {{KEY_LEFT, KEYMOD_CTRL}, "move-to-previous-word"}, - {{KEY_LEFT, KEYMOD_SHIFT}, "select-to-previous-char"}, - {{KEY_LEFT, 0}, "move-to-previous-char"}, - {{KEY_RIGHT, KEYMOD_CTRL | KEYMOD_SHIFT}, "select-to-next-word"}, - {{KEY_RIGHT, KEYMOD_CTRL}, "move-to-next-word"}, - {{KEY_RIGHT, KEYMOD_SHIFT}, "select-to-next-char"}, - {{KEY_RIGHT, 0}, "move-to-next-char"}, - {{KEY_Z, KEYMOD_CTRL | KEYMOD_SHIFT}, "redo"}, - {{KEY_HOME, KEYMOD_CTRL | KEYMOD_SHIFT}, "select-to-start-of-doc"}, - {{KEY_HOME, KEYMOD_SHIFT}, "select-to-start-of-content"}, - {{KEY_HOME, KEYMOD_CTRL}, "move-to-start-of-doc"}, - {{KEY_HOME, 0}, "move-to-start-of-content"}, - {{KEY_END, KEYMOD_CTRL | KEYMOD_SHIFT}, "select-to-end-of-doc"}, - {{KEY_END, KEYMOD_SHIFT}, "select-to-end-of-line"}, - {{KEY_END, KEYMOD_CTRL}, "move-to-end-of-doc"}, - {{KEY_END, 0}, "move-to-end-of-line"}, - {{KEY_PAGEUP, KEYMOD_CTRL}, "move-to-previous-page"}, - {{KEY_PAGEUP, KEYMOD_SHIFT}, "select-to-previous-page"}, - {{KEY_PAGEUP, 0}, "move-to-previous-page"}, - {{KEY_PAGEDOWN, KEYMOD_CTRL}, "move-to-next-page"}, - {{KEY_PAGEDOWN, KEYMOD_SHIFT}, "select-to-next-page"}, - {{KEY_PAGEDOWN, 0}, "move-to-next-page"}, - {{KEY_Y, KEYMOD_CTRL}, "redo"}, - {{KEY_Z, KEYMOD_CTRL}, "undo"}, - {{KEY_TAB, KEYMOD_SHIFT}, "unindent"}, - {{KEY_TAB, 0}, "indent"}, - {{KEY_C, KEYMOD_CTRL}, "copy"}, - {{KEY_X, KEYMOD_CTRL}, "cut"}, - {{KEY_V, KEYMOD_CTRL}, "paste"}, - {{KEY_A, KEYMOD_CTRL}, "select-all"}, - {{KEY_PLUS, KEYMOD_CTRL}, "font-size-grow"}, - {{KEY_KP_PLUS, KEYMOD_CTRL}, "font-size-grow"}, - {{KEY_MINUS, KEYMOD_CTRL}, "font-size-shrink"}, - {{KEY_KP_MINUS, KEYMOD_CTRL}, "font-size-shrink"}, - {{KEY_0, KEYMOD_CTRL}, "font-size-reset"}, - {{KEY_KP_DIVIDE, KEYMOD_CTRL}, "toggle-line-comments"}, - } ); + mKeyBindings.addKeybinds( getDefaultKeybindings() ); } }} // namespace EE::UI diff --git a/src/eepp/ui/uitextinput.cpp b/src/eepp/ui/uitextinput.cpp index d07582f64..17aa80439 100644 --- a/src/eepp/ui/uitextinput.cpp +++ b/src/eepp/ui/uitextinput.cpp @@ -427,6 +427,12 @@ void UITextInput::onDocumentLineCountChange( const size_t&, const size_t& ) {} void UITextInput::onDocumentLineChanged( const Int64& ) {} +void UITextInput::onDocumentUndoRedo( const TextDocument::UndoRedo& ) { + onSelectionChange(); +} + +void UITextInput::onDocumentSaved() {} + UITextInput* UITextInput::setMaxLength( const Uint32& maxLength ) { mMaxLength = maxLength; return this; diff --git a/src/tools/codeeditor/codeeditor.cpp b/src/tools/codeeditor/codeeditor.cpp index aed2557ff..cdc7da7f4 100644 --- a/src/tools/codeeditor/codeeditor.cpp +++ b/src/tools/codeeditor/codeeditor.cpp @@ -1,4 +1,5 @@ #include "codeeditor.hpp" +#include #include App* appInstance = nullptr; @@ -239,6 +240,7 @@ void App::loadConfig() { if ( !FileSystem::fileExists( mConfigPath ) ) FileSystem::makeDir( mConfigPath ); FileSystem::dirPathAddSlashAtEnd( mConfigPath ); + mKeybindingsPath = mConfigPath + "keybindings.cfg"; mIni.loadFromFile( mConfigPath + "config.cfg" ); mIniState.loadFromFile( mConfigPath + "state.cfg" ); std::string recent = mIniState.getValue( "files", "recentfiles", "" ); @@ -310,6 +312,28 @@ void App::saveConfig() { mIniState.writeFile(); } +static std::string keybindFormat( std::string str ) { + if ( !str.empty() ) { + str[0] = std::toupper( str[0] ); + size_t found = str.find_first_of( '+' ); + while ( found != std::string::npos ) { + if ( found + 1 < str.size() ) { + str[found + 1] = std::toupper( str[found + 1] ); + } + found = str.find_first_of( '+', found + 1 ); + } + return str; + } + return ""; +} + +std::string App::getKeybind( const std::string& command ) { + auto it = mKeybindingsInvert.find( command ); + if ( it != mKeybindingsInvert.end() ) + return keybindFormat( it->second ); + return ""; +} + void App::initSearchBar() { auto addClickListener = [&]( UIWidget* widget, std::string cmd ) { widget->addEventListener( Event::MouseClick, [this, cmd]( const Event* event ) { @@ -543,17 +567,17 @@ UIMenu* App::createViewMenu() { mViewMenu->add( "Line Breaking Column" ); mViewMenu->addSeparator(); mViewMenu->addCheckBox( "Full Screen Mode" ) - ->setShortcutText( "Alt+Return" ) + ->setShortcutText( getKeybind( "fullscreen-toggle" ) ) ->setId( "fullscreen-mode" ); mViewMenu->addSeparator(); - mViewMenu->add( "Split Left", findIcon( "split-horizontal" ), "Ctrl+Shift+J" ); - mViewMenu->add( "Split Right", findIcon( "split-horizontal" ), "Ctrl+Shift+L" ); - mViewMenu->add( "Split Top", findIcon( "split-vertical" ), "Ctrl+Shift+I" ); - mViewMenu->add( "Split Bottom", findIcon( "split-vertical" ), "Ctrl+Shift+K" ); + mViewMenu->add( "Split Left", findIcon( "split-horizontal" ), getKeybind( "split-left" ) ); + mViewMenu->add( "Split Right", findIcon( "split-horizontal" ), getKeybind( "split-right" ) ); + mViewMenu->add( "Split Top", findIcon( "split-vertical" ), getKeybind( "split-top" ) ); + mViewMenu->add( "Split Bottom", findIcon( "split-vertical" ), getKeybind( "split-bottom" ) ); mViewMenu->addSeparator(); - mViewMenu->add( "Zoom In", findIcon( "zoom-in" ), "Ctrl++" ); - mViewMenu->add( "Zoom Out", findIcon( "zoom-out" ), "Ctrl+-" ); - mViewMenu->add( "Zoom Reset", findIcon( "zoom-reset" ), "Ctrl+0" ); + mViewMenu->add( "Zoom In", findIcon( "zoom-in" ), getKeybind( "font-size-grow" ) ); + mViewMenu->add( "Zoom Out", findIcon( "zoom-out" ), getKeybind( "font-size-shrink" ) ); + mViewMenu->add( "Zoom Reset", findIcon( "zoom-reset" ), getKeybind( "font-size-reset" ) ); mViewMenu->addEventListener( Event::OnItemClicked, [&]( const Event* event ) { if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) ) return; @@ -675,23 +699,29 @@ Drawable* App::findIcon( const std::string& name ) { UIMenu* App::createEditMenu() { UIPopUpMenu* menu = UIPopUpMenu::New(); - menu->add( "Undo", findIcon( "undo" ), "Ctrl+Z" ); - menu->add( "Redo", findIcon( "redo" ), "Ctrl+Shift+Z" ); + menu->add( "Undo", findIcon( "undo" ), getKeybind( "undo" ) ); + menu->add( "Redo", findIcon( "redo" ), getKeybind( "redo" ) ); menu->addSeparator(); - menu->add( "Cut", findIcon( "cut" ), "Ctrl+X" ); - menu->add( "Copy", findIcon( "copy" ), "Ctrl+C" ); - menu->add( "Paste", findIcon( "paste" ), "Ctrl+V" ); + menu->add( "Cut", findIcon( "cut" ), getKeybind( "cut" ) ); + menu->add( "Copy", findIcon( "copy" ), getKeybind( "copy" ) ); + menu->add( "Paste", findIcon( "paste" ), getKeybind( "paste" ) ); menu->addSeparator(); - menu->add( "Select All", findIcon( "select-all" ), "Ctrl+A" ); + menu->add( "Select All", findIcon( "select-all" ), getKeybind( "select-all" ) ); menu->addSeparator(); - menu->add( "Find/Replace", findIcon( "find-replace" ), "Ctrl+F" ); + menu->add( "Find/Replace", findIcon( "find-replace" ), getKeybind( "find-replace" ) ); + menu->addSeparator(); + menu->add( "Key Bindings", findIcon( "keybindings" ), getKeybind( "keybindings" ) ); menu->addEventListener( Event::OnItemClicked, [&]( const Event* event ) { if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) ) return; String text = String( event->getNode()->asType()->getText() ).toLower(); - String::replaceAll( text, " ", "-" ); - String::replaceAll( text, "/", "-" ); - runCommand( text ); + if ( "key bindings" == text ) { + runCommand( "keybindings" ); + } else { + String::replaceAll( text, " ", "-" ); + String::replaceAll( text, "/", "-" ); + runCommand( text ); + } } ); return menu; } @@ -863,6 +893,24 @@ void App::updateDocumentMenu() { ->setActive( mEditorSplitter->getCurEditor()->isLocked() ); } +void App::loadKeybindings() { + if ( mKeybindings.empty() ) { + IniFile ini( mKeybindingsPath ); + if ( FileSystem::fileExists( mKeybindingsPath ) ) { + mKeybindings = ini.getKeyMap( "keybindings" ); + } else { + KeyBindings bindings( mWindow->getInput() ); + auto map = getDefaultKeybindings(); + for ( auto it : map ) + ini.setValue( "keybindings", bindings.getShortcutString( it.first ), it.second ); + ini.writeFile(); + mKeybindings = ini.getKeyMap( "keybindings" ); + } + for ( auto key : mKeybindings ) + mKeybindingsInvert[key.second] = key.first; + } +} + void App::onDocumentStateChanged( UICodeEditor*, TextDocument& ) { updateEditorState(); } @@ -911,15 +959,28 @@ const UICodeEditorSplitter::CodeEditorConfig& App::getCodeEditorConfig() const { return mConfig.editor; } +std::map App::getDefaultKeybindings() { + auto bindings = UICodeEditorSplitter::getDefaultKeybindings(); + auto local = getLocalKeybindings(); + bindings.insert( local.begin(), local.end() ); + return bindings; +} + +std::map App::getLocalKeybindings() { + return { + {{KEY_RETURN, KEYMOD_LALT}, "fullscreen-toggle"}, + {{KEY_F3, 0}, "repeat-find"}, + {{KEY_F12, 0}, "console-toggle"}, + {{KEY_F, KEYMOD_CTRL}, "find-replace"}, + {{KEY_Q, KEYMOD_CTRL}, "close-app"}, + {{KEY_O, KEYMOD_CTRL}, "open-file"}, + }; +} + void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) { - editor->addKeyBindingString( "alt+return", "fullscreen-toggle", true ); - editor->addKeyBindingString( "alt+keypad enter", "fullscreen-toggle", true ); - editor->addKeyBindingString( "f2", "open-file", true ); - editor->addKeyBindingString( "f3", "repeat-find", false ); - editor->addKeyBindingString( "f12", "console-toggle", true ); - editor->addKeyBindingString( "ctrl+f", "find-replace", false ); - editor->addKeyBindingString( "ctrl+q", "close-app", true ); - editor->addKeyBindingString( "ctrl+o", "open-file", true ); + editor->addKeyBinds( getLocalKeybindings() ); + editor->addUnlockedCommands( + {"fullscreen-toggle", "open-file", "console-toggle", "close-app"} ); doc.setCommand( "save-doc", [&] { saveDoc(); } ); doc.setCommand( "save-as-doc", [&] { saveFileDialog(); } ); doc.setCommand( "find-replace", [&] { showFindView(); } ); @@ -957,38 +1018,36 @@ void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) { updateDocumentMenu(); } } ); + doc.setCommand( "keybindings", + [&] { mEditorSplitter->loadFileFromPathInNewTab( mKeybindingsPath ); } ); - if ( mDefKeybindings.empty() ) { - std::string bindingsPath = mConfigPath + "keybindings.cfg"; - IniFile ini( bindingsPath ); - if ( FileSystem::fileExists( bindingsPath ) ) { - mDefKeybindings = ini.getKeyMap( "keybindings" ); - } else { - const ShortcutMap& map = editor->getKeyBindings().getShortcutMap(); - for ( auto it : map ) { - KeyBindings::Shortcut shortcut( it.first ); - ini.setValue( "keybindings", editor->getKeyBindings().getShortcutString( shortcut ), - it.second ); - } - ini.writeFile(); - mDefKeybindings = ini.getKeyMap( "keybindings" ); + editor->addEventListener( Event::OnSave, [&]( const Event* event ) { + UICodeEditor* editor = event->getNode()->asType(); + if ( editor->getDocument().getFilePath() == mKeybindingsPath ) { + mKeybindings.clear(); + mKeybindingsInvert.clear(); + loadKeybindings(); + mEditorSplitter->forEachEditor( [&]( UICodeEditor* ed ) { + ed->getKeyBindings().reset(); + ed->getKeyBindings().addKeybindsString( mKeybindings ); + } ); } - } + } ); - if ( !mDefKeybindings.empty() ) { + if ( !mKeybindings.empty() ) { editor->getKeyBindings().reset(); - editor->getKeyBindings().addKeybindsString( mDefKeybindings ); + editor->getKeyBindings().addKeybindsString( mKeybindings ); } } void App::createSettingsMenu() { mSettingsMenu = UIPopUpMenu::New(); - mSettingsMenu->add( "New", findIcon( "document-new" ), "Ctrl+T" ); - mSettingsMenu->add( "Open...", findIcon( "document-open" ), "Ctrl+O" ); + mSettingsMenu->add( "New", findIcon( "document-new" ), getKeybind( "create-new" ) ); + mSettingsMenu->add( "Open...", findIcon( "document-open" ), getKeybind( "open-file" ) ); mSettingsMenu->addSubMenu( "Recent Files", findIcon( "document-recent" ), UIPopUpMenu::New() ); mSettingsMenu->addSeparator(); - mSettingsMenu->add( "Save", findIcon( "document-save" ), "Ctrl+S" ); - mSettingsMenu->add( "Save as...", findIcon( "document-save-as" ) ); + mSettingsMenu->add( "Save", findIcon( "document-save" ), getKeybind( "save-doc" ) ); + mSettingsMenu->add( "Save as...", findIcon( "document-save-as" ), getKeybind( "save-as-doc" ) ); mSettingsMenu->addSeparator(); mSettingsMenu->addSubMenu( "Filetype", nullptr, createFiletypeMenu() ); mSettingsMenu->addSubMenu( "Color Scheme", nullptr, createColorSchemeMenu() ); @@ -996,9 +1055,9 @@ void App::createSettingsMenu() { mSettingsMenu->addSubMenu( "Edit", nullptr, createEditMenu() ); mSettingsMenu->addSubMenu( "View", nullptr, createViewMenu() ); mSettingsMenu->addSeparator(); - mSettingsMenu->add( "Close", findIcon( "document-close" ), "Ctrl+W" ); + mSettingsMenu->add( "Close", findIcon( "document-close" ), getKeybind( "close-doc" ) ); mSettingsMenu->addSeparator(); - mSettingsMenu->add( "Quit", findIcon( "quit" ), "Ctrl+Q" ); + mSettingsMenu->add( "Quit", findIcon( "quit" ), getKeybind( "close-app" ) ); mSettingsButton = mUISceneNode->find( "settings" ); mSettingsButton->addEventListener( Event::MouseClick, [&]( const Event* ) { Vector2f pos( mSettingsButton->getPixelsPosition() ); @@ -1113,6 +1172,8 @@ void App::init( const std::string& file, const Float& pidelDensity ) { ContextSettings( true ) ); if ( mWindow->isOpen() ) { + loadKeybindings(); + PixelDensity::setPixelDensity( mConfig.window.pixelDensity ); if ( mConfig.window.maximized ) @@ -1269,6 +1330,7 @@ void App::init( const std::string& file, const Float& pidelDensity ) { addIcon( "zoom-out", 0xf2dd, 12 ); addIcon( "zoom-reset", 0xeb47, 12 ); addIcon( "fullscreen", 0xed9c, 12 ); + addIcon( "keybindings", 0xee75, 12 ); mUISceneNode->getUIIconThemeManager()->setCurrentTheme( iconTheme ); diff --git a/src/tools/codeeditor/codeeditor.hpp b/src/tools/codeeditor/codeeditor.hpp index b42b5e204..8b46ca724 100644 --- a/src/tools/codeeditor/codeeditor.hpp +++ b/src/tools/codeeditor/codeeditor.hpp @@ -99,6 +99,8 @@ class App : public UICodeEditorSplitter::Client { void saveConfig(); + std::string getKeybind( const std::string& command ); + protected: EE::Window::Window* mWindow{nullptr}; UISceneNode* mUISceneNode{nullptr}; @@ -119,8 +121,10 @@ class App : public UICodeEditorSplitter::Client { UIPopUpMenu* mViewMenu{nullptr}; UICodeEditorSplitter* mEditorSplitter{nullptr}; std::string mInitColorScheme; - std::map mDefKeybindings; + std::map mKeybindings; + std::map mKeybindingsInvert; std::string mConfigPath; + std::string mKeybindingsPath; SearchState mSearchState; void onFileDropped( String file ); @@ -165,6 +169,12 @@ class App : public UICodeEditorSplitter::Client { void updateDocumentMenu(); + void loadKeybindings(); + + std::map getDefaultKeybindings(); + + std::map getLocalKeybindings(); + void onDocumentStateChanged( UICodeEditor*, TextDocument& ); void onDocumentModified( UICodeEditor* editor, TextDocument& ); diff --git a/src/tools/uieditor/uieditor.cpp b/src/tools/uieditor/uieditor.cpp index 0b60fa264..d18fab5a8 100644 --- a/src/tools/uieditor/uieditor.cpp +++ b/src/tools/uieditor/uieditor.cpp @@ -790,6 +790,7 @@ void mainLoop() { refreshStyleSheet(); } + Time elapsed = SceneManager::instance()->getElapsed(); SceneManager::instance()->update(); if ( appUiSceneNode->invalidated() || uiSceneNode->invalidated() || console->isActive() || @@ -798,7 +799,7 @@ void mainLoop() { SceneManager::instance()->draw(); - console->draw(); + console->draw( elapsed ); window->display(); } else {