diff --git a/lib/src/actions/actions.dart b/lib/src/actions/actions.dart index 46e6c49f..4b825d35 100644 --- a/lib/src/actions/actions.dart +++ b/lib/src/actions/actions.dart @@ -79,6 +79,8 @@ mixin UndoableAction implements DesignChangingAction { /// Fast actions are not dispatched to normal store for optimization abstract class FastAction extends Action {} +abstract class ChangePropertiesAction extends Action {} + // Wrap an UndoableAction in a SkipUndo in order to apply it, but skip its effect on the undo/redo stacks. abstract class SkipUndo with BuiltJsonSerializable implements Action, Built { UndoableAction get undoable_action; @@ -383,7 +385,7 @@ abstract class SelectModesSet // used to set or remove (set name=null to remove) abstract class StrandNameSet with BuiltJsonSerializable, UndoableAction - implements SingleStrandAction, Built { + implements SingleStrandAction, ChangePropertiesAction, Built { String? get name; Strand get strand; @@ -405,7 +407,7 @@ abstract class StrandNameSet // used to set or remove (set name=null to remove) abstract class StrandLabelSet with BuiltJsonSerializable, UndoableAction - implements SingleStrandAction, Built { + implements SingleStrandAction, ChangePropertiesAction, Built { String? get label; Strand get strand; @@ -428,7 +430,7 @@ abstract class StrandLabelSet // used for Domains, Loopouts, and Extensions abstract class SubstrandNameSet with BuiltJsonSerializable, UndoableAction - implements StrandPartAction, Built { + implements StrandPartAction, ChangePropertiesAction, Built { String? get name; Substrand get substrand; @@ -454,7 +456,7 @@ abstract class SubstrandNameSet // used for Domains, Loopouts, and Extensions abstract class SubstrandLabelSet with BuiltJsonSerializable, UndoableAction - implements StrandPartAction, Built { + implements StrandPartAction, ChangePropertiesAction, Built { String? get label; Substrand get substrand; @@ -2320,7 +2322,7 @@ abstract class ExtensionDisplayLengthAngleSet abstract class ExtensionAdd with BuiltJsonSerializable, UndoableAction - implements SingleStrandAction, Built { + implements SingleStrandAction, ChangePropertiesAction, Built { Strand get strand; bool get is_5p; @@ -2639,7 +2641,7 @@ abstract class JoinStrandsByMultipleCrossovers abstract class StrandsReflect with BuiltJsonSerializable - implements Action, Built { + implements Action, ChangePropertiesAction, Built { BuiltList get strands; bool get horizontal; @@ -3279,7 +3281,7 @@ abstract class HelixGroupMoveCommit abstract class AssignDNA with BuiltJsonSerializable, UndoableAction - implements Built { + implements ChangePropertiesAction, Built { Strand get strand; DNAAssignOptions get dna_assign_options; @@ -3311,7 +3313,9 @@ abstract class AssignDNA /// assign/replace its DNA with the complement of those abstract class AssignDNAComplementFromBoundStrands with BuiltJsonSerializable, UndoableAction - implements Built { + implements + ChangePropertiesAction, + Built { BuiltList get strands; /************************ begin BuiltValue boilerplate ************************/ @@ -3365,6 +3369,7 @@ abstract class AssignDomainNameComplementFromBoundStrands abstract class AssignDomainNameComplementFromBoundDomains with BuiltJsonSerializable, UndoableAction implements + ChangePropertiesAction, Built { BuiltList get domains; @@ -3391,7 +3396,7 @@ abstract class AssignDomainNameComplementFromBoundDomains abstract class RemoveDNA with BuiltJsonSerializable, UndoableAction - implements SingleStrandAction, Built { + implements SingleStrandAction, ChangePropertiesAction, Built { Strand get strand; bool get remove_complements; @@ -3641,6 +3646,7 @@ abstract class ScalePurificationVendorFieldsAssign with BuiltJsonSerializable, UndoableAction implements SingleStrandAction, + ChangePropertiesAction, Built { Strand get strand; @@ -3663,7 +3669,10 @@ abstract class ScalePurificationVendorFieldsAssign // assign plate/well IDT fields of strands abstract class PlateWellVendorFieldsAssign with BuiltJsonSerializable, UndoableAction - implements SingleStrandAction, Built { + implements + SingleStrandAction, + ChangePropertiesAction, + Built { Strand get strand; VendorFields get vendor_fields; @@ -3684,7 +3693,10 @@ abstract class PlateWellVendorFieldsAssign // remove plate/well vendor fields of strands abstract class PlateWellVendorFieldsRemove with BuiltJsonSerializable, UndoableAction - implements SingleStrandAction, Built { + implements + SingleStrandAction, + ChangePropertiesAction, + Built { Strand get strand; /************************ begin BuiltValue boilerplate ************************/ @@ -3702,7 +3714,10 @@ abstract class PlateWellVendorFieldsRemove // remove vendor fields of strands abstract class VendorFieldsRemove with BuiltJsonSerializable, UndoableAction - implements SingleStrandAction, Built { + implements + SingleStrandAction, + ChangePropertiesAction, + Built { Strand get strand; /************************ begin BuiltValue boilerplate ************************/ @@ -4130,7 +4145,7 @@ abstract class SingleStrandAction implements Action { abstract class ScaffoldSet with BuiltJsonSerializable, UndoableAction - implements SingleStrandAction, Built { + implements SingleStrandAction, ChangePropertiesAction, Built { Strand get strand; bool get is_scaffold; @@ -4151,7 +4166,10 @@ abstract class ScaffoldSet abstract class StrandOrSubstrandColorSet with BuiltJsonSerializable, UndoableAction - implements SingleStrandAction, Built { + implements + SingleStrandAction, + ChangePropertiesAction, + Built { Strand get strand; Substrand? get substrand; diff --git a/lib/src/middleware/all_middleware.dart b/lib/src/middleware/all_middleware.dart index 5d3cf1c7..9e7deb7d 100644 --- a/lib/src/middleware/all_middleware.dart +++ b/lib/src/middleware/all_middleware.dart @@ -1,4 +1,5 @@ import 'package:redux/redux.dart'; +import 'package:scadnano/src/middleware/reselected_strands_after_props_updated.dart'; import 'package:scadnano/src/middleware/system_clipboard.dart'; import '../state/app_state.dart'; @@ -68,6 +69,7 @@ final all_middleware = List>.unmodifiable([ reselect_moved_dna_extension_ends_middleware, reselect_moved_copied_strands_middleware, reselect_moved_domains_middleware, + reselected_strands_after_props_updated, selections_intersect_box_compute_middleware, insertion_deletion_batching_middleware, adjust_grid_position_middleware, diff --git a/lib/src/middleware/reselected_strands_after_props_updated.dart b/lib/src/middleware/reselected_strands_after_props_updated.dart new file mode 100644 index 00000000..4bde61e9 --- /dev/null +++ b/lib/src/middleware/reselected_strands_after_props_updated.dart @@ -0,0 +1,37 @@ +import 'package:built_collection/built_collection.dart'; +import 'package:redux/redux.dart'; +import 'package:scadnano/src/actions/actions.dart' as actions; +import 'package:scadnano/src/state/app_state.dart'; +import 'package:scadnano/src/state/design.dart'; +import 'package:scadnano/src/state/strand.dart'; + +bool are_batch_actions(dynamic action) { + for (var action in action.actions) { + if (!((action is actions.SingleStrandAction || action is actions.StrandPartAction))) { + return false; + } + } + return true; +} + +reselected_strands_after_props_updated(Store store, action, NextDispatcher next) { + List prevIds = store.state.ui_state.selectables_store.selected_strands.map((s) => s.id).toList(); + if ((action is actions.ChangePropertiesAction || + (action is actions.ChangePropertiesAction && + action is actions.BatchAction && + are_batch_actions(action))) && + prevIds.length > 1) { + next(action); + + List new_strands = []; + Design newDesign = store.state.design; + for (var strand in newDesign.strands) { + if (prevIds.contains(strand.id)) { + new_strands.add(strand); + } + } + store.dispatch(actions.SelectAll(selectables: new_strands.toBuiltList(), only: true)); + } else { + next(action); + } +}