mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-06-02 11:36:30 +03:00
eepp:
Added Window::flash(). FileSystemModel will not spam invalidations when not needed. UIAbstractTableView and UIAbstractView won't queue more than 1 invalidation per frame when invalidations comes from a non-main thread. ecode: UniversalLocator now understands pasted file paths (with and withouth cursor position) and allows to go to that file and position.
This commit is contained in:
@@ -29,6 +29,12 @@ enum WindowStyle {
|
||||
#endif
|
||||
};
|
||||
|
||||
enum class WindowFlashOperation {
|
||||
Cancel,
|
||||
Briefly,
|
||||
UntilFocused,
|
||||
};
|
||||
|
||||
enum class WindowBackend : Uint32 { SDL2, Default };
|
||||
|
||||
#ifndef EE_SCREEN_KEYBOARD_ENABLED
|
||||
@@ -195,6 +201,9 @@ class EE_API Window {
|
||||
/** This will attempt to raise the window */
|
||||
virtual void raise();
|
||||
|
||||
/** Request a window to demand attention from the user. */
|
||||
virtual void flash( WindowFlashOperation op );
|
||||
|
||||
/** This will attempt to show the window */
|
||||
virtual void show();
|
||||
|
||||
@@ -474,7 +483,7 @@ class EE_API Window {
|
||||
|
||||
/** Shows a native message box.
|
||||
* @return True if message box was shown
|
||||
*/
|
||||
*/
|
||||
virtual bool showMessageBox( const MessageBoxType& type, const std::string& title,
|
||||
const std::string& message );
|
||||
|
||||
|
||||
@@ -1185,6 +1185,7 @@
|
||||
../../src/tools/ecode/plugins/formatter/formatterplugin.hpp
|
||||
../../src/tools/ecode/notificationcenter.cpp
|
||||
../../src/tools/ecode/notificationcenter.hpp
|
||||
../../src/tools/ecode/pathhelper.hpp
|
||||
../../src/tools/ecode/plugins/linter/linterplugin.cpp
|
||||
../../src/tools/ecode/plugins/linter/linterplugin.hpp
|
||||
../../src/tools/ecode/plugins/lsp/lspclientplugin.cpp
|
||||
|
||||
@@ -76,10 +76,14 @@ size_t UIAbstractTableView::getItemCount() const {
|
||||
|
||||
void UIAbstractTableView::onModelUpdate( unsigned flags ) {
|
||||
if ( !Engine::instance()->isMainThread() ) {
|
||||
runOnMainThread( [&, flags] {
|
||||
modelUpdate( flags );
|
||||
createOrUpdateColumns( true );
|
||||
} );
|
||||
static constexpr String::HashType tag = String::hash( "onModelUpdate" );
|
||||
removeActionsByTag( tag );
|
||||
runOnMainThread(
|
||||
[&, flags] {
|
||||
modelUpdate( flags );
|
||||
createOrUpdateColumns( true );
|
||||
},
|
||||
Time::Zero, tag );
|
||||
} else {
|
||||
UIAbstractView::onModelUpdate( flags );
|
||||
createOrUpdateColumns( true );
|
||||
|
||||
@@ -122,7 +122,9 @@ void UIAbstractView::modelUpdate( unsigned flags ) {
|
||||
|
||||
void UIAbstractView::onModelUpdate( unsigned flags ) {
|
||||
if ( !Engine::instance()->isMainThread() ) {
|
||||
runOnMainThread( [&, flags] { modelUpdate( flags ); } );
|
||||
static constexpr String::HashType tag = String::hash( "onModelUpdate" );
|
||||
removeActionsByTag( tag );
|
||||
runOnMainThread( [&, flags] { modelUpdate( flags ); }, Time::Zero, tag );
|
||||
} else {
|
||||
modelUpdate( flags );
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ FileSystemModel::FileSystemModel( const std::string& rootPath, const FileSystemM
|
||||
mDisplayConfig( displayConfig ) {
|
||||
mRoot = std::make_unique<Node>( mRootPath, *this );
|
||||
mInitOK = true;
|
||||
onModelUpdate();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
FileSystemModel::~FileSystemModel() {
|
||||
@@ -317,8 +317,7 @@ FileSystemModel::Node* FileSystemModel::getNodeFromPath( std::string path, bool
|
||||
if ( !folders.empty() ) {
|
||||
for ( size_t i = 0; i < folders.size(); i++ ) {
|
||||
auto& part = folders[i];
|
||||
if ( ( foundNode = curNode->findChildName(
|
||||
part, *this, invalidateTree || i == folders.size() - 1 ) ) ) {
|
||||
if ( ( foundNode = curNode->findChildName( part, *this, invalidateTree ) ) ) {
|
||||
curNode = foundNode;
|
||||
} else {
|
||||
return nullptr;
|
||||
@@ -336,12 +335,12 @@ void FileSystemModel::reload() {
|
||||
void FileSystemModel::refresh() {
|
||||
Lock l( resourceMutex() );
|
||||
mRoot->refresh( *this );
|
||||
onModelUpdate();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void FileSystemModel::update() {
|
||||
mRoot = std::make_unique<Node>( mRootPath, *this );
|
||||
onModelUpdate();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
const FileSystemModel::Node& FileSystemModel::node( const ModelIndex& index ) const {
|
||||
@@ -599,58 +598,58 @@ bool FileSystemModel::handleFileEventLocked( const FileEvent& event ) {
|
||||
: file.getDirectoryPath(),
|
||||
true, false );
|
||||
|
||||
if ( parent ) {
|
||||
auto* childNodeExists =
|
||||
getNodeFromPath( file.getFilepath(), file.isDirectory(), false );
|
||||
if ( childNodeExists )
|
||||
return false;
|
||||
if ( !parent )
|
||||
return false;
|
||||
|
||||
Node* childNode = parent->createChild( file.getFileName(), *this );
|
||||
auto* childNodeExists =
|
||||
getNodeFromPath( file.getFilepath(), file.isDirectory(), false );
|
||||
if ( childNodeExists )
|
||||
return false;
|
||||
|
||||
if ( !childNode->getName().empty() ) {
|
||||
size_t pos = getFileIndex( parent, file );
|
||||
Node* childNode = parent->createChild( file.getFileName(), *this );
|
||||
|
||||
const auto& displayCfg = getDisplayConfig();
|
||||
if ( childNode->getName().empty() )
|
||||
return false;
|
||||
|
||||
if ( displayCfg.fileIsVisibleFn &&
|
||||
!displayCfg.fileIsVisibleFn( file.getFilepath() ) )
|
||||
return false;
|
||||
size_t pos = getFileIndex( parent, file );
|
||||
|
||||
if ( pos == INDEX_ALREADY_EXISTS )
|
||||
return false;
|
||||
const auto& displayCfg = getDisplayConfig();
|
||||
|
||||
beginInsertRows( parent->index( *this, 0 ), pos, pos );
|
||||
if ( displayCfg.fileIsVisibleFn && !displayCfg.fileIsVisibleFn( file.getFilepath() ) )
|
||||
return false;
|
||||
|
||||
if ( pos >= parent->mChildren.size() ) {
|
||||
parent->mChildren.emplace_back( childNode );
|
||||
} else {
|
||||
parent->mChildren.insert( parent->mChildren.begin() + pos, childNode );
|
||||
}
|
||||
if ( pos == INDEX_ALREADY_EXISTS )
|
||||
return false;
|
||||
|
||||
endInsertRows();
|
||||
beginInsertRows( parent->index( *this, 0 ), pos, pos );
|
||||
|
||||
forEachView( [&]( UIAbstractView* view ) {
|
||||
std::vector<ModelIndex> newIndexes;
|
||||
view->getSelection().forEachIndex( [&]( const ModelIndex& selectedIndex ) {
|
||||
Node* curNode = static_cast<Node*>( selectedIndex.internalData() );
|
||||
if ( curNode->getParent() == parent ) {
|
||||
if ( selectedIndex.row() >= (Int64)pos ) {
|
||||
newIndexes.emplace_back( this->index(
|
||||
selectedIndex.row() + 1, selectedIndex.column(),
|
||||
selectedIndex.parent() ) );
|
||||
} else {
|
||||
newIndexes.emplace_back( selectedIndex );
|
||||
}
|
||||
} else {
|
||||
newIndexes.emplace_back( selectedIndex );
|
||||
}
|
||||
} );
|
||||
view->getSelection().set( newIndexes, false );
|
||||
} );
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if ( pos >= parent->mChildren.size() ) {
|
||||
parent->mChildren.emplace_back( childNode );
|
||||
} else {
|
||||
parent->mChildren.insert( parent->mChildren.begin() + pos, childNode );
|
||||
}
|
||||
|
||||
endInsertRows();
|
||||
|
||||
forEachView( [&]( UIAbstractView* view ) {
|
||||
std::vector<ModelIndex> newIndexes;
|
||||
view->getSelection().forEachIndex( [&]( const ModelIndex& selectedIndex ) {
|
||||
Node* curNode = static_cast<Node*>( selectedIndex.internalData() );
|
||||
if ( curNode->getParent() == parent ) {
|
||||
if ( selectedIndex.row() >= (Int64)pos ) {
|
||||
newIndexes.emplace_back( this->index( selectedIndex.row() + 1,
|
||||
selectedIndex.column(),
|
||||
selectedIndex.parent() ) );
|
||||
} else {
|
||||
newIndexes.emplace_back( selectedIndex );
|
||||
}
|
||||
} else {
|
||||
newIndexes.emplace_back( selectedIndex );
|
||||
}
|
||||
} );
|
||||
view->getSelection().set( newIndexes, false );
|
||||
} );
|
||||
|
||||
break;
|
||||
}
|
||||
case FileSystemEventType::Delete: {
|
||||
@@ -710,92 +709,91 @@ bool FileSystemModel::handleFileEventLocked( const FileEvent& event ) {
|
||||
case FileSystemEventType::Moved: {
|
||||
FileInfo file( event.directory + event.filename, false );
|
||||
|
||||
if ( file.exists() ) {
|
||||
auto* node = getNodeFromPath( event.directory + event.oldFilename, false, false );
|
||||
if ( node ) {
|
||||
ModelIndex index = node->index( *this, 0 );
|
||||
if ( !index.isValid() )
|
||||
return false;
|
||||
if ( !file.exists() )
|
||||
return false;
|
||||
|
||||
Node* parent = node->mParent;
|
||||
if ( !parent )
|
||||
return false;
|
||||
|
||||
if ( ( getMode() == Mode::DirectoriesOnly && !file.isDirectory() ) )
|
||||
return false;
|
||||
|
||||
if ( !node->info().isHidden() && getDisplayConfig().ignoreHidden &&
|
||||
file.isHidden() ) {
|
||||
return handleFileEventLocked(
|
||||
{ FileSystemEventType::Delete, event.directory, event.oldFilename } );
|
||||
}
|
||||
|
||||
Node* childNode = parent->mChildren[index.row()];
|
||||
childNode->rename( file );
|
||||
parent->mChildren.erase( parent->mChildren.begin() + index.row() );
|
||||
|
||||
size_t pos = getFileIndex( node->getParent(), file );
|
||||
|
||||
// Don't add the file if already exists (if moved an old file to another old
|
||||
// file)
|
||||
if ( pos == INDEX_ALREADY_EXISTS ) {
|
||||
eeDelete( childNode );
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<UIAbstractView*, std::vector<ModelIndex>> keptSelections;
|
||||
std::map<UIAbstractView*, std::vector<std::string>> prevSelections;
|
||||
std::map<UIAbstractView*, std::vector<ModelIndex>> prevSelectionsModelIndex;
|
||||
|
||||
forEachView( [&]( UIAbstractView* view ) {
|
||||
view->getSelection().forEachIndex( [&]( const ModelIndex& selectedIndex ) {
|
||||
Node* curNode = static_cast<Node*>( selectedIndex.internalData() );
|
||||
if ( curNode->mParent == parent ) {
|
||||
prevSelectionsModelIndex[view].emplace_back( selectedIndex );
|
||||
prevSelections[view].emplace_back(
|
||||
( curNode->getName() == event.oldFilename )
|
||||
? event.filename
|
||||
: curNode->getName() );
|
||||
} else {
|
||||
keptSelections[view].emplace_back( selectedIndex );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
|
||||
beginMoveRows( index.parent(), index.row(), index.row(), index.parent(), pos );
|
||||
|
||||
if ( pos >= parent->mChildren.size() ) {
|
||||
parent->mChildren.emplace_back( childNode );
|
||||
} else {
|
||||
parent->mChildren.insert( parent->mChildren.begin() + pos, childNode );
|
||||
}
|
||||
|
||||
endMoveRows();
|
||||
|
||||
forEachView( [&]( UIAbstractView* view ) {
|
||||
std::vector<std::string> names = prevSelections[view];
|
||||
std::vector<ModelIndex> newIndexes = keptSelections[view];
|
||||
int i = 0;
|
||||
for ( const auto& name : names ) {
|
||||
Int64 row = parent->findChildRowFromName( name, *this );
|
||||
if ( row >= 0 ) {
|
||||
newIndexes.emplace_back(
|
||||
this->index( row, prevSelectionsModelIndex[view][i].column(),
|
||||
prevSelectionsModelIndex[view][i].parent() ) );
|
||||
}
|
||||
++i;
|
||||
}
|
||||
view->getSelection().set( newIndexes, false );
|
||||
} );
|
||||
} else {
|
||||
return handleFileEventLocked(
|
||||
{ FileSystemEventType::Add, event.directory, event.filename } );
|
||||
}
|
||||
auto* node = getNodeFromPath( event.directory + event.oldFilename, false, false );
|
||||
if ( !node ) {
|
||||
return handleFileEventLocked(
|
||||
{ FileSystemEventType::Add, event.directory, event.filename } );
|
||||
}
|
||||
|
||||
ModelIndex index = node->index( *this, 0 );
|
||||
if ( !index.isValid() )
|
||||
return false;
|
||||
|
||||
Node* parent = node->mParent;
|
||||
if ( !parent )
|
||||
return false;
|
||||
|
||||
if ( ( getMode() == Mode::DirectoriesOnly && !file.isDirectory() ) )
|
||||
return false;
|
||||
|
||||
if ( !node->info().isHidden() && getDisplayConfig().ignoreHidden && file.isHidden() ) {
|
||||
return handleFileEventLocked(
|
||||
{ FileSystemEventType::Delete, event.directory, event.oldFilename } );
|
||||
}
|
||||
|
||||
Node* childNode = parent->mChildren[index.row()];
|
||||
childNode->rename( file );
|
||||
parent->mChildren.erase( parent->mChildren.begin() + index.row() );
|
||||
|
||||
size_t pos = getFileIndex( node->getParent(), file );
|
||||
|
||||
// Don't add the file if already exists (if moved an old file to another old
|
||||
// file)
|
||||
if ( pos == INDEX_ALREADY_EXISTS ) {
|
||||
eeDelete( childNode );
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<UIAbstractView*, std::vector<ModelIndex>> keptSelections;
|
||||
std::map<UIAbstractView*, std::vector<std::string>> prevSelections;
|
||||
std::map<UIAbstractView*, std::vector<ModelIndex>> prevSelectionsModelIndex;
|
||||
|
||||
forEachView( [&]( UIAbstractView* view ) {
|
||||
view->getSelection().forEachIndex( [&]( const ModelIndex& selectedIndex ) {
|
||||
Node* curNode = static_cast<Node*>( selectedIndex.internalData() );
|
||||
if ( curNode->mParent == parent ) {
|
||||
prevSelectionsModelIndex[view].emplace_back( selectedIndex );
|
||||
prevSelections[view].emplace_back(
|
||||
( curNode->getName() == event.oldFilename ) ? event.filename
|
||||
: curNode->getName() );
|
||||
} else {
|
||||
keptSelections[view].emplace_back( selectedIndex );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
|
||||
beginMoveRows( index.parent(), index.row(), index.row(), index.parent(), pos );
|
||||
|
||||
if ( pos >= parent->mChildren.size() ) {
|
||||
parent->mChildren.emplace_back( childNode );
|
||||
} else {
|
||||
parent->mChildren.insert( parent->mChildren.begin() + pos, childNode );
|
||||
}
|
||||
|
||||
endMoveRows();
|
||||
|
||||
forEachView( [&]( UIAbstractView* view ) {
|
||||
std::vector<std::string> names = prevSelections[view];
|
||||
std::vector<ModelIndex> newIndexes = keptSelections[view];
|
||||
int i = 0;
|
||||
for ( const auto& name : names ) {
|
||||
Int64 row = parent->findChildRowFromName( name, *this );
|
||||
if ( row >= 0 ) {
|
||||
newIndexes.emplace_back(
|
||||
this->index( row, prevSelectionsModelIndex[view][i].column(),
|
||||
prevSelectionsModelIndex[view][i].parent() ) );
|
||||
}
|
||||
++i;
|
||||
}
|
||||
view->getSelection().set( newIndexes, false );
|
||||
} );
|
||||
break;
|
||||
}
|
||||
case FileSystemEventType::Modified: {
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -814,7 +812,8 @@ bool FileSystemModel::handleFileEvent( const FileEvent& event ) {
|
||||
ret = handleFileEventLocked( event );
|
||||
}
|
||||
|
||||
onModelUpdate( UpdateFlag::DontInvalidateIndexes );
|
||||
if ( ret )
|
||||
invalidate( UpdateFlag::DontInvalidateIndexes );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -785,6 +785,15 @@ void WindowSDL::raise() {
|
||||
SDL_RaiseWindow( mSDLWindow );
|
||||
}
|
||||
|
||||
void WindowSDL::flash( WindowFlashOperation op ) {
|
||||
SDL_FlashOperation sdlOp = SDL_FlashOperation::SDL_FLASH_BRIEFLY;
|
||||
if ( op == WindowFlashOperation::Cancel )
|
||||
sdlOp = SDL_FlashOperation::SDL_FLASH_CANCEL;
|
||||
else if ( op == WindowFlashOperation::UntilFocused )
|
||||
sdlOp = SDL_FlashOperation::SDL_FLASH_UNTIL_FOCUSED;
|
||||
SDL_FlashWindow( mSDLWindow, sdlOp );
|
||||
}
|
||||
|
||||
void WindowSDL::show() {
|
||||
SDL_ShowWindow( mSDLWindow );
|
||||
}
|
||||
|
||||
@@ -67,6 +67,8 @@ class EE_API WindowSDL : public Window {
|
||||
|
||||
virtual void raise();
|
||||
|
||||
virtual void flash( WindowFlashOperation op );
|
||||
|
||||
virtual void show();
|
||||
|
||||
virtual void setPosition( int Left, int Top );
|
||||
|
||||
@@ -517,6 +517,8 @@ void Window::hide() {}
|
||||
|
||||
void Window::raise() {}
|
||||
|
||||
void Window::flash( WindowFlashOperation ) {}
|
||||
|
||||
void Window::show() {}
|
||||
|
||||
void Window::setPosition( int, int ) {}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "ecode.hpp"
|
||||
#include "featureshealth.hpp"
|
||||
#include "pathhelper.hpp"
|
||||
#include "plugins/autocomplete/autocompleteplugin.hpp"
|
||||
#include "plugins/formatter/formatterplugin.hpp"
|
||||
#include "plugins/linter/linterplugin.hpp"
|
||||
@@ -32,48 +33,6 @@ bool firstFrame = true;
|
||||
bool firstUpdate = true;
|
||||
App* appInstance = nullptr;
|
||||
|
||||
static bool pathHasPosition( const std::string& path ) {
|
||||
#if EE_PLATFORM == EE_PLATFORM_WIN
|
||||
bool countedSep = std::count( path.begin(), path.end(), ':' ) > 1;
|
||||
#else
|
||||
bool countedSep = std::count( path.begin(), path.end(), ':' ) > 0;
|
||||
#endif
|
||||
if ( countedSep ) {
|
||||
auto seps = String::split( path, ':' );
|
||||
return String::isNumber( seps.back() );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::pair<std::string, TextPosition> getPathAndPosition( const std::string& path ) {
|
||||
if ( pathHasPosition( path ) ) {
|
||||
auto parts = String::split( path, ':' );
|
||||
if ( parts.size() >= 2 ) {
|
||||
Int64 line = 0;
|
||||
Int64 col = 0;
|
||||
#if EE_PLATFORM == EE_PLATFORM_WIN
|
||||
size_t partCount = 4;
|
||||
#else
|
||||
size_t partCount = 3;
|
||||
#endif
|
||||
int linePos = parts.size() >= partCount ? parts.size() - 2 : parts.size() - 1;
|
||||
int colPos = parts.size() >= partCount ? parts.size() - 1 : -1;
|
||||
if ( String::fromString( line, parts[linePos] ) ) {
|
||||
if ( colPos > 0 )
|
||||
String::fromString( col, parts[colPos] );
|
||||
}
|
||||
std::string npath( parts[0] );
|
||||
if ( parts.size() >= 2 ) {
|
||||
for ( Int64 i = 1; i < linePos; i++ ) {
|
||||
npath += ":" + parts[i];
|
||||
}
|
||||
}
|
||||
return { npath, { eemax( (Int64)0, line - 1 ), col } };
|
||||
}
|
||||
}
|
||||
return { path, { 0, 0 } };
|
||||
}
|
||||
|
||||
void appLoop() {
|
||||
appInstance->mainLoop();
|
||||
}
|
||||
|
||||
56
src/tools/ecode/pathhelper.hpp
Normal file
56
src/tools/ecode/pathhelper.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#ifndef ECODE_PATHHELPER_HPP
|
||||
#define ECODE_PATHHELPER_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <eepp/ui/doc/textposition.hpp>
|
||||
|
||||
using namespace EE;
|
||||
using namespace EE::UI::Doc;
|
||||
|
||||
namespace ecode {
|
||||
|
||||
template <typename T> static bool pathHasPosition( const T& path ) {
|
||||
#if EE_PLATFORM == EE_PLATFORM_WIN
|
||||
bool countedSep = std::count( path.begin(), path.end(), ':' ) > 1;
|
||||
#else
|
||||
bool countedSep = std::count( path.begin(), path.end(), ':' ) > 0;
|
||||
#endif
|
||||
if ( countedSep ) {
|
||||
auto seps = String::split( path, ':' );
|
||||
return String::isNumber( seps.back() );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T> static std::pair<T, TextPosition> getPathAndPosition( const T& path ) {
|
||||
if ( pathHasPosition( path ) ) {
|
||||
auto parts = String::split( path, ':' );
|
||||
if ( parts.size() >= 2 ) {
|
||||
Int64 line = 0;
|
||||
Int64 col = 0;
|
||||
#if EE_PLATFORM == EE_PLATFORM_WIN
|
||||
size_t partCount = 4;
|
||||
#else
|
||||
size_t partCount = 3;
|
||||
#endif
|
||||
int linePos = parts.size() >= partCount ? parts.size() - 2 : parts.size() - 1;
|
||||
int colPos = parts.size() >= partCount ? parts.size() - 1 : -1;
|
||||
if ( String::fromString( line, parts[linePos] ) ) {
|
||||
if ( colPos > 0 )
|
||||
String::fromString( col, parts[colPos] );
|
||||
}
|
||||
std::string npath( parts[0] );
|
||||
if ( parts.size() >= 2 ) {
|
||||
for ( Int64 i = 1; i < linePos; i++ ) {
|
||||
npath += ":" + parts[i];
|
||||
}
|
||||
}
|
||||
return { npath, { eemax( (Int64)0, line - 1 ), col } };
|
||||
}
|
||||
}
|
||||
return { path, { 0, 0 } };
|
||||
}
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
#endif // ECODE_PATHHELPER_HPP
|
||||
@@ -257,6 +257,9 @@ void StatusBuildOutputController::runBuild( const std::string& buildName,
|
||||
if ( cleanButton )
|
||||
cleanButton->setEnabled( true );
|
||||
}
|
||||
|
||||
if ( !mApp->getWindow()->hasFocus() )
|
||||
mApp->getWindow()->flash( WindowFlashOperation::Briefly );
|
||||
} );
|
||||
|
||||
if ( !res.isValid() ) {
|
||||
@@ -344,6 +347,9 @@ void StatusBuildOutputController::runClean( const std::string& buildName,
|
||||
if ( buildButton )
|
||||
buildButton->setEnabled( true );
|
||||
}
|
||||
|
||||
if ( !mApp->getWindow()->hasFocus() )
|
||||
mApp->getWindow()->flash( WindowFlashOperation::Briefly );
|
||||
} );
|
||||
|
||||
if ( !res.isValid() ) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "universallocator.hpp"
|
||||
#include "ecode.hpp"
|
||||
#include "pathhelper.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
namespace ecode {
|
||||
@@ -136,22 +137,28 @@ void UniversalLocator::toggleLocateBar() {
|
||||
}
|
||||
|
||||
void UniversalLocator::updateFilesTable() {
|
||||
auto text = mLocateInput->getText();
|
||||
|
||||
if ( pathHasPosition( text ) ) {
|
||||
auto pathAndPos = getPathAndPosition( text );
|
||||
text = pathAndPos.first;
|
||||
}
|
||||
|
||||
if ( !mApp->isDirTreeReady() ) {
|
||||
mLocateTable->setModel( ProjectDirectoryTree::emptyModel( getLocatorCommands() ) );
|
||||
mLocateTable->getSelection().set( mLocateTable->getModel()->index( 0 ) );
|
||||
} else if ( !mLocateInput->getText().empty() ) {
|
||||
#if EE_PLATFORM != EE_PLATFORM_EMSCRIPTEN || defined( __EMSCRIPTEN_PTHREADS__ )
|
||||
mApp->getDirTree()->asyncFuzzyMatchTree(
|
||||
mLocateInput->getText(), LOCATEBAR_MAX_RESULTS, [&]( auto res ) {
|
||||
mUISceneNode->runOnMainThread( [&, res] {
|
||||
text, LOCATEBAR_MAX_RESULTS, [this, text]( auto res ) {
|
||||
mUISceneNode->runOnMainThread( [this, res] {
|
||||
mLocateTable->setModel( res );
|
||||
mLocateTable->getSelection().set( mLocateTable->getModel()->index( 0 ) );
|
||||
mLocateTable->scrollToTop();
|
||||
} );
|
||||
} );
|
||||
#else
|
||||
mLocateTable->setModel(
|
||||
mApp->getDirTree()->fuzzyMatchTree( mLocateInput->getText(), LOCATEBAR_MAX_RESULTS ) );
|
||||
mLocateTable->setModel( mApp->getDirTree()->fuzzyMatchTree( text, LOCATEBAR_MAX_RESULTS ) );
|
||||
mLocateTable->getSelection().set( mLocateTable->getModel()->index( 0 ) );
|
||||
mLocateTable->scrollToTop();
|
||||
#endif
|
||||
@@ -335,22 +342,13 @@ void UniversalLocator::initLocateBar( UILocateBar* locateBar, UITextInput* locat
|
||||
auto range = rangeStr.isValid()
|
||||
? TextRange::fromString( rangeStr.asStdString() )
|
||||
: TextRange();
|
||||
UITab* tab = mSplitter->isDocumentOpen( path, true );
|
||||
if ( !tab ) {
|
||||
FileInfo fileInfo( path );
|
||||
if ( fileInfo.exists() && fileInfo.isRegularFile() )
|
||||
mApp->loadFileFromPath( path, true, nullptr,
|
||||
[range]( UICodeEditor* editor, auto ) {
|
||||
if ( range.isValid() )
|
||||
editor->goToLine( range.start() );
|
||||
} );
|
||||
} else {
|
||||
tab->getTabWidget()->setTabSelected( tab );
|
||||
if ( range.isValid() ) {
|
||||
UICodeEditor* editor = tab->getOwnedWidget()->asType<UICodeEditor>();
|
||||
editor->goToLine( range.start() );
|
||||
}
|
||||
if ( !range.isValid() && !FileSystem::isRelativePath( path ) &&
|
||||
pathHasPosition( mLocateInput->getText() ) &&
|
||||
String::startsWith( mLocateInput->getText().toUtf8(), path ) ) {
|
||||
auto pathAndPos = getPathAndPosition( mLocateInput->getText() );
|
||||
range = { pathAndPos.second, pathAndPos.second };
|
||||
}
|
||||
focusOrLoadFile( path, range );
|
||||
mLocateBarLayout->execute( "close-locatebar" );
|
||||
} else {
|
||||
Variant rangeStr( modelEvent->getModel()->data(
|
||||
@@ -525,6 +523,24 @@ std::shared_ptr<FileListModel> UniversalLocator::openDocumentsModel( const std::
|
||||
return std::make_shared<FileListModel>( ffiles, fnames );
|
||||
}
|
||||
|
||||
void UniversalLocator::focusOrLoadFile( const std::string& path, const TextRange& range ) {
|
||||
UITab* tab = mSplitter->isDocumentOpen( path, true );
|
||||
if ( !tab ) {
|
||||
FileInfo fileInfo( path );
|
||||
if ( fileInfo.exists() && fileInfo.isRegularFile() )
|
||||
mApp->loadFileFromPath( path, true, nullptr, [range]( UICodeEditor* editor, auto ) {
|
||||
if ( range.isValid() )
|
||||
editor->goToLine( range.start() );
|
||||
} );
|
||||
} else {
|
||||
tab->getTabWidget()->setTabSelected( tab );
|
||||
if ( range.isValid() ) {
|
||||
UICodeEditor* editor = tab->getOwnedWidget()->asType<UICodeEditor>();
|
||||
editor->goToLine( range.start() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UniversalLocator::updateOpenDocumentsTable() {
|
||||
mLocateTable->setModel(
|
||||
openDocumentsModel( mLocateInput->getText().substr( 2 ).trim().toUtf8() ) );
|
||||
|
||||
@@ -86,6 +86,8 @@ class UniversalLocator {
|
||||
void updateOpenDocumentsTable();
|
||||
|
||||
std::shared_ptr<FileListModel> openDocumentsModel( const std::string& match );
|
||||
|
||||
void focusOrLoadFile( const std::string& path, const TextRange& range = {} );
|
||||
};
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
Reference in New Issue
Block a user