From f2040f19aaf562cd164a76298f93d8fb9bc70559 Mon Sep 17 00:00:00 2001 From: Mike Nelson Date: Tue, 12 May 2026 16:35:17 -0500 Subject: [PATCH] move waypoint and jump node to their own dropdown category --- qtfred/help-src/doc/fundamentals.html | 10 ++-- qtfred/help-src/doc/general/Toolbars.html | 16 +++++-- qtfred/help-src/doc/general/Viewport.html | 9 ++-- qtfred/src/mission/Editor.cpp | 2 - qtfred/src/mission/Editor.h | 3 -- qtfred/src/mission/EditorViewport.cpp | 58 +++++++++++++---------- qtfred/src/mission/EditorViewport.h | 16 ++++++- qtfred/src/ui/FredView.cpp | 33 +++++++++++-- qtfred/src/ui/FredView.h | 3 ++ qtfred/src/ui/widgets/ObjectComboBox.cpp | 21 +++++--- qtfred/src/ui/widgets/ObjectComboBox.h | 6 +-- qtfred/src/ui/widgets/renderwidget.cpp | 11 ++++- 12 files changed, 126 insertions(+), 62 deletions(-) diff --git a/qtfred/help-src/doc/fundamentals.html b/qtfred/help-src/doc/fundamentals.html index c6eb1410efa..b7fdb082e68 100644 --- a/qtfred/help-src/doc/fundamentals.html +++ b/qtfred/help-src/doc/fundamentals.html @@ -67,11 +67,11 @@

2. Place the ships

arrive immediately and that is fine for now.

3. Add a waypoint path for the transport

-

Select the waypoint tool in the toolbar and Ctrl+click in the viewport -to lay out a short route from the transport's position toward the Command Ship. -Three or four points is plenty. Open the -Waypoint Editor and name the path -Transport Route.

+

In the Other dropdown on the toolbar, select Waypoint, +then Ctrl+Alt+click in the viewport to lay out a short route from the +transport's position toward the Command Ship. Three or four points is plenty. Open +the Waypoint Editor and name the +path Transport Route.

Open the Ship Editor for Transport 1, go to Initial Orders, and set its initial goal to diff --git a/qtfred/help-src/doc/general/Toolbars.html b/qtfred/help-src/doc/general/Toolbars.html index 4ffec618211..6c12a7b4186 100644 --- a/qtfred/help-src/doc/general/Toolbars.html +++ b/qtfred/help-src/doc/general/Toolbars.html @@ -134,15 +134,16 @@

Tools

Object creation dropdowns

-

Two dropdowns at the right end of the toolbar control what is created when you -click in the viewport.

+

Three dropdowns at the right end of the toolbar control what is created when you +click in the viewport. Each is paired with its own modifier chord, so you can place +ships, props, and waypoints or jump nodes intermixed without switching modes.

- + @@ -150,6 +151,13 @@

Object creation dropdowns

+ + + + +
DropdownUsed byDescription
Ships Ctrl+clickSelects the ship class, waypoint, or jump node to place. The object - created on Ctrl+click is determined by this selection.Selects the ship class to place. The ship created on Ctrl+click is + determined by this selection.
Props Selects the prop class to place. The prop created on Ctrl+Shift+click is determined by this selection.
OtherCtrl+Alt+clickSelects what non-ship, non-prop object to place - Waypoint or + Jump Node. The object created on Ctrl+Alt+click is determined by this + selection.

Context Bar

diff --git a/qtfred/help-src/doc/general/Viewport.html b/qtfred/help-src/doc/general/Viewport.html index 28ce1eb5626..e0cf299a74b 100644 --- a/qtfred/help-src/doc/general/Viewport.html +++ b/qtfred/help-src/doc/general/Viewport.html @@ -12,11 +12,12 @@

Viewport

Creating objects

The toolbar dropdowns determine what type of object is created when you click in -the viewport.

+the viewport. Each dropdown is paired with its own modifier chord:

Selecting objects

diff --git a/qtfred/src/mission/Editor.cpp b/qtfred/src/mission/Editor.cpp index 87aa811a3a2..32ee0ad5a15 100644 --- a/qtfred/src/mission/Editor.cpp +++ b/qtfred/src/mission/Editor.cpp @@ -656,8 +656,6 @@ void Editor::clearMission(bool fast_reload) { } void Editor::initialSetup() { - Id_select_type_waypoint = static_cast(Ship_info.size()); - Id_select_type_jump_node = static_cast(Ship_info.size() + 1); } void Editor::setupCurrentObjectIndices(int selectedObj) { diff --git a/qtfred/src/mission/Editor.h b/qtfred/src/mission/Editor.h index 08636d1d70c..e4fca653382 100644 --- a/qtfred/src/mission/Editor.h +++ b/qtfred/src/mission/Editor.h @@ -189,9 +189,6 @@ class Editor : public QObject { */ bool autoload(); - int Id_select_type_jump_node = 0; - int Id_select_type_waypoint = 0; - // object numbers for ships in a wing. int wing_objects[MAX_WINGS][MAX_SHIPS_PER_WING]; diff --git a/qtfred/src/mission/EditorViewport.cpp b/qtfred/src/mission/EditorViewport.cpp index 5cd10840271..28a916b27e8 100644 --- a/qtfred/src/mission/EditorViewport.cpp +++ b/qtfred/src/mission/EditorViewport.cpp @@ -1094,12 +1094,12 @@ void EditorViewport::drag_rotate_save_backup() { } int EditorViewport::create_object_on_grid(int x, int y, int waypoint_instance) { - return create_object_on_grid(x, y, waypoint_instance, false); + return create_object_on_grid(x, y, waypoint_instance, CreateKind::Ship); } -int EditorViewport::create_object_on_grid(int x, int y, int waypoint_instance, bool create_prop) { +int EditorViewport::create_object_on_grid(int x, int y, int waypoint_instance, CreateKind kind) { float fallbackDist = 200.0f; - if (create_prop) { + if (kind == CreateKind::Prop) { if (cur_prop_index >= 0 && cur_prop_index < prop_info_size()) { prop_info* pip = &Prop_info[cur_prop_index]; if (pip->model_num >= 0) { @@ -1112,16 +1112,14 @@ int EditorViewport::create_object_on_grid(int x, int y, int waypoint_instance, b } } } - } else if (cur_model_index >= 0 && cur_model_index < (int)Ship_info.size() && - cur_model_index != editor->Id_select_type_waypoint && - cur_model_index != editor->Id_select_type_jump_node && + } else if (kind == CreateKind::Ship && cur_model_index >= 0 && cur_model_index < (int)Ship_info.size() && Ship_info[cur_model_index].model_num >= 0) { fallbackDist = model_get_radius(Ship_info[cur_model_index].model_num) * 1.5f; } vec3d pos = getCreatePosition(x, y, fallbackDist); editor->unmark_all(); - int obj = create_object(&pos, waypoint_instance, create_prop); + int obj = create_object(&pos, waypoint_instance, kind); if (obj >= 0) { editor->markObject(obj); @@ -1134,10 +1132,10 @@ int EditorViewport::create_object_on_grid(int x, int y, int waypoint_instance, b return obj; } -int EditorViewport::create_object(vec3d* pos, int waypoint_instance, bool create_prop) { +int EditorViewport::create_object(vec3d* pos, int waypoint_instance, CreateKind kind) { int obj, n; - if (create_prop) { + if (kind == CreateKind::Prop) { if (cur_prop_index < 0 || cur_prop_index >= prop_info_size()) { return -1; } @@ -1146,17 +1144,26 @@ int EditorViewport::create_object(vec3d* pos, int waypoint_instance, bool create if (obj == -1) { return -1; } - } else { - - if (cur_model_index == editor->Id_select_type_waypoint) { + } else if (kind == CreateKind::Other) { + switch (cur_other_kind) { + case OtherKind::Waypoint: obj = editor->create_waypoint(pos, waypoint_instance); - } else if (cur_model_index == editor->Id_select_type_jump_node) { + break; + case OtherKind::JumpNode: { CJumpNode jnp(pos); obj = jnp.GetSCPObjectNumber(); Jump_nodes.push_back(std::move(jnp)); - } else if(Ship_info[cur_model_index].flags[Ship::Info_Flags::No_fred]){ + break; + } + default: obj = -1; - } else { // creating a ship + break; + } + } else { // CreateKind::Ship + if (cur_model_index < 0 || cur_model_index >= (int)Ship_info.size() || + Ship_info[cur_model_index].flags[Ship::Info_Flags::No_fred]) { + obj = -1; + } else { obj = editor->create_ship(nullptr, pos, cur_model_index); if (obj == -1) return -1; @@ -1193,7 +1200,7 @@ int EditorViewport::createShipAtScreenPos(int x, int y, int modelIndex) { } int savedModelIndex = cur_model_index; cur_model_index = modelIndex; - int obj = create_object_on_grid(x, y, -1, false); + int obj = create_object_on_grid(x, y, -1, CreateKind::Ship); cur_model_index = savedModelIndex; return obj; } @@ -1205,29 +1212,30 @@ int EditorViewport::createPropAtScreenPos(int x, int y, int propIndex) { } int savedPropIndex = cur_prop_index; cur_prop_index = propIndex; - int obj = create_object_on_grid(x, y, -1, true); + int obj = create_object_on_grid(x, y, -1, CreateKind::Prop); cur_prop_index = savedPropIndex; return obj; } int EditorViewport::createWaypointAtScreenPos(int x, int y, int waypoint_instance) { - int savedModelIndex = cur_model_index; - cur_model_index = editor->Id_select_type_waypoint; - int obj = create_object_on_grid(x, y, waypoint_instance, false); - cur_model_index = savedModelIndex; + OtherKind savedKind = cur_other_kind; + cur_other_kind = OtherKind::Waypoint; + int obj = create_object_on_grid(x, y, waypoint_instance, CreateKind::Other); + cur_other_kind = savedKind; return obj; } int EditorViewport::createJumpNodeAtScreenPos(int x, int y) { - int savedModelIndex = cur_model_index; - cur_model_index = editor->Id_select_type_jump_node; - int obj = create_object_on_grid(x, y, -1, false); - cur_model_index = savedModelIndex; + OtherKind savedKind = cur_other_kind; + cur_other_kind = OtherKind::JumpNode; + int obj = create_object_on_grid(x, y, -1, CreateKind::Other); + cur_other_kind = savedKind; return obj; } void EditorViewport::initialSetup() { cur_model_index = get_default_player_ship_index(); + cur_other_kind = OtherKind::Waypoint; for (int i = 0; i < prop_info_size(); ++i) { if (!Prop_info[i].flags[Prop::Info_Flags::No_fred]) { cur_prop_index = i; diff --git a/qtfred/src/mission/EditorViewport.h b/qtfred/src/mission/EditorViewport.h index bd12eae0624..ec4f4cd6850 100644 --- a/qtfred/src/mission/EditorViewport.h +++ b/qtfred/src/mission/EditorViewport.h @@ -17,6 +17,17 @@ struct Marking_box { int y2 = 0; }; +enum class CreateKind { + Ship, + Prop, + Other, +}; + +enum class OtherKind { + Waypoint, + JumpNode, +}; + struct ViewSettings { bool Universal_heading = false; bool Show_stars = true; @@ -129,9 +140,9 @@ class EditorViewport { void drag_rotate_save_backup(); int create_object_on_grid(int x, int y, int waypoint_instance); - int create_object_on_grid(int x, int y, int waypoint_instance, bool create_prop); + int create_object_on_grid(int x, int y, int waypoint_instance, CreateKind kind); - int create_object(vec3d *pos, int waypoint_instance = -1, bool create_prop = false); + int create_object(vec3d *pos, int waypoint_instance = -1, CreateKind kind = CreateKind::Ship); vec3d getCreatePosition(int x, int y, float fallbackDist); int createShipAtScreenPos(int x, int y, int modelIndex); @@ -170,6 +181,7 @@ class EditorViewport { int cur_model_index = 0; int cur_prop_index = -1; + OtherKind cur_other_kind = OtherKind::Waypoint; object_orient_pos rotation_backup[MAX_OBJECTS]; diff --git a/qtfred/src/ui/FredView.cpp b/qtfred/src/ui/FredView.cpp index b4b190355e9..4aae189d081 100644 --- a/qtfred/src/ui/FredView.cpp +++ b/qtfred/src/ui/FredView.cpp @@ -187,7 +187,8 @@ void FredView::setEditor(Editor* editor, EditorViewport* viewport) { ui->toolBar->addWidget(shipsLabel); _shipClassBox = new ObjectComboBox(ui->toolBar); _shipClassBox->setFixedWidth(150); - _shipClassBox->initForShips(_viewport); + _shipClassBox->setToolTip(tr("Ctrl+click in the viewport to place")); + _shipClassBox->initForShips(); ui->toolBar->addWidget(_shipClassBox); connect(_shipClassBox, &ObjectComboBox::classSelected, this, &FredView::onShipClassSelected); @@ -196,10 +197,21 @@ void FredView::setEditor(Editor* editor, EditorViewport* viewport) { ui->toolBar->addWidget(propsLabel); _propClassBox = new ObjectComboBox(ui->toolBar); _propClassBox->setFixedWidth(150); + _propClassBox->setToolTip(tr("Ctrl+Shift+click in the viewport to place")); _propClassBox->initForProps(); ui->toolBar->addWidget(_propClassBox); connect(_propClassBox, &ObjectComboBox::classSelected, this, &FredView::onPropClassSelected); + auto otherLabel = new QLabel(tr("Other: "), ui->toolBar); + otherLabel->setContentsMargins(4, 0, 0, 0); + ui->toolBar->addWidget(otherLabel); + _otherClassBox = new ObjectComboBox(ui->toolBar); + _otherClassBox->setFixedWidth(150); + _otherClassBox->setToolTip(tr("Ctrl+Alt+click in the viewport to place")); + _otherClassBox->initForOther(); + ui->toolBar->addWidget(_otherClassBox); + connect(_otherClassBox, &ObjectComboBox::classSelected, this, &FredView::onOtherKindSelected); + initializeContextToolbar(); initializeTransformBar(); @@ -228,6 +240,7 @@ void FredView::setEditor(Editor* editor, EditorViewport* viewport) { connect(this, &FredView::viewIdle, this, &FredView::onUpdateSelectionLock); connect(this, &FredView::viewIdle, this, &FredView::onUpdateShipClassBox); connect(this, &FredView::viewIdle, this, &FredView::onUpdatePropClassBox); + connect(this, &FredView::viewIdle, this, &FredView::onUpdateOtherClassBox); connect(this, &FredView::viewIdle, this, &FredView::onUpdateEditorActions); connect(this, &FredView::viewIdle, this, &FredView::onUpdateWingActionStatus); connect(this, &FredView::viewIdle, this, &FredView::onUpdateContextToolbar); @@ -1876,7 +1889,9 @@ void FredView::initializePopupMenus() { }); _createSubmenu->addMenu(_createPropSubmenu); - auto* createWaypointAction = new QAction(tr("Waypoint"), _createSubmenu); + auto* createOtherSubmenu = new QMenu(tr("Other"), _createSubmenu); + + auto* createWaypointAction = new QAction(tr("Waypoint"), createOtherSubmenu); connect(createWaypointAction, &QAction::triggered, this, [this]() { int waypoint_instance = -1; if (fred->cur_waypoint != nullptr) { @@ -1884,13 +1899,15 @@ void FredView::initializePopupMenus() { } _viewport->createWaypointAtScreenPos(_lastContextMenuLocalPos.x(), _lastContextMenuLocalPos.y(), waypoint_instance); }); - _createSubmenu->addAction(createWaypointAction); + createOtherSubmenu->addAction(createWaypointAction); - auto* createJumpNodeAction = new QAction(tr("Jump Node"), _createSubmenu); + auto* createJumpNodeAction = new QAction(tr("Jump Node"), createOtherSubmenu); connect(createJumpNodeAction, &QAction::triggered, this, [this]() { _viewport->createJumpNodeAtScreenPos(_lastContextMenuLocalPos.x(), _lastContextMenuLocalPos.y()); }); - _createSubmenu->addAction(createJumpNodeAction); + createOtherSubmenu->addAction(createJumpNodeAction); + + _createSubmenu->addMenu(createOtherSubmenu); _viewPopup->addMenu(_createSubmenu); _viewPopup->addSeparator(); @@ -2349,12 +2366,18 @@ void FredView::onUpdatePropClassBox() { } _propClassBox->selectClass(_viewport->cur_prop_index); } +void FredView::onUpdateOtherClassBox() { + _otherClassBox->selectClass(static_cast(_viewport->cur_other_kind)); +} void FredView::onShipClassSelected(int ship_class) { _viewport->cur_model_index = ship_class; } void FredView::onPropClassSelected(int prop_class) { _viewport->cur_prop_index = prop_class; } +void FredView::onOtherKindSelected(int other_kind) { + _viewport->cur_other_kind = static_cast(other_kind); +} void FredView::on_actionAsteroid_Field_triggered(bool) { auto asteroidFieldEditor = new dialogs::AsteroidEditorDialog(this, _viewport); asteroidFieldEditor->setAttribute(Qt::WA_DeleteOnClose); diff --git a/qtfred/src/ui/FredView.h b/qtfred/src/ui/FredView.h index d6b3697c5da..f313294d068 100644 --- a/qtfred/src/ui/FredView.h +++ b/qtfred/src/ui/FredView.h @@ -277,6 +277,7 @@ class FredView: public QMainWindow, public IDialogProvider { ObjectComboBox* _shipClassBox = nullptr; ObjectComboBox* _propClassBox = nullptr; + ObjectComboBox* _otherClassBox = nullptr; Editor* fred = nullptr; EditorViewport* _viewport = nullptr; @@ -297,6 +298,7 @@ class FredView: public QMainWindow, public IDialogProvider { void onUpdateSelectionLock(); void onUpdateShipClassBox(); void onUpdatePropClassBox(); + void onUpdateOtherClassBox(); void onUpdateEditorActions(); void onUpdateWingActionStatus(); @@ -341,6 +343,7 @@ class FredView: public QMainWindow, public IDialogProvider { void onShipClassSelected(int ship_class); void onPropClassSelected(int prop_class); + void onOtherKindSelected(int other_kind); void windowActivated(); void windowDeactivated(); diff --git a/qtfred/src/ui/widgets/ObjectComboBox.cpp b/qtfred/src/ui/widgets/ObjectComboBox.cpp index b7f21b607cf..7c076978efa 100644 --- a/qtfred/src/ui/widgets/ObjectComboBox.cpp +++ b/qtfred/src/ui/widgets/ObjectComboBox.cpp @@ -22,8 +22,7 @@ ObjectComboBox::ObjectComboBox(QWidget* parent) : QComboBox(parent) { &ObjectComboBox::indexChanged); } -void ObjectComboBox::initForShips(EditorViewport* viewport) { - _viewport = viewport; +void ObjectComboBox::initForShips() { fredApp->runAfterInit([this]() { buildShipsModel(); }); @@ -35,6 +34,12 @@ void ObjectComboBox::initForProps() { }); } +void ObjectComboBox::initForOther() { + fredApp->runAfterInit([this]() { + buildOtherModel(); + }); +} + void ObjectComboBox::buildShipsModel() { auto model = new QStandardItemModel(); @@ -50,16 +55,18 @@ void ObjectComboBox::buildShipsModel() { model->appendRow(item); } - auto separator = new QStandardItem(); - separator->setData("separator", Qt::AccessibleDescriptionRole); - model->appendRow(separator); + setModel(model); +} + +void ObjectComboBox::buildOtherModel() { + auto model = new QStandardItemModel(); auto waypoint = new QStandardItem("Waypoint"); - waypoint->setData(_viewport->editor->Id_select_type_waypoint, Qt::UserRole); + waypoint->setData(static_cast(OtherKind::Waypoint), Qt::UserRole); model->appendRow(waypoint); auto jumpNode = new QStandardItem("Jump Node"); - jumpNode->setData(_viewport->editor->Id_select_type_jump_node, Qt::UserRole); + jumpNode->setData(static_cast(OtherKind::JumpNode), Qt::UserRole); model->appendRow(jumpNode); setModel(model); diff --git a/qtfred/src/ui/widgets/ObjectComboBox.h b/qtfred/src/ui/widgets/ObjectComboBox.h index f1f67a8a5d5..21e286ab40c 100644 --- a/qtfred/src/ui/widgets/ObjectComboBox.h +++ b/qtfred/src/ui/widgets/ObjectComboBox.h @@ -10,13 +10,12 @@ namespace fso::fred { class ObjectComboBox : public QComboBox { Q_OBJECT - EditorViewport* _viewport = nullptr; - public: explicit ObjectComboBox(QWidget* parent = nullptr); - void initForShips(EditorViewport* viewport); + void initForShips(); void initForProps(); + void initForOther(); void selectClass(int class_index); @@ -26,6 +25,7 @@ class ObjectComboBox : public QComboBox { private: void buildShipsModel(); void buildPropsModel(); + void buildOtherModel(); void indexChanged(int index); }; diff --git a/qtfred/src/ui/widgets/renderwidget.cpp b/qtfred/src/ui/widgets/renderwidget.cpp index 481993bb91f..7cc6cc8752e 100644 --- a/qtfred/src/ui/widgets/renderwidget.cpp +++ b/qtfred/src/ui/widgets/renderwidget.cpp @@ -229,8 +229,15 @@ void RenderWidget::mousePressEvent(QMouseEvent* event) { if (event->modifiers().testFlag(Qt::ControlModifier)) { // add a new object if (_viewport->on_object == -1) { _viewport->Selection_lock = false; // force off selection lock - auto spawn_prop = event->modifiers().testFlag(Qt::ShiftModifier); - _viewport->on_object = _viewport->create_object_on_grid(event->x(), event->y(), waypoint_instance, spawn_prop); + const bool shift = event->modifiers().testFlag(Qt::ShiftModifier); + const bool alt = event->modifiers().testFlag(Qt::AltModifier); + auto kind = CreateKind::Ship; + if (alt && !shift) { + kind = CreateKind::Other; + } else if (shift && !alt) { + kind = CreateKind::Prop; + } + _viewport->on_object = _viewport->create_object_on_grid(event->x(), event->y(), waypoint_instance, kind); } else { _viewport->Dup_drag = 1;