* installer of map developer's files (common shaders/textures/w/e is included in gamepack)

This commit is contained in:
Garux 2023-08-18 11:51:02 +06:00
parent 1fb1896f11
commit 39f4bdfab6
4 changed files with 158 additions and 2 deletions

View File

@ -455,6 +455,148 @@ void DoShaderInfoDlg( const char* name, const char* filename, const char* title
qt_MessageBox( MainFrame_getWindow(), text.c_str(), title );
}
// =============================================================================
// Install dev files dialog
#include <QListWidget>
#include <QMessageBox>
#include <QScrollBar>
#include <QTextStream>
void DoInstallDevFilesDlg( const char *enginePath ){
std::vector<std::filesystem::path> files; // relative source files paths
const auto sourceBase = std::filesystem::path( g_pGameDescription->mGameToolsPath.c_str() ) / "install/";
const auto targetBase = std::filesystem::path( enginePath ) / basegame_get();
QString description;
{
std::error_code err;
std::filesystem::recursive_directory_iterator dirIter( sourceBase, err );
if( err ){
globalErrorStream() << err.message().c_str() << ' ' << sourceBase.string().c_str() << '\n';
return;
}
for( const auto& dirEntry : dirIter ) {
if( err ){
globalErrorStream() << err.message().c_str() << '\n';
break;
}
if( dirEntry.is_regular_file( err ) && !err ){
if( dirIter.depth() == 0 && dirEntry.path().filename() == ".description" ){
if( QFile f( QString::fromStdString( dirEntry.path().string() ) ); f.open( QIODevice::ReadOnly | QIODevice::Text ) )
description = QTextStream( &f ).readAll();
}
else{
files.push_back( std::filesystem::relative( dirEntry.path(), sourceBase, err ) );
}
}
}
}
if( !files.empty() ){
QDialog dialog( nullptr, Qt::Window );
dialog.setWindowTitle( "Install Map Developer's Files" );
{
auto *box = new QVBoxLayout( &dialog );
{
auto *label = new QLabel( "Would you like to install following files recommended for fluent map development\nto " + QString::fromStdString( targetBase.string() ) + "?" );
label->setAlignment( Qt::AlignmentFlag::AlignHCenter );
box->addWidget( label );
}
QListWidget *listWidget;
{
listWidget = new QListWidget;
listWidget->setSelectionMode( QAbstractItemView::SelectionMode::NoSelection );
box->addWidget( listWidget, 0 );
for( const auto& file : files ){
listWidget->addItem( QString::fromStdString( file.string() ) );
}
}
if( !description.isEmpty() ){
box->addWidget( new QLabel( ".description" ) );
auto *text = new QPlainTextEdit( description );
text->setSizePolicy( QSizePolicy::Policy::MinimumExpanding, QSizePolicy::Policy::MinimumExpanding );
text->setLineWrapMode( QPlainTextEdit::LineWrapMode::NoWrap );
text->setReadOnly( true );
// set minimal size to fit text to avoid the need to resize window/scroll
const auto rect = text->fontMetrics().boundingRect( QRect(), 0, description );
text->setMinimumSize( rect.width() + text->contentsMargins().left() + text->contentsMargins().right()
+ text->document()->documentMargin() * 2 + text->verticalScrollBar()->sizeHint().width(),
rect.height() + text->contentsMargins().top() + text->contentsMargins().bottom()
+ text->document()->documentMargin() * 2 + text->horizontalScrollBar()->sizeHint().height() );
box->addWidget( text, 0 );
}
const auto doCopy = [&](){
QMessageBox::StandardButton overwrite = QMessageBox::StandardButton::Yes;
size_t copiedN = 0;
for( size_t i = 0; i < files.size(); ++i ){
const auto source = sourceBase / files[i];
const auto target = targetBase / files[i];
std::error_code err;
if( ( std::filesystem::exists( target, err ) || err ) && overwrite != QMessageBox::StandardButton::YesToAll ){
if( overwrite == QMessageBox::StandardButton::NoToAll ) continue;
overwrite = (QMessageBox::StandardButton)QMessageBox( QMessageBox::Icon::Question, "File exists",
QString( "File \"" ) + QString::fromStdString( target.string() ) + "\" exists.\nOverwrite it?",
QMessageBox::StandardButton::Yes |
QMessageBox::StandardButton::YesToAll |
QMessageBox::StandardButton::No |
QMessageBox::StandardButton::NoToAll |
QMessageBox::StandardButton::Abort, &dialog ).exec();
if( overwrite == QMessageBox::StandardButton::Abort ) break;
if( overwrite == QMessageBox::StandardButton::NoToAll || overwrite == QMessageBox::StandardButton::No ) continue;
}
const auto copy_file = [&](){
if( std::filesystem::exists( target, err ) ){
if( !std::filesystem::remove( target, err ) ){
return false;
}
}
else if( err ){
return false;
}
std::filesystem::create_directories( target.parent_path(), err );
if( err )
return false;
// std::filesystem::copy_options::overwrite_existing is broken in libstdc++ on windows, thus using std::filesystem::remove
return std::filesystem::copy_file( source, target, std::filesystem::copy_options::none, err );
};
retry:
if( !copy_file() ){
const auto ret = (QMessageBox::StandardButton)QMessageBox( QMessageBox::Icon::Question, "Fail",
"Failed to write \"" + QString::fromStdString( target.string() ) + "\"\n" + err.message().c_str(),
QMessageBox::StandardButton::Retry |
QMessageBox::StandardButton::Ignore |
QMessageBox::StandardButton::Abort, &dialog ).exec();
if( ret == QMessageBox::StandardButton::Retry ) goto retry;
if( ret == QMessageBox::StandardButton::Ignore ) continue;
if( ret == QMessageBox::StandardButton::Abort ) break;
}
auto *item = listWidget->item( i );
item->setCheckState( Qt::CheckState::Checked );
listWidget->scrollToItem( item );
QCoreApplication::processEvents( QEventLoop::ProcessEventsFlag::ExcludeUserInputEvents );
++copiedN;
}
if( copiedN == files.size() )
qt_MessageBox( &dialog, "All files have been copied.", "Great Success!" );
else if( copiedN != 0 )
qt_MessageBox( &dialog, StringOutputStream( 64 )( copiedN, '/', files.size(), " files have been copied." ), "Moderate Success!" );
else
qt_MessageBox( &dialog, "No files have been copied.", "Boo!" );
dialog.accept();
};
{
auto *buttons = new QDialogButtonBox( QDialogButtonBox::StandardButton::Ok | QDialogButtonBox::StandardButton::Cancel );
box->addWidget( buttons );
QObject::connect( buttons, &QDialogButtonBox::accepted, doCopy );
QObject::connect( buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject );
}
}
dialog.exec();
}
}
// =============================================================================
// Shader Editor

View File

@ -35,6 +35,7 @@
bool DoLightIntensityDlg( int *intensity );
void DoShaderInfoDlg( const char* name, const char* filename, const char* title );
void DoShaderView( const char *shaderFileName, const char *shaderName, bool external_editor );
void DoInstallDevFilesDlg( const char *enginePath );
void Game_constructPreferences( class PreferencesPage& page );

View File

@ -319,6 +319,16 @@ void EnginePath_Unrealise(){
}
}
static CopiedString g_installedDevFilesPath; // track last engine path, where dev files installation occured, to prompt again when changed
static void installDevFiles( const CopiedString& enginePath ){
if( !path_equal( enginePath.c_str(), g_installedDevFilesPath.c_str() ) ){
ASSERT_MESSAGE( g_enginepath_unrealised != 0, "installDevFiles: engine path realised" );
DoInstallDevFilesDlg( enginePath.c_str() );
g_installedDevFilesPath = enginePath;
}
}
void setEnginePath( CopiedString& self, const char* value ){
const auto buffer = StringOutputStream( 256 )( DirectoryCleaned( value ) );
if ( !path_equal( buffer.c_str(), self.c_str() ) ) {
@ -342,6 +352,8 @@ void setEnginePath( CopiedString& self, const char* value ){
self = buffer.c_str();
installDevFiles( self );
EnginePath_Realise();
}
}
@ -469,10 +481,12 @@ static bool g_strEnginePath_was_empty_1st_start = false;
void EnginePath_verify(){
if ( !file_exists( g_strEnginePath.c_str() ) || g_strEnginePath_was_empty_1st_start ) {
g_installedDevFilesPath = ""; // trigger install for non existing engine path case
g_PathsDialog.Create( nullptr );
g_PathsDialog.DoModal();
g_PathsDialog.Destroy();
}
installDevFiles( g_strEnginePath ); // try this anytime, as engine path may be set via command line or -gamedetect
}
namespace
@ -2084,6 +2098,7 @@ void MainFrame_Construct(){
GlobalPreferenceSystem().registerPreference( "ExtraResoucePath", CopiedStringImportStringCaller( g_strExtraResourcePath ), CopiedStringExportStringCaller( g_strExtraResourcePath ) );
GlobalPreferenceSystem().registerPreference( "EnginePath", CopiedStringImportStringCaller( g_strEnginePath ), CopiedStringExportStringCaller( g_strEnginePath ) );
GlobalPreferenceSystem().registerPreference( "InstalledDevFilesPath", CopiedStringImportStringCaller( g_installedDevFilesPath ), CopiedStringExportStringCaller( g_installedDevFilesPath ) );
if ( g_strEnginePath.empty() )
{
g_strEnginePath_was_empty_1st_start = true;

View File

@ -177,10 +177,8 @@ void Radiant_detachEnginePathObserver( ModuleObserver& observer );
void Radiant_attachGameToolsPathObserver( ModuleObserver& observer );
void Radiant_detachGameToolsPathObserver( ModuleObserver& observer );
extern CopiedString g_strEnginePath;
void EnginePath_verify();
const char* EnginePath_get();
const char* QERApp_GetGamePath();
extern CopiedString g_strExtraResourcePath;
const char* ExtraResourcePath_get();