From 05684dffc9df0555151929fd6ee58ab5f191cde0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Sun, 17 Dec 2023 19:11:41 -0300 Subject: [PATCH] ecode: Visual improvements. --- include/eepp/ui/uitextview.hpp | 5 ++ src/eepp/ui/uitextview.cpp | 56 ++++++++---- src/eepp/ui/uitooltip.cpp | 1 + src/tools/ecode/applayout.xml.hpp | 5 +- src/tools/ecode/ecode.cpp | 4 + src/tools/ecode/plugins/git/git.cpp | 9 +- src/tools/ecode/plugins/git/git.hpp | 12 +++ src/tools/ecode/plugins/git/gitplugin.cpp | 90 ++++++++++++++----- src/tools/ecode/plugins/git/gitplugin.hpp | 14 ++- .../ecode/plugins/lsp/lspclientplugin.cpp | 5 ++ src/tools/ecode/plugins/pluginmanager.cpp | 4 + src/tools/ecode/plugins/pluginmanager.hpp | 3 + 12 files changed, 163 insertions(+), 45 deletions(-) diff --git a/include/eepp/ui/uitextview.hpp b/include/eepp/ui/uitextview.hpp index 4ca8c60b0..e3edc620d 100644 --- a/include/eepp/ui/uitextview.hpp +++ b/include/eepp/ui/uitextview.hpp @@ -114,6 +114,10 @@ class EE_API UITextView : public UIWidget { bool hasTextOverflow() const; + bool getUsingCustomStyling() const; + + void setUsingCustomStyling( bool usingCustomStyling ); + protected: Text* mTextCache; String mString; @@ -132,6 +136,7 @@ class EE_API UITextView : public UIWidget { Int32 mLastSelCurEnd; Int32 mFontLineCenter; bool mSelecting; + bool mUsingCustomStyling{ false }; std::string mTextOverflow; Float mTextOverflowWidth{ 0 }; TextTransform::Value mTextTransform{ TextTransform::None }; diff --git a/src/eepp/ui/uitextview.cpp b/src/eepp/ui/uitextview.cpp index 950c6846e..e8549b51c 100644 --- a/src/eepp/ui/uitextview.cpp +++ b/src/eepp/ui/uitextview.cpp @@ -686,45 +686,54 @@ bool UITextView::applyProperty( const StyleSheetProperty& attribute ) { setText( getTranslatorString( attribute.value() ) ); break; case PropertyId::TextTransform: - setTextTransform( TextTransform::fromString( attribute.asString() ) ); + if ( !mUsingCustomStyling ) + setTextTransform( TextTransform::fromString( attribute.asString() ) ); break; case PropertyId::Color: - setFontColor( attribute.asColor() ); + if ( !mUsingCustomStyling ) + setFontColor( attribute.asColor() ); break; case PropertyId::TextShadowColor: { - setFontShadowColor( attribute.asColor() ); + if ( !mUsingCustomStyling ) + setFontShadowColor( attribute.asColor() ); break; } case PropertyId::TextShadowOffset: - setFontShadowOffset( attribute.asVector2f() ); + if ( !mUsingCustomStyling ) + setFontShadowOffset( attribute.asVector2f() ); break; case PropertyId::SelectionColor: - mFontStyleConfig.FontSelectedColor = attribute.asColor(); + if ( !mUsingCustomStyling ) + mFontStyleConfig.FontSelectedColor = attribute.asColor(); break; case PropertyId::SelectionBackColor: - setSelectionBackColor( attribute.asColor() ); + if ( !mUsingCustomStyling ) + setSelectionBackColor( attribute.asColor() ); break; case PropertyId::FontFamily: { Font* font = FontManager::instance()->getByName( attribute.value() ); - if ( NULL != font && font->loaded() ) { + if ( !mUsingCustomStyling && NULL != font && font->loaded() ) { setFont( font ); } break; } case PropertyId::FontSize: - setFontSize( lengthFromValue( attribute ) ); + if ( !mUsingCustomStyling ) + setFontSize( lengthFromValue( attribute ) ); break; case PropertyId::FontStyle: { - Uint32 flags = attribute.asFontStyle(); + if ( !mUsingCustomStyling ) { + Uint32 flags = attribute.asFontStyle(); - if ( flags & UI_WORD_WRAP ) { - mFlags |= UI_WORD_WRAP; - flags &= ~UI_WORD_WRAP; - autoWrap(); + if ( flags & UI_WORD_WRAP ) { + mFlags |= UI_WORD_WRAP; + flags &= ~UI_WORD_WRAP; + autoWrap(); + } + + setFontStyle( flags ); } - - setFontStyle( flags ); break; } case PropertyId::Wordwrap: @@ -735,13 +744,16 @@ bool UITextView::applyProperty( const StyleSheetProperty& attribute ) { autoWrap(); break; case PropertyId::TextStrokeWidth: - setOutlineThickness( lengthFromValue( attribute ) ); + if ( !mUsingCustomStyling ) + setOutlineThickness( lengthFromValue( attribute ) ); break; case PropertyId::TextStrokeColor: - setOutlineColor( attribute.asColor() ); + if ( !mUsingCustomStyling ) + setOutlineColor( attribute.asColor() ); break; case PropertyId::TextSelection: - setTextSelection( attribute.asBool() ); + if ( !mUsingCustomStyling ) + setTextSelection( attribute.asBool() ); break; case PropertyId::TextAlign: { std::string align = String::toLower( attribute.value() ); @@ -905,6 +917,14 @@ bool UITextView::hasTextOverflow() const { return !mTextOverflow.empty() && mTextOverflow != "clip"sv; } +bool UITextView::getUsingCustomStyling() const { + return mUsingCustomStyling; +} + +void UITextView::setUsingCustomStyling( bool usingCustomStyling ) { + mUsingCustomStyling = usingCustomStyling; +} + UIAnchor* UIAnchor::New() { return eeNew( UIAnchor, () ); } diff --git a/src/eepp/ui/uitooltip.cpp b/src/eepp/ui/uitooltip.cpp index 62d295106..28ff3b6f6 100644 --- a/src/eepp/ui/uitooltip.cpp +++ b/src/eepp/ui/uitooltip.cpp @@ -230,6 +230,7 @@ void UITooltip::notifyTextChangedFromTextCache() { autoPadding(); onAutoSize(); autoAlign(); + invalidateDraw(); } void UITooltip::setFontShadowOffset( const Vector2f& offset ) { diff --git a/src/tools/ecode/applayout.xml.hpp b/src/tools/ecode/applayout.xml.hpp index 22e1a3fa7..e97dd7365 100644 --- a/src/tools/ecode/applayout.xml.hpp +++ b/src/tools/ecode/applayout.xml.hpp @@ -50,6 +50,7 @@ RelativeLayout > #doc_info { padding: 6dp; opacity: 0.8; layout-gravity: bottom|right; + layout-height: wrap_content; font-size: 1rem; } StatusBar > #doc_info { @@ -61,6 +62,7 @@ StatusBar > #doc_info { padding: 0dp 4dp 0dp 4dp; opacity: 1; layout-gravity: center; + layout-height: match_parent; font-size: 10dp; } #doc_info { @@ -152,7 +154,6 @@ TableView#locate_bar_table > tableview::row:selected > tableview::cell:nth-child } #status_bar { background-color: var(--list-back); - padding-top: 1dp; min-height: 16dp; } #status_bar > .status_but { @@ -164,6 +165,8 @@ TableView#locate_bar_table > tableview::row:selected > tableview::cell:nth-child border-bottom-color: transparent; border-right-color: var(--tab-line); font-size: 10dp; + layout-height: match_parent; + layout-gravity: top; } #status_bar > .status_but:hover { background-color: var(--item-hover); diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 52b278bf8..cba287f7d 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -841,6 +841,8 @@ void App::setUIColorScheme( const ColorSchemePreference& colorScheme ) { return; mUIColorScheme = mConfig.ui.colorScheme = colorScheme; mUISceneNode->setColorSchemePreference( colorScheme ); + if ( !firstFrame ) + mPluginManager->setUIThemeReloaded(); } ColorSchemePreference App::getUIColorScheme() const { @@ -1743,6 +1745,8 @@ void App::setTheme( const std::string& path ) { mTheme = theme; mUISceneNode->reloadStyle( true, true ); + if ( !firstFrame ) + mPluginManager->setUIThemeReloaded(); } bool App::dirInFolderWatches( const std::string& dir ) { diff --git a/src/tools/ecode/plugins/git/git.cpp b/src/tools/ecode/plugins/git/git.cpp index fcdf63e92..587fd5c06 100644 --- a/src/tools/ecode/plugins/git/git.cpp +++ b/src/tools/ecode/plugins/git/git.cpp @@ -49,6 +49,7 @@ std::string Git::branch( std::string projectDir ) { bool Git::setProjectPath( std::string projectPath ) { mProjectPath = ""; + mGitFolder = ""; FileInfo f( projectPath ); if ( !f.isDirectory() ) return false; @@ -57,8 +58,10 @@ bool Git::setProjectPath( std::string projectPath ) { std::string lPath; FileSystem::dirAddSlashAtEnd( path ); while ( path != lPath ) { - if ( FileSystem::fileExists( path + ".git" ) ) { + std::string gitFolder( path + ".git" ); + if ( FileSystem::fileExists( gitFolder ) ) { mProjectPath = path; + mGitFolder = std::move( gitFolder ); return true; } lPath = path; @@ -67,6 +70,10 @@ bool Git::setProjectPath( std::string projectPath ) { return false; } +const std::string& Git::getGitFolder() const { + return mGitFolder; +} + Git::Status Git::status( std::string projectDir ) { Status s; std::string buf; diff --git a/src/tools/ecode/plugins/git/git.hpp b/src/tools/ecode/plugins/git/git.hpp index 389aaec6d..7038a76de 100644 --- a/src/tools/ecode/plugins/git/git.hpp +++ b/src/tools/ecode/plugins/git/git.hpp @@ -26,12 +26,21 @@ class Git { std::string file; int inserts{ 0 }; int deletes{ 0 }; + + bool operator==( const DiffFile& other ) const { + return file == other.file && inserts == other.inserts && deletes == other.deletes; + } }; struct Status { std::vector modified; int totalInserts{ 0 }; int totalDeletions{ 0 }; + + bool operator==( const Status& other ) const { + return totalInserts == other.totalInserts && totalDeletions == other.totalDeletions && + modified == other.modified; + } }; Git( const std::string& projectDir = "", const std::string& gitPath = "" ); @@ -50,9 +59,12 @@ class Git { const std::string& getProjectPath() const { return mProjectPath; } + const std::string& getGitFolder() const; + protected: std::string mGitPath; std::string mProjectPath; + std::string mGitFolder; }; } // namespace ecode diff --git a/src/tools/ecode/plugins/git/gitplugin.cpp b/src/tools/ecode/plugins/git/gitplugin.cpp index 853959f22..6f4fa3565 100644 --- a/src/tools/ecode/plugins/git/gitplugin.cpp +++ b/src/tools/ecode/plugins/git/gitplugin.cpp @@ -139,11 +139,11 @@ void GitPlugin::load( PluginManager* pluginManager ) { setReady(); } -void GitPlugin::updateUINow() { +void GitPlugin::updateUINow( bool force ) { if ( !mGit || !getUISceneNode() ) return; - updateStatusBar(); + updateStatusBar( force ); } void GitPlugin::updateUI() { @@ -154,14 +154,19 @@ void GitPlugin::updateUI() { String::hash( "git::status-update" ) ); } -void GitPlugin::updateStatusBar() { +void GitPlugin::updateStatusBar( bool force ) { if ( !mGit || !mStatusBarDisplayBranch ) return; - mThreadPool->run( [this] { + mThreadPool->run( [this, force] { if ( !mGit ) return; + auto prevBranch = mGitBranch; mGitBranch = mGit->branch(); + auto prevGitStatus = mGitStatus; mGitStatus = mGit->status(); + if ( !force && mGitBranch == prevBranch && mGitStatus == prevGitStatus ) + return; + getUISceneNode()->runOnMainThread( [this] { if ( !mStatusBar ) getUISceneNode()->bind( "status_bar", mStatusBar ); @@ -172,25 +177,50 @@ void GitPlugin::updateStatusBar() { mStatusButton = UIPushButton::New(); mStatusButton->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::MatchParent ); + mStatusButton->setParent( mStatusBar ); mStatusButton->setId( "status_git" ); mStatusButton->setClass( "status_but" ); mStatusButton->setIcon( getManager() ->getUISceneNode() ->findIcon( "source-control" ) - ->getSize( PixelDensity::dpToPxI( 12 ) ) ); - mStatusButton->setParent( mStatusBar ); + ->getSize( PixelDensity::dpToPxI( 10 ) ) ); + mStatusButton->reloadStyle( true, true ); + mStatusButton->getTextBox()->setUsingCustomStyling( true ); auto childCount = mStatusBar->getChildCount(); if ( childCount > 2 ) mStatusButton->toPosition( mStatusBar->getChildCount() - 2 ); } - std::string text( mStatusBarDisplayModifications + std::string text( mStatusBarDisplayModifications && + ( mGitStatus.totalInserts || mGitStatus.totalDeletions ) ? String::format( "%s (+%d / -%d)", mGitBranch.c_str(), mGitStatus.totalInserts, mGitStatus.totalDeletions ) : mGitBranch ); mStatusButton->setText( text ); + + if ( !mStatusCustomTokenizer.has_value() ) { + std::vector patterns; + auto fontColor( getVarColor( "--font" ) ); + auto insertedColor( getVarColor( "--theme-success" ) ); + auto deletedColor( getVarColor( "--theme-error" ) ); + patterns.emplace_back( SyntaxPattern( { ".*%((%+%d+)%s/%s(%-%d+)%)" }, + { "normal", "keyword", "keyword2" } ) ); + SyntaxDefinition syntaxDef( "custom_build", {}, std::move( patterns ) ); + SyntaxColorScheme scheme( "status_bar_git", + { { "normal"_sst, { fontColor } }, + { "keyword"_sst, { insertedColor } }, + { "keyword2"_sst, { deletedColor } } }, + {} ); + mStatusCustomTokenizer = { std::move( syntaxDef ), std::move( scheme ) }; + } + + SyntaxTokenizer::tokenizeText( mStatusCustomTokenizer->def, + mStatusCustomTokenizer->scheme, + *mStatusButton->getTextBox()->getTextCache() ); + + mStatusButton->invalidateDraw(); } ); } ); } @@ -203,7 +233,12 @@ PluginRequestHandle GitPlugin::processMessage( const PluginMessage& msg ) { break; } case ecode::PluginMessageType::UIReady: { - updateStatusBar(); + updateUINow(); + break; + } + case ecode::PluginMessageType::UIThemeReloaded: { + mStatusCustomTokenizer.reset(); + updateUINow( true ); break; } default: @@ -218,22 +253,14 @@ void GitPlugin::onFileSystemEvent( const FileEvent& ev, const FileInfo& file ) { if ( mShuttingDown || isLoading() ) return; + if ( String::startsWith( file.getFilepath(), mGit->getGitFolder() ) ) + return; + updateUI(); } void GitPlugin::displayTooltip( UICodeEditor* editor, const Git::Blame& blame, const Vector2f& position ) { - static std::vector patterns; - - if ( patterns.empty() ) { - patterns.emplace_back( SyntaxPattern( { "([%w:]+)%s(%x+)%s%((%x+)%)" }, - { "normal", "keyword", "number", "number" } ) ); - patterns.emplace_back( SyntaxPattern( { "([%w:]+)%s(.*)%(([%w%.-]+@[%w-]+%.%w+)%)" }, - { "normal", "keyword", "function", "link" } ) ); - patterns.emplace_back( SyntaxPattern( { "([%w:]+)%s(%d%d%d%d%-%d%d%-%d%d[%s%d%-+:]+)" }, - { "normal", "keyword", "warning" } ) ); - } - // HACK: Gets the old font style to restore it when the tooltip is hidden UITooltip* tooltip = editor->createTooltip(); if ( tooltip == nullptr ) @@ -265,15 +292,27 @@ void GitPlugin::displayTooltip( UICodeEditor* editor, const Git::Blame& blame, tooltip->setDontAutoHideOnMouseMove( true ); tooltip->setUsingCustomStyling( true ); tooltip->setData( String::hash( "git" ) ); + tooltip->setBackgroundColor( editor->getColorScheme().getEditorColor( "background"_sst ) ); tooltip->getUIStyle()->setStyleSheetProperty( StyleSheetProperty( "background-color", - editor->getColorScheme().getEditorColor( "background"_sst ).toRgbaString(), true, + editor->getColorScheme().getEditorColor( "background"_sst ).toHexString(), true, StyleSheetSelectorRule::SpecificityImportant ) ); - SyntaxDefinition syntaxDef( "custom_build", {}, std::move( patterns ) ); + if ( !mTooltipCustomSyntaxDef.has_value() ) { + static std::vector patterns; - SyntaxTokenizer::tokenizeText( syntaxDef, editor->getColorScheme(), *tooltip->getTextCache(), 0, - 0xFFFFFFFF, true, "\n\t " ); + patterns.emplace_back( SyntaxPattern( { "([%w:]+)%s(%x+)%s%((%x+)%)" }, + { "normal", "keyword", "number", "number" } ) ); + patterns.emplace_back( SyntaxPattern( { "([%w:]+)%s(.*)%(([%w%.-]+@[%w-]+%.%w+)%)" }, + { "normal", "keyword", "function", "link" } ) ); + patterns.emplace_back( SyntaxPattern( { "([%w:]+)%s(%d%d%d%d%-%d%d%-%d%d[%s%d%-+:]+)" }, + { "normal", "keyword", "warning" } ) ); + SyntaxDefinition syntaxDef( "custom_build", {}, std::move( patterns ) ); + mTooltipCustomSyntaxDef = std::move( syntaxDef ); + } + + SyntaxTokenizer::tokenizeText( *mTooltipCustomSyntaxDef, editor->getColorScheme(), + *tooltip->getTextCache() ); tooltip->notifyTextChangedFromTextCache(); @@ -321,6 +360,11 @@ void GitPlugin::onUnregisterDocument( TextDocument* doc ) { doc->removeCommand( kb.first ); } +Color GitPlugin::getVarColor( const std::string& var ) { + return Color::fromString( + getUISceneNode()->getRoot()->getUIStyle()->getVariable( var ).getValue() ); +} + void GitPlugin::blame( UICodeEditor* editor ) { if ( !mGitFound ) { editor->setTooltipText( diff --git a/src/tools/ecode/plugins/git/gitplugin.hpp b/src/tools/ecode/plugins/git/gitplugin.hpp index cd28d9e55..e1f8bd6b4 100644 --- a/src/tools/ecode/plugins/git/gitplugin.hpp +++ b/src/tools/ecode/plugins/git/gitplugin.hpp @@ -5,6 +5,7 @@ #include "../pluginmanager.hpp" #include "git.hpp" #include +#include namespace ecode { @@ -75,13 +76,22 @@ class GitPlugin : public PluginBase { Uint32 mOldTextAlign{ 0 }; Color mOldBackgroundColor; + struct CustomTokenizer { + SyntaxDefinition def; + SyntaxColorScheme scheme; + }; + std::optional mStatusCustomTokenizer; + std::optional mTooltipCustomSyntaxDef; + + Color getVarColor( const std::string& var ); + void blame( UICodeEditor* editor ); - void updateStatusBar(); + void updateStatusBar( bool force = false ); void updateUI(); - void updateUINow(); + void updateUINow( bool force = false ); }; } // namespace ecode diff --git a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp index c0c7ea103..8b72ec634 100644 --- a/src/tools/ecode/plugins/lsp/lspclientplugin.cpp +++ b/src/tools/ecode/plugins/lsp/lspclientplugin.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -1452,6 +1453,10 @@ void LSPClientPlugin::displayTooltip( UICodeEditor* editor, const LSPHover& resp tooltip->setFontStyle( Text::Regular ); tooltip->setData( String::hash( "lsp" ) ); tooltip->setBackgroundColor( editor->getColorScheme().getEditorColor( "background"_sst ) ); + tooltip->getUIStyle()->setStyleSheetProperty( StyleSheetProperty( + "background-color", + editor->getColorScheme().getEditorColor( "background"_sst ).toHexString(), true, + StyleSheetSelectorRule::SpecificityImportant ) ); const auto& syntaxDef = resp.contents[0].kind == LSPMarkupKind::MarkDown ? SyntaxDefinitionManager::instance()->getByLSPName( "markdown" ) diff --git a/src/tools/ecode/plugins/pluginmanager.cpp b/src/tools/ecode/plugins/pluginmanager.cpp index 69fc9c5c0..ecd95b6ed 100644 --- a/src/tools/ecode/plugins/pluginmanager.cpp +++ b/src/tools/ecode/plugins/pluginmanager.cpp @@ -34,6 +34,10 @@ void PluginManager::setUIReady() { sendBroadcast( PluginMessageType::UIReady, PluginMessageFormat::Empty, nullptr ); } +void PluginManager::setUIThemeReloaded() { + sendBroadcast( PluginMessageType::UIThemeReloaded, PluginMessageFormat::Empty, nullptr ); +} + UICodeEditorPlugin* ecode::PluginManager::get( const std::string& id ) { auto findIt = mPlugins.find( id ); if ( findIt != mPlugins.end() ) diff --git a/src/tools/ecode/plugins/pluginmanager.hpp b/src/tools/ecode/plugins/pluginmanager.hpp index 8bd63bf95..20a4d5b7a 100644 --- a/src/tools/ecode/plugins/pluginmanager.hpp +++ b/src/tools/ecode/plugins/pluginmanager.hpp @@ -89,6 +89,7 @@ enum class PluginMessageType { GetDiagnostics, // Request the diagnostic information from a cursor position QueryPluginCapability, // Requests / queries if a plugin providers a capability UIReady, // Informs the Plugins that the UI is ready to be used + UIThemeReloaded, // Informs the plugins that the UI theme has been reloaded Undefined }; @@ -268,6 +269,8 @@ class PluginManager { void setUIReady(); + void setUIThemeReloaded(); + UICodeEditorPlugin* get( const std::string& id ); bool setEnabled( const std::string& id, bool enable, bool sync = false );