diff --git a/src/application/ScenarioAuthoringWidget.cpp b/src/application/ScenarioAuthoringWidget.cpp index bd7a691..c9c5f70 100644 --- a/src/application/ScenarioAuthoringWidget.cpp +++ b/src/application/ScenarioAuthoringWidget.cpp @@ -224,6 +224,29 @@ ScenarioAuthoringWidget::ScenarioAuthoringWidget( layout_(layout), saveProjectHandler_(std::move(saveProjectHandler)), openProjectHandler_(std::move(openProjectHandler)) { + initializeUi(true); +} + +ScenarioAuthoringWidget::ScenarioAuthoringWidget( + const QString& projectName, + const safecrowd::domain::FacilityLayout2D& layout, + InitialState initialState, + std::function saveProjectHandler, + std::function openProjectHandler, + QWidget* parent) + : QWidget(parent), + projectName_(projectName), + layout_(layout), + saveProjectHandler_(std::move(saveProjectHandler)), + openProjectHandler_(std::move(openProjectHandler)), + scenarios_(std::move(initialState.scenarios)), + currentScenarioIndex_(initialState.currentScenarioIndex), + navigationView_(initialState.navigationView), + rightPanelMode_(initialState.rightPanelMode) { + initializeUi(false); +} + +void ScenarioAuthoringWidget::initializeUi(bool promptForScenario) { auto* rootLayout = new QVBoxLayout(this); rootLayout->setContentsMargins(0, 0, 0, 0); rootLayout->setSpacing(0); @@ -237,11 +260,13 @@ ScenarioAuthoringWidget::ScenarioAuthoringWidget( rootLayout->addWidget(shell_); refreshNavigationPanel(); - showEmptyCanvas(); + refreshCanvas(); refreshInspector(); - QTimer::singleShot(0, this, [this]() { - ensureInitialScenarioPrompt(); - }); + if (promptForScenario) { + QTimer::singleShot(0, this, [this]() { + ensureInitialScenarioPrompt(); + }); + } } void ScenarioAuthoringWidget::addEventDraft(const QString& name, const QString& trigger, const QString& target) { diff --git a/src/application/ScenarioAuthoringWidget.h b/src/application/ScenarioAuthoringWidget.h index 3d56b67..4f8387b 100644 --- a/src/application/ScenarioAuthoringWidget.h +++ b/src/application/ScenarioAuthoringWidget.h @@ -49,7 +49,23 @@ class ScenarioAuthoringWidget : public QWidget { bool stagedForRun{false}; }; + struct InitialState { + std::vector scenarios{}; + int currentScenarioIndex{-1}; + NavigationView navigationView{NavigationView::Layout}; + RightPanelMode rightPanelMode{RightPanelMode::Scenario}; + }; + + explicit ScenarioAuthoringWidget( + const QString& projectName, + const safecrowd::domain::FacilityLayout2D& layout, + InitialState initialState, + std::function saveProjectHandler, + std::function openProjectHandler, + QWidget* parent = nullptr); + private: + void initializeUi(bool promptForScenario); void addEventDraft(const QString& name, const QString& trigger, const QString& target); void createScenarioFromCurrent(); void createScenarioWithName(const QString& name, int sourceIndex); diff --git a/src/application/ScenarioResultWidget.cpp b/src/application/ScenarioResultWidget.cpp index 54cfb0e..2921e28 100644 --- a/src/application/ScenarioResultWidget.cpp +++ b/src/application/ScenarioResultWidget.cpp @@ -1,5 +1,6 @@ #include "application/ScenarioResultWidget.h" +#include #include #include @@ -11,6 +12,8 @@ #include #include +#include "application/ScenarioAuthoringWidget.h" +#include "application/ScenarioCanvasWidget.h" #include "application/SimulationCanvasWidget.h" #include "application/UiStyle.h" #include "application/WorkspaceShell.h" @@ -51,10 +54,67 @@ QString bottleneckSummary(const safecrowd::domain::ScenarioRiskSnapshot& risk) { .arg(static_cast(bottleneck.stalledAgentCount)); } +QString zoneLabel(const safecrowd::domain::Zone2D& zone) { + const auto id = QString::fromStdString(zone.id); + const auto label = QString::fromStdString(zone.label); + return label.isEmpty() ? id : QString("%1 - %2").arg(label, id); +} + +const safecrowd::domain::Zone2D* firstStartZone(const safecrowd::domain::FacilityLayout2D& layout) { + const auto it = std::find_if(layout.zones.begin(), layout.zones.end(), [](const auto& zone) { + return zone.kind == safecrowd::domain::ZoneKind::Room || zone.kind == safecrowd::domain::ZoneKind::Unknown; + }); + return it == layout.zones.end() ? nullptr : &(*it); +} + +const safecrowd::domain::Zone2D* firstDestinationZone(const safecrowd::domain::FacilityLayout2D& layout) { + const auto exitIt = std::find_if(layout.zones.begin(), layout.zones.end(), [](const auto& zone) { + return zone.kind == safecrowd::domain::ZoneKind::Exit; + }); + if (exitIt != layout.zones.end()) { + return &(*exitIt); + } + return layout.zones.empty() ? nullptr : &layout.zones.back(); +} + +ScenarioAuthoringWidget::ScenarioState scenarioStateFromDraft( + const safecrowd::domain::ScenarioDraft& scenario, + const safecrowd::domain::FacilityLayout2D& layout) { + ScenarioAuthoringWidget::ScenarioState state; + state.draft = scenario; + state.events = scenario.control.events; + state.stagedForRun = true; + + if (const auto* startZone = firstStartZone(layout); startZone != nullptr) { + state.startText = zoneLabel(*startZone); + } + if (const auto* destinationZone = firstDestinationZone(layout); destinationZone != nullptr) { + state.destinationText = zoneLabel(*destinationZone); + } + + for (const auto& placement : scenario.population.initialPlacements) { + ScenarioCrowdPlacement uiPlacement; + uiPlacement.id = QString::fromStdString(placement.id); + uiPlacement.name = uiPlacement.id; + uiPlacement.kind = (placement.targetAgentCount <= 1 && placement.area.outline.size() <= 1) + ? ScenarioCrowdPlacementKind::Individual + : ScenarioCrowdPlacementKind::Group; + uiPlacement.zoneId = QString::fromStdString(placement.zoneId); + uiPlacement.area = placement.area.outline; + uiPlacement.occupantCount = static_cast(placement.targetAgentCount); + uiPlacement.velocity = placement.initialVelocity; + state.crowdPlacements.push_back(std::move(uiPlacement)); + } + + return state; +} + QWidget* createResultPanel( const safecrowd::domain::ScenarioDraft& scenario, const safecrowd::domain::SimulationFrame& frame, const safecrowd::domain::ScenarioRiskSnapshot& risk, + std::function backHandler, + std::function editHandler, QWidget* parent) { auto* panel = new QWidget(parent); auto* layout = new QVBoxLayout(panel); @@ -121,17 +181,27 @@ QWidget* createResultPanel( actionsLayout->setContentsMargins(0, 0, 0, 0); actionsLayout->setSpacing(8); auto* backButton = new QPushButton("Back to Run", actions); - backButton->setEnabled(false); backButton->setFont(ui::font(ui::FontRole::Body)); backButton->setStyleSheet(ui::secondaryButtonStyleSheet()); auto* editButton = new QPushButton("Edit Scenario", actions); - editButton->setEnabled(false); editButton->setFont(ui::font(ui::FontRole::Body)); editButton->setStyleSheet(ui::secondaryButtonStyleSheet()); actionsLayout->addWidget(backButton); actionsLayout->addWidget(editButton); layout->addWidget(actions); + QObject::connect(backButton, &QPushButton::clicked, panel, [backHandler = std::move(backHandler)]() { + if (backHandler) { + backHandler(); + } + }); + + QObject::connect(editButton, &QPushButton::clicked, panel, [editHandler = std::move(editHandler)]() { + if (editHandler) { + editHandler(); + } + }); + return panel; } @@ -146,29 +216,74 @@ ScenarioResultWidget::ScenarioResultWidget( std::function saveProjectHandler, std::function openProjectHandler, QWidget* parent) - : QWidget(parent) { + : QWidget(parent), + projectName_(std::move(projectName)), + layout_(std::move(layout)), + scenario_(std::move(scenario)), + frame_(std::move(frame)), + risk_(std::move(risk)), + saveProjectHandler_(std::move(saveProjectHandler)), + openProjectHandler_(std::move(openProjectHandler)) { auto* rootLayout = new QVBoxLayout(this); rootLayout->setContentsMargins(0, 0, 0, 0); rootLayout->setSpacing(0); - auto* shell = new WorkspaceShell(this); - shell->setTools({"Project"}); - shell->setSaveProjectHandler(std::move(saveProjectHandler)); - shell->setOpenProjectHandler(std::move(openProjectHandler)); + shell_ = new WorkspaceShell(this); + shell_->setTools({"Project"}); + shell_->setSaveProjectHandler(saveProjectHandler_); + shell_->setOpenProjectHandler(openProjectHandler_); - auto* canvas = new SimulationCanvasWidget(layout, shell); - canvas->setFrame(frame); - canvas->setHotspotOverlay(risk.hotspots); - shell->setCanvas(canvas); - shell->setReviewPanel(createResultPanel(scenario, frame, risk, shell)); - shell->setReviewPanelVisible(true); + auto* canvas = new SimulationCanvasWidget(layout_, shell_); + canvas->setFrame(frame_); + canvas->setHotspotOverlay(risk_.hotspots); + shell_->setCanvas(canvas); + shell_->setReviewPanel(createResultPanel( + scenario_, + frame_, + risk_, + [this]() { + navigateToAuthoring(true); + }, + [this]() { + navigateToAuthoring(false); + }, + shell_)); + shell_->setReviewPanelVisible(true); - auto* title = new QLabel(QString("%1 - Result").arg(projectName), shell); + auto* title = new QLabel(QString("%1 - Result").arg(projectName_), shell_); title->setFont(ui::font(ui::FontRole::Body)); title->setStyleSheet(ui::mutedTextStyleSheet()); - shell->setTopBarTrailingWidget(title); + shell_->setTopBarTrailingWidget(title); + + rootLayout->addWidget(shell_); +} + +void ScenarioResultWidget::navigateToAuthoring(bool showRunPanel) { + auto* rootLayout = qobject_cast(layout()); + if (rootLayout == nullptr || shell_ == nullptr) { + return; + } + + ScenarioAuthoringWidget::InitialState initial; + initial.scenarios.push_back(scenarioStateFromDraft(scenario_, layout_)); + initial.currentScenarioIndex = 0; + initial.navigationView = ScenarioAuthoringWidget::NavigationView::Layout; + initial.rightPanelMode = showRunPanel + ? ScenarioAuthoringWidget::RightPanelMode::Run + : ScenarioAuthoringWidget::RightPanelMode::Scenario; + + auto* authoringWidget = new ScenarioAuthoringWidget( + projectName_, + layout_, + std::move(initial), + saveProjectHandler_, + openProjectHandler_, + this); - rootLayout->addWidget(shell); + rootLayout->replaceWidget(shell_, authoringWidget); + shell_->hide(); + shell_->deleteLater(); + shell_ = nullptr; } } // namespace safecrowd::application diff --git a/src/application/ScenarioResultWidget.h b/src/application/ScenarioResultWidget.h index 27d7231..b7f0d95 100644 --- a/src/application/ScenarioResultWidget.h +++ b/src/application/ScenarioResultWidget.h @@ -12,6 +12,8 @@ namespace safecrowd::application { +class WorkspaceShell; + class ScenarioResultWidget : public QWidget { public: explicit ScenarioResultWidget( @@ -23,6 +25,18 @@ class ScenarioResultWidget : public QWidget { std::function saveProjectHandler, std::function openProjectHandler, QWidget* parent = nullptr); + +private: + void navigateToAuthoring(bool showRunPanel); + + QString projectName_{}; + safecrowd::domain::FacilityLayout2D layout_{}; + safecrowd::domain::ScenarioDraft scenario_{}; + safecrowd::domain::SimulationFrame frame_{}; + safecrowd::domain::ScenarioRiskSnapshot risk_{}; + std::function saveProjectHandler_{}; + std::function openProjectHandler_{}; + WorkspaceShell* shell_{nullptr}; }; } // namespace safecrowd::application