From 15f9bc3fd8d3f35750b9705aaac9efd1e612b111 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Fri, 3 Oct 2025 00:05:28 -0300 Subject: [PATCH] Arrange correctly the elements in statusbar on some cases. Add the option "Open URL" in the context menu when right clickin a URL. --- include/eepp/ui/uicodeeditor.hpp | 2 +- src/eepp/scene/node.cpp | 2 +- src/eepp/ui/iconmanager.cpp | 2 +- src/eepp/ui/uicodeeditor.cpp | 21 ++++++-- .../plugins/aiassistant/aiassistantplugin.cpp | 50 +++++++++---------- .../plugins/aiassistant/aiassistantplugin.hpp | 3 +- src/tools/ecode/plugins/git/gitplugin.cpp | 24 ++++++--- src/tools/ecode/plugins/git/gitplugin.hpp | 1 + 8 files changed, 66 insertions(+), 39 deletions(-) diff --git a/include/eepp/ui/uicodeeditor.hpp b/include/eepp/ui/uicodeeditor.hpp index 459e434ea..bae125d51 100644 --- a/include/eepp/ui/uicodeeditor.hpp +++ b/include/eepp/ui/uicodeeditor.hpp @@ -1087,7 +1087,7 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client { void checkMouseOverColor( const Vector2i& position ); - String checkMouseOverLink( const Vector2i& position ); + String checkMouseOverLink( const Vector2i& position, bool checkModifiers = true ); String resetLinkOver( const Vector2i& mousePos ); diff --git a/src/eepp/scene/node.cpp b/src/eepp/scene/node.cpp index 149e56bca..5c3b8011b 100644 --- a/src/eepp/scene/node.cpp +++ b/src/eepp/scene/node.cpp @@ -471,7 +471,7 @@ Node* Node::toFront() { } Node* Node::toBack() { - if ( NULL != mParentNode ) { + if ( NULL != mParentNode && mParentNode->mChild != this ) { mParentNode->childAddAt( this, 0 ); } return this; diff --git a/src/eepp/ui/iconmanager.cpp b/src/eepp/ui/iconmanager.cpp index 7a30fb703..f75a64ec7 100644 --- a/src/eepp/ui/iconmanager.cpp +++ b/src/eepp/ui/iconmanager.cpp @@ -82,7 +82,7 @@ UIIconTheme* IconManager::init( const std::string& iconThemeName, FontTrueType* { "file-search", 0xed05 }, { "window", 0xf2c4 }, { "file-lock-fill", 0xecf2 }, - { "filetype-svg", 0xF3C5 }, + { "file type-svg", 0xF3C5 }, { "filetype-png", 0xF3C5 }, { "filetype-jpg", 0xF3C5 }, { "filetype-jpeg", 0xF3C5 }, diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index f0d01d6a5..a519eaaf0 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -1376,6 +1376,11 @@ void UICodeEditor::createDefaultContextMenuOptions( UIPopUpMenu* menu ) { if ( !mCreateDefaultContextMenuOptions ) return; + if ( mInteractiveLinks && !checkMouseOverLink( getInput()->getMousePos(), false ).empty() ){ + menuAdd( menu, i18n( "uicodeeditor_open_url", "Open URL" ), "window", "open-hover-url" ); + menu->addSeparator(); + } + if ( !mLocked ) { menuAdd( menu, i18n( "uicodeeditor_undo", "Undo" ), "undo", "undo" ) ->setEnabled( mDoc->hasUndo() ); @@ -4528,6 +4533,12 @@ void UICodeEditor::registerCommands() { []( Client* client ) { static_cast( client )->fold(); } ); mDoc->setCommand( "unfold", []( Client* client ) { static_cast( client )->unfold(); } ); + mDoc->setCommand( "open-hover-url", []( Client* client ) { + UICodeEditor* editor = static_cast( client ); + if ( !editor->mLink.empty() ) + Engine::instance()->openURI( editor->mLink ); + } ); + mUnlockedCmd.insert( { "copy", "select-all", "open-containing-folder", "copy-containing-folder-path", "copy-file-path", "copy-file-path-and-position", "open-context-menu", "find-replace" } ); @@ -4621,8 +4632,8 @@ void UICodeEditor::checkMouseOverColor( const Vector2i& position ) { } } -String UICodeEditor::checkMouseOverLink( const Vector2i& position ) { - if ( !mInteractiveLinks || !getInput()->isKeyModPressed() ) +String UICodeEditor::checkMouseOverLink( const Vector2i& position, bool checkModifiers ) { + if ( !mInteractiveLinks || ( checkModifiers && !getInput()->isKeyModPressed() ) ) return resetLinkOver( position ); TextPosition pos( resolveScreenPosition( position.asFloat(), false ) ); @@ -4667,8 +4678,10 @@ String UICodeEditor::checkMouseOverLink( const Vector2i& position ) { for ( const auto& link : links ) { if ( pos.column() >= startB.column() + link.first && pos.column() <= startB.column() + link.second ) { - getUISceneNode()->setCursor( Cursor::Hand ); - mHandShown = true; + if ( checkModifiers ) { + getUISceneNode()->setCursor( Cursor::Hand ); + mHandShown = true; + } mLinkPosition = { { startB.line(), startB.column() + link.first }, { startB.line(), startB.column() + link.second } }; mLink = String( linkStr.substr( link.first, link.second - link.first ) ); diff --git a/src/tools/ecode/plugins/aiassistant/aiassistantplugin.cpp b/src/tools/ecode/plugins/aiassistant/aiassistantplugin.cpp index a65323c69..fa2959bfd 100644 --- a/src/tools/ecode/plugins/aiassistant/aiassistantplugin.cpp +++ b/src/tools/ecode/plugins/aiassistant/aiassistantplugin.cpp @@ -20,18 +20,9 @@ static std::initializer_list AIAssistantUnlockedCommandList = { static std::initializer_list AIAssistantCommandList = { - "ai-prompt", - "ai-add-chat", - "ai-chat-history", - "ai-attach-file", - "ai-clone-chat", - "ai-settings", - "ai-toggle-private-chat", - "ai-save-chat", - "ai-rename-chat", - "ai-show-menu", - "ai-chat-toggle-role", - "ai-refresh-local-models", + "ai-prompt", "ai-add-chat", "ai-chat-history", "ai-attach-file", + "ai-clone-chat", "ai-settings", "ai-toggle-private-chat", "ai-save-chat", + "ai-rename-chat", "ai-show-menu", "ai-chat-toggle-role", "ai-refresh-local-models", "new-ai-assistant" }; @@ -152,9 +143,11 @@ AIAssistantPlugin::~AIAssistantPlugin() { waitUntilLoaded(); mShuttingDown = true; - if ( mStatusButton ) - mStatusButton->close(); - + if ( mAIChatButton ) { + if ( mAIChatButtonPosCbId ) + mAIChatButton->getParent()->removeEventListener( mAIChatButtonPosCbId ); + mAIChatButton->close(); + } getPluginContext()->getConfig().removeTabWidgetType( "llm_chatui" ); } @@ -332,7 +325,6 @@ void AIAssistantPlugin::loadAIAssistantConfig( const std::string& path, bool upd mApiKeys["openrouter"] = config.value( "openrouter_api_key", "" ); else if ( updateConfigFile ) config["openrouter_api_key"] = mApiKeys["openrouter"]; - } if ( mKeyBindings.empty() ) { @@ -473,16 +465,24 @@ void AIAssistantPlugin::initUI() { if ( !mStatusBar ) return; - if ( !mStatusButton ) { - mStatusButton = UIPushButton::New(); - mStatusButton->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::MatchParent ); - mStatusButton->setParent( mStatusBar ); - mStatusButton->setId( "ai_assistant_but" ); - mStatusButton->setClass( "status_but" ); - mStatusButton->setIcon( iconDrawable( "chat-sparkle", 14 ) ); - mStatusButton->setTooltipText( i18n( "ai_assistant", "AI Assistant" ) ); - mStatusButton->on( Event::MouseClick, + if ( !mAIChatButton ) { + mAIChatButton = UIPushButton::New(); + mAIChatButton->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::MatchParent ); + mAIChatButton->setParent( mStatusBar ); + mAIChatButton->setId( "ai_assistant_but" ); + mAIChatButton->setClass( "status_but" ); + mAIChatButton->setIcon( iconDrawable( "chat-sparkle", 14 ) ); + mAIChatButton->setTooltipText( i18n( "ai_assistant", "AI Assistant" ) ); + + mAIChatButton->on( Event::MouseClick, [this]( const Event* ) { newAIAssistant()->setFocus(); } ); + + mAIChatButtonPosCbId = + mAIChatButton->getParent()->on( Event::OnChildCountChanged, []( const Event* event ) { + auto statusButton = event->getNode()->find( "ai_assistant_but" ); + if ( statusButton && event->getNode()->getLastChild() != statusButton ) + statusButton->toFront(); + } ); } } diff --git a/src/tools/ecode/plugins/aiassistant/aiassistantplugin.hpp b/src/tools/ecode/plugins/aiassistant/aiassistantplugin.hpp index 2fed972a4..df7f7a5c3 100644 --- a/src/tools/ecode/plugins/aiassistant/aiassistantplugin.hpp +++ b/src/tools/ecode/plugins/aiassistant/aiassistantplugin.hpp @@ -52,9 +52,10 @@ class AIAssistantPlugin : public PluginBase { LLMProviders mProviders; bool mUIInit{ false }; UIWidget* mStatusBar{ nullptr }; - UIPushButton* mStatusButton{ nullptr }; + UIPushButton* mAIChatButton{ nullptr }; UnorderedMap mApiKeys; AIAssistantConfig mConfig; + Uint32 mAIChatButtonPosCbId{ 0 }; AIAssistantPlugin( PluginManager* pluginManager, bool sync ); diff --git a/src/tools/ecode/plugins/git/gitplugin.cpp b/src/tools/ecode/plugins/git/gitplugin.cpp index 32245a9d6..21b89ff24 100644 --- a/src/tools/ecode/plugins/git/gitplugin.cpp +++ b/src/tools/ecode/plugins/git/gitplugin.cpp @@ -87,6 +87,9 @@ GitPlugin::~GitPlugin() { if ( getUISceneNode() ) getUISceneNode()->removeActionsByTag( GIT_STATUS_UPDATE_TAG ); + if ( mStatusBar && mRepositionCbId ) + mStatusBar->removeEventListener( mRepositionCbId ); + { Lock l( mGitBranchMutex ); } @@ -352,13 +355,22 @@ void GitPlugin::updateStatusBarSync() { mPanelSwicher->getListBox()->setSelected( 1 ); } ); - if ( mStatusBar->getNextNode() == nullptr || - mStatusBar->getNextNode()->getId() != "doc_info" ) { - auto docInfo = mStatusBar->find( "doc_info" ); - if ( docInfo != nullptr && docInfo->getParent() == mStatusButton->getParent() ) { - mStatusButton->toPosition( docInfo->getNodeIndex() ); + const auto reposition = [this] { + if ( mStatusBar == nullptr ) + return; + if ( mStatusButton->getNextNode() == nullptr || + mStatusButton->getNextNode()->getId() != "doc_info" ) { + auto docInfo = mStatusBar->find( "doc_info" ); + if ( docInfo != nullptr && docInfo->getParent() == mStatusButton->getParent() ) { + mStatusButton->toPosition( docInfo->getNodeIndex() ); + } } - } + }; + + reposition(); + + mRepositionCbId = + mStatusBar->on( Event::OnChildCountChanged, [reposition]( auto ) { reposition(); } ); } mStatusButton->setVisible( !mGit->getGitFolder().empty() ); diff --git a/src/tools/ecode/plugins/git/gitplugin.hpp b/src/tools/ecode/plugins/git/gitplugin.hpp index 09cf54417..d57dcdfb5 100644 --- a/src/tools/ecode/plugins/git/gitplugin.hpp +++ b/src/tools/ecode/plugins/git/gitplugin.hpp @@ -125,6 +125,7 @@ class GitPlugin : public PluginBase { Mutex mRepoMutex; Mutex mReposMutex; String mLastCommitMsg; + Uint32 mRepositionCbId{ 0 }; struct CustomTokenizer { SyntaxDefinition def;