@@ -146,8 +146,6 @@ struct sexp_list_item {
146146 void add_data (const char * str, int t = (SEXPT_STRING | SEXPT_VALID ));
147147 // Append another linked list to the end of this one
148148 void add_list (sexp_list_item* list);
149- // Copy fields from src without transferring ownership of the next pointer
150- void shallow_copy (const sexp_list_item* src);
151149 // Delete this item and all subsequent items in the linked list
152150 void destroy ();
153151};
@@ -307,7 +305,7 @@ struct SexpContextMenuState {
307305 // Campaign mode filtering
308306 bool campaign_mode = false ;
309307
310- // Data lists for add/replace data submenus (caller must call destroy())
308+ // Data lists for add/replace data submenus
311309 // Entries with op >= 0 are operators to enable; op < 0 are data items for the submenu
312310 sexp_list_item* add_data_list = nullptr ;
313311 int add_data_opf_type = 0 ; // OPF_* type, needed for OPF_VARIABLE_NAME display
@@ -340,7 +338,66 @@ struct SexpContextMenuState {
340338 bool show_container_data = false ;
341339 SCP_vector<ContainerEntry> replace_container_data;
342340
343- // Free the dynamically allocated data lists (must be called when done with this state)
341+ SexpContextMenuState () = default ;
342+ ~SexpContextMenuState ()
343+ {
344+ cleanup ();
345+ }
346+ SexpContextMenuState (const SexpContextMenuState&) = delete ;
347+ SexpContextMenuState& operator =(const SexpContextMenuState&) = delete ;
348+ SexpContextMenuState (SexpContextMenuState&& other) noexcept
349+ {
350+ *this = std::move (other);
351+ }
352+ SexpContextMenuState& operator =(SexpContextMenuState&& other) noexcept
353+ {
354+ if (this != &other) {
355+ cleanup ();
356+
357+ is_labeled_root = other.is_labeled_root ;
358+ is_root_editable = other.is_root_editable ;
359+ can_edit_text = other.can_edit_text ;
360+ can_edit_comment = other.can_edit_comment ;
361+ can_edit_bg_color = other.can_edit_bg_color ;
362+ can_add_variable = other.can_add_variable ;
363+ can_modify_variable = other.can_modify_variable ;
364+ can_copy = other.can_copy ;
365+ can_cut = other.can_cut ;
366+ can_paste = other.can_paste ;
367+ can_paste_add = other.can_paste_add ;
368+ can_delete = other.can_delete ;
369+ can_replace_number = other.can_replace_number ;
370+ can_replace_string = other.can_replace_string ;
371+ can_add_number = other.can_add_number ;
372+ can_add_string = other.can_add_string ;
373+ add_type = other.add_type ;
374+ replace_type = other.replace_type ;
375+ insert_opf_type = other.insert_opf_type ;
376+ add_count = other.add_count ;
377+ replace_count = other.replace_count ;
378+ modify_variable = other.modify_variable ;
379+ campaign_mode = other.campaign_mode ;
380+ add_data_list = other.add_data_list ;
381+ add_data_opf_type = other.add_data_opf_type ;
382+ replace_data_list = other.replace_data_list ;
383+ add_enabled_op_indices = std::move (other.add_enabled_op_indices );
384+ replace_enabled_op_indices = std::move (other.replace_enabled_op_indices );
385+ op_add_enabled = std::move (other.op_add_enabled );
386+ op_replace_enabled = std::move (other.op_replace_enabled );
387+ op_insert_enabled = std::move (other.op_insert_enabled );
388+ replace_variables = std::move (other.replace_variables );
389+ show_container_names = other.show_container_names ;
390+ replace_container_names = std::move (other.replace_container_names );
391+ show_container_data = other.show_container_data ;
392+ replace_container_data = std::move (other.replace_container_data );
393+
394+ other.add_data_list = nullptr ;
395+ other.replace_data_list = nullptr ;
396+ }
397+ return *this ;
398+ }
399+
400+ // Free the dynamically allocated data lists (safe to call multiple times)
344401 void cleanup () {
345402 if (add_data_list) { add_data_list->destroy (); add_data_list = nullptr ; }
346403 if (replace_data_list) { replace_data_list->destroy (); replace_data_list = nullptr ; }
@@ -506,7 +563,7 @@ class SexpTreeModel {
506563
507564 // Analyze the current selection and compute which context menu actions are available.
508565 // The returned state includes operator enablement, variable/container menus, and
509- // clipboard paste validation. Caller must call cleanup() on the result .
566+ // clipboard paste validation. Returned state owns temporary lists and cleans them up automatically .
510567 SexpContextMenuState compute_context_menu_state ();
511568 // Returns true if the given operator value should be hidden from menus (deprecated/hidden ops)
512569 static bool is_operator_hidden (int op_value);
0 commit comments