Skip to content

Commit 4084c75

Browse files
authored
Qtfred Dockable object list (#7368)
* qtfred dockable objects list * fix jumpnode rendering * more ouline panel features * fix for wings * remember list expansions * clean up wing selection and layer handling * disable top and bottom docking * give scene outliner some padding * replace old selection dialog with the scene browser * fix some minor issues * right click for wings and waypoint paths * clang * clang again * fix status bar message * 25 1 checks * clang * more clang * address feedback
1 parent 2894ddb commit 4084c75

25 files changed

Lines changed: 1650 additions & 886 deletions

code/jumpnode/jumpnode.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,14 @@ CJumpNode::CJumpNode(const vec3d* position)
7171
}
7272

7373
CJumpNode::CJumpNode(CJumpNode&& other) noexcept
74-
: m_radius(other.m_radius), m_modelnum(other.m_modelnum), m_objnum(other.m_objnum), m_polymodel_instance_num(other.m_polymodel_instance_num), m_flags(other.m_flags)
74+
: m_radius(other.m_radius), m_modelnum(other.m_modelnum), m_objnum(other.m_objnum), m_polymodel_instance_num(other.m_polymodel_instance_num), m_flags(other.m_flags), m_fred_layer(std::move(other.m_fred_layer))
7575
{
7676
other.m_radius = 0.0f;
7777
other.m_modelnum = -1;
7878
other.m_objnum = -1;
7979
other.m_polymodel_instance_num = -1;
8080
other.m_flags = 0;
81+
other.m_fred_layer = "Default";
8182

8283
m_display_color = other.m_display_color;
8384
m_pos = other.m_pos;
@@ -95,12 +96,14 @@ CJumpNode& CJumpNode::operator=(CJumpNode&& other) noexcept
9596
m_objnum = other.m_objnum;
9697
m_flags = other.m_flags;
9798
m_polymodel_instance_num = other.m_polymodel_instance_num;
99+
m_fred_layer = std::move(other.m_fred_layer);
98100

99101
other.m_radius = 0.0f;
100102
other.m_modelnum = -1;
101103
other.m_objnum = -1;
102104
other.m_flags = 0;
103105
other.m_polymodel_instance_num = -1;
106+
other.m_fred_layer = "Default";
104107

105108
m_display_color = other.m_display_color;
106109
m_pos = other.m_pos;

code/jumpnode/jumpnode.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <cstdlib>
1616

1717
#include "globalincs/globals.h"
18+
#include "globalincs/pstypes.h"
1819
#include "graphics/2d.h"
1920

2021
struct vec3d;
@@ -45,6 +46,7 @@ class CJumpNode
4546
int m_flags {0};
4647
color m_display_color; // Color node will be shown in (Default:0/255/0/255)
4748
vec3d m_pos;
49+
SCP_string m_fred_layer = "Default"; // FRED view layer assignment
4850

4951
CJumpNode(const CJumpNode&);
5052
CJumpNode& operator=(const CJumpNode&) = delete;
@@ -76,6 +78,10 @@ class CJumpNode
7678
void SetDisplayName(const char* new_name);
7779
void SetVisibility(bool enabled);
7880

81+
//Getting/Setting FRED layer
82+
const SCP_string& GetFredLayer() const { return m_fred_layer; }
83+
void SetFredLayer(const SCP_string& layer) { m_fred_layer = layer; }
84+
7985
//Query
8086
bool IsHidden() const;
8187
bool IsColored() const;

code/mission/missionparse.cpp

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5850,20 +5850,33 @@ void parse_waypoint_list(mission *pm)
58505850
stuff_int(&cb);
58515851
}
58525852

5853+
SCP_string wpt_fred_layer = "Default";
5854+
if (optional_string("+Layer:")) {
5855+
stuff_string(wpt_fred_layer, F_NAME);
5856+
if (!mission_has_layer_name(&The_mission, wpt_fred_layer)) {
5857+
if (wpt_fred_layer.empty()) {
5858+
wpt_fred_layer = "Default";
5859+
} else {
5860+
The_mission.fred_layers.push_back(wpt_fred_layer);
5861+
}
5862+
}
5863+
}
5864+
58535865
SCP_vector<vec3d> vec_list;
58545866
required_string("$List:");
58555867
stuff_vec3d_list(vec_list);
58565868

58575869
waypoint_add_list(name_buf, vec_list);
58585870

58595871
// Apply display properties to the list just added
5860-
if (no_draw_lines || has_custom_color) {
5861-
waypoint_list* wl = find_matching_waypoint_list(name_buf);
5862-
if (wl) {
5872+
waypoint_list* wl = find_matching_waypoint_list(name_buf);
5873+
if (wl) {
5874+
if (no_draw_lines || has_custom_color) {
58635875
wl->set_no_draw_lines(no_draw_lines);
58645876
if (has_custom_color)
58655877
wl->set_color(cr, cg, cb);
58665878
}
5879+
wl->set_fred_layer(wpt_fred_layer);
58675880
}
58685881
}
58695882

@@ -5911,6 +5924,19 @@ void parse_waypoints_and_jumpnodes(mission *pm)
59115924
jnp.SetVisibility(!hide);
59125925
}
59135926

5927+
if (optional_string("+Layer:")) {
5928+
SCP_string layer_name;
5929+
stuff_string(layer_name, F_NAME);
5930+
if (!mission_has_layer_name(&The_mission, layer_name)) {
5931+
if (layer_name.empty()) {
5932+
layer_name = "Default";
5933+
} else {
5934+
The_mission.fred_layers.push_back(layer_name);
5935+
}
5936+
}
5937+
jnp.SetFredLayer(layer_name);
5938+
}
5939+
59145940
Jump_nodes.push_back(std::move(jnp));
59155941
}
59165942

@@ -9519,5 +9545,29 @@ bool check_for_24_3_data()
95199545

95209546
bool check_for_25_1_data()
95219547
{
9522-
return (count_items_with_value(Props) > 0);
9548+
if (count_items_with_value(Props) > 0)
9549+
return true;
9550+
9551+
constexpr auto defaultLayer = "Default";
9552+
9553+
for (const auto& so : list_range(&Ship_obj_list))
9554+
{
9555+
auto shipp = &Ships[Objects[so->objnum].instance];
9556+
if (!shipp->fred_layer.empty() && !lcase_equal(shipp->fred_layer, defaultLayer))
9557+
return true;
9558+
}
9559+
9560+
for (const auto& wl : Waypoint_lists)
9561+
{
9562+
if (wl.get_no_draw_lines() || wl.get_has_custom_color())
9563+
return true;
9564+
const auto& layer = wl.get_fred_layer();
9565+
if (!layer.empty() && !lcase_equal(layer, defaultLayer))
9566+
return true;
9567+
}
9568+
9569+
return std::any_of(Jump_nodes.begin(), Jump_nodes.end(), [defaultLayer](const auto& jn) {
9570+
const auto& layer = jn.GetFredLayer();
9571+
return !layer.empty() && !lcase_equal(layer, defaultLayer);
9572+
});
95239573
}

code/missioneditor/missionsave.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4099,7 +4099,7 @@ int Fred_mission_save::save_objects()
40994099

41004100
if (save_config.save_format != MissionFormat::RETAIL &&
41014101
!shipp->fred_layer.empty() &&
4102-
stricmp(shipp->fred_layer.c_str(), "Default") != 0) {
4102+
!lcase_equal(shipp->fred_layer, "Default")) {
41034103
if (optional_string_fred("+Layer:", "$Name:"))
41044104
parse_comments();
41054105
else
@@ -4855,6 +4855,15 @@ int Fred_mission_save::save_waypoints()
48554855
else
48564856
fout(" %s", "false");
48574857
}
4858+
4859+
const SCP_string& jn_layer = jnp->GetFredLayer();
4860+
if (!jn_layer.empty() && !lcase_equal(jn_layer, "Default")) {
4861+
if (optional_string_fred("+Layer:", "$Jump Node:"))
4862+
parse_comments();
4863+
else
4864+
fout("\n+Layer:");
4865+
fout(" %s", jn_layer.c_str());
4866+
}
48584867
}
48594868

48604869
fso_comment_pop();
@@ -4886,6 +4895,15 @@ int Fred_mission_save::save_waypoints()
48864895
}
48874896
fout(" %d %d %d", ii.get_color_r(), ii.get_color_g(), ii.get_color_b());
48884897
}
4898+
4899+
const SCP_string& wpt_layer = ii.get_fred_layer();
4900+
if (!wpt_layer.empty() && !lcase_equal(wpt_layer, "Default")) {
4901+
if (optional_string_fred("+Layer:", "$List:"))
4902+
parse_comments();
4903+
else
4904+
fout("\n+Layer:");
4905+
fout(" %s", wpt_layer.c_str());
4906+
}
48894907
}
48904908

48914909
required_string_fred("$List:");
@@ -5233,7 +5251,7 @@ int Fred_mission_save::save_props()
52335251

52345252
if (save_config.save_format != MissionFormat::RETAIL &&
52355253
!p->fred_layer.empty() &&
5236-
stricmp(p->fred_layer.c_str(), "Default") != 0) {
5254+
!lcase_equal(p->fred_layer, "Default")) {
52375255
if (optional_string_fred("+Layer:", "$Name:"))
52385256
parse_comments();
52395257
else

code/object/waypoint.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,20 +49,23 @@ class waypoint_list
4949
void set_no_draw_lines(bool val);
5050
void set_color(int r, int g, int b);
5151
void clear_color();
52+
void set_fred_layer(const SCP_string& layer) { m_fred_layer = layer; }
5253

5354
// display property accessors
5455
bool get_no_draw_lines() const;
5556
bool get_has_custom_color() const;
5657
int get_color_r() const;
5758
int get_color_g() const;
5859
int get_color_b() const;
60+
const SCP_string& get_fred_layer() const { return m_fred_layer; }
5961

6062
private:
6163
char m_name[NAME_LENGTH];
6264
SCP_vector<waypoint> m_waypoints;
6365
bool m_no_draw_lines;
6466
bool m_has_custom_color;
6567
int m_color_r, m_color_g, m_color_b;
68+
SCP_string m_fred_layer = "Default"; // FRED view layer assignment
6669
};
6770

6871
//********************GLOBALS********************

qtfred/source_groups.cmake

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ add_file_folder("Source/Mission"
3838
add_file_folder("Source/Mission/Dialogs"
3939
src/mission/dialogs/AbstractDialogModel.cpp
4040
src/mission/dialogs/AbstractDialogModel.h
41+
src/mission/dialogs/SceneBrowserModel.cpp
42+
src/mission/dialogs/SceneBrowserModel.h
4143
src/mission/dialogs/AboutDialogModel.cpp
4244
src/mission/dialogs/AboutDialogModel.h
4345
src/mission/dialogs/AsteroidEditorDialogModel.cpp
@@ -84,8 +86,6 @@ add_file_folder("Source/Mission/Dialogs"
8486
src/mission/dialogs/ReinforcementsEditorDialogModel.h
8587
src/mission/dialogs/RelativeCoordinatesDialogModel.cpp
8688
src/mission/dialogs/RelativeCoordinatesDialogModel.h
87-
src/mission/dialogs/SelectionDialogModel.cpp
88-
src/mission/dialogs/SelectionDialogModel.h
8989
src/mission/dialogs/ShieldSystemDialogModel.cpp
9090
src/mission/dialogs/ShieldSystemDialogModel.h
9191
src/mission/dialogs/TeamLoadoutDialogModel.cpp
@@ -196,8 +196,6 @@ add_file_folder("Source/UI/Dialogs"
196196
src/ui/dialogs/RelativeCoordinatesDialog.h
197197
src/ui/dialogs/SaveAsTemplateDialog.cpp
198198
src/ui/dialogs/SaveAsTemplateDialog.h
199-
src/ui/dialogs/SelectionDialog.cpp
200-
src/ui/dialogs/SelectionDialog.h
201199
src/ui/dialogs/ShieldSystemDialog.h
202200
src/ui/dialogs/ShieldSystemDialog.cpp
203201
src/ui/dialogs/TableViewerDialog.cpp
@@ -270,6 +268,13 @@ add_file_folder("Source/UI/General"
270268
src/ui/dialogs/General/ImagePickerDialog.h
271269
)
272270

271+
add_file_folder("Source/UI/Panels"
272+
src/ui/panels/FlowLayout.cpp
273+
src/ui/panels/FlowLayout.h
274+
src/ui/panels/SceneBrowserPanel.cpp
275+
src/ui/panels/SceneBrowserPanel.h
276+
)
277+
273278
add_file_folder("Source/UI/Util"
274279
src/ui/util/default_dir.cpp
275280
src/ui/util/default_dir.h
@@ -346,7 +351,6 @@ add_file_folder("UI"
346351
ui/PropEditorDialog.ui
347352
ui/ReinforcementsDialog.ui
348353
ui/RelativeCoordinatesDialog.ui
349-
ui/SelectionDialog.ui
350354
ui/ShieldSystemDialog.ui
351355
ui/SoundEnvironmentDialog.ui
352356
ui/TableViewerDialog.ui
@@ -366,6 +370,7 @@ add_file_folder("UI"
366370
ui/VariableDialog.ui
367371
ui/WingEditorDialog.ui
368372
ui/SaveAsTemplateDialog.ui
373+
ui/SceneBrowserPanel.ui
369374
ui/TemplateBrowserDialog.ui
370375
)
371376

qtfred/src/mission/Editor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1236,14 +1236,14 @@ int Editor::common_object_delete(int obj) {
12361236
//this causes an ugly crash.
12371237
obj_delete(obj);
12381238

1239-
missionChanged();
12401239
return 0;
12411240
}
12421241

12431242
int Editor::delete_object(int obj) {
12441243
int r;
12451244

12461245
r = common_object_delete(obj);
1246+
missionChanged();
12471247
return r;
12481248
}
12491249

qtfred/src/mission/Editor.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ class Editor : public QObject {
114114
/*! Update the game but doesn't render anything. */
115115
void update();
116116

117+
/*! Emit layerVisibilityChanged — called by EditorViewport after toggling a layer. */
118+
void notifyLayerVisibilityChanged() { layerVisibilityChanged(); }
119+
120+
/*! Emit layerStructureChanged — called by EditorViewport when layers are added/removed or objects move between layers. */
121+
void notifyLayerStructureChanged() { layerStructureChanged(); }
122+
117123
signals:
118124
/**
119125
* @brief Signal for when a new mission has been loaded
@@ -139,6 +145,16 @@ class Editor : public QObject {
139145
*/
140146
void objectMarkingChanged(int obj, bool marked);
141147

148+
/**
149+
* @brief A signal emitted when a layer's visibility has been toggled
150+
*/
151+
void layerVisibilityChanged();
152+
153+
/**
154+
* @brief A signal emitted when the layer list changes (add/remove) or an object moves between layers
155+
*/
156+
void layerStructureChanged();
157+
142158
public:
143159
// --- Undo / autosave state ---
144160
int undoAvailable = 0; ///< Whether an undo state (Backup.002) is available

0 commit comments

Comments
 (0)