Skip to content

P4: qtFRED: rotate around the centre of a multi-selection - #7843

Open
dustinspace217 wants to merge 8 commits into
scp-fs2open:masterfrom
dustinspace217:qtfred/orbit-selection
Open

dustinspace217 wants to merge 8 commits into
scp-fs2open:masterfrom
dustinspace217:qtfred/orbit-selection

Conversation

@dustinspace217

Copy link
Copy Markdown
Contributor

What?

qtFRED's Rotate Around Object (Alt+R) and the orbit-drag camera now pivot on the centre of the selection when more than one object is marked. Fixes #7724.

Why?

With several ships selected, the camera still circled whichever one happened to be the current object, so looking over a formation or a convoy meant picking one ship and losing the others off the edge. The request asked for exactly this: reuse the single-object rotation with a different centre point.

How?

A new EditorViewport::selectionCenter() returns the centroid of the marked objects on the object list when more than one is marked, and the given object's position otherwise. The three places that chose the pivot now call it: the look-at camera update, orbitCameraGetPivot(), and the Alt+R handler that turns the camera toward the target when the mode is switched on. Because orbitCameraGetPivot() also serves middle-mouse orbit and wheel zoom in normal mode, those pivot on the selection centre as well. Every marked type counts at full weight, waypoints and jump nodes included, so the pivot is the centre of what you selected rather than of the ships alone. With a single object marked the result is the object's own position, so nothing changes there. The marked-object walk is the same pattern the view already uses to show a selection's bounding radius, and an assertion checks that the walked count matches the editor's marked count.

Screenshots?

The view after marquee-selecting 28 ships and 4 waypoints and pressing Alt+R, on master and on this branch, in the PR comments below.

Testing?

  • Linux, GCC 16, Qt 6.11, Release: builds with 0 warnings.
  • Headless qtFRED on a virtual display with a retail mission, driven by synthetic input and checked by saving the mission and reading the camera back from +Viewer pos / +Viewer orient: after marquee-selecting 28 ships and 4 waypoints and pressing Alt+R, the camera's forward axis points at the selection centroid (0.00 degrees off; 11.7 degrees off the current object, so the old behaviour would have failed this). After a middle-mouse drag the camera moved but its distance to the centroid stayed the same to a tenth of a unit, so the orbit pivot is the centroid too. Deleting the marked set with look-at on leaves the editor running. With one ship selected (picked from the Scene Browser) the old and new builds save identical cameras after Alt+R, both aimed exactly at that ship.
  • When you add or remove objects from the selection with look-at on, the camera re-aims once at the new centre, the same way it already jumped when the current object changed. Group-rotate moves the centre, so the camera follows it.
  • Not tested: FRED2 (the MFC editor) still rotates around the current object only; I can port the same helper there if you want parity.

Anything Else?

I used Claude Code to trace the camera code and to write the change.

Rotate Around Object (Alt+R) and the orbit pivot both used the current
object's position, so with several ships marked the camera still
circled whichever one happened to be current. Add
EditorViewport::selectionCenter(), which returns the centroid of the
marked objects when more than one is marked and the given object's
position otherwise, and use it at the three places that chose the
point: the look-at camera update, orbitCameraGetPivot(), and the Alt+R
handler that turns the camera toward the target when the mode is
switched on.

orbitCameraGetPivot() also serves middle-mouse orbit and wheel zoom in
normal mode, so those pivot on the selection centre as well. Every
marked type counts at full weight, including waypoints and jump nodes.
With a single object marked nothing changes.

Fixes scp-fs2open#7724
@dustinspace217

Copy link
Copy Markdown
Contributor Author

After marquee-selecting 28 ships and 4 waypoints and pressing Alt+R, on master and on this branch. Master turns toward the current object; this branch turns toward the centre of the selection.

Alt+R with a multi-selection on master and on this branch

@TheForce172 TheForce172 added enhancement A new feature or upgrade of an existing feature to add additional functionality. qtfred A feature or issue related to qtFred. labels Oct 11, 2026
It only reads the marked-object list and the editor's marked count;
clang-tidy (readability-make-member-function-const) flagged it in CI.

@Goober5000 Goober5000 left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a useful change. Since FRED has the same feature, this functionality should be mirrored to FRED too; the two editors should be kept in sync when they have the same feature.

Claude also had this observation which is worth testing:

Group-rotate pivot doesn't match. With look-at on and Group_rotate, game_do_frame rotates the marked objects around the leader (currentObject), while the camera now orbits the centroid. This works, but the camera chases a moving centre during the rotation. It's worth a quick try in-editor to see whether it feels odd. It may be acceptable.

Plus inline notes on Claude's characteristic verbosity.

Comment thread qtfred/src/mission/EditorViewport.cpp Outdated
Comment thread qtfred/src/mission/EditorViewport.cpp Outdated
@github-project-automation github-project-automation Bot moved this from Work In Progress (PRs) to In Review (PRs) in qtFRED2 Oct 12, 2026
@dustinspace217

Copy link
Copy Markdown
Contributor Author

Working on adding parity now. Apologies for the comments - I normally add a rule about that when contributing to outside repos. Forgot when setting this project up. Fix incoming.

FRED gets the same selection_center() as qtFRED's selectionCenter(),
used at the same three places: the look-at camera update, the orbit
pivot, and the Rotate Around Object toggle. Also removes the qtFRED
comments flagged in review.
@dustinspace217

Copy link
Copy Markdown
Contributor Author

Thanks for the review. I've pushed a second commit:

  • FRED now has the same selection_center() as qtFRED and uses it in the same three places: the look-at camera update, the orbit pivot, and Rotate Around Object. I can only build on Linux, so the FRED side has had a syntax check against the engine headers and will get CI's Windows build, but I haven't been able to run it. A quick try in FRED would be welcome.
  • Removed the comments you flagged, along with the other explanatory ones.

On group rotate, I tried it in qtFRED: several ships selected, look-at on, Control Object, then a held yaw key. On master the camera stays put, aimed at the leader, and the group swings around it. With this change the camera keeps its angle but slides sideways to keep the centre of the selection in view, so the group turns in place on screen while the leader moves across it. How far it slides depends on how far the centre is from the leader: about 7 km in this test, where the selection spans most of the mission.

I also tried having look-at follow the current object while in Control Object mode. The camera then holds still during the rotation, but it jumps when you enter Control Object (about 2.8 km here, from the centre to the leader) and again when you leave it (about 5 km, back to the new centre). That seemed worse than the slide, so I left it out, but I can add it, or a version that holds the look-at point fixed during the rotation, if you'd prefer.

Group rotate with look-at on, master (top) and this branch (bottom)

@Goober5000 Goober5000 left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested FRED on Windows. It worked pretty much as expected, but I have some new comments.

  • Using the multi-selection center, rather than the primary selected object's position (both for look-at and orbit), was odd and counterintuitive. Since that's the entire point of the PR, tie it to a menu option (in FRED) or a preference selection (in QtFRED) with the default being the original behavior.
  • The view_universe function (in both editors) uses the bounding box midpoint, while this PR uses the average position. This PR should use the bounding box midpoint as well.
  • The view_universe function, this PR, and the selection bounding radius in QtFRED's onUpdateTransformBar could all delegate to the same utility function. (Put it in code\missioneditor and have it return both the position and radius.)

Look-at and orbit use the current object again unless the new option is
on (qtFRED: Preferences > Controls; FRED: View menu), and the selection
center is now the bounding-box midpoint. view_universe in both editors,
the pivot, and qtFRED's selection radius all use get_object_bounds() in
missioneditor/common.
Wheel zoom reuses the orbit pivot until the camera moves, so without this
the option only took effect for scrolling after the next camera move.
@dustinspace217

Copy link
Copy Markdown
Contributor Author

Thanks for testing it in FRED. I've pushed two commits:

  • The selection center is now opt-in and off by default, so look-at and orbit use the primary object again unless you turn it on: Preferences > Controls > "Look at and orbit around the center of a multi-selection" in qtFRED, and View > "Look At and Orbit Around Selection Center" in FRED.
  • It uses the bounding-box midpoint. get_object_bounds() in missioneditor/common returns the midpoint and radius, and view_universe in both editors, the pivot, and qtFRED's transform-bar radius all use it.
  • Changing the option also resets the cached orbit pivot, so scrolling picks it up straight away.

Two side effects to be aware of: the qtFRED transform-bar radius for a multi-selection now measures from the box midpoint for everyone, and Zoom Extents on a mission with no objects at all now leaves the camera alone instead of moving it.

In qtFRED, with the option off, Alt+R, Zoom Selected and Zoom Extents put the camera in the same place as master; with it on, Alt+R aims at the selection's box midpoint. There's a unit test for get_object_bounds. On the FRED side I syntax-checked the two changed functions, but I can't build or run FRED here, so the menu item hasn't been tried.

@Goober5000 Goober5000 left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, and works well in FRED. I tested with the option on and off, using both Classic and non-Classic menu layouts.

Since this affects the editor behavior, I'd recommend moving the option to Misc (Classic) or Settings (non-Classic), under the "Move Ships When Undocking" option. In both cases, it should have hover help text.

I'd also recommend calling it "Rotate Around Selection Centroid", because "Center" could be mistaken for the center of the selected (marked) ship, and "Look At" isn't a term that's used in the UI.

For iterating over obj_used_list, you could use a for-each pattern with list_range, but that's optional.

Claude pointed out that the unit test would break if objects are used in any other test, and recommended this change:

Call obj_init() in SetUp and TearDown instead of list_init(&obj_used_list), and in add() call list_remove(&obj_free_list, objp) before the list_append. The test then leaves the object system in a valid state whatever runs before or after it.

Claude also pointed out that setOrbitSelectionCenter() resets the orbit state even when nothing changed, and recommended this modified version:

void setOrbitSelectionCenter(bool enabled)
{
	if (_orbitSelectionCenter != enabled) {
		_orbitSelectionCenter = enabled;
		_orbitActive = false;
	}
}

- FRED: the option moves from the View menu to Settings (and Misc in the
  classic layout), under Move Ships When Undocking, with hover help, and is
  renamed Rotate Around Selection Centroid.
- qtFRED: the checkbox moves next to Move Ships When Undocking in the
  preferences dialog, with the same name.
- setOrbitSelectionCenter only resets the orbit when the value changes.
- get_object_bounds iterates with list_range.
- The bounds test resets the object system with obj_init and takes objects
  off the free list, so it leaves a valid state for other tests.
@dustinspace217

Copy link
Copy Markdown
Contributor Author

Thanks for testing both layouts. I've pushed 7a11dd9 with your suggestions:

  • Renamed the option to Rotate Around Selection Centroid and moved it under Move Ships When Undocking, in Settings and in Misc for the Classic layout, with hover help.
  • qtFRED's checkbox sits next to Move Ships When Undocking in Preferences, with the same name and tooltip.
  • setOrbitSelectionCenter only resets the orbit when the value changes.
  • get_object_bounds iterates with list_range.
  • The bounds test calls obj_init() and takes its objects off the free list, so it leaves the object system valid for other tests.

I can't build FRED here, so the Windows CI builds are its compile check.

@Goober5000 Goober5000 left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks excellent, and FRED testing looks good. I have a few more tweaks:

  • Call it Midpoint instead of Centroid. Claude suggested that, which avoids both the "Center" and "Centroid" nits.

  • The following still use the old wording:
    ** Orbit_selection_center and the ini key "Orbit selection center" in FRED2
    ** _orbitSelectionCenter and camera_orbit_selection_center in qtFRED

  • In QtFRED, I actually think the Controls tab is a better fit, not the General tab. It should be below the Mouse Orbit Camera group though, not within the group.

@MjnMixael

Copy link
Copy Markdown
Contributor

QtFred help docs must be updated to explain the feature

@dustinspace217

Copy link
Copy Markdown
Contributor Author

Thanks. Pushed 10bd191:

  • Everything is Midpoint now: the FRED menu item, its ini key ("Orbit selection midpoint"), Orbit_selection_midpoint, the qtFRED setting key camera_orbit_selection_midpoint, _orbitSelectionMidpoint, and the two helpers (selection_midpoint() in FRED, selectionMidpoint() in qtFRED).
  • The qtFRED checkbox moved to Preferences > Controls, below the Mouse Orbit Camera group.
  • The help topics for Preferences and Viewport now describe the option.

As before, FRED is syntax-checked here and compiled by the Windows CI jobs.

@Goober5000 Goober5000 left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One bug and one nit:

Bug: two General-tab preferences now overlap

In QtFRED, in the Appearance group on the General tab, the last commit moved "Viewport label size" (labelFontScaleLabel / labelFontScaleSpin) from row 4 to row 3. Row 3 already holds dataMenuStyleLabel / dataMenuStyleCombo. Both pairs now share the same grid cells, so Qt draws them on top of each other, and row 4 is empty.

The checkbox was never in this group, so this looks like the renumbering from removing it out of the Settings group was also applied to the Appearance grid by mistake. To fix it, change those two row="3" entries back to row="4" (around line 159 of qtfred/ui/PreferencesDialog.ui). The Settings group's own renumbering is correct.

Screenshot for illustration:
Image

Comment thread qtfred/src/mission/EditorViewport.cpp Outdated
settings.setValue("view_label_font_scale", view.Label_font_scale);
settings.setValue("camera_invert_orbit_x", camera.getInvertOrbitX());
settings.setValue("camera_invert_orbit_y", camera.getInvertOrbitY());
settings.setValue("camera_orbit_selection_midpoint", camera.getOrbitSelectionMidpoint());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pedantic: camera.getOrbitSelectionMidpoint()); no longer lines up

@dustinspace217

Copy link
Copy Markdown
Contributor Author

Well, that's embarrassing... moving too fast and getting sloppy, apoligies. Will fix tonight.

…ings line

The last commit renumbered the Viewport label size row of the Appearance
group from 4 to 3, which is the Long list menu style row, so the label
size pair fell out of the layout and its spin box drew over the group
title. Put it back at row 4.
@dustinspace217

Copy link
Copy Markdown
Contributor Author

Fixed in 1fe7f97: the Viewport label size rows are back at row 4, and the settings line in EditorViewport.cpp is realigned. I also checked every qtFRED .ui file for other overlapping rows and found none.

@BMagnu BMagnu added the LLM-authored For PR's mainly created through LLMs and NOT submitted by badged developers label Oct 19, 2026
@dustinspace217 dustinspace217 changed the title qtFRED: rotate around the centre of a multi-selection P4: qtFRED: rotate around the centre of a multi-selection Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement A new feature or upgrade of an existing feature to add additional functionality. LLM-authored For PR's mainly created through LLMs and NOT submitted by badged developers qtfred A feature or issue related to qtFred.

Projects

Status: In Review (PRs)

Development

Successfully merging this pull request may close these issues.

qtFred feature request: Rotate around multiple ships.

5 participants