mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-26 16:17:57 +03:00
More fixes. Added debuggers to health tool.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#include "featureshealth.hpp"
|
||||
#include "plugins/debugger/debuggerplugin.hpp"
|
||||
#include "plugins/formatter/formatterplugin.hpp"
|
||||
#include "plugins/linter/linterplugin.hpp"
|
||||
#include "plugins/lsp/lspclientplugin.hpp"
|
||||
@@ -28,6 +29,7 @@ std::vector<FeaturesHealth::LangHealth> FeaturesHealth::getHealth( PluginManager
|
||||
bool ownsLinter = false;
|
||||
bool ownsFormatter = false;
|
||||
bool ownsLSP = false;
|
||||
bool ownsDebugger = false;
|
||||
|
||||
const auto& definitions = SyntaxDefinitionManager::instance()->getDefinitions();
|
||||
|
||||
@@ -38,6 +40,8 @@ std::vector<FeaturesHealth::LangHealth> FeaturesHealth::getHealth( PluginManager
|
||||
|
||||
LSPClientPlugin* lsp = static_cast<LSPClientPlugin*>( pluginManager->get( "lspclient" ) );
|
||||
|
||||
DebuggerPlugin* debugger = static_cast<DebuggerPlugin*>( pluginManager->get( "debugger" ) );
|
||||
|
||||
if ( !linter ) {
|
||||
ownsLinter = true;
|
||||
linter = static_cast<LinterPlugin*>( LinterPlugin::NewSync( pluginManager ) );
|
||||
@@ -52,6 +56,11 @@ std::vector<FeaturesHealth::LangHealth> FeaturesHealth::getHealth( PluginManager
|
||||
lsp = static_cast<LSPClientPlugin*>( LSPClientPlugin::NewSync( pluginManager ) );
|
||||
}
|
||||
|
||||
if ( !debugger ) {
|
||||
ownsDebugger = true;
|
||||
debugger = static_cast<DebuggerPlugin*>( DebuggerPlugin::NewSync( pluginManager ) );
|
||||
}
|
||||
|
||||
for ( const auto& def : definitions ) {
|
||||
if ( !def.isVisible() )
|
||||
continue;
|
||||
@@ -97,6 +106,18 @@ std::vector<FeaturesHealth::LangHealth> FeaturesHealth::getHealth( PluginManager
|
||||
}
|
||||
}
|
||||
|
||||
if ( debugger ) {
|
||||
std::vector<DapTool> found = debugger->getDebuggersForLang( def.getLSPName() );
|
||||
for ( const auto& dbg : found ) {
|
||||
FeatureStatus debugger;
|
||||
debugger.name = dbg.name;
|
||||
debugger.url = dbg.url;
|
||||
debugger.path = Sys::which( dbg.run.command );
|
||||
debugger.found = !debugger.path.empty();
|
||||
lang.debugger.emplace_back( std::move( debugger ) );
|
||||
}
|
||||
}
|
||||
|
||||
langs.emplace_back( std::move( lang ) );
|
||||
}
|
||||
|
||||
@@ -109,6 +130,9 @@ std::vector<FeaturesHealth::LangHealth> FeaturesHealth::getHealth( PluginManager
|
||||
if ( ownsLSP )
|
||||
eeSAFE_DELETE( lsp );
|
||||
|
||||
if ( ownsDebugger )
|
||||
eeSAFE_DELETE( debugger );
|
||||
|
||||
std::sort( langs.begin(), langs.end(), sortKey );
|
||||
|
||||
return langs;
|
||||
@@ -121,9 +145,9 @@ std::string FeaturesHealth::generateHealthStatus( PluginManager* pluginManager,
|
||||
table.format().border_top( "" ).border_bottom( "" ).border_left( "" ).border_right( "" ).corner(
|
||||
"" );
|
||||
|
||||
size_t numRows = 5;
|
||||
size_t numRows = 6;
|
||||
|
||||
table.add_row( { "Language", "Highlight", "LSP", "Linter", "Formatter" } );
|
||||
table.add_row( { "Language", "Highlight", "LSP", "Linter", "Formatter", "Debugger" } );
|
||||
|
||||
for ( size_t i = 0; i < numRows; ++i ) {
|
||||
table[0][i]
|
||||
@@ -155,7 +179,23 @@ std::string FeaturesHealth::generateHealthStatus( PluginManager* pluginManager,
|
||||
formatterName = "[" + ht.formatter.name + "](" + ht.formatter.url + ")";
|
||||
}
|
||||
|
||||
table.add_row( { ht.lang, check, lspName, linterName, formatterName } );
|
||||
std::string debuggerName =
|
||||
ht.debugger.empty()
|
||||
? "None"
|
||||
: std::accumulate( ht.debugger.begin(), ht.debugger.end(), std::string{},
|
||||
[]( const std::string& acc, const FeatureStatus& item ) {
|
||||
return acc.empty() ? item.name : acc + " / " + item.name;
|
||||
} );
|
||||
if ( OutputFormat::Markdown == format && !ht.debugger.empty() ) {
|
||||
debuggerName = std::accumulate(
|
||||
ht.debugger.begin(), ht.debugger.end(), std::string{},
|
||||
[]( const std::string& acc, const FeatureStatus& item ) {
|
||||
return acc.empty() ? "[" + item.name + "](" + item.url + ")"
|
||||
: acc + " / " + "[" + item.name + "](" + item.url + ")";
|
||||
} );
|
||||
}
|
||||
|
||||
table.add_row( { ht.lang, check, lspName, linterName, formatterName, debuggerName } );
|
||||
|
||||
auto& row = table[table.size() - 1];
|
||||
|
||||
@@ -181,6 +221,16 @@ std::string FeaturesHealth::generateHealthStatus( PluginManager* pluginManager,
|
||||
} else {
|
||||
row[4].format().font_color( tabulate::Color::yellow );
|
||||
}
|
||||
|
||||
if ( !ht.debugger.empty() ) {
|
||||
row[5].format().font_color(
|
||||
std::any_of( ht.debugger.begin(), ht.debugger.end(),
|
||||
[]( const FeatureStatus& item ) { return item.found; } )
|
||||
? tabulate::Color::green
|
||||
: tabulate::Color::red );
|
||||
} else {
|
||||
row[5].format().font_color( tabulate::Color::yellow );
|
||||
}
|
||||
}
|
||||
|
||||
if ( OutputFormat::Markdown == format ) {
|
||||
@@ -239,6 +289,21 @@ void FeaturesHealth::doHealth( PluginManager* pluginManager, const std::string&
|
||||
std::cout << "Configured formatter: " << formatterName << "\n\033[00m";
|
||||
if ( !hr.formatter.name.empty() )
|
||||
std::cout << "Binary for formatter: " << formatterBinary << "\n\033[00m";
|
||||
|
||||
if ( !hr.debugger.empty() ) {
|
||||
for ( const auto& dbg : hr.debugger ) {
|
||||
std::string debuggerName =
|
||||
hr.debugger.empty() ? "\033[33mNone" : "\033[32m" + dbg.name;
|
||||
std::string debuggerBinary =
|
||||
dbg.found ? "\033[32m" + dbg.path : "\033[31m" + notFound;
|
||||
|
||||
std::cout << "Configured debugger: " << debuggerName << "\n\033[00m";
|
||||
if ( !dbg.name.empty() )
|
||||
std::cout << "Binary for debugger: " << debuggerBinary << "\n\033[00m";
|
||||
}
|
||||
} else {
|
||||
std::cout << "Configured debugger: " << "\033[31m" + notFound << "\n\033[00m";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,11 +319,11 @@ class HealthModel : public Model {
|
||||
|
||||
virtual size_t rowCount( const ModelIndex& ) const { return mData.size(); }
|
||||
|
||||
virtual size_t columnCount( const ModelIndex& ) const { return 5; }
|
||||
virtual size_t columnCount( const ModelIndex& ) const { return 6; }
|
||||
|
||||
virtual std::string columnName( const size_t& idx ) const {
|
||||
static const std::vector<std::string> columns = { "language", "highlight", "LSP", "linter",
|
||||
"formatter" };
|
||||
static const std::vector<std::string> columns = { "language", "highlight", "LSP",
|
||||
"linter", "formatter", "debugger" };
|
||||
if ( idx < columns.size() )
|
||||
return mSceneNode->i18n( columns[idx], String::capitalize( columns[idx] ) );
|
||||
return "";
|
||||
@@ -297,6 +362,16 @@ class HealthModel : public Model {
|
||||
return Variant( lang.linter.name.empty() ? none : lang.linter.name );
|
||||
case 4:
|
||||
return Variant( lang.formatter.name.empty() ? none : lang.formatter.name );
|
||||
case 5:
|
||||
return Variant(
|
||||
lang.debugger.empty()
|
||||
? none
|
||||
: std::accumulate(
|
||||
lang.debugger.begin(), lang.debugger.end(), std::string{},
|
||||
[]( const std::string& acc,
|
||||
const FeaturesHealth::FeatureStatus& item ) {
|
||||
return acc.empty() ? item.name : acc + " / " + item.name;
|
||||
} ) );
|
||||
default: {
|
||||
}
|
||||
}
|
||||
@@ -324,6 +399,18 @@ class HealthModel : public Model {
|
||||
else
|
||||
return Variant( HEALTH_NONE );
|
||||
break;
|
||||
case 5:
|
||||
if ( !lang.debugger.empty() )
|
||||
return Variant(
|
||||
std::any_of( lang.debugger.begin(), lang.debugger.end(),
|
||||
[]( const FeaturesHealth::FeatureStatus& item ) {
|
||||
return item.found;
|
||||
} )
|
||||
? HEALTH_SUCCESS
|
||||
: HEALTH_ERROR );
|
||||
else
|
||||
return Variant( HEALTH_NONE );
|
||||
break;
|
||||
default: {
|
||||
}
|
||||
}
|
||||
@@ -463,6 +550,25 @@ void FeaturesHealth::displayHealth( PluginManager* pluginManager, UISceneNode* s
|
||||
lang.formatter.path.empty() ? patherr : "" );
|
||||
}
|
||||
|
||||
for ( const auto& debugger : lang.debugger ) {
|
||||
type = debugger.url.empty() ? "TextView"
|
||||
: String::format( "Anchor href='%s'", debugger.url );
|
||||
l += String::format( "<hbox><TextView text='%s: ' /><%s text='%s' class='%s' /></hbox>",
|
||||
I18N( "configured_debugger", "Configured debugger" ), type,
|
||||
debugger.name.empty() ? none : debugger.name,
|
||||
debugger.found ? "success"
|
||||
: ( debugger.name.empty() ? "none" : "error" ) );
|
||||
|
||||
if ( !debugger.name.empty() ) {
|
||||
l += String::format( "<hbox><TextView text='%s: ' /><TextView text='%s' class='%s' "
|
||||
"tooltip='%s' /></hbox>",
|
||||
I18N( "binary_for_debugger", "Binary for debugger" ),
|
||||
debugger.path.empty() ? notFound : debugger.path,
|
||||
!debugger.path.empty() ? "success" : "error",
|
||||
debugger.path.empty() ? patherr : "" );
|
||||
}
|
||||
}
|
||||
|
||||
sceneNode->loadLayoutFromString( l, healthLangInfo );
|
||||
healthLangInfo->setVisible( true );
|
||||
} );
|
||||
|
||||
@@ -38,6 +38,7 @@ class FeaturesHealth {
|
||||
FeatureStatus linter;
|
||||
FeatureStatus formatter;
|
||||
FeatureStatus lsp;
|
||||
std::vector<FeatureStatus> debugger;
|
||||
};
|
||||
|
||||
static std::vector<LangHealth> getHealth( PluginManager* pluginManager,
|
||||
|
||||
@@ -1226,6 +1226,10 @@ bool AutoCompletePlugin::onMouseMove( UICodeEditor* editor, const Vector2i& posi
|
||||
return false;
|
||||
|
||||
Vector2f localPos( editor->convertToNodeSpace( position.asFloat() ) );
|
||||
|
||||
if ( localPos.x <= editor->getGutterWidth() )
|
||||
return false;
|
||||
|
||||
if ( mBoxRect.contains( localPos ) ) {
|
||||
editor->getUISceneNode()->setCursor( Cursor::Hand );
|
||||
return true;
|
||||
|
||||
@@ -156,9 +156,8 @@ void DebuggerClientListener::debuggeeStopped( const StoppedEvent& event ) {
|
||||
mPlugin->setUIDebuggingState( StatusDebuggerController::State::Paused );
|
||||
|
||||
auto sdc = getStatusDebuggerController();
|
||||
if ( sdc ) {
|
||||
if ( sdc )
|
||||
sdc->getWidget()->runOnMainThread( [sdc] { sdc->show(); } );
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerClientListener::debuggeeContinued( const ContinuedEvent& ) {
|
||||
@@ -216,18 +215,19 @@ void DebuggerClientListener::changeScope( const StackFrame& f ) {
|
||||
|
||||
mCurrentScopePos = { f.source->path, f.line };
|
||||
|
||||
if ( getStatusDebuggerController() && getStatusDebuggerController()->getUIStack() )
|
||||
getStatusDebuggerController()->getUIStack()->setSelection( mStackModel->index( f.id ) );
|
||||
auto sdc = getStatusDebuggerController();
|
||||
if ( sdc && sdc->getUIStack() )
|
||||
sdc->getUIStack()->setSelection( mStackModel->index( f.id ) );
|
||||
}
|
||||
|
||||
void DebuggerClientListener::changeThread( int id ) {
|
||||
mCurrentThreadId = id;
|
||||
if ( mThreadsModel )
|
||||
mThreadsModel->setCurrentThreadId( id );
|
||||
if ( getStatusDebuggerController() && getStatusDebuggerController()->getUIThreads() ) {
|
||||
getStatusDebuggerController()->getUIThreads()->setSelection(
|
||||
mThreadsModel->fromThreadId( id ) );
|
||||
}
|
||||
|
||||
auto sdc = getStatusDebuggerController();
|
||||
if ( sdc && sdc->getUIThreads() )
|
||||
sdc->getUIThreads()->setSelection( mThreadsModel->fromThreadId( id ) );
|
||||
}
|
||||
|
||||
void DebuggerClientListener::stackTrace( const int threadId, StackTraceInfo&& stack ) {
|
||||
@@ -270,14 +270,17 @@ void DebuggerClientListener::scopes( const int /*frameId*/, std::vector<Scope>&&
|
||||
mVariablesHolder->clear();
|
||||
|
||||
for ( const auto& scope : scopes ) {
|
||||
if ( !mPlugin->mDisplayRegisters && scope.name == "Registers" )
|
||||
continue;
|
||||
auto child = std::make_shared<ModelVariableNode>( scope.name, scope.variablesReference );
|
||||
mVariablesHolder->addChild( child );
|
||||
mClient->variables( scope.variablesReference );
|
||||
}
|
||||
|
||||
if ( !getStatusDebuggerController() )
|
||||
auto sdc = getStatusDebuggerController();
|
||||
if ( nullptr == sdc )
|
||||
return;
|
||||
auto uiVars = getStatusDebuggerController()->getUIVariables();
|
||||
auto uiVars = sdc->getUIVariables();
|
||||
if ( uiVars ) {
|
||||
uiVars->runOnMainThread( [uiVars] {
|
||||
auto model = uiVars->getModel();
|
||||
@@ -307,6 +310,7 @@ void DebuggerClientListener::breakpointChanged( const BreakpointEvent& ) {}
|
||||
|
||||
void DebuggerClientListener::expressionEvaluated( const std::string& /*expression*/,
|
||||
const std::optional<EvaluateInfo>& ) {}
|
||||
|
||||
void DebuggerClientListener::gotoTargets( const Source& /*source*/, const int /*line*/,
|
||||
const std::vector<GotoTarget>& /*targets*/ ) {}
|
||||
|
||||
|
||||
@@ -205,6 +205,17 @@ void DebuggerPlugin::onLoadProject( const std::string& projectFolder,
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<DapTool> DebuggerPlugin::getDebuggersForLang( const std::string& language ) {
|
||||
std::vector<DapTool> tools;
|
||||
for ( const auto& dap : mDaps ) {
|
||||
auto found = std::find_if( dap.languagesSupported.begin(), dap.languagesSupported.end(),
|
||||
[&language]( const auto& l ) { return l == language; } );
|
||||
if ( found != dap.languagesSupported.end() )
|
||||
tools.push_back( dap );
|
||||
}
|
||||
return tools;
|
||||
}
|
||||
|
||||
void DebuggerPlugin::resetExpressions() {
|
||||
if ( !mExpressionsHolder )
|
||||
return;
|
||||
@@ -306,6 +317,14 @@ void DebuggerPlugin::loadDAPConfig( const std::string& path, bool updateConfigFi
|
||||
true, true );
|
||||
}
|
||||
|
||||
if ( j.contains( "config" ) ) {
|
||||
auto& config = j["config"];
|
||||
if ( config.contains( "display_registers" ) )
|
||||
mDisplayRegisters = config.value( "display_registers", false );
|
||||
else if ( updateConfigFile )
|
||||
config["display_registers"] = mDisplayRegisters;
|
||||
}
|
||||
|
||||
if ( j.contains( "dap" ) ) {
|
||||
auto& dapArr = j["dap"];
|
||||
mDaps.reserve( dapArr.size() );
|
||||
@@ -577,7 +596,7 @@ void DebuggerPlugin::buildSidePanelTab() {
|
||||
<DropDownList id="debugger_list" layout_width="mp" layout_height="wrap_content" margin-top="2dp" />
|
||||
<TextView text="@string(debugger_configuration, Debugger Configuration)" focusable="false" margin-top="8dp" />
|
||||
<DropDownList id="debugger_conf_list" layout_width="mp" layout_height="wrap_content" margin-top="2dp" />
|
||||
<PushButton id="debugger_run_button" lw="mp" lh="wc" text="@string(run, Run)" margin-top="8dp" icon="icon(play, 12dp)" />
|
||||
<PushButton id="debugger_run_button" lw="mp" lh="wc" text="@string(run, Run)" margin-top="8dp" icon="icon(debug-alt, 12dp)" />
|
||||
<hbox id="panel_debugger_buttons" lw="wc" lh="wc" layout_gravity="center_horizontal" visible="false" clip="none" margin-top="8dp">
|
||||
<PushButton id="panel_debugger_continue" class="debugger_continue" lw="24dp" lh="24dp" icon="icon(debug-continue, 12dp)" tooltip="@string(continue, Continue)" />
|
||||
<PushButton id="panel_debugger_pause" class="debugger_pause" lw="24dp" lh="24dp" icon="icon(debug-pause, 12dp)" tooltip="@string(pause, Pause)" />
|
||||
@@ -1337,8 +1356,6 @@ void DebuggerPlugin::runConfig( const std::string& debugger, const std::string&
|
||||
|
||||
std::string fallbackCommand = debuggerIt->fallbackCommand;
|
||||
|
||||
mRunButton->setEnabled( false );
|
||||
|
||||
mThreadPool->run(
|
||||
[this, protocolSettings = std::move( protocolSettings ),
|
||||
runSettings = std::move( runConfig ), findBinary = std::move( findBinary ),
|
||||
@@ -1517,7 +1534,7 @@ void DebuggerPlugin::updatePanelUIState( StatusDebuggerController::State state )
|
||||
mPanelBoxButtons.stepOut->setVisible( isDebugging )
|
||||
->setEnabled( state == StatusDebuggerController::State::Paused );
|
||||
|
||||
mRunButton->setText( isDebugging ? i18n( "Stop Debugging", "Stop Debugging" )
|
||||
mRunButton->setText( isDebugging ? i18n( "Stop Debugger", "Stop Debugger" )
|
||||
: i18n( "debug", "Debug" ) );
|
||||
}
|
||||
|
||||
@@ -1629,6 +1646,10 @@ bool DebuggerPlugin::onMouseMove( UICodeEditor* editor, const Vector2i& position
|
||||
return false;
|
||||
}
|
||||
|
||||
auto localPos( editor->convertToNodeSpace( position.asFloat() ) );
|
||||
if ( localPos.x <= editor->getGutterWidth() )
|
||||
return false;
|
||||
|
||||
editor->debounce(
|
||||
[this, editor, position]() {
|
||||
if ( !mManager->getSplitter()->editorExists( editor ) )
|
||||
@@ -1637,7 +1658,8 @@ bool DebuggerPlugin::onMouseMove( UICodeEditor* editor, const Vector2i& position
|
||||
auto range = editor->getDocument().getWordRangeInPosition( docPos, true );
|
||||
auto expression = editor->getDocument().getWordInPosition( docPos, true ).toUtf8();
|
||||
|
||||
if ( !range.isValid() || expression.empty() )
|
||||
if ( !range.isValid() || expression.empty() ||
|
||||
LuaPattern::hasMatches( expression, "^[%p%s]+$" ) )
|
||||
return;
|
||||
|
||||
mCurrentHover = range;
|
||||
@@ -1667,6 +1689,7 @@ bool DebuggerPlugin::onMouseMove( UICodeEditor* editor, const Vector2i& position
|
||||
},
|
||||
mHoverDelay, getMouseMoveHash( editor ) );
|
||||
tryHideTooltip( editor, position );
|
||||
editor->updateMouseCursor( position.asFloat() );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,10 +62,13 @@ class DebuggerPlugin : public PluginBase {
|
||||
void onLoadProject( const std::string& projectFolder,
|
||||
const std::string& projectStatePath ) override;
|
||||
|
||||
std::vector<DapTool> getDebuggersForLang( const std::string& lang );
|
||||
|
||||
protected:
|
||||
friend class DebuggerClientListener;
|
||||
|
||||
bool mInitialized{ false };
|
||||
bool mDisplayRegisters{ false };
|
||||
std::string mProjectPath;
|
||||
|
||||
std::vector<DapTool> mDaps;
|
||||
|
||||
@@ -182,10 +182,12 @@ void VariablesHolder::addVariables( const int variablesReference, std::vector<Va
|
||||
|
||||
auto found = parentNode->getChild( var.name );
|
||||
if ( found ) {
|
||||
( *found )->var = std::move( var );
|
||||
ModelVariableNode::NodePtr child = *found;
|
||||
child->var = std::move( var );
|
||||
|
||||
if ( child->var.variablesReference != 0 )
|
||||
nodeMap[child->var.variablesReference] = *found;
|
||||
|
||||
if ( ( *found )->var.variablesReference != 0 )
|
||||
nodeMap[( *found )->var.variablesReference] = *found;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "../../stringhelper.hpp"
|
||||
#include "linterplugin.hpp"
|
||||
#include "linterplugin.hpp"
|
||||
#include "../../stringhelper.hpp"
|
||||
#include <algorithm>
|
||||
#include <eepp/graphics/primitives.hpp>
|
||||
#include <eepp/graphics/text.hpp>
|
||||
@@ -1295,11 +1295,15 @@ bool LinterPlugin::onMouseMove( UICodeEditor* editor, const Vector2i& pos, const
|
||||
tryHideHoveringMatch( editor );
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector2f localPos( editor->convertToNodeSpace( pos.asFloat() ) );
|
||||
TextPosition cursorPosition = editor->resolveScreenPosition( pos.asFloat() );
|
||||
if ( localPos.x <= editor->getGutterWidth() )
|
||||
return false;
|
||||
|
||||
Lock l( mMatchesMutex );
|
||||
auto it = mMatches.find( editor->getDocumentRef().get() );
|
||||
if ( it != mMatches.end() ) {
|
||||
Vector2f localPos( editor->convertToNodeSpace( pos.asFloat() ) );
|
||||
TextPosition cursorPosition = editor->resolveScreenPosition( pos.asFloat() );
|
||||
auto matchIt = it->second.find( cursorPosition.line() );
|
||||
if ( matchIt != it->second.end() ) {
|
||||
auto& matches = matchIt->second;
|
||||
|
||||
@@ -1830,8 +1830,11 @@ void LSPClientPlugin::tryDisplayTooltip( UICodeEditor* editor, const LSPHover& r
|
||||
|
||||
bool LSPClientPlugin::onMouseMove( UICodeEditor* editor, const Vector2i& position,
|
||||
const Uint32& flags ) {
|
||||
auto localPos( editor->convertToNodeSpace( position.asFloat() ) );
|
||||
if ( localPos.x <= editor->getGutterWidth() )
|
||||
return false;
|
||||
|
||||
if ( mBreadcrumb ) {
|
||||
auto localPos( editor->convertToNodeSpace( position.asFloat() ) );
|
||||
if ( localPos.y < mPluginTopSpace && localPos.x < editor->getTopAreaWidth() &&
|
||||
localPos.x >= 0 ) {
|
||||
if ( !mHoveringBreadcrumb ) {
|
||||
|
||||
Reference in New Issue
Block a user