99#include < QInputDialog>
1010#include < QLabel>
1111#include < QLineEdit>
12+ #include < QMessageBox>
1213#include < QPainter>
1314#include < QPushButton>
1415#include < QScrollArea>
@@ -84,6 +85,25 @@ QString blockScheduleSummary(const safecrowd::domain::ConnectionBlockDraft& bloc
8485 return intervals.join (" , " );
8586}
8687
88+ int totalOccupantCount (const ScenarioAuthoringWidget::ScenarioState& scenario) {
89+ int total = 0 ;
90+ for (const auto & placement : scenario.crowdPlacements ) {
91+ total += std::max (0 , placement.occupantCount );
92+ }
93+ if (total > 0 || !scenario.crowdPlacements .empty ()) {
94+ return total;
95+ }
96+
97+ for (const auto & placement : scenario.draft .population .initialPlacements ) {
98+ total += static_cast <int >(placement.targetAgentCount );
99+ }
100+ return total;
101+ }
102+
103+ bool scenarioHasOccupants (const ScenarioAuthoringWidget::ScenarioState& scenario) {
104+ return totalOccupantCount (scenario) > 0 ;
105+ }
106+
87107const safecrowd::domain::Zone2D* firstStartZone (const safecrowd::domain::FacilityLayout2D& layout) {
88108 const auto it = std::find_if (layout.zones .begin (), layout.zones .end (), [](const auto & zone) {
89109 return zone.kind == safecrowd::domain::ZoneKind::Room || zone.kind == safecrowd::domain::ZoneKind::Unknown;
@@ -163,7 +183,7 @@ QWidget* createNavigationRail(
163183 " QToolButton:checked { background: #ffffff; border-left-color: #1f5fae; }" );
164184
165185 auto * layout = new QVBoxLayout (activityBar);
166- layout->setContentsMargins (0 , 0 , 0 , 0 );
186+ layout->setContentsMargins (0 , 0 , 0 , 12 );
167187 layout->setSpacing (0 );
168188
169189 const auto makeActivityButton = [&](const QIcon& icon, const QString& tooltip, ScenarioAuthoringWidget::NavigationView view) {
@@ -385,6 +405,11 @@ ScenarioAuthoringWidget::ScenarioAuthoringWidget(
385405 currentScenarioIndex_(initialState.currentScenarioIndex),
386406 navigationView_(initialState.navigationView),
387407 rightPanelMode_(initialState.rightPanelMode) {
408+ for (auto & scenario : scenarios_) {
409+ if (!scenarioHasOccupants (scenario)) {
410+ scenario.stagedForRun = false ;
411+ }
412+ }
388413 rightPanelMode_ = RightPanelMode::Scenario;
389414 initializeUi (false );
390415}
@@ -424,7 +449,7 @@ SavedScenarioAuthoringState ScenarioAuthoringWidget::currentSavedState() const {
424449 state.scenarios .push_back ({
425450 .draft = std::move (draft),
426451 .baseScenarioId = scenario.baseScenarioId .toStdString (),
427- .stagedForRun = scenario.stagedForRun ,
452+ .stagedForRun = scenario.stagedForRun && scenarioHasOccupants (scenario) ,
428453 });
429454 }
430455 return state;
@@ -573,10 +598,7 @@ void ScenarioAuthoringWidget::refreshInspector() {
573598 if (!hasScenario) {
574599 scenarioSummaryLabel_->setText (" No scenario selected" );
575600 } else {
576- int people = 0 ;
577- for (const auto & placement : scenario->crowdPlacements ) {
578- people += placement.occupantCount ;
579- }
601+ const int people = totalOccupantCount (*scenario);
580602 const auto blockCount = static_cast <int >(scenario->draft .control .connectionBlocks .size ());
581603 scenarioSummaryLabel_->setText (QString (" Name: %1\n Role: %2\n Population: %3\n Start: %4\n Destination: %5\n Events: %6\n Blocked exits: %7" )
582604 .arg (
@@ -613,9 +635,13 @@ void ScenarioAuthoringWidget::refreshInspector() {
613635 newScenarioButton_->setText (hasScenario ? " New Scenario from Current" : " New Scenario" );
614636 }
615637 if (stageScenarioButton_ != nullptr ) {
616- stageScenarioButton_->setEnabled (hasScenario);
617638 const bool staged = hasScenario && scenario->stagedForRun ;
639+ const bool hasOccupants = hasScenario && scenarioHasOccupants (*scenario);
640+ stageScenarioButton_->setEnabled (hasScenario && (staged || hasOccupants));
618641 stageScenarioButton_->setText (staged ? " Unstage" : " Stage Scenario" );
642+ stageScenarioButton_->setToolTip (hasScenario && !staged && !hasOccupants
643+ ? " Add at least one occupant before staging this scenario."
644+ : QString{});
619645 stageScenarioButton_->setStyleSheet (staged
620646 ? QString (
621647 " QPushButton { background: #b42318; border: 1px solid #b42318; border-radius: 12px; color: white; font-weight: 600; padding: 10px 18px; }"
@@ -627,7 +653,7 @@ void ScenarioAuthoringWidget::refreshInspector() {
627653 " QPushButton:disabled { background: #d7e0ea; border-color: #d7e0ea; color: #8a98a8; }" ));
628654 }
629655 const auto stagedCount = std::count_if (scenarios_.begin (), scenarios_.end (), [](const auto & scenario) {
630- return scenario.stagedForRun ;
656+ return scenario.stagedForRun && scenarioHasOccupants (scenario) ;
631657 });
632658 if (stagedScenariosLabel_ != nullptr ) {
633659 QStringList lines;
@@ -636,7 +662,7 @@ void ScenarioAuthoringWidget::refreshInspector() {
636662 } else {
637663 lines << " Staged scenarios" ;
638664 for (const auto & stagedScenario : scenarios_) {
639- if (!stagedScenario.stagedForRun ) {
665+ if (!stagedScenario.stagedForRun || ! scenarioHasOccupants (stagedScenario) ) {
640666 continue ;
641667 }
642668 const auto role = stagedScenario.draft .role == safecrowd::domain::ScenarioRole::Baseline ? " Baseline" : " Alternative" ;
@@ -781,6 +807,15 @@ void ScenarioAuthoringWidget::stageCurrentScenario() {
781807 return ;
782808 }
783809
810+ if (!scenario->stagedForRun && !scenarioHasOccupants (*scenario)) {
811+ QMessageBox::warning (
812+ this ,
813+ " Cannot stage scenario" ,
814+ " Add at least one occupant before staging this scenario." );
815+ refreshInspector ();
816+ return ;
817+ }
818+
784819 scenario->stagedForRun = !scenario->stagedForRun ;
785820 refreshInspector ();
786821}
@@ -803,6 +838,9 @@ void ScenarioAuthoringWidget::updateCurrentScenarioPlacements(const std::vector<
803838 initialPlacement.initialVelocity = placement.velocity ;
804839 scenario->draft .population .initialPlacements .push_back (std::move (initialPlacement));
805840 }
841+ if (!scenarioHasOccupants (*scenario)) {
842+ scenario->stagedForRun = false ;
843+ }
806844
807845 refreshNavigationPanel ();
808846 refreshInspector ();
@@ -899,14 +937,14 @@ QWidget* ScenarioAuthoringWidget::createScenarioPanel() {
899937 stagedScenariosLabel_->setStyleSheet (ui::mutedTextStyleSheet ());
900938 QStringList lines;
901939 const auto stagedCount = std::count_if (scenarios_.begin (), scenarios_.end (), [](const auto & scenario) {
902- return scenario.stagedForRun ;
940+ return scenario.stagedForRun && scenarioHasOccupants (scenario) ;
903941 });
904942 if (stagedCount == 0 ) {
905943 lines << " No staged scenarios" ;
906944 } else {
907945 lines << " Staged scenarios" ;
908946 for (const auto & scenario : scenarios_) {
909- if (!scenario.stagedForRun ) {
947+ if (!scenario.stagedForRun || ! scenarioHasOccupants (scenario) ) {
910948 continue ;
911949 }
912950 const auto role = scenario.draft .role == safecrowd::domain::ScenarioRole::Baseline ? " Baseline" : " Alternative" ;
@@ -960,7 +998,9 @@ const ScenarioAuthoringWidget::ScenarioState* ScenarioAuthoringWidget::currentSc
960998
961999const ScenarioAuthoringWidget::ScenarioState* ScenarioAuthoringWidget::firstStagedBaselineScenario () const {
9621000 const auto it = std::find_if (scenarios_.begin (), scenarios_.end (), [](const auto & scenario) {
963- return scenario.stagedForRun && scenario.draft .role == safecrowd::domain::ScenarioRole::Baseline;
1001+ return scenario.stagedForRun
1002+ && scenarioHasOccupants (scenario)
1003+ && scenario.draft .role == safecrowd::domain::ScenarioRole::Baseline;
9641004 });
9651005 return it == scenarios_.end () ? nullptr : &(*it);
9661006}
0 commit comments