diff --git a/include/eepp/ui/uitreeview.hpp b/include/eepp/ui/uitreeview.hpp index e76955599..ce4d747a3 100644 --- a/include/eepp/ui/uitreeview.hpp +++ b/include/eepp/ui/uitreeview.hpp @@ -113,6 +113,8 @@ class EE_API UITreeView : public UIAbstractTableView { void setDisableCellClipping( bool disableCellCliping ); + void clearViewMetadata(); + protected: enum class IterationDecision { Continue, diff --git a/src/eepp/ui/abstract/uiabstracttableview.cpp b/src/eepp/ui/abstract/uiabstracttableview.cpp index 07d55102a..afaf44884 100644 --- a/src/eepp/ui/abstract/uiabstracttableview.cpp +++ b/src/eepp/ui/abstract/uiabstracttableview.cpp @@ -333,6 +333,11 @@ void UIAbstractTableView::updateColumnsWidth() { if ( columnData( col ).width != width ) { columnData( col ).width = width; updateHeaderSize(); + + ColumnData& colData = columnData( col ); + if ( colData.widget ) + colData.widget->setPixelsSize( colData.width, getHeaderHeight() ); + onColumnSizeChange( col ); } } diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index 2f74870e4..a5fd35e7a 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -1573,7 +1573,9 @@ Uint32 UICodeEditor::onMouseUp( const Vector2i& position, const Uint32& flags ) } else if ( flags & EE_BUTTON_WLMASK ) { setScrollX( mScroll.x - mMouseWheelScroll ); } else if ( !minimapHover && ( flags & EE_BUTTON_RMASK ) ) { - onCreateContextMenu( position, flags ); + Vector2f localPos( convertToNodeSpace( position.asFloat() ) ); + if ( localPos.x >= mPaddingPx.Left + getGutterWidth() && localPos.y >= mPluginsTopSpace ) + onCreateContextMenu( position, flags ); } return UIWidget::onMouseUp( position, flags ); diff --git a/src/eepp/ui/uitreeview.cpp b/src/eepp/ui/uitreeview.cpp index be8572fbe..37a83a837 100644 --- a/src/eepp/ui/uitreeview.cpp +++ b/src/eepp/ui/uitreeview.cpp @@ -88,10 +88,10 @@ void UITreeView::traverseTree( TreeViewCallback callback ) const { } void UITreeView::createOrUpdateColumns( bool resetColumnData ) { - updateContentSize(); if ( !getModel() ) return; UIAbstractTableView::createOrUpdateColumns( resetColumnData ); + updateContentSize(); } size_t UITreeView::getItemCount() const { @@ -184,8 +184,8 @@ UIWidget* UITreeView::setupCell( UITableCell* widget, UIWidget* rowWidget, widget->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed ); widget->setTextAlign( UI_HALIGN_LEFT ); widget->setCurIndex( index ); + bindNavigationClick( widget ); if ( index.column() == (Int64)getModel()->treeColumn() ) { - bindNavigationClick( widget ); widget->onClick( [this]( const MouseEvent* mouseEvent ) { if ( mSingleClickNavigation ) return; @@ -740,6 +740,10 @@ void UITreeView::setDisableCellClipping( bool disableCellClipping ) { mDisableCellClipping = disableCellClipping; } +void UITreeView::clearViewMetadata() { + mViewMetadata.clear(); +} + void UITreeView::onSortColumn( const size_t& ) { // Do nothing. return; diff --git a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp index afe3b2239..c1ee6d01c 100644 --- a/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerclientlistener.cpp @@ -1,7 +1,8 @@ +#include "debuggerclientlistener.hpp" #include "../../notificationcenter.hpp" #include "../../statusappoutputcontroller.hpp" -#include "debuggerclientlistener.hpp" #include "debuggerplugin.hpp" +#include "eepp/window/clipboard.hpp" #include "models/stackmodel.hpp" #include "models/threadsmodel.hpp" #include "models/variablesmodel.hpp" @@ -87,13 +88,73 @@ void DebuggerClientListener::initUI() { uiVariables->setModel( mVariablesHolder->getModel() ); uiVariables->removeEventsOfType( Event::OnModelEvent ); uiVariables->onModelEvent( [this]( const ModelEvent* modelEvent ) { + auto idx( modelEvent->getModelIndex() ); if ( modelEvent->getModelEventType() == Abstract::ModelEventType::OpenTree ) { - ModelVariableNode* node = - static_cast( modelEvent->getModelIndex().internalData() ); + ModelVariableNode* node = static_cast( idx.internalData() ); mClient->variables( node->var.variablesReference ); - mVariablesHolder->saveExpandedState( modelEvent->getModelIndex() ); + mVariablesHolder->saveExpandedState( idx ); } else if ( modelEvent->getModelEventType() == Abstract::ModelEventType::CloseTree ) { - mVariablesHolder->removeExpandedState( modelEvent->getModelIndex() ); + mVariablesHolder->removeExpandedState( idx ); + } else if ( modelEvent->getModelEventType() == Abstract::ModelEventType::OpenMenu && + idx.isValid() ) { + + auto context = mPlugin->getPluginContext(); + UIPopUpMenu* menu = UIPopUpMenu::New(); + + ModelVariableNode* node = static_cast( idx.internalData() ); + Variable var( node->var ); + + menu->add( context->i18n( "debugger_copy_variable_value", "Copy Value" ), + context->findIcon( "copy" ) ) + ->setId( "debugger_copy_variable_value" ); + + menu->add( context->i18n( "debugger_copy_variable_name", "Copy Name" ), + context->findIcon( "copy" ) ) + ->setId( "debugger_copy_variable_name" ); + + if ( var.type ) { + menu->add( context->i18n( "debugger_copy_variable_type", "Copy Type" ), + context->findIcon( "copy" ) ) + ->setId( "debugger_copy_variable_type" ); + } + + if ( var.evaluateName ) { + menu->add( context->i18n( "debugger_copy_variable_evaluate_name", + "Copy Evaluate Name" ), + context->findIcon( "copy" ) ) + ->setId( "debugger_copy_variable_evaluate_name" ); + } + + if ( var.memoryReference ) { + menu->add( context->i18n( "debugger_copy_variable_memory_reference", + "Copy Memory Reference" ), + context->findIcon( "copy" ) ) + ->setId( "debugger_copy_variable_memory_reference" ); + } + + menu->on( Event::OnItemClicked, [this, var = std::move( var )]( const Event* event ) { + UIMenuItem* item = event->getNode()->asType(); + std::string id( item->getId() ); + if ( id == "debugger_copy_variable_value" ) { + mPlugin->getUISceneNode()->getWindow()->getClipboard()->setText( var.value ); + } else if ( id == "debugger_copy_variable_name" ) { + mPlugin->getUISceneNode()->getWindow()->getClipboard()->setText( var.name ); + } else if ( id == "debugger_copy_variable_type" ) { + mPlugin->getUISceneNode()->getWindow()->getClipboard()->setText( *var.type ); + } else if ( id == "debugger_copy_variable_evaluate_name" ) { + mPlugin->getUISceneNode()->getWindow()->getClipboard()->setText( + *var.evaluateName ); + } else if ( id == "debugger_copy_variable_memory_reference" ) { + mPlugin->getUISceneNode()->getWindow()->getClipboard()->setText( + *var.memoryReference ); + } + } ); + + Vector2f pos( context->getWindow()->getInput()->getMousePos().asFloat() ); + menu->nodeToWorldTranslation( pos ); + UIMenu::findBestMenuPos( pos, menu ); + menu->setPixelsPosition( pos ); + menu->show(); } } ); diff --git a/src/tools/ecode/plugins/debugger/debuggerplugin.cpp b/src/tools/ecode/plugins/debugger/debuggerplugin.cpp index b7d969145..6847e1bd8 100644 --- a/src/tools/ecode/plugins/debugger/debuggerplugin.cpp +++ b/src/tools/ecode/plugins/debugger/debuggerplugin.cpp @@ -178,6 +178,8 @@ void DebuggerPlugin::onLoadProject( const std::string& projectFolder, if ( !FileSystem::fileGet( debuggerStatePath, data ) ) return; + auto sdc = getStatusDebuggerController(); + json j; try { j = json::parse( data, nullptr, true, true ); @@ -199,6 +201,9 @@ void DebuggerPlugin::onLoadProject( const std::string& projectFolder, } } } + + if ( sdc && sdc->getWidget() && sdc->getUIExpressions() ) + sdc->getUIExpressions()->setModel( mExpressionsHolder->getModel() ); } if ( config.contains( "breakpoints" ) && config["breakpoints"].is_object() ) { @@ -221,13 +226,16 @@ void DebuggerPlugin::onLoadProject( const std::string& projectFolder, mBreakpointsModel = std::make_shared( mBreakpoints, getUISceneNode() ); } + + if ( sdc && sdc->getWidget() && sdc->getUIBreakpoints() ) + sdc->getUIBreakpoints()->setModel( mBreakpointsModel ); } } } catch ( const json::exception& e ) { Log::error( "DebuggerPlugin::onLoadProject - Error parsing config from path %s, error: %s, config " "file content:\n%s", - debuggerStatePath.c_str(), e.what(), data.c_str() ); + debuggerStatePath, e.what(), data ); } } @@ -246,8 +254,11 @@ void DebuggerPlugin::resetExpressions() { if ( !mExpressionsHolder ) return; mExpressionsHolder->clear( true ); + std::vector childs; + childs.reserve( mExpressions.size() ); for ( const auto& expression : mExpressions ) - mExpressionsHolder->addChild( std::make_shared( expression, 0 ) ); + childs.emplace_back( std::make_shared( expression, 0 ) ); + mExpressionsHolder->addChilds( childs ); } void DebuggerPlugin::closeProject() { @@ -760,8 +771,7 @@ void DebuggerPlugin::removeExpression( const std::string& name ) { resetExpressions(); } -void DebuggerPlugin::openExpressionMenu( UITreeView* uiExpressions, ModelIndex idx, - bool fromMouseClick ) { +void DebuggerPlugin::openExpressionMenu( ModelIndex idx ) { UIPopUpMenu* menu = UIPopUpMenu::New(); auto context = getPluginContext(); @@ -801,19 +811,10 @@ void DebuggerPlugin::openExpressionMenu( UITreeView* uiExpressions, ModelIndex i } } ); - UITableCell* cell = uiExpressions->getCellFromIndex( idx ); - if ( fromMouseClick || cell == nullptr ) { - Vector2f pos( context->getWindow()->getInput()->getMousePos().asFloat() ); - menu->nodeToWorldTranslation( pos ); - UIMenu::findBestMenuPos( pos, menu ); - menu->setPixelsPosition( pos ); - } else { - Vector2f pos( 0, cell->getPixelsSize().getHeight() ); - cell->nodeToWorldTranslation( pos ); - UIMenu::findBestMenuPos( pos, menu ); - menu->setPixelsPosition( pos ); - } - + Vector2f pos( context->getWindow()->getInput()->getMousePos().asFloat() ); + menu->nodeToWorldTranslation( pos ); + UIMenu::findBestMenuPos( pos, menu ); + menu->setPixelsPosition( pos ); menu->show(); } void DebuggerPlugin::buildStatusBar() { @@ -842,9 +843,9 @@ void DebuggerPlugin::buildStatusBar() { UITreeView* uiExpressions = sdc->getUIExpressions(); uiExpressions->setModel( mExpressionsHolder->getModel() ); uiExpressions->removeEventsOfType( Event::OnModelEvent ); - uiExpressions->onModelEvent( [this, uiExpressions]( const ModelEvent* modelEvent ) { + uiExpressions->onModelEvent( [this]( const ModelEvent* modelEvent ) { if ( modelEvent->getModelEventType() == Abstract::ModelEventType::OpenMenu ) { - openExpressionMenu( uiExpressions, modelEvent->getModelIndex(), true ); + openExpressionMenu( modelEvent->getModelIndex() ); } else if ( mDebugger && mListener && modelEvent->getModelEventType() == Abstract::ModelEventType::OpenTree ) { ModelVariableNode* node = @@ -861,11 +862,8 @@ void DebuggerPlugin::buildStatusBar() { } } ); uiExpressions->removeEventsOfType( Event::MouseClick ); - uiExpressions->onClick( - [this, uiExpressions]( const MouseEvent* ) { - openExpressionMenu( uiExpressions, {}, true ); - }, - MouseButton::EE_BUTTON_RIGHT ); + uiExpressions->onClick( [this]( const MouseEvent* ) { openExpressionMenu( {} ); }, + MouseButton::EE_BUTTON_RIGHT ); auto uiBreakpoints = sdc->getUIBreakpoints(); if ( nullptr == uiBreakpoints->onBreakpointEnabledChange ) { @@ -947,8 +945,7 @@ void DebuggerPlugin::sendPendingBreakpoints() { for ( const auto& pbp : mPendingBreakpoints ) sendFileBreakpoints( pbp ); mPendingBreakpoints.clear(); - if ( mDebugger ) - mDebugger->resume( mListener->getCurrentThreadId() ); + resume( mListener->getCurrentThreadId() ); } void DebuggerPlugin::sendFileBreakpoints( const std::string& filePath ) { @@ -1227,7 +1224,7 @@ void DebuggerPlugin::onRegisterDocument( TextDocument* doc ) { doc->setCommand( "debugger-continue-interrupt", [this] { if ( mDebugger && mListener ) { if ( mListener->isStopped() ) { - mDebugger->resume( mListener->getCurrentThreadId() ); + resume( mListener->getCurrentThreadId() ); } else { mDebugger->pause( 1 ); } @@ -1763,6 +1760,18 @@ UIWindow* DebuggerPlugin::processPicker() { return win; } +bool DebuggerPlugin::resume( int threadId, bool singleThread ) { + mHoverExpressionsHolder->clear( true ); + + if ( mHoverTooltip && mHoverTooltip->isVisible() ) + mHoverTooltip->hide(); + + if ( !mDebugger ) + return false; + + return mDebugger->resume( threadId, singleThread ); +} + std::optional DebuggerPlugin::debuggerBinaryExists( const std::string& debugger, std::optional optRunConfig ) { @@ -2025,17 +2034,11 @@ static Action::UniqueID getMouseMoveHash( UICodeEditor* editor ) { reinterpret_cast( editor ) ); } -void DebuggerPlugin::hideTooltip( UICodeEditor* ) { - // if ( mHoverTooltip ) { - // mHoverTooltip->hide(); - // } -} - void DebuggerPlugin::displayTooltip( UICodeEditor* editor, const std::string& expression, const EvaluateInfo& info, const Vector2f& position ) { if ( mHoverTooltip == nullptr ) { - UIWindow* win = - UIWindow::NewOpt( UIMessageBox::WindowBaseContainerType::VERTICAL_LINEAR_LAYOUT ); + UIWindow* win = UIWindow::New(); + win->setId( "debugger_hover_window" ); win->setMinWindowSize( 400, 250 ); win->setKeyBindingCommand( "closeWindow", [this, win, editor] { win->closeWindow(); @@ -2044,20 +2047,26 @@ void DebuggerPlugin::displayTooltip( UICodeEditor* editor, const std::string& ex editor->setFocus(); } ); win->getKeyBindings().addKeybind( { KEY_ESCAPE }, "closeWindow" ); - win->setWindowFlags( UI_WIN_NO_DECORATION | UI_WIN_SHADOW | UI_WIN_EPHEMERAL ); + win->setWindowFlags( UI_WIN_CLOSE_BUTTON | UI_WIN_USE_DEFAULT_BUTTONS_ACTIONS | + UI_WIN_SHADOW | UI_WIN_EPHEMERAL | UI_WIN_RESIZEABLE | + UI_WIN_DRAGABLE_CONTAINER | UI_WIN_SHARE_ALPHA_WITH_CHILDS ); win->center(); win->on( Event::OnWindowClose, [this]( auto ) { mHoverTooltip = nullptr; } ); win->on( Event::OnWindowReady, [win]( auto ) { win->setFocus(); } ); + UILinearLayout* vbox = UILinearLayout::NewVertical(); + vbox->setParent( win->getContainer() ); + vbox->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent ); + UITreeView* tv = UITreeView::New(); + tv->setId( "debugger_hover_treeview" ); tv->setHeadersVisible( false ); - tv->setAutoExpandOnSingleColumn( true ); tv->setAutoColumnsWidth( true ); + tv->setFitAllColumnsToWidget( true ); tv->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::Fixed ); tv->setLayoutWeight( 1 ); - tv->setParent( win->getContainer() ); + tv->setParent( vbox ); tv->setModel( mHoverExpressionsHolder->getModel() ); - tv->expandAll(); tv->setFocusOnSelection( false ); tv->on( Event::OnModelEvent, [this]( const Event* event ) { @@ -2078,6 +2087,10 @@ void DebuggerPlugin::displayTooltip( UICodeEditor* editor, const std::string& ex mHoverTooltip = win; } + if ( editor->getTooltip() ) + editor->getTooltip()->hide(); + + mHoverTooltip->find( "debugger_hover_treeview" )->asType()->clearViewMetadata(); mHoverExpressionsHolder->clear( true ); Variable var; @@ -2098,25 +2111,11 @@ void DebuggerPlugin::displayTooltip( UICodeEditor* editor, const std::string& ex mHoverTooltip->showWhenReady(); } -void DebuggerPlugin::tryHideTooltip( UICodeEditor* editor, const Vector2i& position ) { - if ( ( editor->hasDocument() && editor->getDocument().isLoading() ) || - !mCurrentHover.isValid() || - ( mCurrentHover.isValid() && - !mCurrentHover.contains( editor->resolveScreenPosition( position.asFloat() ) ) ) ) - hideTooltip( editor ); -} - bool DebuggerPlugin::onMouseMove( UICodeEditor* editor, const Vector2i& position, const Uint32& flags ) { if ( !mDebugger || !mListener || !mDebugger->isServerConnected() || - mDebuggingState != StatusDebuggerController::State::Paused ) { - tryHideTooltip( editor, position ); - return false; - } - - if ( flags != 0 ) { - tryHideTooltip( editor, position ); + mDebuggingState != StatusDebuggerController::State::Paused || flags != 0 ) { return false; } @@ -2167,7 +2166,6 @@ bool DebuggerPlugin::onMouseMove( UICodeEditor* editor, const Vector2i& position } ); }, mHoverDelay, getMouseMoveHash( editor ) ); - tryHideTooltip( editor, position ); editor->updateMouseCursor( position.asFloat() ); return true; } diff --git a/src/tools/ecode/plugins/debugger/debuggerplugin.hpp b/src/tools/ecode/plugins/debugger/debuggerplugin.hpp index 861f03088..66943a249 100644 --- a/src/tools/ecode/plugins/debugger/debuggerplugin.hpp +++ b/src/tools/ecode/plugins/debugger/debuggerplugin.hpp @@ -203,13 +203,9 @@ class DebuggerPlugin : public PluginBase { void updatePanelUIState( StatusDebuggerController::State state ); - void hideTooltip( UICodeEditor* editor ); - void displayTooltip( UICodeEditor* editor, const std::string& expression, const EvaluateInfo& info, const Vector2f& position ); - void tryHideTooltip( UICodeEditor* editor, const Vector2i& position ); - bool onMouseMove( UICodeEditor* editor, const Vector2i& position, const Uint32& flags ) override; @@ -217,7 +213,7 @@ class DebuggerPlugin : public PluginBase { void loadProjectConfigurations(); - void openExpressionMenu( UITreeView* uiExpressions, ModelIndex idx, bool fromMouseClick ); + void openExpressionMenu( ModelIndex idx ); void updateSelectedDebugConfig(); @@ -238,6 +234,8 @@ class DebuggerPlugin : public PluginBase { std::unordered_map solvedInputs ); UIWindow* processPicker(); + + bool resume( int threadId, bool singleThread = false ); }; } // namespace ecode diff --git a/src/tools/ecode/plugins/debugger/models/variablesmodel.cpp b/src/tools/ecode/plugins/debugger/models/variablesmodel.cpp index f5836c031..4a3e3f795 100644 --- a/src/tools/ecode/plugins/debugger/models/variablesmodel.cpp +++ b/src/tools/ecode/plugins/debugger/models/variablesmodel.cpp @@ -213,6 +213,15 @@ void VariablesHolder::addChild( ModelVariableNode::NodePtr child ) { mModel->invalidate( Model::UpdateFlag::InvalidateAllIndexes ); } +void VariablesHolder::addChilds( const std::vector& childs ) { + Lock l( mMutex ); + for ( auto& child : childs) { + mRootNode->addChild( child ); + mNodeMap[child->var.variablesReference] = child; + } + mModel->invalidate( Model::UpdateFlag::InvalidateAllIndexes ); +} + void VariablesHolder::upsertRootChild( Variable&& var ) { Lock l( mMutex ); for ( size_t i = 0; i < mRootNode->children.size(); i++ ) { diff --git a/src/tools/ecode/plugins/debugger/models/variablesmodel.hpp b/src/tools/ecode/plugins/debugger/models/variablesmodel.hpp index 70f4137d1..144069f1c 100644 --- a/src/tools/ecode/plugins/debugger/models/variablesmodel.hpp +++ b/src/tools/ecode/plugins/debugger/models/variablesmodel.hpp @@ -131,6 +131,8 @@ class VariablesHolder { void addChild( ModelVariableNode::NodePtr child ); + void addChilds( const std::vector& childs ); + void upsertRootChild( Variable&& ); void clear( bool all = false ); diff --git a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp index 742de12a8..10e4e68d0 100644 --- a/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp +++ b/src/tools/ecode/plugins/debugger/statusdebuggercontroller.cpp @@ -159,8 +159,11 @@ void StatusDebuggerController::createContainer() { #app_debugger_buttons > PushButton:disabled { tint: var(--disabled-color); } + #app_debugger.vertical_bar { + background-color: none; + } - + @@ -176,7 +179,7 @@ void StatusDebuggerController::createContainer() { - +