* qtFRED: rotate around the centre of a multi-selection
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#7724
* Make EditorViewport::selectionCenter const
It only reads the marked-object list and the editor's marked count;
clang-tidy (readability-make-member-function-const) flagged it in CI.
* Mirror the multi-selection orbit pivot to FRED, trim comments
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.
* Make the selection-center pivot optional and share object bounds
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.
* Reset the cached orbit pivot when the selection-center option changes
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.
* Address review: move and rename the selection-centroid option
- 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.
* Rename the option to Selection Midpoint, move it to qtFRED's Controls tab, and document it
* Fix overlapping Appearance rows in qtFRED Preferences, realign a settings 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.
---------
Co-authored-by: Dustinspace217 <[email protected]>
Add generate_ship_usage_list_team alongside the weaponry twin that already existed in missioneditor/common, so both loadout editors can drop their TVT/non-TVT branches and simply iterate Num_teams.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Neither editor had a teardown to match FSO's game_shutdown(), so the engine
data they set up was never freed. Add editor_free_engine_data() to free it,
and call it from a new fred_shutdown() in FRED and from qtFRED's shutdown(),
before the graphics system closes.
Also:
- Delete FRED's modeless editors if they are still open at exit.
- Make FRED's dialog tooltips and sexp tree image lists members, since
they were leaked or depended on OnDestroy() being called.
- Parent qtFRED's item models so they are deleted with their widgets.
- Enable the CRT leak report in qtFRED, which previously had none.
- In qtFRED, call shutdown() last in closeEvent(), since it destroys the
window.
- Make the preferences path and user SID strings function-level statics,
so MFC's leak dump no longer reports them as leaks.
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
FRED2, qtFRED, and the shared mission save code each carried their own copy of the loadout usage builders. The weaponry pair already had shared versions in missioneditor/common; this converts those to the SCP_map<int,int> signature the editors now use, adds the missing ship builder alongside them, and deletes both editors' private copies.
FRED2's playerstarteditor/freddoc and qtFRED's Editor/ErrorChecker all call the shared functions now, following the update_custom_wing_indexes consolidation precedent. missionsave's used_pool becomes a map as well, which removes its MAX_WEAPON_TYPES stack array.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
The sexp tree refactor (#7301) moved the OPF listing logic into a shared
model that asks the editor for campaign-aware lists via virtual methods
on SexpTreeEditorInterface. QtFRED's campaign editor got the necessary
overrides, but FRED2's never did, so its OPF_MISSION_NAME /
OPF_GOAL_NAME / OPF_EVENT_NAME dropdowns fell back to the currently
loaded mission's data instead of the campaign's.
Backport the overrides to FRED2, restoring its pre-refactor behavior
(including listing only missions at earlier campaign levels), and hoist
QtFRED's loadAndFindCampaignMission helper into missioneditor/common so
both editors share one copy.
Co-Authored-By: Claude Fable 5 <[email protected]>
The ship editor, wing editor, waypoint path dialog, and jump node
dialog all had near-identical code to check whether a new name
conflicts with an existing ship, wing, waypoint path, jump node, or
target priority group (or is empty, or begins with '<'). Both FRED2
and qtFRED carried their own copies of this logic.
Extract it into a single check_name_conflict() function in
code/missioneditor/common.cpp, shared by both editors, and replace the
duplicated validation at each call site with a one-line call:
- FRED2: shipeditordlg, wing_editor, waypointpathdlg, jumpnodedlg
- qtFRED: ShipEditorDialogModel, WaypointEditorDialogModel,
JumpNodeEditorDialogModel, and Editor::validate_wing_name
This also aligns a few small behavioral differences that had crept in
between the two editors: the waypoint and jump node dialogs now skip
empty wing slots (wave_count == 0) when checking for wing-name
collisions, and the qtFRED wing editor now rejects names beginning
with '<'.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
reassign_wing_slot moves a wing between Wings[] slots, fixing up every
back-reference: Ships[i].wingnum, the Starting/Squadron/TVT_wings caches
(via update_custom_wing_indexes), the FRED-side parallel array
wing_objects, and cur_wing (passed via FredWingSlotConfig so non-FRED
callers can opt out). swap_wing_slots wraps it as a three-leg swap
through a temporary empty slot.
Also consolidates update_custom_wing_indexes (previously duplicated
verbatim in fred2/management.cpp and qtfred Editor) into common.cpp so
the new utility — and any future caller — has one shared implementation.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
reassign_ship_slot moves a ship between Ships[] slots, fixing up every
back-reference: Objects[].instance, Ai_info[].shipnum, Wings[].ship_index[],
Player_start_shipnum, Ship_registry's cached shipnum, and the FRED-side
parallel arrays Fred_alt_names/Fred_callsigns plus cur_ship (passed via
FredShipSlotConfig so non-FRED callers can opt out). swap_ship_slots
wraps it as a three-leg swap through a temporary empty slot.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
In single-player missions, the "Set as Player Ship" button is supposed to make
the selected ship the one and only player start. FRED did this correctly, but
qtFRED routed the button through the same setPlayer() toggle used by the
multiplayer "Player Ship" checkbox, which only promoted the selected ship and
never demoted the previous player start. Since the checkbox is disabled in
single player, there was no way to demote the old start, so single-player
missions could accumulate multiple player starts.
Consolidate the exclusive logic into a shared helper,
set_single_player_start() in missioneditor/common.cpp, and call it from both
FRED's OnSetAsPlayerShip() and a new qtFRED model method,
makeSolePlayerStart(), which the button now uses. This also avoids
setPlayer()'s early return on stale dialog state, which could cause the button
to silently do nothing.
Follow-up to #7600.
Co-authored-by: Claude Fable 5 <[email protected]>
If a player ship is changed to a regular ship, be sure that
Player_start_shipnum does not still point to the old ship.
Consolidate the several near-duplicate copies of the "repoint
Player_start_shipnum to a valid player start" logic, in both FRED and
qtFRED, into a single shared helper, ensure_valid_player_start_shipnum()
in missioneditor/common.cpp.
Also add some guards in situations where Player_start_shipnum might
be -1.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
* set line edit fields to max length in code
* fix some dialog window titles
* remove unused context help button on Windows
* address some easy todo items
* static access
Testing in FotG exposed a bug that dates back to retail. During mission parsing, arrival and departure anchors were represented by indexes into `Parse_names`. After parsing, they were converted to ship indexes -- but only in FRED. Since some functions are shared between FRED and FS2, this can produce inconsistent results, which can be hard to detect since parse indexes and ship indexes are usually the same.
This refactors arrival and departure anchors to be represented by ship registry indexes in all cases. It also adds conversion functions for the benefit of FRED and QtFRED since those dialogs were designed with ship indexes in mind.
* Generalize mission save from original FRED
* make qtfred use the new generalized missionsave
* split campaign save into a sister class
* allow unlimited campaign description length to be saved
* have the campaign editor pass the links to save properly
* cleanup
* future todo
* fixes
* more fixes
* cleanup vars
* clang
* add missing guardian threshold and fix var name
* more clang
* conflict resolution error
* update qtfred to use the new campaign save