From 55e8a239efb16f3f42563410106642c2c6348b04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Wed, 16 Mar 2022 20:10:51 -0300 Subject: [PATCH] UICodeEditor link hover improvements. --- bin/assets/colorschemes/colorschemes.conf | 6 +- include/eepp/ui/doc/syntaxcolorscheme.hpp | 8 +- include/eepp/ui/uicodeeditor.hpp | 4 + premake4.lua | 4 +- premake5.lua | 4 +- projects/linux/ee.creator.user | 6 +- src/eepp/ui/doc/syntaxcolorscheme.cpp | 9 +- src/eepp/ui/uicodeeditor.cpp | 131 +++++++++++++++++----- 8 files changed, 130 insertions(+), 42 deletions(-) diff --git a/bin/assets/colorschemes/colorschemes.conf b/bin/assets/colorschemes/colorschemes.conf index aab18d3c6..cc3f92c13 100644 --- a/bin/assets/colorschemes/colorschemes.conf +++ b/bin/assets/colorschemes/colorschemes.conf @@ -25,7 +25,8 @@ literal = #FFA94D string = #f7c95c operator = #93DDFA function = #93DDFA -link = #93DDFA,underline +link = #93DDFA +link_hover = transparent,underline [eepp] background = #282a36 @@ -54,7 +55,8 @@ literal = #f1fa8c,shadow string = #ffcd8b operator = #51f0e7 function = #00dc7f,shadow -link = #6ae0f9,shadow,underline,#FFFFFF11 +link = #6ae0f9,shadow +link_hover = transparent,shadow,underline [fall] background = #343233 diff --git a/include/eepp/ui/doc/syntaxcolorscheme.hpp b/include/eepp/ui/doc/syntaxcolorscheme.hpp index 76ceaf069..cd27504ae 100644 --- a/include/eepp/ui/doc/syntaxcolorscheme.hpp +++ b/include/eepp/ui/doc/syntaxcolorscheme.hpp @@ -44,9 +44,9 @@ class EE_API SyntaxColorScheme { Style( const Color& color ) : color( color ) {} Style( const Color& color, const Color& background, const Uint32& style ) : color( color ), background( background ), style( style ) {} - Color color{Color::White}; - Color background{Color::Transparent}; - Uint32 style{0}; + Color color{ Color::White }; + Color background{ Color::Transparent }; + Uint32 style{ 0 }; }; SyntaxColorScheme(); @@ -57,6 +57,8 @@ class EE_API SyntaxColorScheme { const Style& getSyntaxStyle( const std::string& type ) const; + bool hasSyntaxStyle( const std::string& type ) const; + void setSyntaxStyles( const std::unordered_map& styles ); void setSyntaxStyle( const std::string& type, const Style& style ); diff --git a/include/eepp/ui/uicodeeditor.hpp b/include/eepp/ui/uicodeeditor.hpp index 2e348048c..81c5cd214 100644 --- a/include/eepp/ui/uicodeeditor.hpp +++ b/include/eepp/ui/uicodeeditor.hpp @@ -428,6 +428,8 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client { bool mInteractiveLinks{ true }; bool mHandShown{ false }; bool mDisplayLoaderIfDocumentLoading{ true }; + TextRange mLinkPosition; + String mLink; Uint32 mTabWidth; Vector2f mScroll; Float mMouseWheelScroll; @@ -591,6 +593,8 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client { String checkMouseOverLink( const Vector2i& position ); + String resetLinkOver(); + void resetPreviewColor(); void disableEditorFeatures(); diff --git a/premake4.lua b/premake4.lua index a9a98f2a6..293b1e369 100644 --- a/premake4.lua +++ b/premake4.lua @@ -496,7 +496,7 @@ end function generate_os_links() if os.is_real("linux") then - multiple_insert( os_links, { "rt", "pthread", "X11", "GL" } ) + multiple_insert( os_links, { "rt", "pthread", "GL" } ) if not _OPTIONS["with-mojoal"] then table.insert( os_links, "openal" ) @@ -512,7 +512,7 @@ function generate_os_links() elseif os.is_real("macosx") then multiple_insert( os_links, { "OpenGL.framework", "CoreFoundation.framework" } ) elseif os.is_real("freebsd") then - multiple_insert( os_links, { "rt", "pthread", "X11", "GL", "Xcursor" } ) + multiple_insert( os_links, { "rt", "pthread", "GL" } ) elseif os.is_real("haiku") then multiple_insert( os_links, { "GL", "network" } ) elseif os.is_real("ios") then diff --git a/premake5.lua b/premake5.lua index 20d93e573..8ae12331e 100644 --- a/premake5.lua +++ b/premake5.lua @@ -269,7 +269,7 @@ end function generate_os_links() if os.istarget("linux") then - multiple_insert( os_links, { "rt", "pthread", "X11", "GL", "Xcursor" } ) + multiple_insert( os_links, { "rt", "pthread", "GL", "Xcursor" } ) if _OPTIONS["with-static-eepp"] then table.insert( os_links, "dl" ) @@ -281,7 +281,7 @@ function generate_os_links() elseif os.istarget("macosx") then multiple_insert( os_links, { "OpenGL.framework", "CoreFoundation.framework" } ) elseif os.istarget("bsd") then - multiple_insert( os_links, { "rt", "pthread", "X11", "GL", "Xcursor" } ) + multiple_insert( os_links, { "rt", "pthread", "GL" } ) elseif os.istarget("haiku") then multiple_insert( os_links, { "GL", "network" } ) elseif os.istarget("ios") then diff --git a/projects/linux/ee.creator.user b/projects/linux/ee.creator.user index 526a6758c..2c4814b75 100644 --- a/projects/linux/ee.creator.user +++ b/projects/linux/ee.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -186,7 +186,7 @@ true - gmake + --with-mojoal gmake premake4 %{buildDir}../../../ ProjectExplorer.ProcessStep @@ -227,7 +227,7 @@ true - gmake + --with-mojoal gmake premake4 %{buildDir}../../../ ProjectExplorer.ProcessStep diff --git a/src/eepp/ui/doc/syntaxcolorscheme.cpp b/src/eepp/ui/doc/syntaxcolorscheme.cpp index 32614b979..0daf3c18a 100644 --- a/src/eepp/ui/doc/syntaxcolorscheme.cpp +++ b/src/eepp/ui/doc/syntaxcolorscheme.cpp @@ -40,7 +40,8 @@ SyntaxColorScheme SyntaxColorScheme::getDefault() { { "string", Color( "#f7c95c" ) }, { "operator", Color( "#93DDFA" ) }, { "function", Color( "#93DDFA" ) }, - { "link", { Color( "#93DDFA" ), Color::Transparent, Text::Underlined } }, + { "link", { Color( "#93DDFA" ) } }, + { "link_hover", { Color( "#93DDFA" ), Color::Transparent, Text::Underlined } }, }, { { "background", Color( "#2e2e32" ) }, { "text", Color( "#97979c" ) }, @@ -162,11 +163,15 @@ const SyntaxColorScheme::Style& SyntaxColorScheme::getSyntaxStyle( const std::st auto it = mSyntaxColors.find( type ); if ( it != mSyntaxColors.end() ) return it->second; - else if ( type == "link" ) + else if ( type == "link" || type == "link_hover" ) return getSyntaxStyle( "function" ); return StyleEmpty; } +bool SyntaxColorScheme::hasSyntaxStyle( const std::string& type ) const { + return mSyntaxColors.find( type ) != mSyntaxColors.end(); +} + void SyntaxColorScheme::setSyntaxStyles( const std::unordered_map& styles ) { mSyntaxColors.insert( styles.begin(), styles.end() ); } diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index 59035426e..4dd187a66 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -753,7 +753,7 @@ Uint32 UICodeEditor::onKeyUp( const KeyEvent& event ) { if ( module->onKeyUp( this, event ) ) return 1; if ( mHandShown && !getUISceneNode()->getWindow()->getInput()->isControlPressed() ) - getUISceneNode()->setCursor( Cursor::IBeam ); + resetLinkOver(); return UIWidget::onKeyUp( event ); } @@ -866,7 +866,7 @@ Uint32 UICodeEditor::onMouseClick( const Vector2i& position, const Uint32& flags String link( checkMouseOverLink( position ) ); if ( !link.empty() ) { Engine::instance()->openURL( link.toUtf8() ); - getUISceneNode()->setCursor( Cursor::IBeam ); + resetLinkOver(); } } else if ( ( flags & EE_BUTTON_LMASK ) && mLastDoubleClick.getElapsedTime() < Milliseconds( 300.f ) ) { @@ -1905,11 +1905,85 @@ void UICodeEditor::drawLineText( const Int64& index, Vector2f position, const Fl line.setStyleConfig( mFontStyleConfig ); if ( style.style ) line.setStyle( style.style ); + line.setColor( Color( style.color ).blendAlpha( mAlpha ) ); + + if ( mHandShown && mLinkPosition.isValid() && mLinkPosition.inSameLine() && + mLinkPosition.start().line() == index ) { + if ( mLinkPosition.start().column() >= curChar && + mLinkPosition.end().column() <= curChar + curCharsWidth ) { + size_t linkPos = text.find( mLink ); + if ( linkPos != String::InvalidPos ) { + String beforeString( text.substr( 0, linkPos ) ); + String afterString( text.substr( linkPos + mLink.size() ) ); + + Float offset = 0.f; + Uint32 lineStyle = line.getStyle(); + + if ( !beforeString.empty() ) { + Float beforeWidth = getTextWidth( beforeString ); + if ( style.background != Color::Transparent ) { + primitives.setColor( + Color( style.background ).blendAlpha( mAlpha ) ); + primitives.drawRectangle( + Rectf( position, Sizef( beforeWidth, lineHeight ) ) ); + } + line.setString( beforeString ); + line.draw( position.x, position.y ); + offset += beforeWidth; + } + + SyntaxColorScheme::Style linkStyle = style; + + if ( mColorScheme.hasSyntaxStyle( "link_hover" ) ) { + linkStyle = mColorScheme.getSyntaxStyle( "link_hover" ); + if ( linkStyle.color != Color::Transparent ) + line.setColor( Color( linkStyle.color ).blendAlpha( mAlpha ) ); + line.setStyle( linkStyle.style ); + } else { + line.setStyle( ( lineStyle & Text::Underlined ) + ? ( lineStyle | Text::Bold ) + : ( lineStyle | Text::Underlined ) ); + } + + Float linkWidth = getTextWidth( mLink ); + if ( linkStyle.background != Color::Transparent ) { + primitives.setColor( + Color( linkStyle.background ).blendAlpha( mAlpha ) ); + primitives.drawRectangle( + Rectf( Vector2f( position.x + offset, position.y ), + Sizef( linkWidth, lineHeight ) ) ); + } + line.setString( mLink ); + line.draw( position.x + offset, position.y ); + offset += linkWidth; + + if ( !afterString.empty() ) { + Float afterWidth = getTextWidth( afterString ); + if ( style.background != Color::Transparent ) { + primitives.setColor( + Color( style.background ).blendAlpha( mAlpha ) ); + primitives.drawRectangle( + Rectf( Vector2f( position.x + offset, position.y ), + Sizef( afterWidth, lineHeight ) ) ); + } + line.setColor( Color( style.color ).blendAlpha( mAlpha ) ); + line.setStyle( lineStyle ); + line.setString( afterString ); + line.draw( position.x + offset, position.y ); + } + + position.x += textWidth; + curChar += text.size(); + continue; + } + } + } + if ( style.background != Color::Transparent ) { primitives.setColor( Color( style.background ).blendAlpha( mAlpha ) ); primitives.drawRectangle( Rectf( position, Sizef( textWidth, lineHeight ) ) ); } - line.setColor( Color( style.color ).blendAlpha( mAlpha ) ); + if ( curPositionChar + curChar + curCharsWidth > curMaxPositionChar ) { if ( curChar < curPositionChar ) { Int64 charsToVisible = curPositionChar - curChar; @@ -2122,40 +2196,28 @@ void UICodeEditor::checkMouseOverColor( const Vector2i& position ) { } String UICodeEditor::checkMouseOverLink( const Vector2i& position ) { - if ( !mInteractiveLinks || !getUISceneNode()->getWindow()->getInput()->isControlPressed() ) { - getUISceneNode()->setCursor( Cursor::IBeam ); - return ""; - } + if ( !mInteractiveLinks || !getUISceneNode()->getWindow()->getInput()->isControlPressed() ) + return resetLinkOver(); TextPosition pos( resolveScreenPosition( position.asFloat(), false ) ); - if ( mDoc->getChar( pos ) == '\n' ) { - getUISceneNode()->setCursor( Cursor::IBeam ); - return ""; - } + if ( mDoc->getChar( pos ) == '\n' ) + return resetLinkOver(); - if ( pos.line() > (Int64)mDoc->linesCount() ) { - getUISceneNode()->setCursor( Cursor::IBeam ); - return ""; - } + if ( pos.line() > (Int64)mDoc->linesCount() ) + return resetLinkOver(); const String& line = mDoc->line( pos.line() ).getText(); - if ( pos.column() >= (Int64)line.size() - 1 ) { - getUISceneNode()->setCursor( Cursor::IBeam ); - return ""; - } + if ( pos.column() >= (Int64)line.size() - 1 ) + return resetLinkOver(); TextPosition startB( mDoc->previousSpaceBoundaryInLine( pos ) ); TextPosition endB( mDoc->nextSpaceBoundaryInLine( pos ) ); - if ( startB.column() >= (Int64)line.size() || endB.column() >= (Int64)line.size() ) { - getUISceneNode()->setCursor( Cursor::IBeam ); - return ""; - } + if ( startB.column() >= (Int64)line.size() || endB.column() >= (Int64)line.size() ) + return resetLinkOver(); - if ( pos.column() <= startB.column() || pos.column() >= endB.column() ) { - getUISceneNode()->setCursor( Cursor::IBeam ); - return ""; - } + if ( pos.column() <= startB.column() || pos.column() >= endB.column() ) + return resetLinkOver(); String partialLine( line.substr( startB.column(), endB.column() ) ); @@ -2178,12 +2240,25 @@ String UICodeEditor::checkMouseOverLink( const Vector2i& position ) { pos.column() <= startB.column() + link.second ) { getUISceneNode()->setCursor( Cursor::Hand ); mHandShown = true; - return String( linkStr.substr( link.first, link.second - link.first ) ); + mLinkPosition = { { startB.line(), startB.column() + link.first }, + { startB.line(), startB.column() + link.second } }; + mLink = String( linkStr.substr( link.first, link.second - link.first ) ); + invalidateDraw(); + return mLink; } } } + return resetLinkOver(); +} + +String UICodeEditor::resetLinkOver() { + if ( mHandShown ) + invalidateDraw(); + mHandShown = false; getUISceneNode()->setCursor( Cursor::IBeam ); + mLinkPosition = TextRange(); + mLink.clear(); return ""; }