Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/application/LayoutNavigationPanelWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,8 @@ LayoutNavigationPanelWidget::LayoutNavigationPanelWidget(
QWidget* parent,
QWidget* headerWidget,
NavigationTreeState navigationState,
std::function<void(const QSet<QString>&)> expandedStateChangedHandler)
std::function<void(const QSet<QString>&)> expandedStateChangedHandler,
std::function<void(const QString&)> deleteElementHandler)
: QWidget(parent) {
auto* layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
Expand All @@ -387,7 +388,10 @@ LayoutNavigationPanelWidget::LayoutNavigationPanelWidget(
this,
headerWidget,
std::move(navigationState),
std::move(expandedStateChangedHandler)));
std::move(expandedStateChangedHandler),
std::move(deleteElementHandler),
{},
QString("Settings...")));
}

} // namespace safecrowd::application
3 changes: 2 additions & 1 deletion src/application/LayoutNavigationPanelWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ class LayoutNavigationPanelWidget : public QWidget {
QWidget* parent = nullptr,
QWidget* headerWidget = nullptr,
NavigationTreeState navigationState = {},
std::function<void(const QSet<QString>&)> expandedStateChangedHandler = {});
std::function<void(const QSet<QString>&)> expandedStateChangedHandler = {},
std::function<void(const QString&)> deleteElementHandler = {});
};

} // namespace safecrowd::application
27 changes: 27 additions & 0 deletions src/application/LayoutPreviewWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2992,6 +2992,33 @@ void LayoutPreviewWidget::focusElement(const QString& elementId) {
focusIssueTarget(elementId);
}

bool LayoutPreviewWidget::deleteElement(const QString& elementId) {
if (!importResult_.layout.has_value() || elementId.isEmpty() || elementId.startsWith("floor:")) {
return false;
}

if (containsConnection(*importResult_.layout, elementId)) {
deleteConnection(elementId);
return true;
}
if (containsBarrier(*importResult_.layout, elementId)) {
deleteBarrier(elementId);
return true;
}
if (containsZone(*importResult_.layout, elementId)) {
selectedBarrierId_.clear();
selectedBarrierIds_.clear();
selectedConnectionId_.clear();
selectedConnectionIds_.clear();
selectedZoneId_ = elementId;
selectedZoneIds_ = QStringList{elementId};
deleteSelectedElements();
return true;
}

return false;
}

void LayoutPreviewWidget::focusIssueTarget(const QString& targetId) {
selectedZoneId_.clear();
selectedZoneIds_.clear();
Expand Down
1 change: 1 addition & 0 deletions src/application/LayoutPreviewWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class LayoutPreviewWidget : public QWidget {

void focusElement(const QString& elementId);
void focusIssueTarget(const QString& targetId);
bool deleteElement(const QString& elementId);
void resetView();
void setImportResult(safecrowd::domain::ImportResult importResult);
void setSelectionChangedHandler(std::function<void(const PreviewSelection&)> handler);
Expand Down
9 changes: 8 additions & 1 deletion src/application/LayoutReviewWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ QWidget* createNavigationPanel(
bool showIssues,
std::function<void(const safecrowd::domain::ImportIssue&)> selectIssueHandler,
std::function<void(const QString&)> selectLayoutElementHandler,
std::function<void(const QString&)> deleteLayoutElementHandler,
NavigationTreeState layoutNavigationState,
std::function<void(const QSet<QString>&)> layoutExpandedStateChangedHandler,
const WorkspaceShell* shell,
Expand All @@ -173,7 +174,8 @@ QWidget* createNavigationPanel(
content,
shell != nullptr ? shell->createPanelHeader("Layout", content, false) : nullptr,
std::move(layoutNavigationState),
std::move(layoutExpandedStateChangedHandler)));
std::move(layoutExpandedStateChangedHandler),
std::move(deleteLayoutElementHandler)));
return content;
}

Expand Down Expand Up @@ -503,6 +505,11 @@ void LayoutReviewWidget::refreshNavigationPanel() {
[this](const QString& elementId) {
handleLayoutElementSelected(elementId);
},
[this](const QString& elementId) {
if (preview_ != nullptr) {
preview_->deleteElement(elementId);
}
},
NavigationTreeState{
.expandedNodeIds = layoutExpandedNodeIds_,
.selectedId = selectedLayoutElementId_,
Expand Down
57 changes: 56 additions & 1 deletion src/application/NavigationTreeWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <QColor>
#include <QFrame>
#include <QLabel>
#include <QMenu>
#include <QMouseEvent>
#include <QPainter>
#include <QSet>
Expand Down Expand Up @@ -274,7 +275,10 @@ NavigationTreeWidget::NavigationTreeWidget(
QWidget* parent,
QWidget* headerWidget,
NavigationTreeState state,
std::function<void(const QSet<QString>&)> expandedStateChangedHandler)
std::function<void(const QSet<QString>&)> expandedStateChangedHandler,
std::function<void(const QString&)> deleteItemHandler,
std::function<void(const QString&)> settingsItemHandler,
const QString& settingsLabel)
: QWidget(parent) {
auto* layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
Expand Down Expand Up @@ -358,6 +362,57 @@ NavigationTreeWidget::NavigationTreeWidget(
});
}

if (deleteItemHandler || settingsItemHandler) {
auto* viewport = tree->viewport();
if (viewport != nullptr) {
tree->setContextMenuPolicy(Qt::CustomContextMenu);
viewport->setContextMenuPolicy(Qt::CustomContextMenu);

const auto showMenu = [tree, viewport, deleteItemHandler, settingsItemHandler, settingsLabel](const QPoint& pos, QWidget* source) {
auto* item = tree->itemAt(pos);
if (item == nullptr) {
return;
}

const auto selectable = item->data(0, kSelectableRole).toBool();
const auto id = item->data(0, kIdRole).toString();
if (!selectable || id.isEmpty()) {
return;
}

QMenu menu;
QAction* settingsAction = nullptr;
if (settingsItemHandler) {
settingsAction = menu.addAction(settingsLabel);
}
QAction* deleteAction = nullptr;
if (deleteItemHandler) {
deleteAction = menu.addAction("Delete");
if (id.startsWith("floor:")) {
deleteAction->setEnabled(false);
}
}

const auto* selectedAction = menu.exec(source->mapToGlobal(pos));
if (selectedAction == nullptr) {
return;
}
if (selectedAction == settingsAction && settingsItemHandler) {
settingsItemHandler(id);
} else if (selectedAction == deleteAction && deleteItemHandler) {
deleteItemHandler(id);
}
};

QObject::connect(viewport, &QWidget::customContextMenuRequested, tree, [showMenu, viewport](const QPoint& pos) {
showMenu(pos, viewport);
});
QObject::connect(tree, &QWidget::customContextMenuRequested, tree, [showMenu, tree](const QPoint& pos) {
showMenu(pos, tree);
});
}
}

layout->addWidget(tree, 1);
}

Expand Down
5 changes: 4 additions & 1 deletion src/application/NavigationTreeWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ class NavigationTreeWidget : public QWidget {
QWidget* parent = nullptr,
QWidget* headerWidget = nullptr,
NavigationTreeState state = {},
std::function<void(const QSet<QString>&)> expandedStateChangedHandler = {});
std::function<void(const QSet<QString>&)> expandedStateChangedHandler = {},
std::function<void(const QString&)> deleteItemHandler = {},
std::function<void(const QString&)> settingsItemHandler = {},
const QString& settingsLabel = QString("Settings..."));
};

} // namespace safecrowd::application
144 changes: 140 additions & 4 deletions src/application/ScenarioAuthoringWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
#include <utility>

#include <QComboBox>
#include <QDialog>
#include <QDialogButtonBox>
#include <QFormLayout>
#include <QFrame>
#include <QHBoxLayout>
#include <QInputDialog>
Expand All @@ -12,6 +15,7 @@
#include <QLayoutItem>
#include <QMessageBox>
#include <QPainter>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QScrollArea>
#include <QSizePolicy>
Expand All @@ -36,6 +40,58 @@ QLabel* createLabel(const QString& text, QWidget* parent, ui::FontRole role = ui
return label;
}

bool editOperationalEvent(
safecrowd::domain::OperationalEventDraft* event,
QWidget* parent) {
if (event == nullptr) {
return false;
}

QDialog dialog(parent);
dialog.setWindowTitle("Edit event");

auto* root = new QVBoxLayout(&dialog);
root->setContentsMargins(16, 16, 16, 16);
root->setSpacing(12);

auto* form = new QFormLayout();
form->setContentsMargins(0, 0, 0, 0);
form->setSpacing(8);

auto* nameEdit = new QLineEdit(&dialog);
nameEdit->setText(QString::fromStdString(event->name));
auto* triggerEdit = new QPlainTextEdit(&dialog);
triggerEdit->setPlainText(QString::fromStdString(event->triggerSummary));
triggerEdit->setMinimumHeight(72);
auto* targetEdit = new QPlainTextEdit(&dialog);
targetEdit->setPlainText(QString::fromStdString(event->targetSummary));
targetEdit->setMinimumHeight(72);

form->addRow("Name", nameEdit);
form->addRow("Trigger", triggerEdit);
form->addRow("Target", targetEdit);
root->addLayout(form);

auto* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);
QObject::connect(buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
QObject::connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
root->addWidget(buttons);

if (dialog.exec() != QDialog::Accepted) {
return false;
}

const auto name = nameEdit->text().trimmed();
if (name.isEmpty()) {
return false;
}

event->name = name.toStdString();
event->triggerSummary = triggerEdit->toPlainText().trimmed().toStdString();
event->targetSummary = targetEdit->toPlainText().trimmed().toStdString();
return true;
}

QString zoneLabel(const safecrowd::domain::Zone2D& zone) {
const auto id = QString::fromStdString(zone.id);
const auto label = QString::fromStdString(zone.label);
Expand Down Expand Up @@ -459,6 +515,7 @@ QWidget* createCrowdPanel(
std::function<void(const QString&)> selectPlacementHandler,
NavigationTreeState navigationState,
std::function<void(const QSet<QString>&)> expandedStateChangedHandler,
std::function<void(const QString&)> deletePlacementHandler,
const WorkspaceShell* shell,
QWidget* parent) {
return new NavigationTreeWidget(
Expand All @@ -469,7 +526,8 @@ QWidget* createCrowdPanel(
parent,
shell != nullptr ? shell->createPanelHeader("Crowd", parent, false) : nullptr,
std::move(navigationState),
std::move(expandedStateChangedHandler));
std::move(expandedStateChangedHandler),
std::move(deletePlacementHandler));
}

std::vector<NavigationTreeNode> buildEventsTree(
Expand Down Expand Up @@ -613,14 +671,21 @@ QWidget* createEventsPanel(
const safecrowd::domain::FacilityLayout2D& layout,
const ScenarioAuthoringWidget::ScenarioState* scenario,
const WorkspaceShell* shell,
QWidget* parent) {
QWidget* parent,
std::function<void(const QString&)> deleteItemHandler,
std::function<void(const QString&)> settingsItemHandler) {
return new NavigationTreeWidget(
"Events",
buildEventsTree(layout, scenario),
"No operational events or blocked exits yet",
{},
parent,
shell != nullptr ? shell->createPanelHeader("Events", parent, false) : nullptr);
shell != nullptr ? shell->createPanelHeader("Events", parent, false) : nullptr,
{},
{},
std::move(deleteItemHandler),
std::move(settingsItemHandler),
QString("Settings..."));
}

SavedNavigationView savedNavigationView(ScenarioAuthoringWidget::NavigationView view) {
Expand Down Expand Up @@ -1095,11 +1160,82 @@ void ScenarioAuthoringWidget::refreshNavigationPanel() {
[this](const QSet<QString>& expandedNodeIds) {
crowdExpandedNodeIds_ = expandedNodeIds;
},
[this](const QString& crowdElementId) {
if (canvas_ != nullptr) {
canvas_->deleteCrowdElementById(crowdElementId);
}
},
shell_,
shell_));
return;
}
shell_->setNavigationPanel(createEventsPanel(layout_, currentScenario(), shell_, shell_));
shell_->setNavigationPanel(createEventsPanel(
layout_,
currentScenario(),
shell_,
shell_,
[this](const QString& rawId) {
auto* scenario = currentScenario();
if (scenario == nullptr || rawId.isEmpty()) {
return;
}

const auto id = rawId.section('/', 0, 0);
if (canvas_ != nullptr && canvas_->deleteConnectionBlockById(id)) {
return;
}
if (canvas_ != nullptr && canvas_->deleteRouteGuidanceById(id)) {
return;
}

const auto eventId = id.toStdString();
auto& events = scenario->events;
const auto it = std::remove_if(events.begin(), events.end(), [&](const auto& event) {
return event.id == eventId;
});
if (it == events.end()) {
return;
}
events.erase(it, events.end());
scenario->draft.control.events = scenario->events;
recomputeDiffKeysAfterScenarioChanged(*scenario);
refreshNavigationPanel();
refreshInspector();
},
[this](const QString& rawId) {
if (canvas_ == nullptr || rawId.isEmpty()) {
return;
}

const auto id = rawId.section('/', 0, 0);
if (canvas_->editConnectionBlockScheduleById(id)) {
return;
}
if (canvas_->editRouteGuidanceById(id)) {
return;
}

auto* scenario = currentScenario();
if (scenario == nullptr) {
return;
}

const auto eventId = id.toStdString();
auto& events = scenario->events;
const auto it = std::find_if(events.begin(), events.end(), [&](auto& event) {
return event.id == eventId;
});
if (it == events.end()) {
return;
}
if (!editOperationalEvent(&(*it), this)) {
return;
}
scenario->draft.control.events = scenario->events;
recomputeDiffKeysAfterScenarioChanged(*scenario);
refreshNavigationPanel();
refreshInspector();
}));
}

void ScenarioAuthoringWidget::refreshRightPanel() {
Expand Down
Loading
Loading