diff --git a/bin/assets/ui/breeze.css b/bin/assets/ui/breeze.css index f1ef5d817..9b863c0ac 100644 --- a/bin/assets/ui/breeze.css +++ b/bin/assets/ui/breeze.css @@ -935,8 +935,8 @@ treeview.selection_type_cell tableview::cell:selected { tableview::cell, treeview::cell { - padding-left: 6dp; - padding-right: 6dp; + padding-left: 4dp; + padding-right: 4dp; min-icon-size: 16dp 16dp; } diff --git a/include/eepp/ui/uipopupmenu.hpp b/include/eepp/ui/uipopupmenu.hpp index 86bf192ce..ae35d550d 100644 --- a/include/eepp/ui/uipopupmenu.hpp +++ b/include/eepp/ui/uipopupmenu.hpp @@ -35,6 +35,10 @@ class EE_API UIPopUpMenu : public UIMenu { void setCloseSubMenusOnClose( bool closeSubMenusOnClose ); + void showAtScreenPosition( Vector2f pos ); + + void showOverMouseCursor(); + protected: Action* mHidingAction{ nullptr }; bool mCloseOnHide{ false }; diff --git a/src/eepp/ui/uipopupmenu.cpp b/src/eepp/ui/uipopupmenu.cpp index bbd4bb081..cf650627b 100644 --- a/src/eepp/ui/uipopupmenu.cpp +++ b/src/eepp/ui/uipopupmenu.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include namespace EE { namespace UI { @@ -58,6 +60,17 @@ bool UIPopUpMenu::show() { return false; } +void UIPopUpMenu::showAtScreenPosition( Vector2f pos ) { + nodeToWorldTranslation( pos ); + UIMenu::findBestMenuPos( pos, this ); + setPixelsPosition( pos ); + show(); +} + +void UIPopUpMenu::showOverMouseCursor() { + showAtScreenPosition( getUISceneNode()->getWindow()->getInput()->getMousePosf() ); +} + bool UIPopUpMenu::hide() { if ( isVisible() && !mHidingAction ) { if ( NULL != getUISceneNode() && diff --git a/src/eepp/ui/uitreeview.cpp b/src/eepp/ui/uitreeview.cpp index 87451bf36..83ca883e5 100644 --- a/src/eepp/ui/uitreeview.cpp +++ b/src/eepp/ui/uitreeview.cpp @@ -258,21 +258,21 @@ UIWidget* UITreeView::updateCell( const int& rowIndex, const ModelIndex& index, bool hasChilds = false; - if ( widget->isType( UI_TYPE_TREEVIEW_CELL ) ) { + if ( widget->isType( UI_TYPE_TREEVIEW_CELL ) && + index.column() == (Int64)getModel()->treeColumn() ) { UITreeViewCell* tcell = widget->asType(); UIImage* image = widget->asType()->getImage(); - Float minIndent = - !mExpandersAsIcons && mExpandIcon && mContractIcon - ? eemax( mExpandIcon->getSize( mExpanderIconSize )->getPixelsSize().getWidth(), - mContractIcon->getSize( mExpanderIconSize ) - ->getPixelsSize() - .getWidth() ) + - PixelDensity::dpToPx( image->getLayoutMargin().Right ) - : 0; + Float minIndent = 0; + if ( !mExpandersAsIcons && mExpandIcon && mContractIcon ) { + minIndent = + eemax( + mExpandIcon->getSize( mExpanderIconSize )->getPixelsSize().getWidth(), + mContractIcon->getSize( mExpanderIconSize )->getPixelsSize().getWidth() ) + + image->getLayoutPixelsMargin().Right; + } - if ( index.column() == (Int64)getModel()->treeColumn() ) - tcell->setIndentation( minIndent + getIndentWidth() * indentLevel ); + Float indentation = minIndent + getIndentWidth() * indentLevel; hasChilds = getModel()->rowCount( index ) > 0; @@ -286,15 +286,14 @@ UIWidget* UITreeView::updateCell( const int& rowIndex, const ModelIndex& index, image->setVisible( true ); image->setPixelsSize( drawable ? drawable->getPixelsSize() : Sizef( 0, 0 ) ); image->setDrawable( drawable ); - if ( !mExpandersAsIcons ) { - tcell->setIndentation( - tcell->getIndentation() - image->getPixelsSize().getWidth() - - PixelDensity::dpToPx( image->getLayoutMargin().Right ) ); - } + if ( !mExpandersAsIcons ) + indentation = indentation - image->getPixelsSize().getWidth(); } } else { image->setVisible( false ); } + + tcell->setIndentation( indentation ); } if ( hasChilds && mExpandersAsIcons && cell->hasIcon() ) { diff --git a/src/tools/ecode/plugins/git/git.cpp b/src/tools/ecode/plugins/git/git.cpp index b2c712e41..6f981867a 100644 --- a/src/tools/ecode/plugins/git/git.cpp +++ b/src/tools/ecode/plugins/git/git.cpp @@ -134,17 +134,50 @@ std::string Git::setSafeDirectory( const std::string& projectDir ) const { return buf; } +Git::Result Git::pull( const std::string& projectDir ) { + std::string buf; + Git::Result res; + int retCode = git( "pull", projectDir, buf ); + res.returnCode = retCode; + res.result = buf; + return res; +} + Git::CheckoutResult Git::checkout( const std::string& branch, const std::string& projectDir ) const { std::string buf; int retCode = git( String::format( "checkout %s", branch ), projectDir, buf ); Git::CheckoutResult res; - if ( EXIT_SUCCESS != retCode ) { - res.returnCode = retCode; - res.error = buf; - } else { - res.branch = branch; - } + res.returnCode = retCode; + res.result = buf; + res.branch = branch; + return res; +} + +Git::Result Git::add( const std::string& file, const std::string& projectDir ) { + std::string buf; + int retCode = git( String::format( "add --force -- %s", file ), projectDir, buf ); + Git::CheckoutResult res; + res.returnCode = retCode; + res.result = buf; + return res; +} + +Git::Result Git::restore( const std::string& file, const std::string& projectDir ) { + std::string buf; + int retCode = git( String::format( "restore %s", file ), projectDir, buf ); + Git::CheckoutResult res; + res.returnCode = retCode; + res.result = buf; + return res; +} + +Git::Result Git::reset( const std::string& file, const std::string& projectDir ) { + std::string buf; + int retCode = git( String::format( "reset -q HEAD -- %s", file ), projectDir, buf ); + Git::CheckoutResult res; + res.returnCode = retCode; + res.result = buf; return res; } @@ -157,12 +190,9 @@ Git::CheckoutResult Git::checkoutNewBranch( const std::string& newBranch, args += " " + fromBranch; int retCode = git( args, projectDir, buf ); Git::CheckoutResult res; - if ( EXIT_SUCCESS != retCode ) { - res.returnCode = retCode; - res.error = buf; - } else { - res.branch = buf; - } + res.returnCode = retCode; + res.result = buf; + res.branch = buf; return res; } diff --git a/src/tools/ecode/plugins/git/git.hpp b/src/tools/ecode/plugins/git/git.hpp index 7563b3e3c..7ba6733d7 100644 --- a/src/tools/ecode/plugins/git/git.hpp +++ b/src/tools/ecode/plugins/git/git.hpp @@ -135,8 +135,12 @@ class Git { }; struct Result { - std::string error; + std::string result; int returnCode = 0; + + bool success() const { return returnCode == EXIT_SUCCESS; } + + bool fail() const { return !success(); } }; struct CheckoutResult : public Result { @@ -195,6 +199,12 @@ class Git { Status status( bool recurseSubmodules, const std::string& projectDir = "" ); + Result add( const std::string& file, const std::string& projectDir = "" ); + + Result restore( const std::string& file, const std::string& projectDir = "" ); + + Result reset( const std::string& file, const std::string& projectDir = "" ); + bool setProjectPath( const std::string& projectPath ); const std::string& getGitPath() const; @@ -205,6 +215,8 @@ class Git { std::string setSafeDirectory( const std::string& projectDir ) const; + Result pull( const std::string& projectDir = "" ); + CheckoutResult checkout( const std::string& branch, const std::string& projectDir = "" ) const; CheckoutResult checkoutNewBranch( const std::string& newBranch, diff --git a/src/tools/ecode/plugins/git/gitplugin.cpp b/src/tools/ecode/plugins/git/gitplugin.cpp index 9d3141dcf..4c7faf973 100644 --- a/src/tools/ecode/plugins/git/gitplugin.cpp +++ b/src/tools/ecode/plugins/git/gitplugin.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -128,8 +129,7 @@ class GitBranchModel : public Model { if ( index.column() == (Int64)treeColumn() ) { if ( index.hasParent() ) { Git::Branch* branch = static_cast( index.internalData() ); - return mPlugin->getUISceneNode()->findIcon( - branch->type == Git::RefType::Tag ? GIT_TAG : GIT_REPO ); + return mPlugin->findIcon( branch->type == Git::RefType::Tag ? GIT_TAG : GIT_REPO ); } } return nullptr; @@ -371,8 +371,7 @@ class GitStatusModel : public Model { case ModelRole::Icon: { if ( (Int64)treeColumn() == index.column() ) { if ( index.internalId() == Repo ) { - return Variant( - mPlugin->getManager()->getUISceneNode()->findIcon( "repo" ) ); + return Variant( mPlugin->findIcon( "repo" ) ); } else if ( index.internalId() == GitFile ) { const Git::DiffFile& s = mStatus[index.parent().parent().row()] .type[index.parent().row()] @@ -396,6 +395,14 @@ class GitStatusModel : public Model { virtual bool classModelRoleEnabled() { return true; } + const DiffFile* file( const ModelIndex& index ) const { + if ( index.internalId() != GitFile ) + return nullptr; + return &mStatus[index.parent().parent().row()] + .type[index.parent().row()] + .files[index.row()]; + } + protected: std::vector mStatus; GitPlugin* mPlugin{ nullptr }; @@ -573,10 +580,7 @@ void GitPlugin::updateStatusBarSync() { mStatusButton->setParent( mStatusBar ); mStatusButton->setId( "status_git" ); mStatusButton->setClass( "status_but" ); - mStatusButton->setIcon( getManager() - ->getUISceneNode() - ->findIcon( "source-control" ) - ->getSize( PixelDensity::dpToPxI( 10 ) ) ); + mStatusButton->setIcon( iconDrawable( "source-control", 10 ) ); mStatusButton->reloadStyle( true, true ); mStatusButton->getTextBox()->setUsingCustomStyling( true ); auto childCount = mStatusBar->getChildCount(); @@ -839,6 +843,83 @@ void GitPlugin::blame( UICodeEditor* editor ) { } ); } +void GitPlugin::checkout( const std::string& branch ) { + if ( !mGit ) + return; + mLoader->setVisible( true ); + mThreadPool->run( [this, branch] { + auto result = mGit->checkout( branch ); + if ( result.success() ) { + { + Lock l( mGitBranchMutex ); + mGitBranch = branch; + } + if ( mBranchesTree->getModel() ) + mBranchesTree->getModel()->invalidate( Model::DontInvalidateIndexes ); + } else { + showMessage( LSPMessageType::Warning, result.result ); + } + getUISceneNode()->runOnMainThread( [this] { mLoader->setVisible( false ); } ); + } ); +} + +void GitPlugin::pull() { + if ( !mGit ) + return; + mLoader->setVisible( true ); + mThreadPool->run( [this] { + auto res = mGit->pull(); + if ( res.fail() ) + showMessage( LSPMessageType::Warning, res.result ); + getUISceneNode()->runOnMainThread( [this] { mLoader->setVisible( false ); } ); + } ); +} + +void GitPlugin::stage( const std::string& file ) { + if ( !mGit ) + return; + mLoader->setVisible( true ); + mThreadPool->run( [this, file] { + auto res = mGit->add( file ); + if ( res.fail() ) + showMessage( LSPMessageType::Warning, res.result ); + getUISceneNode()->runOnMainThread( [this] { mLoader->setVisible( false ); } ); + updateStatus( true ); + } ); +} + +void GitPlugin::unstage( const std::string& file ) { + if ( !mGit ) + return; + mLoader->setVisible( true ); + mThreadPool->run( [this, file] { + auto res = mGit->reset( file ); + if ( res.fail() ) + showMessage( LSPMessageType::Warning, res.result ); + getUISceneNode()->runOnMainThread( [this] { mLoader->setVisible( false ); } ); + updateStatus( true ); + } ); +} + +void GitPlugin::discard( const std::string& file ) { + if ( !mGit ) + return; + mLoader->setVisible( true ); + mThreadPool->run( [this, file] { + auto res = mGit->restore( file ); + if ( res.fail() ) + showMessage( LSPMessageType::Warning, res.result ); + getUISceneNode()->runOnMainThread( [this] { mLoader->setVisible( false ); } ); + updateStatus( true ); + } ); +} + +void GitPlugin::openFile( const std::string& file ) { + getUISceneNode()->runOnMainThread( [this, file] { + mManager->getLoadFileFn()( mGit->getProjectPath() + file, []( auto, auto ) {} ); + } ); +} + void GitPlugin::onRegister( UICodeEditor* editor ) { PluginBase::onRegister( editor ); @@ -858,6 +939,8 @@ void GitPlugin::onRegister( UICodeEditor* editor ) { if ( mTab ) mTab->setTabSelected(); } ); + doc.setCommand( "git-pull", [this]() { pull(); } ); + doc.setCommand( "git-checkout", [this]() { checkout( mGitBranch ); } ); } void GitPlugin::onUnregister( UICodeEditor* editor ) { @@ -878,8 +961,7 @@ bool GitPlugin::onCreateContextMenu( UICodeEditor*, UIPopUpMenu* menu, const Vec const std::string& icon = "" ) { subMenu ->add( i18n( txtKey, txtVal ), - !icon.empty() ? mManager->getUISceneNode()->findIcon( icon )->getSize( - PixelDensity::dpToPxI( 12 ) ) + !icon.empty() ? findIcon( icon )->getSize( PixelDensity::dpToPxI( 12 ) ) : nullptr, KeyBindings::keybindFormat( mKeyBindings[txtKey] ) ) ->setId( txtKey ); @@ -946,13 +1028,12 @@ void GitPlugin::buildSidePanelTab() { return; if ( mSidePanel == nullptr ) getUISceneNode()->bind( "panel", mSidePanel ); - UIIcon* icon = getUISceneNode()->findIcon( "source-control" ); + UIIcon* icon = findIcon( "source-control" ); UIWidget* node = getUISceneNode()->loadLayoutFromString( R"html( - +