diff --git a/.ecode/project_build.json b/.ecode/project_build.json index 0417c4d53..11992a159 100644 --- a/.ecode/project_build.json +++ b/.ecode/project_build.json @@ -70,6 +70,20 @@ "relative_file_paths": true } }, + "run": [ + { + "args": "-x", + "command": "${project_root}/bin/ecode-debug", + "name": "ecode-debug", + "working_dir": "${project_root}/bin/" + }, + { + "args": "-x", + "command": "${project_root}/bin/ecode", + "name": "ecode-release", + "working_dir": "${project_root}/bin/" + } + ], "var": { "build_dir": "${project_root}/projects/${os}" } @@ -150,7 +164,14 @@ { "args": "-x", "command": "ecode-debug", - "working_dir": "${project_root}/bin/" + "name": "ecode-debug", + "working_dir": "${project_root}/bin" + }, + { + "args": "-x", + "command": "ecode", + "name": "ecode-release", + "working_dir": "${project_root}/bin" } ], "var": { @@ -188,6 +209,20 @@ "relative_file_paths": true } }, + "run": [ + { + "args": "-x", + "command": "${project_root}/bin/ecode-debug", + "name": "ecode-debug", + "working_dir": "${project_root}/bin/" + }, + { + "args": "-x", + "command": "${project_root}/bin/ecode", + "name": "ecode-release", + "working_dir": "${project_root}/bin/" + } + ], "var": { "build_dir": "${project_root}/projects/${os}" } diff --git a/src/eepp/ui/uidropdownlist.cpp b/src/eepp/ui/uidropdownlist.cpp index 6dbec8c03..ca546f126 100644 --- a/src/eepp/ui/uidropdownlist.cpp +++ b/src/eepp/ui/uidropdownlist.cpp @@ -239,6 +239,7 @@ void UIDropDownList::setStyleConfig( const StyleConfig& styleConfig ) { void UIDropDownList::onWidgetClear( const Event* ) { setText( "" ); + sendCommonEvent( Event::OnClear ); } void UIDropDownList::onItemKeyDown( const Event* Event ) { diff --git a/src/eepp/ui/uilistbox.cpp b/src/eepp/ui/uilistbox.cpp index 7511efb11..829c60c40 100644 --- a/src/eepp/ui/uilistbox.cpp +++ b/src/eepp/ui/uilistbox.cpp @@ -214,6 +214,9 @@ void UIListBox::removeListBoxItems( std::vector ItemsIndex ) { if ( selectedSize != mSelected.size() ) sendCommonEvent( Event::OnSelectionChanged ); + + if ( mTexts.empty() ) + sendCommonEvent( Event::OnClear ); } void UIListBox::clear() { @@ -231,7 +234,7 @@ void UIListBox::clear() { } Uint32 UIListBox::removeListBoxItem( Uint32 ItemIndex ) { - removeListBoxItems( std::vector( 1, ItemIndex ) ); + removeListBoxItems( { ItemIndex } ); return ItemIndex; } diff --git a/src/tools/ecode/appconfig.cpp b/src/tools/ecode/appconfig.cpp index 9009c1084..b0f3e8145 100644 --- a/src/tools/ecode/appconfig.cpp +++ b/src/tools/ecode/appconfig.cpp @@ -395,6 +395,7 @@ void AppConfig::saveProject( std::string projectFolder, UICodeEditorSplitter* ed cfg.setValueI( "document", "line_breaking_column", docConfig.doc.lineBreakingColumn ); cfg.setValue( "build", "build_name", buildConfig.buildName ); cfg.setValue( "build", "build_type", buildConfig.buildType ); + cfg.setValue( "build", "run_name", buildConfig.runName ); cfg.setValue( "nodes", "documents", saveNode( editorSplitter->getBaseLayout()->getFirstChild() ).dump() ); cfg.deleteKey( "files" ); @@ -540,6 +541,7 @@ void AppConfig::loadProject( std::string projectFolder, UICodeEditorSplitter* ed ProjectBuildConfiguration prjCfg; prjCfg.buildName = cfg.getValue( "build", "build_name", "" ); prjCfg.buildType = cfg.getValue( "build", "build_type", "" ); + prjCfg.runName = cfg.getValue( "build", "run_name", "" ); app->getProjectBuildManager()->setConfig( prjCfg ); } diff --git a/src/tools/ecode/appconfig.hpp b/src/tools/ecode/appconfig.hpp index 49a1adf9c..690829fee 100644 --- a/src/tools/ecode/appconfig.hpp +++ b/src/tools/ecode/appconfig.hpp @@ -118,6 +118,7 @@ struct ProjectBuildConfiguration { ProjectBuildConfiguration() {} std::string buildName; std::string buildType; + std::string runName; }; class NewTerminalOrientation { diff --git a/src/tools/ecode/applayout.xml.hpp b/src/tools/ecode/applayout.xml.hpp index 9115197b5..432a67f94 100644 --- a/src/tools/ecode/applayout.xml.hpp +++ b/src/tools/ecode/applayout.xml.hpp @@ -317,6 +317,9 @@ TableView#locate_bar_table > tableview::row:selected > tableview::cell:nth-child .settings_panel .buttons_box > * { margin-bottom: 4dp; } +.settings_panel .stack_margins > * { + margin-right:4dp; +} .settings_panel TableView { margin-top: 4dp; } diff --git a/src/tools/ecode/iconmanager.cpp b/src/tools/ecode/iconmanager.cpp index 7048b2a28..19832bc7b 100644 --- a/src/tools/ecode/iconmanager.cpp +++ b/src/tools/ecode/iconmanager.cpp @@ -241,6 +241,7 @@ void IconManager::init( UISceneNode* sceneNode, FontTrueType* iconFont, FontTrue { "extensions", 0xeae6 }, { "window-opt", 0xeb7f }, { "tools", 0xeb6d }, + { "play", 0xeb2c }, }; for ( const auto& icon : codIcons ) diff --git a/src/tools/ecode/projectbuild.cpp b/src/tools/ecode/projectbuild.cpp index f4f459efb..457822773 100644 --- a/src/tools/ecode/projectbuild.cpp +++ b/src/tools/ecode/projectbuild.cpp @@ -92,13 +92,12 @@ json ProjectBuild::serialize( const ProjectBuild::Map& builds ) { jclean.push_back( step ); } - // TODO: Support multiple-runs if ( curBuild.hasRun() ) { bj["run"] = json::array(); auto& jrun = bj["run"]; - { - const auto& run = curBuild.mRun; + for ( auto& run : curBuild.mRun ) { json step; + step["name"] = run.name; step["working_dir"] = run.workingDir; step["args"] = run.args; step["command"] = run.cmd; @@ -519,12 +518,13 @@ ProjectBuild::Map ProjectBuild::deserialize( const json& j, const std::string& p const auto& runArray = buildObj["run"]; for ( const auto& step : runArray ) { ProjectBuildStep rstep; + rstep.name = step.value( "name", "" ); rstep.cmd = step.value( "command", "" ); rstep.args = step.value( "args", "" ); rstep.workingDir = step.value( "working_dir", "" ); rstep.enabled = step.value( "enabled", true ); rstep.runInTerminal = step.value( "run_in_terminal", false ); - b.mRun = std::move( rstep ); + b.mRun.emplace_back( std::move( rstep ) ); } } @@ -686,25 +686,20 @@ ProjectBuildConfiguration ProjectBuildManager::getConfig() const { } void ProjectBuildManager::setConfig( const ProjectBuildConfiguration& config ) { - bool buildNameChanged = false; - bool buildTypeChanged = false; - if ( mConfig.buildName != config.buildName ) { mConfig.buildName = config.buildName; - buildNameChanged = true; updateSidePanelTab(); } if ( mConfig.buildType != config.buildType ) { mConfig.buildType = config.buildType; - buildTypeChanged = true; updateBuildType(); } - if ( buildNameChanged ) - updateSidePanelTab(); - else if ( buildTypeChanged ) - updateBuildType(); + if ( mConfig.runName != config.runName ) { + mConfig.runName = config.runName; + updateRunConfig(); + } } void ProjectBuildManager::buildCurrentConfig( StatusBuildOutputController* sboc ) { @@ -736,18 +731,30 @@ void ProjectBuildManager::cleanCurrentConfig( StatusBuildOutputController* sboc } void ProjectBuildManager::runCurrentConfig( StatusBuildOutputController* /* not used yet */ ) { - if ( !isBuilding() && !getBuilds().empty() ) { + if ( !mRunning && !isBuilding() && !getBuilds().empty() ) { + BoolScopedOp op( mRunning, true ); const ProjectBuild* build = nullptr; for ( const auto& buildIt : getBuilds() ) if ( buildIt.second.getName() == mConfig.buildName ) build = &buildIt.second; if ( build && build->hasRun() ) { - auto finalBuild( build->replaceVars( build->mRun ) ); + const ProjectBuildStep* run = nullptr; + for ( const auto& crun : build->mRun ) { + if ( crun.name == mConfig.runName || mConfig.runName.empty() ) { + run = &crun; + break; + } + } + + if ( nullptr == run ) + return; + + auto finalBuild( build->replaceVars( *run ) ); auto cmd = finalBuild.cmd + " " + finalBuild.args; if ( finalBuild.runInTerminal ) { - UITerminal* term = - mApp->getTerminalManager()->createTerminalInSplitter( finalBuild.workingDir ); + UITerminal* term = mApp->getTerminalManager()->createTerminalInSplitter( + finalBuild.workingDir, false ); if ( term == nullptr || term->getTerm() == nullptr ) { mApp->getTerminalManager()->openInExternalTerminal( cmd ); } else { @@ -920,17 +927,20 @@ void ProjectBuildManager::buildSidePanelTab() { R"html( - - + + - - + + + + + )html" ); @@ -958,6 +968,7 @@ void ProjectBuildManager::updateSidePanelTab() { UIDropDownList* buildList = buildTab->find( "build_list" ); UIPushButton* buildButton = buildTab->find( "build_button" ); UIPushButton* cleanButton = buildTab->find( "clean_button" ); + UIPushButton* runButton = buildTab->find( "run_button" ); UIPushButton* buildAdd = buildTab->find( "build_add" ); UIPushButton* buildEdit = buildTab->find( "build_edit" ); @@ -988,12 +999,16 @@ void ProjectBuildManager::updateSidePanelTab() { updateBuildType(); + updateRunConfig(); + if ( !buildList->hasEventsOfType( Event::OnItemSelected ) ) { buildList->on( Event::OnItemSelected, [this, buildEdit, buildList]( const Event* ) { mConfig.buildName = buildList->getListBox()->getItemSelectedText(); mConfig.buildType = ""; + mConfig.runName = ""; buildEdit->setEnabled( true ); updateBuildType(); + updateRunConfig(); } ); } @@ -1023,6 +1038,11 @@ void ProjectBuildManager::updateSidePanelTab() { } ); } + if ( !runButton->hasEventsOfType( Event::MouseClick ) ) { + runButton->onClick( + [this]( auto ) { runCurrentConfig( mApp->getStatusBuildOutputController() ); } ); + } + if ( !buildAdd->hasEventsOfType( Event::MouseClick ) ) { buildAdd->onClick( [this, buildTab]( auto ) { addBuild( buildTab ); } ); } @@ -1064,10 +1084,65 @@ void ProjectBuildManager::updateBuildType() { } buildTypeList->setEnabled( !buildTypeList->getListBox()->isEmpty() ); - if ( !buildTypeList->hasEventsOfType( Event::OnItemSelected ) ) + if ( !buildTypeList->hasEventsOfType( Event::OnItemSelected ) ) { buildTypeList->on( Event::OnItemSelected, [this, buildTypeList]( const Event* ) { mConfig.buildType = buildTypeList->getListBox()->getItemSelectedText(); } ); + } +} + +void ProjectBuildManager::updateRunConfig() { + if ( mTab == nullptr ) + return; + UIWidget* buildTab = mTab->getOwnedWidget()->find( "build_tab_view" ); + if ( buildTab == nullptr ) + return; + UIDropDownList* buildList = buildTab->find( "build_list" ); + UIDropDownList* runConfigList = buildTab->find( "run_config_list" ); + + runConfigList->getListBox()->clear(); + + String first = buildList->getListBox()->getItemSelectedText(); + if ( !first.empty() ) { + auto foundIt = mBuilds.find( first ); + if ( foundIt != mBuilds.end() ) { + const auto& runConfigs = foundIt->second.runConfigs(); + std::vector items; + size_t i = 1; + for ( const auto& run : runConfigs ) { + auto name = run.name.empty() ? String::format( mApp->i18n( "custom_executable_num", + "Custom Executable %d" ) + .toUtf8(), + i ) + : run.name; + items.emplace_back( name ); + i++; + } + runConfigList->getListBox()->addListBoxItems( items ); + if ( runConfigList->getListBox()->getItemIndex( mConfig.runName ) != + eeINDEX_NOT_FOUND ) { + runConfigList->getListBox()->setSelected( mConfig.runName ); + } else if ( !runConfigList->getListBox()->isEmpty() ) { + runConfigList->getListBox()->setSelected( 0 ); + mConfig.runName = runConfigList->getListBox()->getItemSelectedText(); + } + } + } + runConfigList->setEnabled( !runConfigList->getListBox()->isEmpty() ); + buildTab->find( "run_button" )->setEnabled( !runConfigList->getListBox()->isEmpty() ); + + if ( !runConfigList->hasEventsOfType( Event::OnItemSelected ) ) { + runConfigList->on( Event::OnItemSelected, [this, runConfigList, buildTab]( const Event* ) { + mConfig.runName = runConfigList->getListBox()->getItemSelectedText(); + buildTab->find( "run_button" )->setEnabled( !runConfigList->getListBox()->isEmpty() ); + } ); + } + if ( !runConfigList->hasEventsOfType( Event::OnClear ) ) { + runConfigList->on( Event::OnClear, [this, runConfigList, buildTab]( const Event* ) { + mConfig.runName = ""; + buildTab->find( "run_button" )->setEnabled( !runConfigList->getListBox()->isEmpty() ); + } ); + } } std::map ProjectBuildOutputParser::getPresets() { diff --git a/src/tools/ecode/projectbuild.hpp b/src/tools/ecode/projectbuild.hpp index a17132626..c3cf6e86b 100644 --- a/src/tools/ecode/projectbuild.hpp +++ b/src/tools/ecode/projectbuild.hpp @@ -82,6 +82,7 @@ struct ProjectBuildStep { std::string cmd; std::string args; std::string workingDir; + std::string name; bool enabled{ true }; bool runInTerminal{ false }; }; @@ -172,7 +173,7 @@ class ProjectBuild { const ProjectBuildSteps& cleanSteps() const { return mClean; } - const ProjectBuildStep& runStep() const { return mRun; } + const ProjectBuildSteps& runConfigs() const { return mRun; } const ProjectBuildKeyVal& envs() const { return mEnvs; } @@ -183,7 +184,8 @@ class ProjectBuild { bool hasClean() const { return !mClean.empty(); } bool hasRun() const { - return !mRun.cmd.empty() || !mRun.args.empty() || !mRun.workingDir.empty(); + return !mRun.empty() && ( !mRun.front().cmd.empty() || !mRun.front().args.empty() || + !mRun.front().workingDir.empty() ); } ProjectBuildStep replaceVars( const ProjectBuildStep& step ) const; @@ -204,7 +206,7 @@ class ProjectBuild { std::set mBuildTypes; ProjectBuildSteps mBuild; ProjectBuildSteps mClean; - ProjectBuildStep mRun; + ProjectBuildSteps mRun; ProjectBuildKeyVal mEnvs; ProjectBuildKeyVal mVars; ProjectBuildConfig mConfig; @@ -317,6 +319,7 @@ class ProjectBuildManager { bool mBuilding{ false }; bool mShuttingDown{ false }; bool mCancelBuild{ false }; + bool mRunning{ false }; std::unordered_map> mCbs; void runBuild( const std::string& buildName, const std::string& buildType, @@ -336,6 +339,8 @@ class ProjectBuildManager { void updateBuildType(); + void updateRunConfig(); + void addNewBuild(); bool cloneBuild( const std::string& build, std::string newBuildName ); diff --git a/src/tools/ecode/terminalmanager.cpp b/src/tools/ecode/terminalmanager.cpp index 33b9528c8..8ca3768ed 100644 --- a/src/tools/ecode/terminalmanager.cpp +++ b/src/tools/ecode/terminalmanager.cpp @@ -6,7 +6,8 @@ namespace ecode { TerminalManager::TerminalManager( App* app ) : mApp( app ) {} -UITerminal* TerminalManager::createTerminalInSplitter( const std::string& workingDir ) { +UITerminal* TerminalManager::createTerminalInSplitter( const std::string& workingDir, + bool fallback ) { UITerminal* term = nullptr; auto splitter = mApp->getSplitter(); auto& config = mApp->getConfig(); @@ -15,34 +16,36 @@ UITerminal* TerminalManager::createTerminalInSplitter( const std::string& workin UIOrientation orientation = splitter->getMainSplitOrientation(); if ( config.term.newTerminalOrientation == NewTerminalOrientation::Vertical && orientation == UIOrientation::Horizontal ) { - term = createNewTerminal( "", splitter->getTabWidgets()[1], workingDir ); + term = createNewTerminal( "", splitter->getTabWidgets()[1], workingDir, "", {}, + fallback ); } else if ( config.term.newTerminalOrientation == NewTerminalOrientation::Horizontal && orientation == UIOrientation::Vertical ) { - term = createNewTerminal( "", splitter->getTabWidgets()[1], workingDir ); + term = createNewTerminal( "", splitter->getTabWidgets()[1], workingDir, "", {}, + fallback ); } else { term = createNewTerminal( "", nullptr, workingDir ); } } else { term = createNewTerminal(); } - } else { + } else if ( splitter ) { switch ( config.term.newTerminalOrientation ) { case NewTerminalOrientation::Vertical: { auto cwd = workingDir.empty() ? mApp->getCurrentWorkingDir() : workingDir; splitter->split( UICodeEditorSplitter::SplitDirection::Right, splitter->getCurWidget(), false ); - term = createNewTerminal( "", nullptr, cwd ); + term = createNewTerminal( "", nullptr, cwd, "", {}, fallback ); break; } case NewTerminalOrientation::Horizontal: { auto cwd = workingDir.empty() ? mApp->getCurrentWorkingDir() : workingDir; splitter->split( UICodeEditorSplitter::SplitDirection::Bottom, splitter->getCurWidget(), false ); - term = createNewTerminal( "", nullptr, cwd ); + term = createNewTerminal( "", nullptr, cwd, "", {}, fallback ); break; } case NewTerminalOrientation::Same: { - term = createNewTerminal(); + term = createNewTerminal( "", nullptr, "", "", {}, fallback ); break; } } @@ -283,8 +286,8 @@ static void openExternal( const std::string& defShell, const std::string& cmd = std::vector options; if ( !defShell.empty() ) options.push_back( defShell ); - options.push_back( "powershell" ); options.push_back( "cmd" ); + options.push_back( "powershell" ); #else static void openExternal( const std::string&, const std::string& cmd = "" ) { std::vector options = { "gnome-terminal", "konsole", "xterm", "st" }; @@ -294,7 +297,7 @@ static void openExternal( const std::string&, const std::string& cmd = "" ) { if ( !externalShell.empty() ) { if ( !cmd.empty() ) { #if EE_PLATFORM == EE_PLATFORM_WIN - auto fcmd = externalShell + " /c " + cmd; + auto fcmd = externalShell + " /q /c " + cmd; #else auto fcmd = externalShell + " -e " + cmd; #endif @@ -343,7 +346,8 @@ void TerminalManager::displayError() { UITerminal* TerminalManager::createNewTerminal( const std::string& title, UITabWidget* inTabWidget, const std::string& workingDir, std::string program, - const std::vector& args ) { + const std::vector& args, + bool fallback ) { #if EE_PLATFORM == EE_PLATFORM_EMSCRIPTEN UIMessageBox* msgBox = UIMessageBox::New( UIMessageBox::OK, @@ -390,7 +394,8 @@ UITerminal* TerminalManager::createNewTerminal( const std::string& title, UITabW mApp->termConfig().scrollback, nullptr, mUseFrameBuffer ); if ( term == nullptr || term->getTerm() == nullptr ) { - displayError(); + if ( fallback ) + displayError(); return nullptr; } diff --git a/src/tools/ecode/terminalmanager.hpp b/src/tools/ecode/terminalmanager.hpp index 95e0bdde6..023b920ef 100644 --- a/src/tools/ecode/terminalmanager.hpp +++ b/src/tools/ecode/terminalmanager.hpp @@ -15,12 +15,14 @@ class TerminalManager { public: TerminalManager( App* app ); - UITerminal* createTerminalInSplitter( const std::string& workingDir = "" ); + UITerminal* createTerminalInSplitter( const std::string& workingDir = "", + bool fallback = true ); UITerminal* createNewTerminal( const std::string& title = "", UITabWidget* inTabWidget = nullptr, const std::string& workingDir = "", std::string program = "", - const std::vector& args = {} ); + const std::vector& args = {}, + bool fallback = true ); void applyTerminalColorScheme( const TerminalColorScheme& colorScheme ); diff --git a/src/tools/ecode/uibuildsettings.cpp b/src/tools/ecode/uibuildsettings.cpp index 2bd6fc970..7fa27721c 100644 --- a/src/tools/ecode/uibuildsettings.cpp +++ b/src/tools/ecode/uibuildsettings.cpp @@ -82,30 +82,30 @@ class UICustomOutputParserWindow : public UIWindow { mCfg( cfg ) { static const auto CUSTOM_OUTPUT_PARSER_XML = R"xml( - + @string("error", "Error") @string("warning", "Warning") @string("notice", "Notice") - + - + - + - + - + - + @@ -215,6 +215,10 @@ class UIBuildStep : public UILinearLayout { mStep = buildStep; addClass( String::toString( mStepNum ) ); + forEachChild( [buildStep]( Node* node ) { node->setEnabled( buildStep != nullptr ); } ); + if ( buildStep == nullptr ) + return; + auto stepName = findByClass( "step_name" ); if ( isBuildOrClean() ) { stepName->setText( String::format( mBuildSettings->getUISceneNode() @@ -250,7 +254,7 @@ class UIBuildStep : public UILinearLayout { static const auto BUILD_STEP_XML = R"xml( - + @@ -259,15 +263,15 @@ class UIBuildStep : public UILinearLayout { - + - + - + @@ -338,9 +342,9 @@ static const auto SETTINGS_PANEL_XML = R"xml( - + - + @@ -353,24 +357,33 @@ static const auto SETTINGS_PANEL_XML = R"xml( - + - + - - + + + + + + + + + + + - + @@ -386,7 +399,7 @@ static const auto SETTINGS_PANEL_XML = R"xml( - + @@ -400,9 +413,9 @@ static const auto SETTINGS_PANEL_XML = R"xml( - + - + @@ -413,15 +426,15 @@ static const auto SETTINGS_PANEL_XML = R"xml( - - - + + + generic - + @@ -434,7 +447,7 @@ static const auto SETTINGS_PANEL_XML = R"xml( - + )xml"; @@ -527,8 +540,6 @@ UIBuildSettings::UIBuildSettings( ->setParent( buildCleanStepsParent ); } ); - UIBuildStep::New( UIBuildStep::StepType::Run, this, 0, &mBuild.mRun ) - ->setParent( find( "run_step_cont" ) ); auto buildTypeDropDown = find( "build_type_list" ); auto panelBuildTypeDDL = getUISceneNode() @@ -701,6 +712,8 @@ UIBuildSettings::UIBuildSettings( modelOP->invalidate(); } } ); + + runSetup(); } void UIBuildSettings::updateOS() { @@ -801,7 +814,6 @@ void UIBuildSettings::deleteStep( size_t stepNum, bool isClean ) { isClean ? find( "build_clean_steps_cont" ) : find( "build_steps_cont" ); for ( auto step = stepNum; step < steps.size(); step++ ) cont->findByClass( String::toString( step ) )->clearBindings(); - // cppcheck-suppress mismatchingContainerIterator steps.erase( steps.begin() + stepNum ); cont->findByClass( String::toString( stepNum ) )->close(); for ( auto step = stepNum + 1; step <= steps.size(); step++ ) @@ -809,4 +821,280 @@ void UIBuildSettings::deleteStep( size_t stepNum, bool isClean ) { ->updateStep( step - 1, &steps[step - 1] ); } +void UIBuildSettings::runSetup() { + if ( mBuild.mRun.empty() ) { + mBuild.mRun.push_back( {} ); + mBuild.mRun.back().name = i18n( "custom_executable", "Custom Executable" ); + } + + UIBuildStep::New( UIBuildStep::StepType::Run, this, 0, &mBuild.mRun[runIndex()] ) + ->setParent( find( "run_cont" ) ); + + UIDropDownList* runList = find( "run_list" )->asType(); + auto panelRunListDDL = getUISceneNode() + ->getRoot() + ->querySelector( "#build_tab_view #run_config_list" ) + ->asType(); + + runUpdate( true, runList, panelRunListDDL ); + + runList->getListBox()->setSelected( runIndex() ); + if ( panelRunListDDL ) + panelRunListDDL->getListBox()->setSelected( runIndex() ); + + runSelect( runIndex() ); + + runList->on( Event::OnItemSelected, [this, runList, panelRunListDDL]( auto ) { + mConfig.runName = runList->getListBox()->getItemSelectedText().toUtf8(); + runSelect( runIndex() ); + if ( panelRunListDDL ) + panelRunListDDL->getListBox()->setSelected( mConfig.runName ); + } ); + + if ( panelRunListDDL ) { + mCbs[panelRunListDDL].push_back( panelRunListDDL->on( + Event::OnItemSelected, [this, runList, panelRunListDDL]( const Event* ) { + mConfig.runName = panelRunListDDL->getListBox()->getItemSelectedText().toUtf8(); + if ( runList ) + runList->getListBox()->setSelected( mConfig.runName ); + } ) ); + mCbs[panelRunListDDL].push_back( panelRunListDDL->on( + Event::OnClose, [this, panelRunListDDL]( auto ) { mCbs.erase( panelRunListDDL ); } ) ); + } + + find( "run_add" )->onClick( [this, runList, panelRunListDDL]( auto ) { + UIMessageBox* msgBox = UIMessageBox::New( + UIMessageBox::INPUT, i18n( "run_configuration_name", "Run configuration name:" ) ); + msgBox->setTitle( i18n( "run_settings", "Run Settings" ) ); + msgBox->setCloseShortcut( { KEY_ESCAPE, KEYMOD_NONE } ); + msgBox->showWhenReady(); + msgBox->on( Event::OnConfirm, [this, msgBox, runList, panelRunListDDL]( auto ) { + bool unique = true; + auto newName = msgBox->getTextInput()->getText().toUtf8(); + for ( const auto& run : mBuild.mRun ) { + if ( newName == run.name ) { + unique = false; + break; + } + } + + if ( unique ) { + mBuild.mRun.push_back( {} ); + mBuild.mRun.back().name = newName; + + runList->getListBox()->addListBoxItem( newName ); + runList->getListBox()->setSelected( newName ); + + if ( panelRunListDDL ) { + panelRunListDDL->getListBox()->addListBoxItem( newName ); + panelRunListDDL->getListBox()->setSelected( newName ); + } + + runUpdate( false, runList, panelRunListDDL ); + } else { + UIMessageBox* uniqueAlert = UIMessageBox::New( + UIMessageBox::OK, i18n( "run_configuration_name_must_be_unique", + "Run configuration name must be unique!" ) ); + uniqueAlert->setTitle( i18n( "run_settings", "Run Settings" ) ); + uniqueAlert->setCloseShortcut( { KEY_ESCAPE, KEYMOD_NONE } ); + uniqueAlert->showWhenReady(); + } + + msgBox->close(); + } ); + } ); + + find( "run_remove" )->onClick( [this, runList, panelRunListDDL]( auto ) { + UIMessageBox* msgBox = UIMessageBox::New( + UIMessageBox::OK_CANCEL, + i18n( "run_configuration_delete_confirm", + "Are you sure you want to delete the currently selected run configuration?" ) ); + msgBox->setTitle( i18n( "run_configuration", "Run Configuration" ) ); + msgBox->setCloseShortcut( { KEY_ESCAPE, KEYMOD_NONE } ); + msgBox->showWhenReady(); + msgBox->on( Event::OnConfirm, [this, runList, panelRunListDDL]( auto ) { + runRemove( false, runList, panelRunListDDL ); + } ); + } ); + + find( "run_remove_all" )->onClick( [this, runList, panelRunListDDL]( auto ) { + UIMessageBox* msgBox = UIMessageBox::New( + UIMessageBox::OK_CANCEL, + i18n( "run_configuration_delete_all_confirm", + "Are you sure you want to delete all the run configurations?" ) ); + msgBox->setTitle( i18n( "run_configuration", "Run Configuration" ) ); + msgBox->setCloseShortcut( { KEY_ESCAPE, KEYMOD_NONE } ); + msgBox->showWhenReady(); + msgBox->on( Event::OnConfirm, [this, runList, panelRunListDDL]( auto ) { + runRemove( true, runList, panelRunListDDL ); + } ); + } ); + + find( "run_rename" )->onClick( [this, runList, panelRunListDDL]( auto ) { + UIMessageBox* msgBox = UIMessageBox::New( + UIMessageBox::INPUT, i18n( "run_configuration_rename", "Rename configuration name:" ) ); + msgBox->setTitle( i18n( "run_settings", "Run Settings" ) ); + msgBox->setCloseShortcut( { KEY_ESCAPE, KEYMOD_NONE } ); + msgBox->getTextInput()->setText( runList->getText() ); + msgBox->getTextInput()->getDocument().selectAll(); + msgBox->showWhenReady(); + auto selectedIndex = runList->getListBox()->getItemSelectedIndex(); + msgBox->on( + Event::OnConfirm, [this, msgBox, selectedIndex, runList, panelRunListDDL]( auto ) { + bool unique = true; + auto newName = msgBox->getTextInput()->getText().toUtf8(); + for ( size_t i = 0; i < mBuild.mRun.size(); i++ ) { + const auto& run = mBuild.mRun[i]; + if ( newName == run.name && i != selectedIndex ) { + unique = false; + break; + } + } + + if ( unique && selectedIndex < mBuild.mRun.size() ) { + if ( mBuild.mRun[selectedIndex].name == mConfig.runName ) + mConfig.runName = newName; + mBuild.mRun[selectedIndex].name = newName; + runList->getListBox()->setItemText( selectedIndex, newName ); + if ( panelRunListDDL ) + panelRunListDDL->getListBox()->setItemText( selectedIndex, newName ); + } else { + UIMessageBox* uniqueAlert = UIMessageBox::New( + UIMessageBox::OK, i18n( "run_configuration_name_must_be_unique", + "Run configuration name must be unique!" ) ); + uniqueAlert->setTitle( i18n( "run_settings", "Run Settings" ) ); + uniqueAlert->setCloseShortcut( { KEY_ESCAPE, KEYMOD_NONE } ); + uniqueAlert->showWhenReady(); + } + + msgBox->close(); + } ); + } ); + + find( "run_clone" )->onClick( [this, runList, panelRunListDDL]( auto ) { + UIMessageBox* msgBox = UIMessageBox::New( + UIMessageBox::INPUT, i18n( "run_configuration_name", "Run configuration name:" ) ); + msgBox->setTitle( i18n( "run_settings", "Run Settings" ) ); + msgBox->setCloseShortcut( { KEY_ESCAPE, KEYMOD_NONE } ); + msgBox->getTextInput()->setText( runList->getText() ); + msgBox->getTextInput()->getDocument().selectAll(); + msgBox->showWhenReady(); + msgBox->on( Event::OnConfirm, [this, msgBox, runList, panelRunListDDL]( auto ) { + bool unique = true; + auto newName = msgBox->getTextInput()->getText().toUtf8(); + for ( const auto& run : mBuild.mRun ) { + if ( newName == run.name ) { + unique = false; + break; + } + } + + if ( unique ) { + auto selectedIndex = runList->getListBox()->getItemSelectedIndex(); + if ( selectedIndex < mBuild.mRun.size() ) { + mBuild.mRun.push_back( mBuild.mRun[selectedIndex] ); + } else { + mBuild.mRun.push_back( {} ); + } + mBuild.mRun.back().name = newName; + + runList->getListBox()->addListBoxItem( newName ); + runList->getListBox()->setSelected( newName ); + if ( panelRunListDDL ) { + panelRunListDDL->getListBox()->addListBoxItem( newName ); + panelRunListDDL->getListBox()->setSelected( newName ); + } + } else { + UIMessageBox* uniqueAlert = UIMessageBox::New( + UIMessageBox::OK, i18n( "run_configuration_name_must_be_unique", + "Run configuration name must be unique!" ) ); + uniqueAlert->setTitle( i18n( "run_settings", "Run Settings" ) ); + uniqueAlert->setCloseShortcut( { KEY_ESCAPE, KEYMOD_NONE } ); + uniqueAlert->showWhenReady(); + } + + msgBox->close(); + } ); + } ); +} + +void UIBuildSettings::runSelect( Uint32 index ) { + UIWidget* cont = find( "run_cont" ); + auto bs = cont->findByClass( String::toString( 0 ) ); + if ( index < mBuild.mRun.size() ) { + bs->updateStep( 0, &mBuild.mRun[index] ); + } else { + if ( mBuild.mRun.empty() ) { + mBuild.mRun.push_back( {} ); + mBuild.mRun.back().name = i18n( "custom_executable", "Custom Executable" ); + } + bs->updateStep( 0, &mBuild.mRun[0] ); + } +} + +void UIBuildSettings::runRemove( bool all, UIDropDownList* runList, + UIDropDownList* panelRunListDDL ) { + + if ( runList->getListBox()->isEmpty() ) + return; + + if ( all ) { + runList->getListBox()->clear(); + if ( panelRunListDDL ) + panelRunListDDL->getListBox()->clear(); + mBuild.mRun.clear(); + } else { + auto name = runList->getListBox()->getItemSelectedText(); + mBuild.mRun.erase( mBuild.mRun.begin() + runList->getListBox()->getItemSelectedIndex() ); + runList->getListBox()->removeListBoxItem( name ); + if ( panelRunListDDL ) + panelRunListDDL->getListBox()->removeListBoxItem( name ); + } + + runUpdate( false, runList, panelRunListDDL ); + + if ( all ) + runSelect(); +} + +void UIBuildSettings::runUpdate( bool recreateList, UIDropDownList* runList, + UIDropDownList* panelRunListDDL ) { + if ( recreateList ) { + runList->getListBox()->clear(); + if ( panelRunListDDL ) + panelRunListDDL->getListBox()->clear(); + + size_t i = 1; + for ( const auto& run : mBuild.mRun ) { + auto name = + run.name.empty() + ? String::format( + i18n( "custom_executable_num", "Custom Executable %d" ).toUtf8(), i ) + : run.name; + runList->getListBox()->addListBoxItem( name ); + if ( panelRunListDDL ) + panelRunListDDL->getListBox()->addListBoxItem( name ); + i++; + } + } + + bool runButEnabled = !runList->getListBox()->isEmpty(); + runList->setEnabled( runButEnabled ); + if ( panelRunListDDL ) + panelRunListDDL->setEnabled( runButEnabled ); + find( "run_cont" )->setEnabled( runButEnabled )->setVisible( runButEnabled ); + find( "run_remove" )->setEnabled( runButEnabled ); + find( "run_remove_all" )->setEnabled( runButEnabled ); + find( "run_rename" )->setEnabled( runButEnabled ); + find( "run_clone" )->setEnabled( runButEnabled ); +} + +Uint32 UIBuildSettings::runIndex() const { + for ( size_t i = 0; i < mBuild.mRun.size(); i++ ) { + if ( mBuild.mRun[i].name == mConfig.runName ) + return i; + } + return 0; +} + } // namespace ecode diff --git a/src/tools/ecode/uibuildsettings.hpp b/src/tools/ecode/uibuildsettings.hpp index 5b33c212c..326f561ec 100644 --- a/src/tools/ecode/uibuildsettings.hpp +++ b/src/tools/ecode/uibuildsettings.hpp @@ -5,6 +5,9 @@ #include #include +namespace EE { namespace UI { +class UIDropDownList; +}} // namespace EE::UI using namespace EE::UI; namespace ecode { @@ -52,6 +55,16 @@ class UIBuildSettings : public UIRelativeLayout { void refreshTab(); void bindTable( const std::string& name, const std::string& key, ProjectBuildKeyVal& data ); + + void runSelect( Uint32 index = 0xFFFFFFFF ); + + void runRemove( bool all, UIDropDownList* runList, UIDropDownList* panelRunListDDL ); + + void runUpdate( bool recreateList, UIDropDownList* runList, UIDropDownList* panelRunListDDL ); + + Uint32 runIndex() const; + + void runSetup(); }; } // namespace ecode