Skip to content

Commit

Permalink
Merge branch 'dev' into 941-dna-sequences-justified
Browse files Browse the repository at this point in the history
  • Loading branch information
rayzhuca authored Jan 27, 2024
2 parents bf718f2 + 2cfac1f commit d0adc28
Show file tree
Hide file tree
Showing 29 changed files with 346 additions and 96 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# scadnano

[scadnano](http://scadnano.org)
("
scriptable-cadnano", [source code repository here](https://github.com/UC-Davis-molecular-computing/scadnano))
("scriptable-cadnano", [source code repository here](https://github.com/UC-Davis-molecular-computing/scadnano))
is a program for designing synthetic DNA structures such as DNA origami.
The scadnano project is developed and maintained by the UC Davis Molecular Computing group.
Note that [cadnano](https://cadnano.org) is a separate project, developed and maintained by
Expand Down
19 changes: 19 additions & 0 deletions lib/src/actions/actions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4369,6 +4369,25 @@ abstract class DisablePngCachingDnaSequencesSet
_$disablePngCachingDnaSequencesSetSerializer;
}

abstract class RetainStrandColorOnSelectionSet
with BuiltJsonSerializable
implements Action, Built<RetainStrandColorOnSelectionSet, RetainStrandColorOnSelectionSetBuilder> {
bool get retain_strand_color_on_selection;

/************************ begin BuiltValue boilerplate ************************/
factory RetainStrandColorOnSelectionSet(bool retain_strand_color_on_selection) =>
RetainStrandColorOnSelectionSet.from(
(b) => b..retain_strand_color_on_selection = retain_strand_color_on_selection);

factory RetainStrandColorOnSelectionSet.from(
[void Function(RetainStrandColorOnSelectionSetBuilder) updates]) = _$RetainStrandColorOnSelectionSet;

RetainStrandColorOnSelectionSet._();

static Serializer<RetainStrandColorOnSelectionSet> get serializer =>
_$retainStrandColorOnSelectionSetSerializer;
}

abstract class DisplayReverseDNARightSideUpSet
with BuiltJsonSerializable
implements Action, Built<DisplayReverseDNARightSideUpSet, DisplayReverseDNARightSideUpSetBuilder> {
Expand Down
1 change: 1 addition & 0 deletions lib/src/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,7 @@ const css_selector_deletion = 'deletion-cross';
const css_selector_insertion_group = 'insertion-group';
const css_selector_deletion_group = 'deletion-group';
const css_selector_selected = 'selected';
const css_selector_selected_pink = 'selected-pink';

const css_selector_context_menu_item_disabled = 'context_menu_item_disabled';

Expand Down
41 changes: 31 additions & 10 deletions lib/src/middleware/export_svg.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export_svg_middleware(Store<AppState> store, dynamic action, NextDispatcher next
action.type == actions.ExportSvgType.selected) {
var elt = document.getElementById("main-view-svg");
if (action.type == actions.ExportSvgType.selected) {
List<Element> selected_elts = get_selected_strands(store);
List<Element> selected_elts = get_selected_svg_elements(store.state);
if (selected_elts.length == 0) {
window.alert("No strands are selected, so there is nothing to export.\n"
"Please select some strands before choosing this option.");
Expand All @@ -64,7 +64,7 @@ export_svg_middleware(Store<AppState> store, dynamic action, NextDispatcher next
_export_from_element(elt, 'side');
}
} else if (action is actions.CopySelectedStandsToClipboardImage) {
List<Element> selected_elts = get_selected_strands(store);
List<Element> selected_elts = get_selected_svg_elements(store.state);
if (selected_elts.length != 0) {
_copy_from_elements(selected_elts);
}
Expand All @@ -75,18 +75,38 @@ export_svg_middleware(Store<AppState> store, dynamic action, NextDispatcher next
}
}

List<Element> get_selected_strands(Store<AppState> store) {
var selected_strands = store.state.ui_state.selectables_store.selected_strands;
List<Element> get_selected_svg_elements(AppState state) {
BuiltSet<Strand> selected_strands = state.ui_state.selectables_store.selected_strands;
List<Element> selected_elts = [];
if (selected_strands.length != 0) {
for (var strand in selected_strands) {
if (app.state.ui_state.show_base_pair_lines) {
var base_pairs = state.ui_state.show_base_pair_lines_with_mismatches
? state.design.selected_base_pairs_with_mismatches(selected_strands)
: state.design.selected_base_pairs(selected_strands);
selected_elts.addAll(get_svg_elements_of_base_pairs(base_pairs));
}
selected_elts.addAll(get_svg_elements_of_strands(selected_strands));
return selected_elts;
}

List<Element> get_svg_elements_of_strands(BuiltSet<Strand> strands) {
List<Element> elts = [];
if (strands.length != 0) {
for (var strand in strands) {
var strand_elt = document.getElementById(strand.id);
var dna_seq_elt = document.getElementById('dna-sequence-${strand.id}');
var mismatch_elts = document.getElementsByClassName('mismatch-${strand.id}');
selected_elts.addAll([strand_elt, if (dna_seq_elt != null) dna_seq_elt, ...mismatch_elts]);
elts.addAll([strand_elt, if (dna_seq_elt != null) dna_seq_elt, ...mismatch_elts]);
}
}
return selected_elts;
return elts;
}

List<Element> get_svg_elements_of_base_pairs(BuiltMap<int, BuiltList<int>> base_pairs) {
List<Element> elts = [];
for (int helix in base_pairs.keys) {
elts.addAll(base_pairs[helix].map((offset) => document.getElementById('base_pair-${helix}-${offset}')));
}
return elts;
}

List<double> rotate_vector(List<double> vec, double ang) {
Expand Down Expand Up @@ -284,10 +304,11 @@ _copy_from_elements(List<Element> svg_elements) {

_export_from_element(Element svg_element, String filename_append) {
var cloned_svg_element_with_style;
if (filename_append != "selected")
if (filename_append != "selected") {
cloned_svg_element_with_style = clone_and_apply_style(svg_element);
else
} else {
cloned_svg_element_with_style = svg_element;
}
// if element is not an svg element (it can be a child element of svg e.g. groups, lines, text, etc), wrap in svg tag
if (!(svg_element is svg.SvgSvgElement))
cloned_svg_element_with_style = SvgSvgElement()..children = [cloned_svg_element_with_style];
Expand Down
4 changes: 4 additions & 0 deletions lib/src/reducers/app_ui_state_reducer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ int slice_bar_offset_set_reducer(int _, actions.SliceBarOffsetSet action) => act
bool disable_png_caching_dna_sequences_reducer(bool _, actions.DisablePngCachingDnaSequencesSet action) =>
action.disable_png_caching_dna_sequences;

bool retain_strand_color_on_selection_reducer(bool _, actions.RetainStrandColorOnSelectionSet action) =>
action.retain_strand_color_on_selection;

bool display_reverse_DNA_right_side_up_reducer(bool _, actions.DisplayReverseDNARightSideUpSet action) =>
action.display_reverse_DNA_right_side_up;

Expand Down Expand Up @@ -437,6 +440,7 @@ AppUIStateStorables app_ui_state_storable_local_reducer(AppUIStateStorables stor
..show_slice_bar = TypedReducer<bool, actions.ShowSliceBarSet>(show_slice_bar_reducer)(storables.show_slice_bar, action)
..slice_bar_offset = TypedReducer<int, actions.SliceBarOffsetSet>(slice_bar_offset_set_reducer)(storables.slice_bar_offset, action)
..disable_png_caching_dna_sequences = TypedReducer<bool, actions.DisablePngCachingDnaSequencesSet>(disable_png_caching_dna_sequences_reducer)(storables.disable_png_caching_dna_sequences, action)
..retain_strand_color_on_selection = TypedReducer<bool, actions.RetainStrandColorOnSelectionSet>(retain_strand_color_on_selection_reducer)(storables.retain_strand_color_on_selection, action)
..display_reverse_DNA_right_side_up = TypedReducer<bool, actions.DisplayReverseDNARightSideUpSet>(display_reverse_DNA_right_side_up_reducer)(storables.display_reverse_DNA_right_side_up, action)
..local_storage_design_choice = TypedReducer<LocalStorageDesignChoice, actions.LocalStorageDesignChoiceSet>(local_storage_design_choice_reducer)(storables.local_storage_design_choice, action).toBuilder()
..clear_helix_selection_when_loading_new_design = TypedReducer<bool, actions.ClearHelixSelectionWhenLoadingNewDesignSet>(clear_helix_selection_when_loading_new_design_set_reducer)(storables.clear_helix_selection_when_loading_new_design, action)
Expand Down
1 change: 1 addition & 0 deletions lib/src/serializers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ part 'serializers.g.dart';
SetDisplayMajorTickWidthsAllHelices,
SliceBarOffsetSet,
DisablePngCachingDnaSequencesSet,
RetainStrandColorOnSelectionSet,
DisplayReverseDNARightSideUpSet,
SliceBarMoveStart,
SliceBarMoveStop,
Expand Down
2 changes: 2 additions & 0 deletions lib/src/state/app_ui_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@ abstract class AppUIState with BuiltJsonSerializable implements Built<AppUIState

bool get disable_png_caching_dna_sequences => storables.disable_png_caching_dna_sequences;

bool get retain_strand_color_on_selection => storables.retain_strand_color_on_selection;

bool get display_reverse_DNA_right_side_up => storables.display_reverse_DNA_right_side_up;

bool get show_mouseover_data => storables.show_mouseover_data;
Expand Down
3 changes: 3 additions & 0 deletions lib/src/state/app_ui_state_storables.dart
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ abstract class AppUIStateStorables

bool get disable_png_caching_dna_sequences;

bool get retain_strand_color_on_selection;

bool get display_reverse_DNA_right_side_up;

bool get selection_box_intersection;
Expand Down Expand Up @@ -175,6 +177,7 @@ abstract class AppUIStateStorables
b.show_slice_bar = false;
b.slice_bar_offset = null;
b.disable_png_caching_dna_sequences = false;
b.retain_strand_color_on_selection = false;
b.display_reverse_DNA_right_side_up = false;
b.local_storage_design_choice = LocalStorageDesignChoice().toBuilder();
b.clear_helix_selection_when_loading_new_design = false;
Expand Down
24 changes: 21 additions & 3 deletions lib/src/state/design.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2101,21 +2101,39 @@ abstract class Design with UnusedFields implements Built<Design, DesignBuilder>,

/// maps each helix_idx to a list of offsets where there is a complementary base pair on each strand
@memoized
BuiltMap<int, BuiltList<int>> get base_pairs => this._base_pairs(false);
BuiltMap<int, BuiltList<int>> get base_pairs => this._base_pairs(false, strands.toBuiltSet());

/// maps each helix_idx to a list of offsets where there is a base on each strand,
/// NOT necessarily complementary
@memoized
BuiltMap<int, BuiltList<int>> get base_pairs_with_mismatches => this._base_pairs(true);
BuiltMap<int, BuiltList<int>> get base_pairs_with_mismatches =>
this._base_pairs(true, strands.toBuiltSet());

BuiltMap<int, BuiltList<int>> _base_pairs(bool allow_mismatches) {
// returns a subset of base_pairs that is connected to selected_strands
BuiltMap<int, BuiltList<int>> selected_base_pairs(BuiltSet<Strand> selected_strands) =>
this._base_pairs(false, selected_strands);

// returns a subset of base_pairs_with_mismatches that is connected to selected_strands
BuiltMap<int, BuiltList<int>> selected_base_pairs_with_mismatches(BuiltSet<Strand> selected_strands) =>
this._base_pairs(true, selected_strands);

BuiltMap<int, BuiltList<int>> _base_pairs(bool allow_mismatches, BuiltSet<Strand> selected_strands) {
var base_pairs = Map<int, BuiltList<int>>();
BuiltSet<Domain> selected_domains = selected_strands
.map((s) => s.substrands)
.expand((x) => x)
.where((x) => x is Domain)
.map((x) => x as Domain)
.toBuiltSet();
for (int idx in this.helices.keys) {
List<int> offsets = [];
List<Tuple2<Domain, Domain>> overlapping_domains = find_overlapping_domains_on_helix(idx);
for (var domain_pair in overlapping_domains) {
Domain dom1 = domain_pair.item1;
Domain dom2 = domain_pair.item2;
if (!selected_domains.contains(dom1) || !selected_domains.contains(dom2)) {
continue;
}
var start_and_end = dom1.compute_overlap(dom2);
int start = start_and_end.item1;
int end = start_and_end.item2;
Expand Down
3 changes: 3 additions & 0 deletions lib/src/view/design_main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ UiFactory<DesignMainProps> ConnectedDesignMain = connect<AppState, DesignMainPro
..invert_y = state.ui_state.invert_y
..selection_rope = state.ui_state.selection_rope
..disable_png_caching_dna_sequences = state.ui_state.disable_png_caching_dna_sequences
..retain_strand_color_on_selection = state.ui_state.retain_strand_color_on_selection
..display_reverse_DNA_right_side_up = state.ui_state.display_reverse_DNA_right_side_up);
}
},
Expand Down Expand Up @@ -137,6 +138,7 @@ mixin DesignMainPropsMixin on UiProps {
String displayed_group_name;
SelectionRope selection_rope;
bool disable_png_caching_dna_sequences;
bool retain_strand_color_on_selection;
bool display_reverse_DNA_right_side_up;
BuiltMap<int, Point<num>> helix_idx_to_svg_position_map;
bool invert_y;
Expand Down Expand Up @@ -263,6 +265,7 @@ class DesignMainComponent extends UiComponent2<DesignMainProps> {
..only_display_selected_helices = props.only_display_selected_helices
..helix_idx_to_svg_position_map = props.helix_idx_to_svg_position_map
..disable_png_caching_dna_sequences = props.disable_png_caching_dna_sequences
..retain_strand_color_on_selection = props.retain_strand_color_on_selection
..display_reverse_DNA_right_side_up = props.display_reverse_DNA_right_side_up
..key = 'dna-sequences')(),

Expand Down
12 changes: 8 additions & 4 deletions lib/src/view/design_main_base_pair_lines.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:html';

import 'package:over_react/over_react.dart';
import 'package:built_collection/built_collection.dart';
import 'package:scadnano/scadnano.dart';
import 'package:scadnano/src/state/group.dart';
import 'package:scadnano/src/state/helix.dart';

Expand All @@ -28,14 +29,16 @@ mixin DesignMainBasePairLinesProps on UiProps {
class DesignMainBasePairLinesComponent extends UiComponent2<DesignMainBasePairLinesProps> with PureComponent {
@override
render() {
List<ReactElement> base_pair_lines_components = this._create_base_pair_lines_components();
List<ReactElement> base_pair_lines_components =
this.create_base_pair_lines_components(app.state.design.strands.toBuiltSet());
return (Dom.g()..className = 'base-pair-lines-main-view')(base_pair_lines_components);
}

List<ReactElement> _create_base_pair_lines_components() {
List<ReactElement> create_base_pair_lines_components(BuiltSet<Strand> strands) {
List<ReactElement> base_pair_lines_components = [];
var base_pairs =
props.with_mismatches ? props.design.base_pairs_with_mismatches : props.design.base_pairs;
BuiltMap<int, BuiltList<int>> base_pairs = props.with_mismatches
? props.design.selected_base_pairs_with_mismatches(strands)
: props.design.selected_base_pairs(strands);

for (int helix_idx in base_pairs.keys) {
if (!props.only_display_selected_helices || props.side_selected_helix_idxs.contains(helix_idx)) {
Expand All @@ -52,6 +55,7 @@ class DesignMainBasePairLinesComponent extends UiComponent2<DesignMainBasePairLi
var base_svg_forward_pos = helix.svg_base_pos(offset, true, svg_position_y);
var base_svg_reverse_pos = helix.svg_base_pos(offset, false, svg_position_y);
var base_pair_line = (Dom.line()
..id = 'base_pair-${helix_idx}-${offset}'
..x1 = base_svg_forward_pos.x
..y1 = base_svg_forward_pos.y
..x2 = base_svg_reverse_pos.x
Expand Down
2 changes: 1 addition & 1 deletion lib/src/view/design_main_dna_sequence.dart
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ class DesignMainDNASequenceComponent extends UiComponent2<DesignMainDNASequenceP
..startOffset = start_offset
..style = style_map);
return (Dom.text()
..key = 'extension-dna-'
..key = 'extension-dna-${ext.is_5p ? "5'" : "3'"}'
'H${ext.adjacent_domain.helix},${ext.adjacent_domain.start}-${ext.adjacent_domain.end}'
..dy = dy)(text_path_props(subseq));
}
Expand Down
1 change: 1 addition & 0 deletions lib/src/view/design_main_dna_sequences.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ mixin DesignMainDNASequencesProps on UiProps {
bool only_display_selected_helices;
BuiltMap<int, Point<num>> helix_idx_to_svg_position_map;
bool disable_png_caching_dna_sequences;
bool retain_strand_color_on_selection;
bool display_reverse_DNA_right_side_up;
}

Expand Down
Loading

0 comments on commit d0adc28

Please sign in to comment.