diff --git a/lib/src/actions/actions.dart b/lib/src/actions/actions.dart index 9d2c2b9e..493ad6bb 100644 --- a/lib/src/actions/actions.dart +++ b/lib/src/actions/actions.dart @@ -4011,6 +4011,22 @@ abstract class ExampleDesignsLoad static Serializer get serializer => _$exampleDesignsLoadSerializer; } +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +// pair lines display + +abstract class BasePairTypeSet + with BuiltJsonSerializable + implements Action, Built { + int get selected_idx; + + /************************ begin BuiltValue boilerplate ************************/ + factory BasePairTypeSet({int selected_idx}) = _$BasePairTypeSet._; + + BasePairTypeSet._(); + + static Serializer get serializer => _$basePairTypeSetSerializer; +} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // change helix position diff --git a/lib/src/reducers/app_ui_state_reducer.dart b/lib/src/reducers/app_ui_state_reducer.dart index 6bd4442d..2f5f329c 100644 --- a/lib/src/reducers/app_ui_state_reducer.dart +++ b/lib/src/reducers/app_ui_state_reducer.dart @@ -4,6 +4,7 @@ import 'package:built_collection/built_collection.dart'; import 'package:redux/redux.dart'; import 'package:scadnano/src/reducers/design_reducer.dart'; import 'package:scadnano/src/reducers/strands_copy_info_reducer.dart'; +import 'package:scadnano/src/state/base_pair_display_type.dart'; import 'package:scadnano/src/state/dna_assign_options.dart'; import 'package:scadnano/src/state/modification.dart'; import 'package:scadnano/src/state/strand.dart'; @@ -230,6 +231,10 @@ bool display_major_tick_widths_all_helices_reducer( bool _, actions.SetDisplayMajorTickWidthsAllHelices action) => action.show; +BasePairDisplayType base_pair_type_idx_reducer( + BasePairDisplayType set_base_pair_display, actions.BasePairTypeSet action) => + BasePairDisplayType.types[action.selected_idx]; + bool show_base_pair_lines_reducer(bool _, actions.ShowBasePairLinesSet action) => action.show_base_pair_lines; bool show_base_pair_lines_with_mismatches_reducer( @@ -451,6 +456,7 @@ AppUIStateStorables app_ui_state_storable_local_reducer(AppUIStateStorables stor ..display_base_offsets_of_major_ticks_only_first_helix = TypedReducer(display_base_offsets_of_major_ticks_only_first_helix_reducer)(storables.display_base_offsets_of_major_ticks_only_first_helix, action) ..display_major_tick_widths = TypedReducer(display_major_tick_widths_reducer)(storables.display_major_tick_widths, action) ..display_major_tick_widths_all_helices = TypedReducer(display_major_tick_widths_all_helices_reducer)(storables.display_major_tick_widths_all_helices, action) + ..base_pair_display_type = TypedReducer(base_pair_type_idx_reducer)(storables.base_pair_display_type, action) ..show_base_pair_lines = TypedReducer(show_base_pair_lines_reducer)(storables.show_base_pair_lines, action) ..show_base_pair_lines_with_mismatches = TypedReducer(show_base_pair_lines_with_mismatches_reducer)(storables.show_base_pair_lines_with_mismatches, action) ..export_svg_text_separately = TypedReducer(export_svg_text_separately_reducer)(storables.export_svg_text_separately, action) diff --git a/lib/src/serializers.dart b/lib/src/serializers.dart index fff3cc41..3e3adf1d 100644 --- a/lib/src/serializers.dart +++ b/lib/src/serializers.dart @@ -6,6 +6,7 @@ import 'package:built_collection/built_collection.dart'; import 'package:built_value/standard_json_plugin.dart'; import 'package:color/color.dart'; import 'package:scadnano/src/dna_file_type.dart'; +import 'package:scadnano/src/state/base_pair_display_type.dart'; import 'package:scadnano/src/state/dna_extensions_move.dart'; import 'package:scadnano/src/state/undo_redo.dart'; import 'package:tuple/tuple.dart'; @@ -137,6 +138,7 @@ part 'serializers.g.dart'; SelectionBoxRemove, SelectionRope, Line, + BasePairDisplayType, SelectionRopeCreate, SelectionRopeMouseMove, SelectionRopeAddPoint, @@ -316,6 +318,7 @@ part 'serializers.g.dart'; StrandPasteKeepColorSet, ExampleDesigns, ExampleDesignsLoad, + BasePairTypeSet, HelixPositionSet, HelixGridPositionSet, InlineInsertionsDeletions, diff --git a/lib/src/state/app_ui_state.dart b/lib/src/state/app_ui_state.dart index 38a9c4a0..25983558 100644 --- a/lib/src/state/app_ui_state.dart +++ b/lib/src/state/app_ui_state.dart @@ -12,6 +12,7 @@ import '../state/local_storage_design_choice.dart'; import 'app_ui_state_storables.dart'; import '../serializers.dart'; +import 'base_pair_display_type.dart'; import 'context_menu.dart'; import 'dialog.dart'; import 'design.dart'; @@ -162,6 +163,8 @@ abstract class AppUIState with BuiltJsonSerializable implements Built storables.show_domain_labels; + BasePairDisplayType get base_pair_display_type => storables.base_pair_display_type; + bool get show_base_pair_lines => storables.show_base_pair_lines; bool get show_base_pair_lines_with_mismatches => storables.show_base_pair_lines_with_mismatches; diff --git a/lib/src/state/app_ui_state_storables.dart b/lib/src/state/app_ui_state_storables.dart index b83fd76e..fdac0928 100644 --- a/lib/src/state/app_ui_state_storables.dart +++ b/lib/src/state/app_ui_state_storables.dart @@ -4,6 +4,7 @@ import 'package:built_value/built_value.dart'; import '../state/local_storage_design_choice.dart'; import '../serializers.dart'; +import 'base_pair_display_type.dart'; import 'select_mode_state.dart'; import 'edit_mode.dart'; import '../constants.dart' as constants; @@ -34,6 +35,8 @@ abstract class AppUIStateStorables bool get show_domain_labels; + BasePairDisplayType get base_pair_display_type; + bool get show_base_pair_lines; bool get show_base_pair_lines_with_mismatches; @@ -139,6 +142,7 @@ abstract class AppUIStateStorables b.show_strand_labels = false; b.show_domain_names = false; b.show_domain_labels = false; + b.base_pair_display_type = BasePairDisplayType.none; b.show_base_pair_lines = false; b.show_base_pair_lines_with_mismatches = false; b.strand_name_font_size = constants.default_strand_name_font_size; diff --git a/lib/src/state/base_pair_display_type.dart b/lib/src/state/base_pair_display_type.dart new file mode 100644 index 00000000..8f664e93 --- /dev/null +++ b/lib/src/state/base_pair_display_type.dart @@ -0,0 +1,54 @@ +import 'dart:html'; + +import 'package:built_value/built_value.dart'; +import 'package:built_value/serializer.dart'; +import 'package:built_collection/built_collection.dart'; + +part 'base_pair_display_type.g.dart'; + +class BasePairDisplayType extends EnumClass { + const BasePairDisplayType._(String name) : super(name); + + @memoized + int get hashCode; + + static Serializer get serializer => _$basePairDisplayTypeSerializer; + + /******************** end BuiltValue boilerplate *********************/ + + static const BasePairDisplayType none = _$none; + static const BasePairDisplayType lines = _$lines; + static const BasePairDisplayType rectangle = _$rectangle; // used to join two Domains with Crossover + static BuiltList types = const [none, lines, rectangle].toBuiltList(); + + static BuiltSet get values => _$values; + + static BasePairDisplayType valueOf(String name) => _$valueOf(name); + + String to_json() => name; + + String display_name() { + // edit this to display a different string than the identifier name above + switch (this) { + case none: + return 'none'; + case lines: + return 'lines'; + case rectangle: + return 'rectangle'; + } + return super.toString(); + } + + @override + String toString() => display_name(); + + static BasePairDisplayType from_json(String the_name) { + for (var val in values) { + if (val.name == the_name) { + return val; + } + } + throw ArgumentError('there is no base pair display type with name "${the_name}"'); + } +} diff --git a/lib/src/state/dialog.dart b/lib/src/state/dialog.dart index 74c53ebb..ca37e13c 100644 --- a/lib/src/state/dialog.dart +++ b/lib/src/state/dialog.dart @@ -47,6 +47,7 @@ class DialogType extends EnumClass { static const DialogType move_selected_helices_to_group = _$move_selected_helices_to_group; static const DialogType export_dna_sequences = _$export_dna_sequences; static const DialogType load_example_dna_design = _$load_example_dna_design; + static const DialogType base_pair_display = _$base_pair_display; static const DialogType add_extension = _$add_extension; static const DialogType set_extension_name = _$set_extension_name; static const DialogType set_extension_display_length_angle = _$set_extension_display_length_angle; diff --git a/lib/src/view/menu.dart b/lib/src/view/menu.dart index 08e98c79..1d84fdb9 100644 --- a/lib/src/view/menu.dart +++ b/lib/src/view/menu.dart @@ -4,6 +4,7 @@ import 'package:built_collection/built_collection.dart'; import 'package:path/path.dart' as path; import 'package:over_react/over_react.dart'; import 'package:over_react/over_react_redux.dart'; +import 'package:scadnano/src/state/base_pair_display_type.dart'; import 'react_bootstrap.dart'; @@ -134,6 +135,7 @@ mixin MenuPropsMixin on UiProps { bool autofit; bool only_display_selected_helices; ExampleDesigns example_designs; + // SetBasePairDisplay base_pair_display_types; bool design_has_insertions_or_deletions; bool undo_stack_empty; bool redo_stack_empty; @@ -1001,6 +1003,10 @@ or real coordinates in nanometers, depending on whether a grid is selected).''' ..id = 'view_menu_base_pairs' ..key = 'view_menu_base_pairs-dropdown' ..className = 'submenu_item')([ + (MenuDropdownItem() + ..on_click = ((_) => app.disable_keyboard_shortcuts_while(base_pair_display_dialog)) + ..display = 'Base pair display' + ..key = 'base-pair-display')(), (MenuBoolean() ..value = props.show_base_pair_lines ..display = 'Base pair lines' @@ -1436,6 +1442,20 @@ However, it may be less stable than the main site.''' int selected_idx = (results[0] as DialogRadio).selected_idx; props.dispatch(actions.ExampleDesignsLoad(selected_idx: selected_idx)); } + + Future base_pair_display_dialog() async { + var dialog = Dialog(title: 'Base pair display', type: DialogType.base_pair_display, items: [ + DialogRadio( + label: 'types', + options: BasePairDisplayType.types.map((v) => v.display_name()), + ), + ]); + List results = await util.dialog(dialog); + if (results == null) return; + + int selected_idx = (results[0] as DialogRadio).selected_idx; + props.dispatch(actions.BasePairTypeSet(selected_idx: selected_idx)); + } } typedef ActionFromIntCreator = actions.Action Function(int);